Está en la página 1de 6

22/3/2020 ATSAM4S ADC

Empezar (index.html)
Hardware (hardware.html)
Programación (programming.html)
Cargador de arranque (bootloader.html)
Bit Twiddling (bittwiddling.html)
GPIO - Entrada/salida de uso general (gpio.html)
PMC - Reloj del sistema (clock.html)
INT - Interrupciones (interrupts.html)
UART - Receptor-Transmisor Asíncrono Universal (uart.html)
TC - Interrupción de desbordamiento de temporizador/contador (timercounter.html)
TC - Temporizador/Contador Comparar Interrupción (timercounterdelay.html)
I2C - Circuito interintegrado (i2c.html)
SPI - Interfaz periférica serie (spi.html)
GPIO - GLCD (gpio-glcd.html)
RTC - Reloj en tiempo real (rtc.html)
RTT - Temporizador de tiempo real (rtt.html)
ADC - Convertidor Digital Analógico (adc.html)
DACC - Convertidor Analógico Digital (dacc.html)
SUPCC - Ahorro de energía/sueño/despertar (sleep.html)
QDEC - Decodificador de señal de cuadratura (qdec.html)
PWM - Modulación de ancho de pulso (pwm.html)
Depuración (debugging.html)

ADC: Conversión analógica a digital


El ADC en el ATSAM4S tiene 16 canales con 12 bits de resolución. El reloj ADC se puede configurar mediante un
preescalador de 8 bits (fcpu/2 si prescaler-0 y fcpu/512 si el preescalador es 255). Compruebe la página 1172 en
los parámetros de frecuencia de reloj de la hoja de datos. A diferencia del AVR y el XMEGA, el SAM4S no tiene
una referencia de voltaje interno y debemos conectar el pin ADVREF a una fuente de voltaje.
La configuración del controlador PIO es un poco diferente para el ADC en comparación con los otros periféricos.
Para otros periféricos desactivamos el PIO para los pines que queremos utilizar estableciendo bits en el
REG_PIA_PDR. Para el ADC, establecemos bits en el REG_ADC_CHER - adc channel enable register. Cuando
se establece un bit para un pin correspondiente que el canal adc está habilitado, pio deshabilitado en el pin
correspondiente, configurado automáticamente para la entrada, pull up habilitado y conectado a tierra.

*nota* Cada vez que cambie la referencia de voltaje de entrada en el ADVREF, se debe ejecutar una
configuración automática de una sola vez.

Configuración
habilitar el reloj ADC en PMC
permitir interrupciones para ADC en NVIC
habilitar canales ADC (deshabilitar PIO)
establecer el preescalador del reloj ADC
establecer IBCTL en REG_ADC_ACR dependiendo de la frecuencia del reloj ADC
habilitar el tipo de interrupción
iniciar una conversión
escribir controlador de interrupción

En el primer ejemplo conectaremos la salida de un sensor de temperatura externo al canal ADC 0, que está en
PA17.

habilitar los canales, establezca los bits adecuados en el registro REG_ADC_CHER.

www.mwmw.ca/adc.html 1/6
22/3/2020 ATSAM4S ADC

(images/adclm35.jpg)

Hay dos interrupciones que se pueden usar para desencadenar un evento de fin de conversión.
EOC (fin de la conversión) o DRDY (datos listos). Ambos bits se pueden establecer en el registro de
REG_ADC_IER. Para borrar el indicador de interrupción EOC en el REG_ADC_ISR el REG_ADC_CDRx (registro
de datos del canal) necesita ser leído. Para borrar el indicador de interrupción DRDY, es necesario leer el
REG_ADC_LCDR (último registro de datos convertido).
Después de iniciar una conversión estableciendo el bit de inicio en el REG_ADC_CR el ADC convertirá los datos
y desencadenará una interrupción cuando haya
terminado.

(images/reg_adc_cdrx.jpg)

*nota* En la página 1117 muestra el Registro de Datos del Canal ADC (REG_ADC_CDRx) Parece que se puede
leer los registros en REG_ADC_CDR0, REG_ADC_CDR1, ... , REG_ADC_CDR15, pero si nos fijamos en las
definiciones en adc.h sólo se puede encontrar REG_ADC_CDR que se establece en la dirección 0x40038050 que
es channel0.
Tenemos que hacer nuestras propias definiciones para leer los otros registros.

(images/reg_adc_cdr.jpg)

Aquí está una lista de los registros y direcciones para REG_ADC_CDRx: Entonces, si queremos leer el valor de
REG_ADC_CDR15 (registro de datos de canal 15) entonces en nuestra configuración podemos definir esto como:

#define REG_ADC_CDR15 (*(__I uint32_t*)0x4003808CU)

Ejemplo: Leer canal 0


Conectaremos un sensor de temperatura al canal0 y leeremos la salida de voltaje de nuestro sensor para obtener
la temperatura ambiente.

12 bit Resolution/advref voltage = adc reading/voltage


4095/3300 = 266/voltage
voltage = 214mv

Para este sensor en particular, emite 10mv para cada grado C. Eso significa que es 21.4 C en esta habitación.
www.mwmw.ca/adc.html 2/6
22/3/2020 ATSAM4S ADC

#include "sam.h"
#include "basic_uart.h"

void clock_init(){
REG_CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN;
while (!(REG_PMC_SR & PMC_SR_MOSCXTS));
REG_CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL;
REG_PMC_MCKR |= MC_MCKR_CSS_MAIN_CLK;
while (!(REG_PMC_SR & PMC_SR_MCKRDY));
REG_PMC_MCKR |= PMC_MCKR_PRES_CLK_1;
while (!(REG_PMC_SR & PMC_SR_MCKRDY));
}

