martes, 28 de marzo de 2017

Conversión A/D -ARM Cortex-M4-

Programa
/* Febrero de 2016
Tarjeta: STM32 Discovery
Microcontrolador: STM32F411VET6U
IDE: IAR Embedded Workbench
Programa que lee la tensión variable de un potenciómetro conectado a los 3 V de
la tarjeta Discovery y cuyo pin central está conectado a PA1 (ADC1). Si el
resultado de la conversión analógico-digital supera un determinado valor, los
LED de la tarjeta STM32 Discovery se encienden.
- LED verde (PD12), LED naranja (PD13), LED rojo (PD14), LED azul (PD15)
*/

#include "stm32f4xx.h"

int resultado_ADC;

//--- Función que inicializa el puerto D y configura los pines que encienden 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. 
 }

//--- Función que inicializa el puerto A, ADC1 y habilita PA1 ---
void ini_ADC1 (void){
  RCC->AHB1ENR |= 0x00000001;    // Habilita el reloj para el puerto A
  RCC->APB2ENR |= 0x00000100;     // Habilita el reloj para ADC1 (bit 8 = 1)
  GPIOA->MODER |= 0x0000000C;   // Configura PA1 en modo analógico
  ADC1->CR2    |= 0x00000001;          // Habilita ADC1: ADON = 1
  ADC1->SQR3   |= 0x00000001;        // Elige ADC1_1 (en PA1) como primer canal de
                                                              // la secuencia de conversión (es el único)
}

//--- Función principal del programa ---
void main (void)  {  
  ini_LED_Discovery();
  ini_ADC1();
 
  while (1) { 
    ADC1->CR2 |= 0x40000000;            // Inicia la conversión A/D
    for (int j = 0; j<100; j++){};              // Retardo
    resultado_ADC = ADC1->DR;         // Guarda el resultado de la conversión
    if (resultado_ADC > 4000){              // Si el resultado es superior a un 
        GPIOD->BSRRL = 0xF000;         // determinado valor, enciende los LED
    }
    else GPIOD->BSRRH = 0xF000;      // Si es inferior, los apaga
  }
}



➤ Circuito




➤ Observaciones

- 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, RCC_APB2ENR, GPIOA_MODERADC1_CR2, ADC1_SQR3 y GPIOD_BSRR.

- En este ejemplo se realiza una conversión A/D simple de un solo canal. Si se utilizara el modo continuo de conversión A/D, el módulo ADC del microcontrolador empezaría una nueva conversión en cuanto finalizase la anterior.

- El módulo ADC del microcontrolador posee dos tipos de canales: regulares e inyectados.  Este programa utiliza un canal regular. Ver apartado 11.3.3 del documento RM0383 Reference Manual.

-  En el programa: la resolución de la conversión A/D es de 12 bits (bits 25 y 24 del registro ADC_CR1), el watchdog está deshabilitado (bit 23 del registro ADC_CR1), el DMA está deshabilitado (bit 8 del registro ADC_CR2), se produce alineación a la derecha de los datos almacenados después de la conversión (bit 11 del registro ADC_CR2), el tiempo de muestreo es de 3 ciclos de reloj del ADC (se utiliza el registro ADC_SMPR1 o ADC_SMPR2, según el canal usado). Todos estos parámetros están configurados por defecto, por lo que no es necesario acceder a sus registros.

- Esta familia de microcontroladores sólo posee un módulo ADC y éste es ADC1. El canal ADC1_1 (o ADC1_IN1) se corresponde con el pin PA1

- Las órdenes contenidas en la función ini_LED_Discovery() y las que usan el registro GPIOD_BSRR están explicadas en esta entrada del blog y en esta otra.

- RCC->APB2ENR |= 0x00000100: habilita el reloj para el módulo ADC1. Pone a '1' el bit 8 del registro RCC_APB2ENR.

- GPIOA->MODER |= 0x0000000C: configura PA1 en modo analógico. Pone a ‘1’ los bits 2 y 3 del registro MODER del puerto A.

- ADC1->CR2 |= 0x00000001: habilita el módulo ADC1, poniendo ADON a ‘1’. ADON es el bit 0 del registro ADC_CR2.

- ADC1->SQR3 |= 0x00000001: los canales regulares y también su orden en la secuencia de conversión deben ser seleccionados con los registros ADC_SQRx (con ADC_JSQRx se puede hacer lo mismo para los canales inyectados). En estos registros, los bits son escritos mediante programación con el número de canal (0...18) en el puesto que se desee de la secuencia. En este caso, al canal 1 (ADC1_1) se le asigna la primera posición de la secuencia y por ese motivo se escribe '00001' en SQ1[4:0]. Aunque es cierto que aquí sólo se utiliza un canal y que no se efectúa una secuencia propiamente dicha, esta orden es imprescindible porque el microcontrolador ha de saber el canal elegido (ADC1_1, que está asociado al pin PA1).

- ADC1->CR2 |= 0x40000000: inicia la conversión A/D. Poniendo a '1' el bit SWSTART (bit 30) del registro ADC_CR2, empieza la conversión A/D de los canales regulares. Este bit se habilita por software para comenzar la conversión y se deshabilita por hardware en cuanto la conversión empieza SWSTART sólo puede ser habilitado cuando ADON vale '1', de otro modo, la conversión no tendría lugar.

- resultado_ADC = ADC1->DR: al terminar la conversión A/D, su resultado se almacena en los 16 primeros bits del registro ADC1_DR (los otros 16 bits del registro están reservados). Ese resultado es un número entero entre 0 y 4095 (12 bits de resolución), que se guarda en la variable entera  resultado_ADC.

- GPIOD->BSRRL = 0xF000 y GPIOD->BSRRH = 0xF000: ver esta entrada del blog.



➤ Registros empleados

Las siguientes imágenes representan los registros utilizados en el programa y en ellas están señalados los bits que éste modifica o consulta. Las marcas rojas se refieren a las salidas digitales del programa y las verdes, a la conversión A/D. 

A pesar usar una única figura, el programa maneja dos registros MODER diferentes: uno es GPIOA_MODER (marca verde) y el otro es GPIOD_MODER (marca roja).

Para más información, ver el documento RM0383 Reference Manual.




















No hay comentarios: