为什么我必须一次启用一个外设时钟?

dus*_*uff 7 embedded arm stm32

在最小的STM32应用程序中,我编写了将字符写入USART1,当我尝试同时启用我需要的所有时钟时,USART似乎不起作用:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA
                       | RCC_APB2Periph_AFIO
                       | RCC_APB2Periph_USART1, ENABLE);
Run Code Online (Sandbox Code Playgroud)

但是,当我一次启用一个时钟时,它可以工作:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,  ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,   ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
Run Code Online (Sandbox Code Playgroud)

为什么是这样?是否有特定的顺序必须启用这些时钟?(如果是这样,这在哪里记录?)

(我在此之后省略了所有代码,初始化GPIO引脚,设置USART,并开始发送内容,因为它在每个应用程序中都是相同的.如果相关,请告诉我,我会包含它.)

我正在使用的设备是STM32F103VET6.


由于对所涉及的装配有一些兴趣,这里就是.对于所有三个时钟:

00000000 <main>:
   0:   b590            push    {r4, r7, lr}
   2:   b089            sub     sp, #36 ; 0x24
   4:   af00            add     r7, sp, #0
   6:   f244 0014       movw    r0, #16389      ; 0x4005
   a:   2101            movs    r1, #1
   c:   f7ff fffe       bl      0 <RCC_APB2PeriphClockCmd>
Run Code Online (Sandbox Code Playgroud)

一次一个时钟:

00000000 <main>:
   0:   b590            push    {r4, r7, lr}
   2:   b089            sub     sp, #36 ; 0x24
   4:   af00            add     r7, sp, #0
   6:   2004            movs    r0, #4
   8:   2101            movs    r1, #1
   a:   f7ff fffe       bl      0 <RCC_APB2PeriphClockCmd>
   e:   2001            movs    r0, #1
  10:   2101            movs    r1, #1
  12:   f7ff fffe       bl      0 <RCC_APB2PeriphClockCmd>
  16:   f44f 4080       mov.w   r0, #16384      ; 0x4000
  1a:   2101            movs    r1, #1
  1c:   f7ff fffe       bl      0 <RCC_APB2PeriphClockCmd>
  ...
Run Code Online (Sandbox Code Playgroud)

这是RCC_APB2PeriphClockCmd:

00000000 <RCC_APB2PeriphClockCmd>:
   0:   4b04            ldr     r3, [pc, #16]   ; (14 <RCC_APB2PeriphClockCmd+0x14>)
   2:   699a            ldr     r2, [r3, #24]
   4:   b109            cbz     r1, a <RCC_APB2PeriphClockCmd+0xa>
   6:   4310            orrs    r0, r2
   8:   e001            b.n     e <RCC_APB2PeriphClockCmd+0xe>
   a:   ea22 0000       bic.w   r0, r2, r0
   e:   6198            str     r0, [r3, #24]
  10:   4770            bx      lr
  12:   bf00            nop
  14:   40021000        .word   0x40021000
Run Code Online (Sandbox Code Playgroud)

0x40021000是RCC外设的基地址; 该#24偏移指向RCC_APB2ENR寄存器,其中有一个有点针对要启用的每个时钟.(详情请参阅RM0008第109页.)

小智 5

好吧,我想我想通了,结果证明根本不是硬件问题……我的工具链配置有很多问题:

  1. 我正在设置-nostdlib。这导致无法生成一些全局初始化代码。我不确定这有多重要,但其他问题包括:

  2. 我没有将-mthumb其他 CPU 选项传递给链接器。这导致一些生成的启动代码是垃圾。

  3. 我的启动文件不包含对__libc_init_array. 这导致更多的初始化代码在链接时被丢弃。

我仍然不确定为什么拆分外围时钟初始化设法解决这个问题。也许代码量的变化会影响到正确的对齐方式?无论如何,到目前为止,解决潜在问题似乎已经解决了一些问题(尽管我仍然对一些剩余的启动代码持怀疑态度)。