STM32F0 系统时钟 PLL 配置 and/or 温度导致错误?
STM32F0 System Clock PLL configuration and/or temperature causing error?
我的项目开始遇到 SysTick 速率通常但并不总是设置得太快的问题。相关的代码我没有改,好像是温度相关的。
我正在使用 STM32F072B-DISCOVERY 开发板,在 Visual Studio Community 2015 上使用 VisualGDB。
我的初始化代码包括以下函数:
void Setup_Init_Clocks()
{
// Set up 48 MHz Core Clock using HSI (8Mhz) with PLL x 6
RCC_PLLConfig(RCC_PLLSource_HSI, RCC_PLLMul_6);
RCC_PLLCmd(ENABLE);
// Wait for PLLRDY after enabling PLL.
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != SET)
{ }
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // Select the PLL as clock source.
SystemCoreClockUpdate();
}
RCC_SYSCLKConfig()
状态 "If a clock source which is not yet ready is selected, the switch will occur when the clock source will be ready." 的注释检查 PLLRDY RCC 标志应该可以识别这种情况,以便立即发生时钟变化,以便立即设置时钟。
SystemCoreClockUpdate()
来自标准 STM32 库(在文件 system_stm32f0xx.c 中)并重新计算稍后用于设置 SysTick 的值:
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, prediv1factor = 0;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case 0x00: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
case 0x04: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case 0x08: /* PLL used as system clock */
/* Get PLL clock source and multiplication factor ----------------------*/
pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
pllmull = ( pllmull >> 18) + 2;
if (pllsource == 0x00)
{
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
}
else
{
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
/* HSE oscillator clock selected as PREDIV1 clock entry */
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
}
break;
default: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK clock frequency ----------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
在调试器中,我可以看到失败的地方:tmp = RCC->CFGR & RCC_CFGR_SWS;
,导致选择了不正确的大小写。
这在反汇编程序中看起来相对简单:
237: tmp = RCC->CFGR & RCC_CFGR_SWS;
0x08003262 2A 4B ldr r3, [pc, #168] ; (0x800330c SystemCoreClockUpdate+192>)
0x08003264 5B 68 ldr r3, [r3, #4]
0x08003266 0C 22 movs r2, #12
0x08003268 13 40 ands r3, r2
0x0800326a FB 60 str r3, [r7, #12]
RCC CFGR 寄存器的值为 0x0010800a。 RCC_CFGR_SWS
掩码是 0x0000000c。 的结果应该被tmp
分配0x08,选择PLL情况,SystemCoreClock
设置为48000000。
1) 如果我在此语句上或之前设置一个断点,并且单步执行它会正常运行,tmp
分配 0x08,并且时钟设置正确。
2) 如果我随后立即在 switch
语句上设置断点,它通常*会失败。 tmp
被赋值为 0x0010800a,就好像 ands r3, r2
指令被跳过了一样!这导致 default
案例被执行,并且 SystemCoreClock 被设置为 8000000,尽管芯片 运行 在 48MHz;结果是快速的 SysTick。
3) 如果我注释掉 RCC_SYSCLKConfig()
调用,选择启动 HSI 时钟,tmp
被分配为 0x00,一切都按预期工作,芯片 运行在 8MHz,而不是我想要的 48MHz。
4) 如果我把它拔掉几分钟,它会在第一次通电时正常工作,但在热重置(包括调试)时会失败,或者如果拔掉插头的时间很短(~15 秒)
5) 我怀疑PLL Initialization受温度影响。我已经一个多月没有从事该项目了,我的工作区现在季节性变暖了。我通过在芯片上放一小杯自来水来稍微冷却芯片。这是成功的,因为程序 运行 每次都正确!取下杯子用手指加热芯片后,再次失败。
对系统时钟配置的这种更改会以某种方式影响计算的完整性吗?我应该做些什么来确保时钟设置正确?
你在开始之前有没有放慢闪光灯。是的,我知道你直到之后才使用更快的时钟,但也许它在倍增之前切换到 1x 的外部时钟。对闪存进行超频会导致奇怪的行为,尽管单步 may/should 仍然会导致一些奇怪的事情
我的项目开始遇到 SysTick 速率通常但并不总是设置得太快的问题。相关的代码我没有改,好像是温度相关的。
我正在使用 STM32F072B-DISCOVERY 开发板,在 Visual Studio Community 2015 上使用 VisualGDB。
我的初始化代码包括以下函数:
void Setup_Init_Clocks()
{
// Set up 48 MHz Core Clock using HSI (8Mhz) with PLL x 6
RCC_PLLConfig(RCC_PLLSource_HSI, RCC_PLLMul_6);
RCC_PLLCmd(ENABLE);
// Wait for PLLRDY after enabling PLL.
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != SET)
{ }
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // Select the PLL as clock source.
SystemCoreClockUpdate();
}
RCC_SYSCLKConfig()
状态 "If a clock source which is not yet ready is selected, the switch will occur when the clock source will be ready." 的注释检查 PLLRDY RCC 标志应该可以识别这种情况,以便立即发生时钟变化,以便立即设置时钟。
SystemCoreClockUpdate()
来自标准 STM32 库(在文件 system_stm32f0xx.c 中)并重新计算稍后用于设置 SysTick 的值:
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, prediv1factor = 0;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case 0x00: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
case 0x04: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case 0x08: /* PLL used as system clock */
/* Get PLL clock source and multiplication factor ----------------------*/
pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
pllmull = ( pllmull >> 18) + 2;
if (pllsource == 0x00)
{
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
}
else
{
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
/* HSE oscillator clock selected as PREDIV1 clock entry */
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
}
break;
default: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK clock frequency ----------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
在调试器中,我可以看到失败的地方:tmp = RCC->CFGR & RCC_CFGR_SWS;
,导致选择了不正确的大小写。
这在反汇编程序中看起来相对简单:
237: tmp = RCC->CFGR & RCC_CFGR_SWS;
0x08003262 2A 4B ldr r3, [pc, #168] ; (0x800330c SystemCoreClockUpdate+192>)
0x08003264 5B 68 ldr r3, [r3, #4]
0x08003266 0C 22 movs r2, #12
0x08003268 13 40 ands r3, r2
0x0800326a FB 60 str r3, [r7, #12]
RCC CFGR 寄存器的值为 0x0010800a。 RCC_CFGR_SWS
掩码是 0x0000000c。 的结果应该被tmp
分配0x08,选择PLL情况,SystemCoreClock
设置为48000000。
1) 如果我在此语句上或之前设置一个断点,并且单步执行它会正常运行,tmp
分配 0x08,并且时钟设置正确。
2) 如果我随后立即在 switch
语句上设置断点,它通常*会失败。 tmp
被赋值为 0x0010800a,就好像 ands r3, r2
指令被跳过了一样!这导致 default
案例被执行,并且 SystemCoreClock 被设置为 8000000,尽管芯片 运行 在 48MHz;结果是快速的 SysTick。
3) 如果我注释掉 RCC_SYSCLKConfig()
调用,选择启动 HSI 时钟,tmp
被分配为 0x00,一切都按预期工作,芯片 运行在 8MHz,而不是我想要的 48MHz。
4) 如果我把它拔掉几分钟,它会在第一次通电时正常工作,但在热重置(包括调试)时会失败,或者如果拔掉插头的时间很短(~15 秒)
5) 我怀疑PLL Initialization受温度影响。我已经一个多月没有从事该项目了,我的工作区现在季节性变暖了。我通过在芯片上放一小杯自来水来稍微冷却芯片。这是成功的,因为程序 运行 每次都正确!取下杯子用手指加热芯片后,再次失败。
对系统时钟配置的这种更改会以某种方式影响计算的完整性吗?我应该做些什么来确保时钟设置正确?
你在开始之前有没有放慢闪光灯。是的,我知道你直到之后才使用更快的时钟,但也许它在倍增之前切换到 1x 的外部时钟。对闪存进行超频会导致奇怪的行为,尽管单步 may/should 仍然会导致一些奇怪的事情