ADC ASF Driver Tutorial

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.

ADC ASF Tutorial Hardware and Software

Hardware

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.

ADC Potentiometer Connection to SAM4N Board
ADC Potentiometer Connection to SAM4N Board
SAM4N Potentiometer Circuit
SAM4N Potentiometer Circuit Connected to EXT1

Software

As with the previous part of this tutorial series, a terminal emulator will be needed such as Tera Term for Windows.

Creating the ADC ASF Tutorial Project

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.

ASF Modules

Add the following modules to the project using the ASF Wizard.

  • System Clock Control (service)
  • IOPORT - General purpose I/O service (service)
  • Standard serial I/O (stdio)(driver)
  • ADC - Analog-to-digital Converter (driver)
ASF Modules used in the ADC Project
ASF Modules used in the ADC Project

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.

Hardware Definitions and Configuration (conf_board.h and conf_uart_serial.h)

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 */

Hardware Initialization (init.c)

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);
}

Application Code (main.c)

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.