2
\$\begingroup\$

I'm writing bare metal firmware for an STM32F070. When I set the AHB Prescaler (AHBCLKDivider) to a value greater than 1, the systick interrupt never happens, i.e. SysTick_Handler() is never called. This in turn makes HAL_Delay() hang the system when called.

Why is this happening? Is it possible to have the systick interrupt enabled when using the AHB Prescaler?

My clock initialization code is below. I tweaked it based on code generated by STM32CubeMX.

Also, what is the meaning of the parameter that is passed to HAL_SYSTICK_Config()? Does it need to be adjusted based on the prescaler settings?

void SystemClock_Config(void)
{
   RCC_OscInitTypeDef RCC_OscInitStruct;
   RCC_ClkInitTypeDef RCC_ClkInitStruct;
   RCC_PeriphCLKInitTypeDef PeriphClkInit;

   /**Initializes the CPU, AHB and APB busses clocks 
   */
   RCC_OscInitStruct.OscillatorType =
      RCC_OSCILLATORTYPE_HSE |
      RCC_OSCILLATORTYPE_HSI |
      RCC_OSCILLATORTYPE_LSE |
      RCC_OSCILLATORTYPE_LSI |
      RCC_OSCILLATORTYPE_HSI14;
   RCC_OscInitStruct.HSEState   = RCC_HSE_OFF;
   RCC_OscInitStruct.HSIState   = RCC_HSI_ON;
   RCC_OscInitStruct.HSICalibrationValue = 16;
   RCC_OscInitStruct.HSI14State = RCC_HSI14_OFF;
   RCC_OscInitStruct.LSEState   = RCC_LSE_OFF;
   RCC_OscInitStruct.LSIState   = RCC_LSI_ON;
   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF;

   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
   {
      Error_Handler();
   }

   /**Initializes the CPU, AHB and APB busses clocks 
   */
   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                               | RCC_CLOCKTYPE_PCLK1;
   RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_HSI;
   RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1; //TODO
   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;   //TODO

   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
   {
      Error_Handler();
   }

   PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
   PeriphClkInit.RTCClockSelection    = RCC_RTCCLKSOURCE_LSI;

   if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
   {
      Error_Handler();
   }

   GPIO_InitTypeDef gpioInit =
   {
      .Pin  = GPIO_PIN_0,
      .Mode = GPIO_MODE_OUTPUT_PP,
      .Pull = GPIO_NOPULL,
      //.Speed = GPIO_SPEED_FREQ_LOW,
      //.Alternate = 0,
   };

   /**Configure the Systick interrupt time 
   */
   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 8000); //TODO: is this correct when using prescalers?

   /**Configure the Systick 
   */
   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);

   /* SysTick_IRQn interrupt configuration */
   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
\$\endgroup\$
  • \$\begingroup\$ I would start a new project and run just this code and your systick interrupt without other timers if you haven't done that already \$\endgroup\$ – Voltage Spike Mar 10 '17 at 22:02
  • \$\begingroup\$ @laptop2d Problem persists, even when stripped down to this. int main(void) { HAL_Init(); SystemClock_Config(); while (1){} }. \$\endgroup\$ – cp.engr Mar 10 '17 at 22:26
  • \$\begingroup\$ What voltage are you running at \$\endgroup\$ – Voltage Spike Mar 10 '17 at 22:29
  • \$\begingroup\$ @laptop2d VDD is 2.7 V (measured). \$\endgroup\$ – cp.engr Mar 10 '17 at 22:34
1
\$\begingroup\$

The meaning of the parameter you pass to HAL_SYSTICK_Config is the number of ticks before a SYSTICK interrupt is generated. So in the example code, the SYSCLK is the HSI with 8 MHz. And the HCLK has no prescaler, so HCLK is also 8 MHz.

A SYSTICK interrupt will be generated every 8 000 000 / 8 000 = 1 000 ticks, because the SYSTICK clock has an own prescaler of 8 based on HCLK, the actual SYSTICK frequency will be 1 MHz. 1 000 ticks turns into a SYSTICK interrupt of 1 ms.

So if you set your HCLK to be 2 MHz, it will set it to 250 ticks, resulting in still 1 ms interrupts. So you don't have to change that value with changing prescaler.

I currently don't see a reason why this won't work. Maybe you can go into debug and see what the result of HAL_RCC_GetHCLKFreq() is when you have a divider in place. Maybe divide that line into two like to make it easier to debug:

uint32_t hclk = HAL_RCC_GetHCLKFreq();
HAL_SYSTICK_Config(hclk/8000);

RANT

Ugh this is a mess as always with STM32. One of the reasons I'm not using the ST HAL or Cube is the quality of documentation, it's already bad in the reference manual, but worse when you try to understand the API (for example will it return the frequency in Hz, kHz or MHz? nowhere to be found (it is Hz)).

\$\endgroup\$
  • \$\begingroup\$ Sorry it'll probably be a few more days until I can really get back into this... \$\endgroup\$ – cp.engr Mar 14 '17 at 18:39
  • \$\begingroup\$ the HCLK has no prescaler - According to the clock tree that Cube is showing me, HCLK is affected by the AHB Prescaler. Or did you just mean to say that it's not scaled down in my code above? \$\endgroup\$ – cp.engr Mar 14 '17 at 18:42
  • \$\begingroup\$ So if you set your HCLK to be 2 MHz, *it* will set it to 250 ticks - what will set it? \$\endgroup\$ – cp.engr Mar 14 '17 at 18:43
  • \$\begingroup\$ "I'm not using the ST HAL or Cube..." - What then do you use? \$\endgroup\$ – cp.engr Mar 14 '17 at 18:44
  • \$\begingroup\$ @cp.engr I meant your code is not scaling it down, the AHB prescaler of course affects the HCLK. The call to HAL_SYSTICK_Config will set the interrupt to 250 ticks. We have written our own HAL in C++. It doesn't expose every feature available but common features available on most micros, so we can move to a different controller quite easily with just implementing the HAL (there are exceptions of course, but it worked two times flawlessly) \$\endgroup\$ – Arsenal Mar 14 '17 at 23:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.