Estoy escribiendo firmware bare metal para un STM32F070 . Cuando configuro AHB Prescaler ( AHBCLKDivider
) en un valor mayor que 1
, la interrupción del sysstick nunca sucede, es decir, SysTick_Handler()
nunca se llama. Esto a su vez hace que HAL_Delay()
el sistema cuelgue cuando se le llama.
¿Por qué está pasando esto? ¿Es posible tener habilitada la interrupción del sysstick cuando se usa el Prescaler de AHB?
El código de inicialización de mi reloj está debajo. Lo modifiqué según el código generado por STM32CubeMX.
Además, ¿cuál es el significado del parámetro que se pasa a HAL_SYSTICK_Config()
? ¿Es necesario ajustarlo en función de la configuración del preescalador?
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);
}
El significado del parámetro al que pasa HAL_SYSTICK_Config
es el número de tics antes de que se genere una interrupción SYSTICK. Entonces, en el código de ejemplo, SYSCLK es el HSI con 8 MHz. Y el HCLK no tiene preescalador, por lo que HCLK también es de 8 MHz.
Se generará una interrupción SYSTICK cada 8 000 000 / 8 000 = 1 000 tics, debido a que el reloj SYSTICK tiene un preescalador propio de 8 basado en HCLK, la frecuencia real de SYSTICK será de 1 MHz. 1 000 tics se convierte en una interrupción SYSTICK de 1 ms.
Entonces, si configura su HCLK en 2 MHz, lo configurará en 250 tics, lo que resultará en interrupciones de 1 ms. Por lo tanto, no tiene que cambiar ese valor cambiando el preescalador.
Actualmente no veo una razón por la que esto no funcione. Tal vez pueda entrar en depuración y ver cuál HAL_RCC_GetHCLKFreq()
es el resultado cuando tiene un divisor en su lugar. Tal vez divida esa línea en dos para que sea más fácil de depurar:
uint32_t hclk = HAL_RCC_GetHCLKFreq();
HAL_SYSTICK_Config(hclk/8000);
DESPOTRICAR
Uf, esto es un desastre como siempre con STM32. Una de las razones por las que no estoy usando ST HAL o Cube es la calidad de la documentación, ya es mala en el manual de referencia, pero peor cuando intentas entender la API (por ejemplo, devolverá la frecuencia en Hz, kHz o MHz? no se encuentra por ninguna parte (es Hz)).
the HCLK has no prescaler
- Según el árbol de reloj que me muestra Cube, HCLK se ve afectado por el Prescaler AHB. ¿O solo quisiste decir que no está reducido en mi código anterior?So if you set your HCLK to be 2 MHz, *it* will set it to 250 ticks
- ¿ Qué lo establecerá?HAL_SYSTICK_Config
establecerá la interrupción en 250 tics. Hemos escrito nuestro propio HAL en C++. No expone todas las funciones disponibles, sino las funciones comunes disponibles en la mayoría de los micros, por lo que podemos pasar a un controlador diferente con bastante facilidad con solo implementar HAL (hay excepciones, por supuesto, pero funcionó dos veces sin problemas)
Pico de voltaje
cp.engr
int main(void) { HAL_Init(); SystemClock_Config(); while (1){} }
.Pico de voltaje
cp.engr