STM32启用RCC外设时钟后,如何正确实现2时钟周期延迟?
STM32外设时钟使能后2时钟周期延迟的正确实现
先明确背景:根据《RM0454 STM32G0x0参考手册》5.2.16节的说明,外设时钟使能位带有同步机制以消除毛刺,设置使能位后必须等待2个对应总线的时钟周期(挂载AHB的外设等2个AHB周期,挂载APB的外设等2个APB周期),外设时钟才会真正激活。STM32L0的HAL驱动注释也明确了这一要求。
下面两种实现方式都是正确的,只是适用场景不同:
示例1:读取RCC外设时钟使能寄存器
RCC->AHB1ENR |= (1 << RCC_AHB1ENR_GPIOAEN_Pos); // do two dummy reads after enabling the peripheral clock, as per the errata volatile uint32_t dummy; dummy = RCC->AHB1ENR; dummy = RCC->AHB1ENR;
- 有效性说明:RCC的时钟使能寄存器大多挂载在AHB总线上,两次
volatile读取会强制CPU执行两次总线访问,每次访问至少占用1个AHB时钟周期,刚好满足2个周期的延迟要求。如果是APB外设,读取对应的APB使能寄存器(比如RCC->APB1ENR),两次读取也能保证2个APB周期的延迟——因为APB总线的访问响应会对齐自身时钟。 - 优势:代码简洁,不依赖其他外设,通用性强,无需考虑外设是否存在于目标芯片。
- 适用场景:大多数常规开发场景,尤其是需要跨芯片移植的代码。
示例2:读取对应总线的外设寄存器
void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles) { volatile uint32_t unused __attribute__((unused)); if (bus == BUS_AHB) { while (cycles--) unused = STM32_DMA1_REGS->isr; } else { /* APB */ while (cycles--) unused = STM32_USART_BRR(STM32_USART1_BASE); } }
- 有效性说明:直接读取挂载在目标总线上的外设寄存器,每次读取会消耗1个对应总线的时钟周期,循环2次就能精准匹配要求的延迟。比如当APB总线是AHB分频得到时,这种方式能确保延迟的是APB周期,而非AHB周期。
- 优势:延迟精度更高,完全匹配目标总线的时钟,不会因总线分频关系出现偏差。
- 注意事项:必须选择安全的只读寄存器(比如状态寄存器、波特率寄存器这类读取后不会改变硬件状态的寄存器),同时要确保目标外设在所用芯片上存在,避免移植时出现问题。
- 适用场景:对时序要求极高的场景,或者总线分频逻辑复杂的系统。
总结
- 追求简洁通用优先选择示例1;
- 需要精准匹配总线周期时选择示例2。
内容的提问来源于stack exchange,提问作者user2953113
相关产品推荐
相关产品推荐

