STM32 - AHB Prescaler deaktiviert Systick

Ich schreibe Bare-Metal-Firmware für einen STM32F070 . Wenn ich den AHB Prescaler ( AHBCLKDivider) auf einen Wert größer als setze 1, passiert der Systick-Interrupt nie, dh er SysTick_Handler()wird nie aufgerufen. Dies wiederum lässt HAL_Delay()das System hängen, wenn es angerufen wird.

Warum passiert das? Kann der Systick-Interrupt aktiviert werden, wenn der AHB Prescaler verwendet wird?

Mein Uhr-Initialisierungscode ist unten. Ich habe es basierend auf dem von STM32CubeMX generierten Code optimiert.

Und was ist die Bedeutung des Parameters, der an übergeben wird HAL_SYSTICK_Config()? Muss es basierend auf den Prescaler-Einstellungen angepasst werden?

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);
}
Ich würde ein neues Projekt starten und nur diesen Code und Ihren Systick-Interrupt ohne andere Timer ausführen, wenn Sie das noch nicht getan haben
@laptop2d Das Problem bleibt bestehen, auch wenn es darauf reduziert ist. int main(void) { HAL_Init(); SystemClock_Config(); while (1){} }.
Mit welcher Spannung fährst du
@laptop2d VDD beträgt 2,7 V (gemessen).

Antworten (1)

Die Bedeutung des übergebenen Parameters HAL_SYSTICK_Configist die Anzahl der Ticks, bevor ein SYSTICK-Interrupt generiert wird. Im Beispielcode ist der SYSCLK also der HSI mit 8 MHz. Und der HCLK hat keinen Prescaler, also ist HCLK auch 8 MHz.

Ein SYSTICK-Interrupt wird alle 8 000 000 / 8 000 = 1 000 Ticks generiert, da die SYSTICK-Uhr einen eigenen Prescaler von 8 basierend auf HCLK hat, beträgt die tatsächliche SYSTICK-Frequenz 1 MHz. 1 000 Ticks werden zu einem SYSTICK-Interrupt von 1 ms.

Wenn Sie also Ihren HCLK auf 2 MHz einstellen, wird er auf 250 Ticks eingestellt, was immer noch zu 1-ms-Interrupts führt. Sie müssen diesen Wert also nicht ändern, indem Sie den Prescaler ändern.

Ich sehe derzeit keinen Grund, warum dies nicht funktionieren sollte. Vielleicht können Sie ins Debuggen gehen und sehen, was das Ergebnis HAL_RCC_GetHCLKFreq()ist, wenn Sie einen Teiler haben. Teilen Sie diese Zeile vielleicht in zwei Teile, um das Debuggen zu erleichtern:

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

SCHIMPFEN

Ugh, das ist wie immer bei STM32 ein Durcheinander. Einer der Gründe, warum ich ST HAL oder Cube nicht verwende, ist die Qualität der Dokumentation, sie ist bereits im Referenzhandbuch schlecht, aber noch schlimmer, wenn Sie versuchen, die API zu verstehen (gibt sie beispielsweise die Frequenz in Hz, kHz oder MHz? nirgends zu finden (es ist Hz)).

Tut mir leid, es wird wahrscheinlich noch ein paar Tage dauern, bis ich mich wirklich wieder darauf einlassen kann ...
the HCLK has no prescaler- Laut dem Uhrenbaum, den Cube mir zeigt, ist HCLK vom AHB Prescaler betroffen. Oder wollten Sie nur sagen, dass es in meinem obigen Code nicht verkleinert wurde?
So if you set your HCLK to be 2 MHz, *it* will set it to 250 ticks- was wird es einstellen?
"Ich benutze nicht den ST HAL oder Cube ..." - Was verwenden Sie dann?
@cp.engr Ich meinte, Ihr Code skaliert ihn nicht herunter, der AHB-Prescaler wirkt sich natürlich auf den HCLK aus. Der Aufruf von HAL_SYSTICK_Configsetzt den Interrupt auf 250 Ticks. Wir haben unsere eigene HAL in C++ geschrieben. Es stellt nicht alle verfügbaren Funktionen zur Verfügung, aber gemeinsame Funktionen, die auf den meisten Mikros verfügbar sind, sodass wir ganz einfach zu einem anderen Controller wechseln können, indem wir einfach die HAL implementieren (es gibt natürlich Ausnahmen, aber es hat zweimal einwandfrei funktioniert).