最近也是无意间拿到一块焊错了25M晶振的stm32f103晶振的板子来调试。在此总结一下,stm32f103和stm32f103修改外部晶振的学习过程。
cl:互联型产品,stm32f105/107系列
xl:超高密度产品,stm32f101/103系列
从代码看起来,在stm32f10x.h中,
#if !defined HSE_VALUE
#ifdef STM32F10X_CL //STM32F105/107互联性
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#else //其他的,stm32f103也包括其中
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */
由于板子焊接的是25M晶振,所以将 #define HSE_VALUE ((uint32_t)8000000) 改为 #define HSE_VALUE ((uint32_t)25000000)。
打开system_stm32f10x.c文件,
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
#define SYSCLK_FREQ_24MHz 24000000
#else
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000
#endif
默认为72Mhz,不用修改。
再找到倍频函数 static void SetSysClockTo72(void)中。
#ifdef STM32F10X_CL //stm32f105或者stm32f107互联性的倍频函数设置
/* Configure PLLs ------------------------------------------------------*/
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}
/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL9);
#else //stm32f103的倍频函数设置
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */
在stm32f103的倍频函数设置和stm32f105的倍频函数设置这里对比,才发现!!!stm32f103这里的倍频函数中里面没有分频的设置。也就是25M的外部晶振倍频个3,是75M。是最接近72M的了,所以决定先测试一下,看看是否行得通。
之后调试了串口打印和滴答时钟。在串口打印效果来看,是可以使用的。
但是在滴答时钟定时了100ms,调试现象发现是滴答时钟实际变成了900多ms。所以,滴答时钟测试结果反映出了问题。
在查询了资料后发现,stm32f103默认的外部晶振范围是4~16M。由于25M的外部晶振,超出了。滴答时钟当外部晶振出问题时,不能使用会转换为HSI(内部高速晶振8M)。原因就出在了这里。
再返回来看一下滴答时钟的配置函数就可以发现原因。
void SysTick_Init(void)
{
//这里的SystemCoreClock 是定义的72M
if (SysTick_Config(SystemCoreClock / 100000))
{
/* Capture error */
while (1);
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_MSK;
}
SysTick_Config(SystemCoreClock / 100000)函数,其中也就是将SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; 计数了100000次。那滴答的时间就应该是{(SystemCoreClock / 100000)*(1 / f)}。滴答时钟本来是使用外部晶振作用的,经过倍频之后应该是72M,正确的定时时间应该是{72M / 100000*(1 / 72M)} =1 / 100000s。但是现在外部晶振异常,转换成使用了HSI(8M)。那实际上是{(72M / 100000)*(1 / 8M) } = 9 / 100000s。
现在就清楚了,滴答实际的定时时间是设置的9倍,所以就出现了调试中滴答定时100ms,却在900多ms才触发的现象。