void ADC_init(){
/*enabling the channel automatically gives peripheral control of the pin instead of the PIO
automatically configures pin to input, pull up enabled and connect to ground*/

//enable ADC channel0


REG_ADC_CHER |= ADC_CHER_CH0;

//set ADC clock to 1mhz


/*datasheet page 1172
for clock 500khz to 1mhz set ADC_ACR IBCTL = 01
*/
REG_ADC_ACR |= ADC_ACR_IBCTL(1);
/*clock prescaler = (fcpu / (2*adc_freq)) - 1
20,000,000 / (2*1000000) - 1 = 9
*/
REG_ADC_MR |= ADC_MR_PRESCAL(9);

//Enable ADC interrupts for end of conversion


REG_ADC_IER |= ADC_IER_EOC0;

//Need to just run once. If you change the voltage on ADVREF you need to run again
//ADC software reset
//REG_ADC_CR |= ADC_CR_SWRST;
//autocalibration
//REG_ADC_CR |= ADC_CR_AUTOCAL;
}

int main(void)
{
/* Initialize the SAM system */
SystemInit();
clock_init();
UART_Init();

//enable clock for ADC


REG_PMC_PCER0|= PMC_PCER0_PID29;

//enable ADC interrupts


NVIC_EnableIRQ(ADC_IRQn);

ADC_init();

//start a conversion
REG_ADC_CR |= ADC_CR_START;
while (1)
{
}
}

//when ADC conversion is complete it will trigger an interrupt and interrupt will end by starting
void ADC_Handler( void) {
//read interrupt flag status register
uint32_t status = REG_ADC_ISR;
uint32_t adcData;
if ((status & ADC_IMR_EOC15) > 0){
//reading this register clears flag in ISR
www.mwmw.ca/adc.html 3/6
22/3/2020 ATSAM4S ADC
//reading this register clears flag in ISR
adcData = REG_ADC_CDR;
printString("Sensor Output: ");
printWord(adcData);
printString("\r\n");
}
//start the next conversion
REG_ADC_CR |= ADC_CR_START;
}

Ejemplo: Leer el canal 15 del sensor de temperatura interno


Canal 15 es un sensor de temperatura interno que da una salida lineal de 4.7mv / grado C. Hay un
desplazamiento que debe calibrarse. Puede encontrar información sobre el sensor de temperatura en la hoja de
datos de la página 1183. Además de activar el chanel 15, el programador también debe activar el sensor de
temperatura ajustando el bit TSON en el registro de REG_ADC_ACR.

www.mwmw.ca/adc.html 4/6
22/3/2020 ATSAM4S ADC

#include "sam.h"
#include "basic_uart.h"

void clock_init(){
REG_CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN;
while (!(REG_PMC_SR & PMC_SR_MOSCXTS));
REG_CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL;
REG_PMC_MCKR |= MC_MCKR_CSS_MAIN_CLK;
while (!(REG_PMC_SR & PMC_SR_MCKRDY));
REG_PMC_MCKR |= PMC_MCKR_PRES_CLK_1;
while (!(REG_PMC_SR & PMC_SR_MCKRDY));
}

void ADC_init(){
/*enabling the channel automatically gives peripheral control of the pin instead of the PIO
automatically configures pin to input, pull up enabled and connect to ground*/

//enable ADC channel15 (internal temperature sensor)


REG_ADC_CHER |= ADC_CHER_CH15;
//enable internal temperature sensor
REG_ADC_ACR |= ADC_ACR_TSON;

//set ADC clock to 1mhz


/*datasheet page 1172
for clock 500khz to 1mhz set ADC_ACR IBCTL = 01
*/
REG_ADC_ACR |= ADC_ACR_IBCTL(1);
/*clock prescaler = (fcpu / (2*adc_freq)) - 1
20,000,000 / (2*1000000) - 1 = 9
*/
REG_ADC_MR |= ADC_MR_PRESCAL(9);

//Enable ADC interrupts for end of conversion


REG_ADC_IER |= ADC_IER_EOC15;

//Need to just run once. If you change the voltage on ADVREF you need to run again
//ADC software reset
//REG_ADC_CR |= ADC_CR_SWRST;
//autocalibration
//REG_ADC_CR |= ADC_CR_AUTOCAL;
}

#define REG_ADC_CDR15 (*(__I uint32_t*)0x4003808CU) /**< \brief (ADC) Channel Data Register */

int main(void)
{
/* Initialize the SAM system */
SystemInit();
clock_init();
UART_Init();

//enable clock for ADC


REG_PMC_PCER0 |= PMC_PCER0_PID29;

//enable ADC interrupts


NVIC_EnableIRQ(ADC_IRQn);

ADC_init();
//start a conversion
REG_ADC_CR |= ADC_CR_START;

while (1)
{
}
}

//when ADC conversion is complete it will trigger an interrupt and interrupt will end by starting
void ADC_Handler( void) {

www.mwmw.ca/adc.html 5/6
22/3/2020 ATSAM4S ADC

//read interrupt flag status register


uint32_t status = REG_ADC_ISR;
uint32_t adcData;
if ((status & ADC_IMR_EOC15) > 0){
//reading this register clears flag in ISR
adcData = REG_ADC_CDR15;
printString("Sensor Output: ");
printWord(adcData);
printString("\r\n");
}
REG_ADC_CR |= ADC_CR_START;
}

www.mwmw.ca/adc.html 6/6

También podría gustarte