viernes, 7 de abril de 2017

Generación de un retardo -ARM Cortex-M4-

Programa

/* Marzo de 2016
Tarjeta: STM32 Discovery
Microcontrolador: STM32F411VET6U
IDE: IAR Embedded Workbench
Programa que produce el parpadeo cíclico de LED verde (PD12) de la tarjeta
STM32 Discovery cada segundo. El retardo se genera manejando Systick.
*/

#include "stm32f4xx.h"

//--- Función que inicializa el puerto D y configura PD12 ---
void ini_LED_verde(void){
  RCC->AHB1ENR   |= 0x00000008;       // Habilita el reloj para el puerto D
  GPIOD->MODER   |= 0x01000000;       // Configura el pin 12 como salida
  GPIOD->OSPEEDR |= 0x03000000;      // PD12 podrá funcionar a alta velocidad 
}

//--- Función que configura Systick ---
void config_systick_retardo(void) {
  SysTick->CTRL &= ~(SysTick_CTRL_CLKSOURCE_Msk); // La señal de reloj para
                                                                                                       // Systick es AHB / 8
                                                                                                       // ( = 12 MHz, en este caso)
  SysTick->LOAD  = 12000 - 1;        // Systick contará 12000 ciclos de una
señal de reloj de 12 MHz
 }

//--- Función que genera un retardo en milisegundos igual a num_ms ---
void retardo_ms(uint32_t num_ms) {
  SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;           // Habilita Systick
  while (num_ms != 0) {
    // Espera hasta que el valor del bit COUNTFLAG del registro de control de
Systick sea igual a '1'
    while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0) {}
    --num_ms;
  }
  SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk);    // Deshabilita Systick
}

//--- Función principal del programa ---
void main (void)  {        
  ini_LED_verde();                 
  config_systick_retardo();           
    
  while (1) {
    GPIOD->BSRRL = 0x1000;         // Enciende el LED
    retardo_ms(1000);                         // Retardo de 1 segundo 
    GPIOD->BSRRH = 0x1000;         // Apaga el LED    
    retardo_ms(1000);                         // Retardo de 1 segundo 
   }
}




➤ Observaciones

- No es necesario ningún componente electrónico externo a la tarjeta Discovery, dado que se utiliza el LED verde de la misma.

- El programa accede a los siguientes registros: RCC_AHB1ENR, GPIOD_MODER, GPIOD_OSPEEDR,  STK_CTRLSTK_LOAD. 

- En este programa se genera un retardo mediante el temporizador del sistema, SysTick.

- SysTick es un temporizador pensado para sistemas operativos en tiempo real, pero también puede ser usado como contador descendente estándar. Dispone de: un contador descendente de 24 bits, capacidad de auto-recarga, un sistema de generación de interrupciones cuando el contador llega a 0 y una fuente de señal de reloj programable.


- SysTick cuenta de manera descendente desde el valor de carga hasta 0, recarga ese valor en el registro STK_LOAD en el siguiente flanco de reloj y entonces cuenta descendentemente en los siguientes ciclos de reloj. Es decir, cuenta cíclicamente desde el valor cargado en STK_LOAD hasta 0.

- config_sysTick_retardo(): efectúa una llamada a la función encargada de configurar SysTick.

- retardo_ms(1000): llama a la función que crea el retardo valiéndose de SysTick. En este caso, la función llamada crea un retardo de 1000 milisegundos. 


- SysTick->CTRL &= ~(SysTick_CTRL_CLKSOURCE_Msk): selecciona la fuente de la señal de reloj para SysTick. En este caso, poniendo a ‘0’ el bit CLKSOURCE del registro STK_CTRL (bit 2), se decide que la señal de reloj de SysTick sea AHB / 8, que es la frecuencia a la salida del prescaler AHB dividida entre 8. En la entrada anterior del blog se había elegido una frecuencia para AHB de 96 MHz. La constante SysTick_CTRL_CLKSOURCE_Msk está definida en el archivo core_m4.h, al igual que el resto de constantes relacionadas con SysTick y empleadas en este programa.


- SysTick->LOAD = 12000 – 1: carga el valor ‘11999’ en el registro STK_VAL (bits 23:0, RELOAD). Este valor se carga en el registro STK_VAL cuando el contador está habilitado y alcanza 0. El valor de RELOAD puede ser cualquiera en el rango comprendido entre ‘0x00000001’ y ‘0x00FFFFFF’.


- El valor de RELOAD se calcula según su uso: para generar un temporizador multidisparo con un periodo de N ciclos de reloj del procesador, hay que usar un valor de RELOAD de N-1. Por ejemplo, si se requiere una interrupción de SysTick cada 100 pulsos de reloj, RELOAD tiene que valer 99. 


- Según el apartado 10.1.2 del documento
RM0383 Reference Manual, el valor de calibración está fijado en 10500, lo que da una referencia de la base de tiempos de 1 ms para una frecuencia de reloj de SysTick de 10,5 MHz (HCLK/8, con HCLK ajustado a 84 MHz). En este programa, el valor de RELOAD hace que SysTick cuente 12000 ciclos de una señal de reloj de 12 MHz; para efectuar esta operación es necesario 1 milisegundo de tiempo.

- SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk: habilita el contador, escribiendo un ‘1’ en el bit ENABLE del registro SysTick->CTRL. Cuando este bit está a ‘1’ el contador carga el valor de RELOAD desde el registro STK_LOAD y empieza a contar de manera descendente. Al llegar a 0, pone el bit COUNTFLAG (bit 16) a ‘1’ y opcionalmente activa la petición de excepción, dependiendo del valor de TICKINT, que es el bit 1 del registro STK_CTRL (en este ejemplo no se habilita la petición de excepción). Después de esto, carga el valor de RELOAD otra vez y sigue contando.


- while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0) {}: esta instrucción sirve para esperar hasta que el valor del bit COUNTFLAG del registro STK_CTRL sea igual a ‘1’. El bit COUNTFLAG devuelve un ’1’, si la cuenta del temporizador ha llegado a ‘0’; cuando sucede esto, que es cada milisegundo, se decrementa en una unidad el valor numérico contenido en la variable num_ms.


- SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk): deshabilita el contador, poniendo a ‘0’ el bit ENABLE del registro SysTick_CTRL. Esto es necesario porque mientras este bit esté habilitado el contador seguirá contando de manera cíclica. 



➤ Registros empleados

Las siguientes imágenes representan una parte de los registros utilizados en el programa y en ellas están señalados los bits que éste modifica o consulta. Únicamente aparecen los registros relacionados con la generación del retardo, los demás pueden encontrarse en las primeras entradas del blog.

Para más información, ver los documentos RM0383 Reference Manual y PM0214 Programming manual.










No hay comentarios: