实验环境
- STM32F411芯片
- HAL库
- 利用CubeMX生成的Bootloader和APP工程
现象描述
将Bootloader和APP程序分别下载到板子上,Bootlader程序可以正常运行,而APP程序会死在Error_Handler()
的while(1)
循环中。
具体调试发现程序是在执行HAL_RCC_OscConfig()
函数的PLL 配置部分检测到当前PLL已经被配置为了系统时钟而返回了HAL_ERROR
的返回值导致进入了Error_Handler()
。为什么bootloader程序中的时钟配置没有问题,而APP中的时钟配置就会有问题呢?
分析
网上搜索了一下,发现了一种说法:PLL在启动之后便不能够重新配置。感觉有一定的道理,为了进一步验证这个说法,查看了参考手册的PLL部分:
大概意思就是:一旦启用了PLL,就无法更改主PLL配置参数,因此建议在启用PLL之前先对其进行配置(选择HSI或HSE振荡器为PLL时钟源,以及除法因子M,P,Q和乘法因子N的配置)。
参考手册中的描述将这个问题的原因描述的很清楚了。
解决
通过查看ST官方的RCC参考例程,在重复配置时钟时是按照参考手册中的描述先将系统时钟源
配置为HSI然后再进行下面的PLL配置,这样便不会导致HAL_ERROR
的问题了
void SystemClockHSE_Config(void)
{
/* -1- Select HSI as system clock source to allow modification of the PLL configuration */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* -2- Enable HSE Oscillator, select it as PLL source and finally activate the PLL */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 400;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* -3- Select the PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* -4- Optional: Disable HSI Oscillator (if the HSI is no more needed by the application)*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
}