1
votes

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.

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();
}

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() 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;  
}

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] 

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) 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) 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) 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) 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) 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?

1
Look as harsware ploblem. If this initialization code - you can try to configure power on reset (POR), and do some pause (by simple loop) about 1s or less before any work code start - this for sure that HSI is stabilized.imbearr
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.old_timer
@dwelch Thank you - I did not realize that this was necessary, as I had not read the FLASH section of the reference manual in detail, and it is not mentioned in the clock section that I can find. For the STM32F072, the latency must be set to 1 for 24 MHz ≤ SYSCLK ≤ 48 MHz. Adding "FLASH_SetLatency(FLASH_Latency_1);" before setting the clock resolves the issue. Add this as an answer, and I will accept it.mbmcavoy
Thinking - I had previously attempted to use DMA to communicate a few bytes at a time via SPI. The program would seem to run fine for several minutes before generating a hard fault It seemed to consistently occur in the same instruction within FreeRTOS after several tens of thousands of cycles! I reverted the program to use polling instead of DMA, which fixed the problem, but I now suspect it was related to the FLASH latency as well. I will have to revisit.mbmcavoy

1 Answers

1
votes

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