Precisión de SysTick en STM32

He codificado una verificación de tiempo simple para mi placa Discovery STM32F4.

#define IT_PER_SEC 100

int main(void)
{
   if (SysTick_Config(SystemCoreClock / IT_PER_SEC)) 
   {          
      while (1){}; // error
   }

   initGPIO();

   for(;;)
   {
   }

   return 0;
}

void SysTick_Handler(void)
{
   static uint32_t csec  = 0;
   static uint32_t ctime = 0;

   ++csec;
   if(csec == IT_PER_SEC) // every second
   {
      // every second
      GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
      csec = 0;

      // clock
      ++ctime;

      if((ctime % 10) == 0) // every 10 seconds
      {
         GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
      }

      if((ctime % 60) == 0)     // every minute
      {
         GPIO_ToggleBits(GPIOD, GPIO_Pin_14);
      }

      if(ctime == 3600)         // every hour
      {
         GPIO_ToggleBits(GPIOD, GPIO_Pin_15);
         ctime = 0;
      }
   }
}

Esto parece estar funcionando bien. Lo comprobé con la aplicación de cronómetro en mi teléfono Android. Pero después de una hora y algo me di cuenta de que la sincronización del LED se adelantó aproximadamente un segundo y después de dos horas y media estoy casi en dos segundos.

Supongo que mi aplicación no tiene la culpa aquí, ¿o sí? El SysTick también debería estar bien, supongo. Así que debe ser mi código...

Los esquemas son los esquemas estándar de la placa Discovery STM32F4. Se pueden encontrar en el manual de usuario en la página 32. Allí se puede encontrar un cristal de 8 MHz junto con los dos condensadores comunes de 20 pF.

¿Podría cargar o describir la parte del esquema que muestra el oscilador (cristal, resonador cerámico, RC) y asegurarse de qué tipo de oscilador está configurado para usar su chip? Ya hay buenas respuestas que apuntan hacia este problema ...
Los esquemas son los esquemas estándar de la placa Discovery STM32F4. Se pueden encontrar en el manual de usuario en la página 32:
No dé por sentado que el reloj de su teléfono Android es confiable, o que alguna aplicación aleatoria elige usar una fuente de reloj confiable dentro del teléfono. Por ejemplo, un reloj que se corrige desde la red no debe usarse para la sincronización relativa y, en algunas versiones anteriores de Android, incluso los relojes que se suponía que no debían corregirse recibían ajustes de corrección. Volviendo a la placa STM, además de los errores de fuente de reloj mencionados, considere la posibilidad de interrupciones perdidas.

Respuestas (5)

Los cristales suelen tener una precisión mucho mejor que 50 ppm ... PERO ... los cristales tienen dos modos de resonancia: resonancia en serie y resonancia en paralelo (con un gráfico de impedancia, verá que la impedancia aumenta hacia el infinito en resonancia paralela y cae hacia cero en resonancia en serie ).

Ahora, la importancia de esto es que los dos modos resonantes generalmente están separados por unos pocos cientos de PPM, ¡y solo uno de ellos estará en la frecuencia marcada!

Si acaba de comprar un cristal de "8 MHz" sin prestar la debida atención a la letra pequeña, puede obtener un corte a 8 MHz en el modo incorrecto; y su oscilador estará desafinado varios cientos de PPM.

(La resonancia paralela también se puede sintonizar a más de 50 ppm, por lo que generalmente se especifica en una capacitancia de carga determinada).

Uno pensaría que la mayoría de los diseñadores profesionales prestarían más atención y seleccionarían el cristal correcto, y por lo general tendrían razón, ¡pero incluso he visto algunos equipos de audio digital de alto precio en los que se cometió este error!

O tal vez la compra de componentes encontró un "buen trato" o simplemente se decidió que para una placa de evaluación de presupuesto, el precio era más importante que la precisión del tiempo...

Pero de todos modos, supongo que el cristal está funcionando en el modo incorrecto para producir un error de frecuencia de 300 ppm.

+1 para una buena suposición del problema, puedo desenterrar mi placa Discovery más tarde y realizar algunas pruebas en el cristal. De hecho, es común que los diseñadores coloquen cualquier cristal viejo sin tener en cuenta el nivel de la unidad, la carga, la temperatura, etc.
No estoy muy seguro de lo que se supone que debo verificar/hacer ahora
Arreglarlo de alguna manera. Posiblemente: (1) use un oscilador externo de 8 MHz, (2) encuentre un corte de cristal que se adapte al oscilador (como está funcionando demasiado rápido, sospecho que necesita uno sintonizado en resonancia en serie) (3) use el cristal actual en el correcto topología de resonador (supongo que es resonancia paralela, es decir, con el cristal como elemento vertical en una red en "T") o (4) aplicar una corrección de software, es decir, manipular la relación de división. En orden creciente de dificultad aproximadamente...
Alternativamente; parece haber 2 osciladores de cristal en el tablero e instrucciones en la guía del usuario para seleccionar uno (o el osc de 32768Hz). ¿Quizás uno de los otros osciladores está afinado?

Systick se deriva del reloj del procesador, que a su vez probablemente se deriva de un xtal (¿o del oscilador RC interno?).

1 segundo de error en 1 hora es 1: 3600 o 277 ppm. Se garantiza que un xtal común y corriente tiene una precisión de 50 ppm, por lo que es poco probable que esto se deba solo a la inexactitud de xtal.

¿Estás seguro de que tu chip se ejecuta en el xtal? Los chips LPC con los que estoy familiarizado funcionan por defecto en su oscilador RC interno, que es mucho menos preciso que un xtal.

