STM32实战项目经验:HAL_RCC_OscConfig中程序卡死问题解决办法
打个广告
博主做的脱机烧录器:重磅来袭!CMSIS-DAP 脱机烧录器 EasyFlasher 发布~
某宝店铺:觉皇工作室
购买链接:https://item.taobao.com/item.htm?abbucket=18&id=841061310319
实物图,MINI版:
实物图,COOL版:
工程环境
- STM32CUBEIDE
- STM32F405VG
现象复现
项目中一个是IAP程序,另一个是APP程序,两个程序都是使用STM32CubeIDE生成,当程序跳转到APP中并且执行到函数SystemClock_Config中的时候,在初始化锁相环调用HAL_RCC_OscConfig函数的时候返回HAL_ERROR或者直接卡死在里面。
为什么在IAP中可以初始化通过,但是在APP中却通不过,查阅STM32F4xx参考手册发现这么一段话:
那么出现这个问题的原因也就清楚了,因为在IAP中已经初始化了PLL,在APP中再次初始化就不成功。
解决办法
我查找ST官方HAL固件库中对重复配置RCC时钟的时候,发现他是这么做的:
- 先将时钟源选择为内部时钟
- 初始化锁相环
- 将时钟源在切换回外部时钟源
- 禁用内部高速时钟(可选步骤,如果内部高速时钟不用的话,建议禁掉)
官方代码如下:
以下是我的示例代码:
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
// 先将时钟源选择为内部时钟
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
// 初始化锁相环
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 = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
// 锁相环已经初始化完毕了,将时钟源在切换回外部时钟源
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
// 禁用内部高速时钟
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)
{
Error_Handler();
}
}
通过以上操作后,问题成功解决!
解决F4系列这个问题之后,我又去看F1系列的参考手册,发现:
同样的也是需要在使能PLL之前完成时钟配置,不过在实际中发现,F1系列的IAP跳转到APP中并没有卡死在HAL_RCC_OscConfig
函数中。
还有一个更快捷方便的办法,就是在IAP中不使用PLL,直接使用HSE或HSI的8M晶振作为系统时钟,如下图时钟的配置:
ends…