Created on: 4 July 2016
Part 13 of the ASF ARM Tutorial
How to use the Analog to Digital Converter (ADC) Atmel Software Framework (ASF) driver to initialize and use the ADC on an Atmel ARM Cortex microcontroller.
In this part of the ASF ARM tutorial, the ASF ADC driver is used to initialize the ADC and read the analog value from one of the ADC's channels. The ADC is polled by software to get the channel value.
The result of each ADC conversion is sent out of the serial port of the ARM microcontroller and displayed in a terminal window.
An Atmel SAM4N Xplained Pro board with ATSAM4N16C microcontroller is used in this tutorial. Make the necessary changes to the software and hardware connections if you are using a different board.
A 10k potentiometer is connected to pin header EXT1 of the board with one of the outside pins of the pot. connected to GND and the other outside pin connected to Vcc (3.3V). The centre wiper of the pot. is connected to PA17 which is AD0 of the ADC and pin 3 of the EXT1 header.
The images below show the physical connection of the potentiometer to the SAM4N board and the circuit diagram of the pot. connections to header EXT1.
As with the previous part of this tutorial series, a terminal emulator will be needed such as Tera Term for Windows.
Create a new ASF project called adc in Atmel Studio as explained in the new ASF project quick start checklist.
This project uses printf() to output text to the terminal window over the serial port, so the project is based on part 11 of this tutorial series which uses a UART for stdio functions.
Add the following modules to the project using the ASF Wizard.
The ADC driver ASF module adds the ADC functionality to the project. IOPORT and Standard serial I/O are used to set up the UART for stdio functions.
UART0 is defined as the console UART as it is connected to the EDBG virtual COM port on the SAM4N Xplained Pro board.
\src\config\conf_board.h
#ifndef CONF_BOARD_H #define CONF_BOARD_H #define CONSOLE_UART UART0 // clock resonators #define BOARD_FREQ_SLCK_XTAL (32768U) #define BOARD_FREQ_SLCK_BYPASS (32768U) #define BOARD_FREQ_MAINCK_XTAL (12000000U) #define BOARD_FREQ_MAINCK_BYPASS (12000000U) #define BOARD_MCK CHIP_FREQ_CPU_MAX #define BOARD_OSC_STARTUP_US 15625 #endif // CONF_BOARD_H
Uncomment the USART settings in conf_uart_serial.h as shown in the code listing below. Be sure to set the UART name (CONF_UART) to point to the correct UART for the board.
\src\config\conf_uart_serial.h
#ifndef CONF_USART_SERIAL_H #define CONF_USART_SERIAL_H /* A reference setting for UART */ /** UART Interface */ //#define CONF_UART CONSOLE_UART /** Baudrate setting */ //#define CONF_UART_BAUDRATE 115200 /** Parity setting */ //#define CONF_UART_PARITY UART_MR_PAR_NO /* A reference setting for USART */ /** USART Interface */ #define CONF_UART CONSOLE_UART /** Baudrate setting */ #define CONF_UART_BAUDRATE 115200 /** Character length setting */ #define CONF_UART_CHAR_LENGTH US_MR_CHRL_8_BIT /** Parity setting */ #define CONF_UART_PARITY US_MR_PAR_NO /** Stop bits setting */ #define CONF_UART_STOP_BITS US_MR_NBSTOP_1_BIT #endif /* CONF_USART_SERIAL_H_INCLUDED */
The UART pins are configured in init.c.
\src\ASF\common\boards\user_board\init.c
#include <asf.h> #include <board.h> #include <conf_board.h> void board_init(void) { WDT->WDT_MR = WDT_MR_WDDIS; // disable watchdog ioport_init(); // call before using IOPORT service // configure UART pins ioport_set_port_mode(IOPORT_PIOA, PIO_PA9A_URXD0 | PIO_PA10A_UTXD0, IOPORT_MODE_MUX_A); ioport_disable_port(IOPORT_PIOA, PIO_PA9A_URXD0 | PIO_PA10A_UTXD0); }
The main application code sets up stdio functions to use the UART. ADC channel 0 is then enabled and polled in the main loop. Values from the ADC are sent out of the UART serial port and displayed in a terminal window.
\src\main.c
#include <asf.h> int main (void) { // structure used to initialize UART for use with stdio functions const usart_serial_options_t usart_serial_options = { .baudrate = CONF_UART_BAUDRATE, .charlength = CONF_UART_CHAR_LENGTH, .paritytype = CONF_UART_PARITY, .stopbits = CONF_UART_STOP_BITS }; struct adc_config adc_conf; // struct for configuring ADC uint32_t adc_val; // holds ADC value read from ADC channel sysclk_init(); board_init(); // initialize stdio functions so printf() uses the UART stdio_serial_init(CONF_UART, &usart_serial_options); // configure and enable the ADC adc_enable(); // enable ADC adc_get_config_defaults(&adc_conf); // read ADC default values adc_init(ADC, &adc_conf); // initialize the ADC with default values adc_set_trigger(ADC, ADC_TRIG_SW); // set ADC to trigger with software for polling adc_channel_enable(ADC, ADC_CHANNEL_0); // enable ADC channel 0 (AD0, pin PA17 on ATSAM4N16C) while (1) { // start the ADC conversion adc_start_software_conversion(ADC); // wait until the conversion complete bit for AD0 is set while (!(adc_get_interrupt_status(ADC) & (1 << ADC_CHANNEL_0))); // read the value from the ADC for channel 0 adc_val = adc_channel_get_value(ADC, ADC_CHANNEL_0); // display the ADC value in decimal and hexadecimal printf("ADC value: %04u, 0x%04x\r\n", (unsigned)adc_val, (unsigned)adc_val); } }
In the while(1) loop, the ADC conversion is started. A bit is then polled in the ADC_ISR register which will be set when the conversion for AD0 is complete. Polling of the register is done by calling adc_get_interrupt_status(). When the conversion is complete, the ADC value for channel 0 is read from the ADC and sent to the terminal window.