STM32 - Systick de desactivación del preescalador AHB

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);
}
Comenzaría un nuevo proyecto y ejecutaría solo este código y la interrupción de su sysstick sin otros temporizadores si aún no lo ha hecho
@ laptop2d El problema persiste, incluso cuando se reduce a esto. int main(void) { HAL_Init(); SystemClock_Config(); while (1){} }.
a que voltaje andas
@laptop2d VDD es 2.7 V (medido).

Respuestas (1)

El significado del parámetro al que pasa HAL_SYSTICK_Configes 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)).

Lo siento, probablemente pasarán unos días más hasta que realmente pueda volver a esto...
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á?
"No estoy usando el ST HAL o el Cubo..." - ¿Qué usas entonces?
@cp.engr Quise decir que su código no lo está reduciendo, el preescalador AHB, por supuesto, afecta el HCLK. La llamada a HAL_SYSTICK_Configestablecerá 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)