Otro culpable podría ser una inicialización incorrecta, ¿estás seguro de que se hizo correctamente?

Nota al margen: para un mantenimiento preciso de los tiempos, los cristales de 32 kHz parecen ser más populares, pero no veo uno en una foto de una placa Discovery STM32F4. Hay un lugar vacío marcado como X3, tal vez sea para tal xtal.

1:86400 sería 1 segundo en un día completo. Durante una hora, esto contaría hasta 278 ppm.
Joder, error de cálculo. ¡Actualizaré mi respuesta!
Entiendo tu argumento. Aunque no se que puede estar fallando ahi. La inicialización se realiza automáticamente (system_stm32f4xx.c) y todo parece estar bien allí (frecuencia HSE (Hz) 8000000, SYSCLK (Hz) 168000000).
Como comentario aparte, no creo que los cristales de 32 kHz sean necesariamente más precisos, pero los relojes en tiempo real que funcionan a esta baja frecuencia consumen mucha menos energía y pueden funcionar con celdas tipo moneda.
Aparte, uno de los principales avances tecnológicos del siglo XVIII fue la invención de un reloj que podía marcar la hora durante un período de semanas, en condiciones de temperatura variables, con una precisión comparable a la de un cristal moderno sin compensación de temperatura. La electrónica no es necesaria para un buen cronometraje (¡aunque sí hace que el cronometraje sea relativamente bueno y económico!)

En la hoja de datos del STM32F4 encontré esto, tal vez sea tu respuesta:

Registro de valores de calibración SysTick

El valor de calibración de SysTick se fija en 18750, lo que proporciona una base de tiempo de referencia de 1 ms con el reloj SysTick configurado en 18,75 MHz (HCLK/8, con HCLK configurado en 150 MHz).

Supongo que no veo cómo responde esto a la pregunta: ¿cómo explica esto el aparente error?

Parece que su uC se está ejecutando desde el oscilador HSI: tengo un Discovery F4 y creo recordar que al principio tuve un poco de dificultad para que se ejecutara desde el oscilador externo.

Una manera fácil de probar es probar el pin de salida del oscilador externo para ver si está funcionando.

Si echa un vistazo a la documentación de la biblioteca de periféricos, en CMSIS, verá las funciones SystemInity . SetSysClockIIRC, al reiniciar, el comportamiento normal es usar el HSI a menos que se defina lo contrario. Asegúrese de tener definido STD_PERIPH_DRIVER y verifique su archivo system_stm32f4xx.c para asegurarse de que esté seleccionado el oscilador correcto. Asegúrese de que su HSE_VALUE esté definido (y establecido en el valor correcto) también.

Básicamente, eche un vistazo a los archivos de configuración del sistema CMSIS y la documentación en la biblioteca; olvidé de mi cabeza exactamente lo que necesita configurar (estoy medio dormido aquí, y muy pronto seré la otra mitad ... .), pero todo está en alguna parte (los comentarios del código lo guiarán sobre cómo configurar el oscilador correcto), por ejemplo, en el archivo system_stm32f4xx tiene este comentario en la parte superior:

* 5. This file configures the system clock as follows:
  *=============================================================================
  *=============================================================================
  *        Supported STM32F4xx device revision    | Rev A
  *-----------------------------------------------------------------------------
  *        System Clock source                    | PLL (HSE)
  *-----------------------------------------------------------------------------
  *        SYSCLK(Hz)                             | 168000000
  *-----------------------------------------------------------------------------
  *        HCLK(Hz)                               | 168000000
  *-----------------------------------------------------------------------------
  *        AHB Prescaler                          | 1
  *-----------------------------------------------------------------------------
  *        APB1 Prescaler                         | 4
  *-----------------------------------------------------------------------------
  *        APB2 Prescaler                         | 2
  *-----------------------------------------------------------------------------
  *        HSE Frequency(Hz)                      | 25000000
  *-----------------------------------------------------------------------------
  *        PLL_M                                  | 25
  *-----------------------------------------------------------------------------
  *        PLL_N                                  | 336
  *-----------------------------------------------------------------------------
  *        PLL_P                                  | 2
  *-----------------------------------------------------------------------------
  *        PLL_Q                                  | 7
  *-----------------------------------------------------------------------------
  *        PLLI2S_N                               | NA
  *-----------------------------------------------------------------------------
  *        PLLI2S_R                               | NA
  *-----------------------------------------------------------------------------
  *        I2S input clock                        | NA
  *-----------------------------------------------------------------------------
  *        VDD(V)                                 | 3.3
  *-----------------------------------------------------------------------------
  *        High Performance mode                  | Enabled
  *-----------------------------------------------------------------------------
  *        Flash Latency(WS)                      | 5
  *-----------------------------------------------------------------------------
  *        Prefetch Buffer                        | OFF
  *-----------------------------------------------------------------------------
  *        Instruction cache                      | ON
  *-----------------------------------------------------------------------------
  *        Data cache                             | ON
  *-----------------------------------------------------------------------------
  *        Require 48MHz for USB OTG FS,          | Enabled
  *        SDIO and RNG clock                     |
  *----------------------------------------------------------------------------- 
Los primeros siete valores son idénticos a los míos. Mi frecuencia HSE está configurada en 8000000, lo que debería estar bien para la placa Discovery, supongo. Por otra parte, no soy de ninguna manera un experto en esto ...

Hay un par de formas de calibrar el reloj HSI para que sea más realista, use la red eléctrica de 50 Hz o RTC. La nota de ST está aquí .

Básicamente cuente hasta un segundo usando Systick y RTC y divida en hardware usando los bits HSITRIM.