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

时间:2014-03-16 03:14:04

标签: embedded arm stm32

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

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA
                       | RCC_APB2Periph_AFIO
                       | RCC_APB2Periph_USART1, ENABLE);

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

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,  ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,   ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

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

(我已经遗漏了之后的所有代码,初始化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>

一次一个时钟:

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>
  ...

这里是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

0x40021000是RCC外设的基地址; #24偏移量指向RCC_APB2ENR寄存器,该寄存器对于每个启用的时钟都有一位。 (有关详细信息,请参阅RM0008的第109页。)

2 个答案:

答案 0 :(得分:4)

嗯,我想我弄明白了,结果却不是硬件问题......我的工具链配置存在很多问题:

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

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

  3. 我的启动文件未包含对__libc_init_array的调用。这导致在链接时删除一些更多的初始化代码。

  4. 我仍然不确定为什么要拆分周边时钟初始化设法解决这个问题。也许代码数量的变化会使某些东西碰到正确的对齐?无论如何,到目前为止,解决潜在的问题似乎已经修补了一些问题(尽管我仍然对一些剩余的启动代码持怀疑态度。)

答案 1 :(得分:1)

您可能想让我们确切地知道您正在使用哪种设备和/或查看该设备的勘误表。例如,STM32L100x6 / 8 / B-A(和其他)设备的勘误表具有以下内容(http://www.st.com/web/en/resource/technical/document/errata_sheet/DM00097022.pdf):

  

2.6.1 RCC外设时钟使能后的延迟

     

描述

     

RCC外设时钟使能与有效之间的延迟   应考虑外围设备以便进行管理   外设读/写寄存器。

     

此延迟取决于外围设备的映射:

     
      
  • 如果外围设备映射在AHB上:延迟应该等于2个AHB周期。
  •   
  • 如果外设映射到APB:延迟应该等于1 +(AHB / APB预分频器)周期。
  •   
     

变通方法

     
      
  1. 使用DSB指令停止Cortex-M CPU管道,直到指令完成。
  2.   
  3. 插入&#34; n&#34; RCC之间的NOP使能位写入和外设寄存器写入(对于AHB外设,n = 2,n = 1 + AHB / APB   APB外设的预分频器。)
  4.   

这听起来并不像你的问题,但它可能是相关的(也许一次一个启用会引入一个必要的延迟)。