/* Febrero de 2016
Tarjeta: STM32 Discovery
Microcontrolador: STM32F411VET6U
IDE: IAR Embedded Workbench
Programa que, empleando una interrupción externa, cambia el estado de los LED
de la tarjeta Discovery cada vez que se presiona un pulsador conectado entre el
pin de 3V de la tarjeta y PE3 (el pulsador no está conectado a ningún circuito
anti-rebotes).
*/
#include "stm32f4xx.h"
#define LED_Discovery_on 0x0000F000; // LED verde (PD12), LED naranja (PD13),
// LED rojo (PD14), LED azul (PD15),
// [Bits 12, 13, 14 y 15 de ODR] = 1
#define LED_Discovery_off 0xFFFF0FFF; // [Bits 12, 13, 14 y 15 de ODR] = 0
int estado_LED = 0; // Estado de los LED de la tarjeta
//--- Función que inicializa el puerto D y configura los pines de los LED
void ini_LED_Discovery (void){
RCC->AHB1ENR |= 0x00000008; // Habilita el reloj para el puerto D
GPIOD->MODER |= 0x55000000; // Config. PD12, PD13, PD14 y PD15 como sal. dig.
GPIOD->OSPEEDR |= 0xFF000000; // PD12, PD13, PD14 y PD15 funcionarán a alta
// velocidad
}
//--- Función que inicializa el puerto E y configura el pin del pulsador
void ini_pulsador(){
RCC->AHB1ENR |= 0x00000010; // Habilita reloj puerto E
//GPIOE->MODER |= 0x00000000; // Configura puerto E como entrada
GPIOE->PUPDR |= 0x00000080; // Pull-down para PE3
GPIOE->OSPEEDR |= 0x000000C0; // PE3 a alta velocidad
}
//---- Rutina de servicio de interrupción. Esta función usa un código anti-rebotes:
// ejecuta retardo; comprueba si el pulsador está pulsado (*); si es así, se ejecuta la
// orden estado_LED ^= 1. Aunque sería mejor utilizar un circuito anti-rebotes
// para no emplear retardos dentro de la subrutina de servicio interrupción y para no comprobar el estado del pin.
void EXTI3_IRQHandler (void) {
for (int i=0; i<30000; i++); // Retardo
if (GPIOE->IDR & 0x00000008){ // (*)
for (int i=0; i<30000; i++); // Retardo
estado_LED ^= 1; // Conmuta de 0 a 1 o de 1 a 0
}
EXTI->PR |= 0x00000008; // Borra el indicador de interr. para EXTI3
if (estado_LED == 1) GPIOD->ODR |= LED_Discovery_on; // Enciende los LED
if (estado_LED == 0) GPIOD->ODR &= LED_Discovery_off; // Apaga los LED
}
//--- Función principal del programa
void main (void) {
ini_LED_Discovery();
ini_pulsador();
// Órdenes para configurar y habilitar la interrupción externa
RCC->APB2ENR |= 0x00004000; // Habilita el reloj para SYSCFG
EXTI->IMR |= 0x00000008; // Hab. solicitud interrupción en EXTI3
EXTI->RTSR |= 0x00000008; // Hab. disparo de interrupción por flanco de subida
SYSCFG->EXTICR[0] |= 0x00004000; // Selecciona PE3 para EXTI3
NVIC->ISER[0] |= 0x00000200; // Hab. interrupción para EXTI3 en NVIC
// Bucle infinito
while (1) {
}
}
- Para no complicar el programa, el retardo utilizado se realiza con un bucle for. Las cuestiones relativas a la señal de reloj del microcontrolador se explican en esta entrada del blog y la forma de generar un retardo, de una manera más adecuada, se detalla en esta otra.
- En el programa se accede a los siguientes registros: RCC_AHB1ENR, GPIOD_MODER, GPIOD_OSPEEDR, GPIOE_PUPDR, GPIOE_OSPEEDR, GPIOE_IDR, GPIOD_ODR, RCC_APB2ENR, EXTI_IMR, EXTI_RTSR, SYSCFG_EXTICR1, NVIC_ISER0.
- Las órdenes contenidas en ini_LED_Discovery() e ini_pulsador() están explicadas en las primeras entradas del blog. En el programa está inactiva la orden GPIOE->MODER |= 0x00000000, debido a que es el valor que tiene el registro GPIOE_MODER por defecto, lo cual implica que todos los pines del puerto están configurados como entradas digitales. En este ejemplo, es necesario que PE3 sea una entrada digital.
- Dentro la función principal, están las órdenes para configurar y habilitar una interrupción interna (también podría haberse hecho escribiendo todas estas órdenes dentro de una función).
- Aunque en este ejemplo, para las salidas digitales, se ha empleado el registro GPIOD_ODR, es preferible usar BSRR.
- Ver apartado 10.2.4 de RM0383 Reference Manual. Para generar una interrupción, la línea de interrupción tiene que ser configurada y habilitada. La forma de hacerlo es programando los dos registros de disparo con el tipo de flanco deseado (de subida o de bajada) y habilitando la solicitud de interrupción; esto último se realiza escribiendo un ‘1’ en el correspondiente bit en el registro de máscara de interrupción. Se genera una solicitud de interrupción cuando se produce un flanco, del tipo seleccionado, en la línea de interrupción externa, . El pending bit correspondiente a la línea de interrupción también se habilita. Esta solicitud se puede borrar escribiendo un ‘1’ en el pending register. Una interrupción también puede ser generada escribiendo un ‘1’ en el registro de interrupciones/eventos.
- Ver apartado 10.2.4 de RM0383 Reference Manual. Para configurar las 23 líneas como fuentes de interrupción hay que hacer lo siguiente: (1) Configurar el bit de máscara de las 23 líneas de interrupción (EXTI_IMR); (2) configurar los bits de selección de disparador de las líneas de interrupción (EXTI_RTSR y EXTI_FTSR); (3) configurar los bits de habilitación y de máscara que controlan el canal NVIC_IRQ asignado al controlador de interrupciones externas (EXTI), de manera que una interrupción proveniente de una de las 23 líneas pueda ser correctamente admitida.
- Todas las interrupciones son manejadas por NVIC (nested vectored interrupt controller). Los registros de NVIC están detallados en el documento PM0214 Programming manual.
- RCC->APB2ENR |= 0x00004000: pone a ‘1’ el bit 14 del registro RCC_APB2ENR para habilitar el reloj de SYSCFG (system configuration controller). SYSCFG es el controlador de configuración del sistema y se utiliza principalmente para reasignar la memoria accesible en el área de código y gestionar la conexión de la línea de interrupción externa de los pines GPIO del microcontrolador.
- EXTI->IMR |= 0x00000008: habilita la solicitud de interrupción en EXTI3, poniendo a ‘1' el bit 3 del registro EXTI_IMR.
- EXTI->RTSR |= 0x00000008: habilita el disparo de la interrupción por flanco de subida para EXTI3 y queda deshabilitado para las demás líneas de interrupción. Escribe un '1' en el bit 3. Para usar un flanco de bajada sería necesario utilizar el registro EXTI->FTSR.
- SYSCFG->EXTICR[0] |= 0x00004000: escribe ‘0100’ en los bits 15, 14, 13 y 12 (EXTI3[3:0]) del registro 1 de configuración de interrupciones externas (SYSCFG_EXTICR1). Con esta operación, el pin que se elige para EXTI3 es PE3. Para EXTI3, sólo es posible escoger los pines designados por el número 3 de cada puerto del microcontrolador (ver la figura 30, arriba).
- NVIC->ISER[0] |= 0x00000200: escribe un ‘1’ en el bit 9 del registro NVIC_ISER0, lo cual produce la habilitación de la interrupción asociada a EXTI3. El registro NVIC_ISER0 tiene que ver con las 32 primeras posiciones de la tabla de vectores de los microcontroladores STM32F411xC/E, dicha tabla enumera las fuentes de interrupción del microcontrolador. La interrupción correspondiente a EXTI3 ocupa la posición número 9 de la tabla, de ahí que haya que escribir un ‘1’ el bit 9 del registro ISER0 (ver tabla 27, arriba). La información sobre el registro NVIC_ISER0 se puede consultar en el documento PM0214 Programming manual.
- EXTI->PR |= 0x00000008: esta instrucción, que esta dentro de la rutina de servicio de interrupción, se encarga de borrar el indicador de interupción para EXTI3. El bit 3 (PR3) del registro EXTI_PR (pending register) queda habilitado cuando se produce un flanco de subida en la línea de interrupción externa EXTI3, es decir, cuando tiene lugar una petición de interrupción procedente de EXTI3. La forma de deshabilitar ese bit es poniéndolo a ‘1’.
- Los registros NVIC_ISERx sirven para habilitar interrupciones, pero también muestran qué interrupciones han sido habilitadas.
- También se puede establecer la prioridad de la interrupción mediante uno de los registros NVIC_IPRx, pero en este ejemplo no es necesario, dado que sólo se usa una interrupción.
- while (1) {}: es un bucle infinito. En este ejemplo, sirve para demostrar que aunque el programa esté permanentemente ocupado con alguna tarea, puede ir atendiendo las interrupciones que se produzcan.
Para más información, ver el documento RM0383 Reference Manual y PM0214 Programming manual.
No hay comentarios:
Los comentarios nuevos no están permitidos.