本帖最后由 zhangbaoyin 于 2023-6-11 22:52 编辑
目录:
- 时钟树框图
- 外设连接到的总线查看
- 配置系统时钟的步骤
- 获取系统时钟频率
- 系统滴答定时器
- 程序运行中更新运行频率
雅特力F435微处理器为CortexTM-M4F的ARM内核,但可配置的时钟灵活性不逊色于M7内核的处理器,以下是其时钟框图:
从图中可以看到:
- PLL倍频器具有以下参数:预分配系数(/MS)、倍频系数(xNS)、后分频系数(/FR)。PLL时钟输出到AHB总线上。
- 时钟的输入可以选择为HICK、HECK、LEXT、LICK,分别为内部高速时钟、外部高速时钟、外部低速时钟、内部低速时钟。其中,可以连接到PLL倍频的时钟为外部高速时钟(HECK)和内部高速时钟(HICK)。板载外部高速时钟建议为8MHz,这样倍频之后的时钟可以跑满AHB的总线速度288MHz;芯片内置的内部高速时钟为48MHz,如果需要PLL倍频,会将时钟先6分频为8MHz,然后进入PLL倍频。
- APB1/2的时钟最高速率为144MHz。
- 外部高速时钟(HECK)和内部高速时钟(HICK)直接可以连接到AHB总线上,不经过PLL倍频。
- HICK 振荡器时钟由芯片内的高速RC 振荡器提供。HICK 时钟的内部频率为48MHz,频率精度较差,但启动时间比HEXT 晶体振荡器短,每颗芯片的HICK 时钟频率在出厂前已经被校准到1%(25°C),工厂校准值被装载到时钟控制寄存器的HICKCAL[7:0]位。考虑不同的电压或环境温度对HICK 的RC 振荡器的影响,用户可以通过时钟控制寄存器里的HICKTRIM[5:0]位来调整HICK 频率。HICK 时钟直到稳定后才会被释放出来。
从固件库函数at32f435_437_crm.h中101行开始,有每个外设的总线连接,可以看到,所有的GPIO都连接到高速总线AHB上。
从固件库中读取函数system_clock_config()的配置步骤可以总结如下:
- system clock = (hext * pll_ns)/(pll_ms * pll_fr)
- system clock source = pll (hext)
- hext = 8000000
- sclk = 288000000
- ahbdiv = 1
- ahbclk = 288000000
- apb2div = 2
- apb2clk = 144000000
- apb1div = 2
- apb1clk = 144000000
- pll_ns = 144
- pll_ms = 1
- pll_fr = 4
- 计算要配置的系统时钟频率
- 选择时钟来源
- 选择时钟源频率
- 确认AHB、APB1/2时钟频率
- 计算PLL预分配系数(/MS)、倍频系数(xNS)、后分频系数(/FR)
下面给出固件库中设置好的几种 基于外部8M晶振的PLL配置选项
系统复位后,默认系统时钟为内部的高速时钟(48M),只有当用户初始化外部时钟,且当外部时钟稳定后,才会却换到PLL外部高速时钟。要获取时钟频率,需要在初始化外部时钟后,调用 void system_core_clock_update(void) 函数来更新全局变量 pll_clock_source、pll_ns、pll_ms、pll_fr、pllrcsfreq。在 system_at32f435_437.c 文件135行有使用PLL进行更新系统时钟频率的方法。更新之后的频率会保存在全局变量 system_core_clock 中。
要获取系统时钟频率,可以使用这些全局变量计算得到:
AHB时钟
= PLL 输出时钟
= PLL 输入时钟 x PLL 倍频系数 /(PLL 预分频系数 x PLL 后分频系数)
= pll_clock_source * pll_ms / ( pll_ns * pll_fr )
Systick定时器连接到AHB总线上,系统嘀嗒定时器(SysTick)使用HCLK 或HCLK 的8 分频作为时钟。系统嘀嗒定时器是一个24 位递减计数器,递减至零可自动重载计数初值。容易计算出在288MHz下、使用HCLK作为驱动源,最大的计数时间为:(1<<24) / 288 = 58254us = 58ms。所以在 delay_ms() 函数中,如果计数周期大于50ms,就需要分开计数,每50ms更新一次重装载计数器,不足50ms的部分按照 delay_ms() 计数。
话不多说,看代码
void updata_Sysclk(u16 freq)
{
/* reset crm */
crm_reset();
/* enable pwc periph clock */
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
/* config ldo voltage */
pwc_ldo_output_voltage_set(PWC_LDO_OUTPUT_1V3);
/* set the flash clock divider */
flash_clock_divider_set(FLASH_CLOCK_DIV_3);
crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE);
/* wait till hext is ready */
while(crm_hext_stable_wait() == ERROR);
/* config pll clock resource */
crm_pll_config(CRM_PLL_SOURCE_HEXT, freq, 1, CRM_PLL_FR_8);
/* enable pll */
crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);
/* wait till pll is ready */
while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET);
/* config ahbclk */
crm_ahb_div_set(CRM_AHB_DIV_1);
/* config apb2clk, the maximum frequency of APB1/APB2 clock is 144 MHz */
crm_apb2_div_set(CRM_APB2_DIV_2);
/* config apb1clk, the maximum frequency of APB1/APB2 clock is 144 MHz */
crm_apb1_div_set(CRM_APB1_DIV_2);
/* enable auto step mode */
crm_auto_step_mode_enable(TRUE);
/* select pll as system clock source */
crm_sysclk_switch(CRM_SCLK_PLL);
/* wait till pll is used as system clock source */
while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL);
/* disable auto step mode */
crm_auto_step_mode_enable(FALSE);
/* update system_core_clock global variable */
system_core_clock_update();
/* set the flash clock divider */
flash_clock_divider_set(FLASH_CLOCK_DIV_2);
}
更改系统时钟之后,一定要重新初始化其他硬件
void hardWareConfig(void)
{
at32_board_init();
uart_print_init(115200);
}
如果不初始化其他硬件,得到的效果如下,串口和delay运行不正常:
d77be4b83396a396fdd88b534d6ab489
如果初始化其他硬件,得到的效果如下,串口和delay正常运行:
15f6dcd9b3bf2c744ecc86dedbbe49d2