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);
}
Die Bedeutung des übergebenen Parameters HAL_SYSTICK_Config
ist 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)).
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?HAL_SYSTICK_Config
setzt 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).
Spannungsspitze
vgl.engr
int main(void) { HAL_Init(); SystemClock_Config(); while (1){} }
.Spannungsspitze
vgl.engr