问题描述
我的项目开始遇到一个问题,其中 SysTick 速率通常设置得太快,但并不总是设置得太快.相关的代码我没改过,好像和温度有关.
My project has started experiencing a problem in which the SysTick rate is usually, but not always set too fast. I have not changed the code that is relevant, and it seems to be temperature-related.
我正在使用 STM32F072B-DISCOVERY 开发板,在 Visual Studio Community 2015 上使用 VisualGDB.
I am using an STM32F072B-DISCOVERY board, with VisualGDB on Visual Studio Community 2015.
我的初始化代码包括以下函数:
My initialization code includes the following function:
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()
的注释说明如果选择了尚未准备好的时钟源,则在时钟源准备好时进行切换."检查 PLLRDY RCC 标志应识别这种情况,以便立即发生时钟变化,从而立即设置时钟.
The notes for RCC_SYSCLKConfig()
state "If a clock source which is not yet ready is selected, the switch will occur when the clock source will be ready." Checking the PLLRDY RCC flag should identify this condition so the clock change occurs immediately, so that the clock is set immediately.
SystemCoreClockUpdate()
来自标准 STM32 库(在文件 system_stm32f0xx.c 中)并重新计算稍后用于设置 SysTick 的值:
SystemCoreClockUpdate()
is from the standard STM32 libraries (in file system_stm32f0xx.c) and recomputes values that are later used to set 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;
,导致选择不正确的case.
In the debugger, I can see where this is failing: tmp = RCC->CFGR & RCC_CFGR_SWS;
, causing the incorrect case to be selected.
这在反汇编器中看起来相对简单:
This looks relative straightforward in the disassembler:
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.
The RCC CFGR register has a value of 0x0010800a. The RCC_CFGR_SWS
mask is 0x0000000c. The result of this should be tmp
assigned 0x08, selecting the PLL case, with SystemCoreClock
is set to 48000000.
1) 如果我在此语句上或之前设置了一个断点,并正确执行它,tmp
被分配为 0x08,并且时钟设置正确.
1) If I set a breakpoint on or before this statement, and step through it functions correctly, with tmp
assigned 0x08, and the clocks are correctly set.
2) 如果我之后立即在 switch
语句上设置断点,它通常*会失败.tmp
被赋值为 0x0010800a,就好像跳过了 ands r3, r2
指令!这会导致default
case 被执行,SystemCoreClock 设置为8000000,尽管芯片运行在48MHz;结果是快速的 SysTick.
2) If I set the breakpoint on the switch
statement immediately afterwards, it usually* fails. tmp
is assigned 0x0010800a, as if the ands r3, r2
instruction were skipped! This causes the default
case to be executed, and SystemCoreClock is set to 8000000, despite the chip running at 48MHz; with the fast SysTick as a result.
3) 如果我注释掉 RCC_SYSCLKConfig()
调用,选择启动 HSI 时钟,tmp
被分配 0x00,一切都按预期工作,使用芯片运行在 8MHz,而不是我想要的 48MHz.
3) if I comment out the RCC_SYSCLKConfig()
call, leaving the start-up HSI clock selected, tmp
is assigned 0x00 and everything works as expected, with the chip running at 8MHz, not the 48MHz that I want.
4) 如果我将它拔掉几分钟,它会在第一次通电时正常工作,但在热复位(包括调试)或短时间拔掉电源(约 15 秒)时会失败
4) If I leave it unplugged for a few minutes, it will work OK on the first power-up, but fail on warm resets (including debugging), or if unplugged for short durations (~15 seconds)
5) 我怀疑 PLL 初始化受温度影响.我已经一个多月没有参与这个项目了,我的工作区现在季节性温暖.我在芯片上放了一小杯自来水,稍微冷却了芯片.这是成功的,因为程序每次都正确运行!取下杯子,用手指加热芯片后,再次失败.
5) I suspected that the PLL Initialization is affected by temperature. I haven't working on the project in over a month and my workspace is now seasonally warmer. I cooled the chip down slightly by putting a small cup of tap water on the chip. This was successful in that the program ran correctly every time! After removing the cup and warming the chip with my finger, it again failed.
系统时钟配置的这种更改会以某种方式影响计算的完整性吗?我应该做些什么来确保时钟设置正确?
Can such a change to the System Clock configuration somehow affect the integrity of computation? Is there something different that I should be doing to ensure the clock is set up properly?
推荐答案
在开始之前,您是否减慢了闪光灯的速度.是的,我知道您直到之后才使用更快的时钟,但也许它在乘法之前以 1x 切换到外部时钟.超频闪存会导致奇怪的行为,尽管单步执行可能/应该仍然会导致一些奇怪的事情
Did you slow down the flash before you started. yes I understand that you are not on the faster clock until after, but maybe it is switching to an external clock at 1x before multiplying up. overclocking the flash would result in strange behavior, although single stepping may/should still result in something strange
这篇关于STM32F0 系统时钟 PLL 配置和/或温度导致错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!