RCC : RCC 与CRM 总闸开关
距离上一章更新已经月余,期间一方面阳康,一方面春节,断更时间确实有点长,今日继续更。
上一章我们聊到时钟树的分频参数配置属于整体系统初始化准备工作,配置完毕之后MCU 的cpu内核工作频率、总线工作频率等相关参数就配置好了,但是要正式启用设备,还要有几个步骤需要走。
简单来说一个外设能够正常工作,一般要经过三步:
Enable 对应外设的时钟,既本章节内容
初始化配置对应外设参数,如GPIO 的模式、spi的相位、时钟、LSB/MSB等,如果用到DMA还需要提前配置DMA 的信息等
如果存在功能复用的情况还需要配置功能复用(STM32 叫 AF, alternative function ,AT叫 Mux )根据具体的使用模式,配置中断处理、DMA处理等响应函数,最后使能外设,进入到工作状态
可见使能外设时钟是保证芯片外设功能启用的第一步,外设时钟的管理,在MCU里一般都在“复位和时钟控制”章节,具体详情可以参考具体的芯片手册,一般都包括芯片复位的条件及时序、时钟选择(内部时钟源与外部时钟源、PLL、总线分频等,上一章节已经铺垫)、时钟控制寄存器等信息。
本篇我们继续说时钟控制寄存器,时钟控制寄存器 包括时钟源配置(含PLL参数、时钟输出MCO)与外设时钟源开关两部分 , 时钟源的配置我们已经在上个章节聊过,我们继续聊bf的MCO 和外设时钟开关两部分
MCO:
MCO的主要功能有两部分用途,一、引出时钟源,作为其他芯片的时钟源输入,实现芯片之间主-从频率同步, 避免使用不同的时钟源导致芯片之间的不同步。 二、引出时钟源做诊断,判断当前芯片的频率是否准确,是否存在温飘等。
bf 的mco 配置包括三部分:
USE_MCO 宏,在 src/main/target/common_pre.h 中不同芯片是否定义此宏,决定是否启用mco特性,bf 的各种编译配置信息也基本都在 common_pre.h common_post.h 以及对应target.h、target.c中通过宏定义进行配置。
src/main/pg/mco.h mco 的开关 、时钟源、分频系数进行配置,在 init.c 中配置mco
src/main/drivers/mco.h mco.c 的mco 配置函数
void mcoConfigure(MCODevice_e device, const mcoConfig_t *config);
函数主要流程:
初始化 GPIO
配置 GPIO AF
配置 MCO输出时钟源 、分频系数
配置MCO 输出使能
能够输出MCO 的GPIO针脚,需要查询用户手册、数据手册的GPIO mux 表,stm32 与at32 支持PA8 作为默认mco输出, 另外部分STM32芯片支持第二路mco 输出等。
时钟源开关配置
bf 的时钟源开关配置代码,在src/main/drivers/rcc.h rcc.c ,默认使用了 HAL 的RCC宏,主要是 RCC_ClockCmd函数 RCC_ResetCmd 两个宏,
比如开启GPIOA 的时钟 使用 RCC_ClockCmd(GPIOA,ENABLE)
移植的重点与难点:
STM32 的HAL库是通过RCC 宏定义直接操作 时钟外设使能控制寄存器如 RCC->AHBxENR 以及 时钟外设复位控制器如 RCC->AHBxRST ,对对应外设进行时钟使能和复位控制,但是在AT32 的bsp库里,寄存器设置类似,但是未采用响应的库函数设计, at32采用了
void crm_periph_clock_enable(crm_periph_clock_type value, confirm_state new_state);
void crm_periph_reset(crm_periph_reset_type value, confirm_state new_state);
在代码使用上如果大面积修改为通过函数调用方式来移植,势必代码修改量很大而且兼容性也不是特别好。 因此在迁移到AT32 的时候,采用了一个取巧的方式,
1、新增 rcc_at32_periph.h ,根据AT32 具体外设的寄存器偏移量,构建每个外设的操作掩码
配置,兼容HAL库的寄存器操作方式
2、修改 rcc.c 中3个宏定义为直接操作 AT32 的CRM寄存器,通过掩码来操作寄存器位,实现与HAL库RCC 宏操作移植
通过上述移植,实现了bf 内全量RCC_ClockCmd 函数在At32 MCU上的兼容。