编写基础RCC(Reset and Clock Control)
AHB、APB1、APB2最大频率都是170MHz。
时钟树
要想配置时钟首先必须要看明白时钟树。
PLL
配置时钟精髓就是PLL倍频,因此搞清楚了它就很好解决了。
手册上对PLL配置步骤如下图:
首先通过上面的时钟树也可以看出来PLL的时钟源有两种:HSI、HSE。PLL的分频、倍频配置在RCC_PLLCFGR寄存器中。
配置PLL的过程是:
- 将RCC_CR的PLLON位清零来关闭PLL。
- 查询RCC_CR的PLLRDY是否被清零了,如果该位为0说明PLL已经关闭。
- 配置分频、倍频系数等(单纯的使能或者关闭PLL_P、PLL_Q或者PLL_R不需要这些步骤,直接操作即可)。
- 将PLLON设置为1,再次启用PLL。
- 通过在RCC_PLLCFGR寄存器中配置PLLPEN、PLLQEN、PLLREN来启用所需的PLL输出。 注:PLL输出频率不得大于170MHz。 当一个时钟源被直接使用或通过PLL作为一个系统时钟,是不可能停止它。
PWR
在不同的工作频率下,对应的电源模式也不一样。
可能是为了满足不同频率下的功耗管理,高时钟对应高内核电压,我使用TI的5529时也有倍频时修改内核电压的的操作。
g474的电源模式与各个时钟频率对应关系如下表:
PWR_CR1的VOS[1:0]对应Range2和Range1:
至于Range1的normal模式和boost模式是在PWR_CR5寄存器的R1MODE位配置,R1MODE为0就是boost模式:
g474的R1MODE位与SYSCLK的对应关系如下:
手册中还介绍了从range_normal切换到range_boost模式的步骤:
- 在切换到更高的系统频率之前,系统时钟必须用AHB分频器除以2。
- 清除的R1MODE位在PWR_CR5寄存器中。
- 在range1 boost模式中,根据新的频率目标调整等待状态的数量。
- 配置并切换到新的系统频率。
- 等待至少1us,然后重新配置AHB预压器以获得所需的HCLK时钟频率
FLASH
这个是我原来忽略的地方,原来就配置了PLL和PWR,然后倍频到140MHz就是极限了,后来我反复查阅手册,才发现了原来少了对FLASH的访问比率的配置。(可以看到上面的range_normal切换到range_boost模式步骤里已经提到了修改FLASH访问比率的事,但是由于没看懂是什么意思,还以为是延时1us,因此配置170MHz时候就失败了。)
上面提到range_normal切换到range_boost步骤里有这么一句:
- 在range1 boost模式中,根据新的频率目标调整等待状态的数量(FLASH_ACR的LATENCY位)。
那么就看看这个 FLASH_ACR 的 LATENCY到底是个什么。
查阅手册找到这个寄存器:
可以看到LATENCY在最低位:
LATENCY[3:0]:这些位表示SYSCLK(系统时钟)周期与Flash访问时间的比率。
知道了它是干嘛的,那么它到底设置为多少合适呢?如下图所示:
为了正确地从闪存读取数据,等待状态(延迟)的数量必须根据CPU时钟(HCLK)的频率和内部电压范围的设备VCORE被正确地编程在闪存访问控制寄存器(FLASH_ACR)。参考第6.1.5节:动态电压缩放管理。表29显示了等待状态和CPU时钟频率之间的对应关系。
对号入座,我要设置为170MHz,模式为Range 1 Boost模式,那么对应LATENCY值应该为4WS,因此将其配置为4。
FLASH->ACR |= FLASH_ACR_LATENCY_4WS;
配置函数
有了上面的概念就可以进行编写时钟函数了。
步骤如下:
- 开启HSE(鄙人的板子HSE为8MHz)并确认HSE就绪;
- 关闭PLL并确认PLL已经关闭;
- AHB二分频;
- 配置为range1_boost(默认复位为range1_normal模式);
- 配置FLASH_ACR的访问时间比率;
- 配置PLL;
- 打开PLL并确认PLL就绪;
- 使能PLL_R;
- 配置系统时钟为PLL输入,并确认系统时钟就绪;
- 延时至少1us后切换AHB为不分频。
- u8 SYSCLK_140MHz(void)
- {
- u16 temp = 0x2000;
- RCC->CR |= RCC_CR_HSEON;//打开HSE
- while((!(RCC->CR & RCC_CR_HSERDY))&&(--temp));//等待HSE就绪
- if(!temp)//检查是否超时
- {
- return FAILED;
- }
- RCC->CR &= ~RCC_CR_PLLON;//关闭PLL
- temp = 0x2000;
- while((RCC->CR & RCC_CR_PLLRDY) && (--temp));//等待PLL下线
- if(!temp)//检查是否超时
- {
- return FAILED;
- }
- RCC->CFGR = RCC_CFGR_PPRE2_DIV2|RCC_CFGR_PPRE1_DIV4|RCC_CFGR_HPRE_DIV2|RCC_CFGR_SW_HSI;
- //系统时钟选择内部高速时钟,AHB二分频,APB1四分频,APB2二分频
- temp = 0x2000;
- while(--temp);//等待AHB稳定
- PWR->CR5 &= ~PWR_CR5_R1MODE;//设置为range1_boost模式
- FLASH->ACR &= ~FLASH_ACR_LATENCY;//清除LATENCY
- FLASH->ACR |= FLASH_ACR_LATENCY_4WS;//配置LATENCY为4WS
- temp = 0x2000;
- while(--temp);//等待系统稳定
- RCC->PLLCFGR = (70<<RCC_PLLCFGR_PLLN_Pos)|(1<<RCC_PLLCFGR_PLLM_Pos)|RCC_PLLCFGR_PLLSRC_HSE;//(8*70)/2 = VCO = 280MHz
- RCC->CR |= RCC_CR_PLLON;//打开PLL
- temp = 0xf000;
- while((!(RCC->CR & RCC_CR_PLLRDY)) && (--temp));//等待PLL准备就绪
- if(!temp)
- {
- return FAILED;
- }
- RCC->PLLCFGR |= RCC_PLLCFGR_PLLREN;//使能PLL_R
- RCC->CFGR |= RCC_CFGR_SW_PLL;//设置系统时钟选择PLL
- temp = 0xf000;
- while(((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS) && (--temp));//等待系统设置PLL主时钟完成标志位置位
- if(temp)
- {
- temp = 0;
- while(--temp);//等待系统稳定
- RCC->CFGR &= ~RCC_CFGR_HPRE;//AHB 不分频 == SYSCLK
- return SUCCEED;
- }
- else
- {
- return FAILED;
- }
- }
复制代码
然后就配置结束了,通过定时器验证确实为170MHz。
附录:RCC寄存器
最后:
附上本人写的寄存器配置,方便个人配置,要啥直接删注释就好:
下面是RCC寄存器:
|