Skip to content

Analog-to-Digital Conversion (ADC) ​

Introduction ​

What Is an ADC? ​

An Analog-to-Digital Converter samples a continuous (analog) voltage and produces a discrete (digital) number. The TM4C123 microcontroller provides:

  • Resolution: 12 bits (0-4095)
  • Reference Voltage (Vref): Typically 3.3 V (can vary if externally configured)
  • Multiple analog input channels (AN0-AN11) mapped to specific GPIO pins
  • 4 Sample Sequencers (SS0-SS3) with different depths (SS3: 1 sample, SS2: 4, SS1: 4, SS0: 8)
  • 2 ADC modules (ADC0, ADC1) sharing the same input pins.

ADC Input Channel Mapping ​

ADC ChannelAN0AN1AN2AN3AN4AN5AN6AN7AN8AN9AN10AN11
PinPE3PE2PE1PE0PD3PD2PD1PD0PE5PE4PB4PB5

Key Concepts ​

  • Sampling: Capturing the analog value at a specific instant (sample rate must satisfy Nyquist criteria for varying signals)
  • Quantization: Mapping the sampled voltage to one of 2^12 discrete codes
  • Resolution (LSB size): Vref / 4096. For Vref = 3.3 V ⇒ ~0.000805 V per count
  • Conversion Formula: Voltage = (Result * Vref) / 4095

Sequencers ​

Each Sample Sequencer:

  • Collects one or more samples into a FIFO
  • Can be triggered by: processor, timer, PWM, comparator, GPIO, always, etc.
  • Is configured via:
    • EMUX (event trigger)
    • SSMUXn (channel selection)
    • SSCTLn (end/sample interrupt control)
    • IM (interrupt mask)
    • ACTSS (enable/disable)

Simplified Polling Flow ​

  1. Enable clocks: ADC + GPIO (for analog pin)
  2. Configure GPIO pin as analog input:
    • Disable digital (DEN)
    • Enable alternate function & analog mode (AFSEL/AMSEL)
  3. Disable target sample sequencer
  4. Set trigger source (processor for simplest)
  5. Select input channel in SSMUXn
  6. Configure SSCTLn (END0 | IE0)
  7. Enable sample sequencer
  8. Start conversion (PSSI)
  9. Poll RIS or check FIFO not empty
  10. Read SSFIFOx
  11. Clear interrupt (ISC)
  12. Convert to voltage

Interrupt-Driven Flow Differences ​

  • Enable interrupt in ADC IM
  • Enable NVIC interrupt line
  • ISR reads FIFO, clears flag, processes data

Sample Voltage Conversion (C) ​

c
float voltage = (sample * 3.3f) / 4095.0f;

Choosing Polling vs Interrupt ​

  • Polling: Simpler, CPU waits or loops
  • Interrupt: Efficient for periodic or multi-channel sampling
  • Timer-trigger + interrupt: Deterministic sampling rate
ModeProsConsUse When
PollingSimple, predictable orderCPU busy-waitSingle slow sensor
InterruptCPU free between samplesSlight overheadPeriodic sampling / display tasks
Timer + ADCStable sampling frequencyMore setupSignal analysis / filtering

Examples ​

Polling ADC ​

c
#include "TM4C123.h"
#include <stdio.h>

volatile unsigned int adc_value;

int main(void)
{

    /* Enable Clock to ADC0 and GPIO pins*/
    SYSCTL->RCGCGPIO |= (1 << 4); /* Enable Clock to GPIOE or PE3/AN0 */
    SYSCTL->RCGCADC |= (1 << 0);  /* AD0 clock enable*/

    /* initialize PE3 for AIN0 input  */
    GPIOE->AFSEL |= (1 << 3); /* enable alternate function */
    GPIOE->DEN &= ~(1 << 3);  /* disable digital function */
    GPIOE->AMSEL |= (1 << 3); /* enable analog function */

    /* initialize sample sequencer3 */
    ADC0->ACTSS &= ~(1 << 3);            /* disable SS3 during configuration */
    ADC0->EMUX &= ~0xF000;               /* software trigger conversion */
    ADC0->SSMUX3 = 0;                    /* get input from channel 0 */
    ADC0->SSCTL3 |= (1 << 1) | (1 << 2); /* take one sample at a time, set flag at 1st sample */
    ADC0->ACTSS |= (1 << 3);             /* enable ADC0 sequencer 3 */

    /*Iniitialize PF3 as a digital output pin */

    SYSCTL->RCGCGPIO |= 0x20; // turn on bus clock for GPIOF
    GPIOF->DIR |= 0x08;       // set GREEN pin as a digital output pin
    GPIOF->DEN |= 0x08;       // Enable PF3 pin as a digital pin

    while (1)
    {

        ADC0->PSSI |= (1 << 3); /* Enable SS3 conversion or start sampling data from AN0 */
        while ((ADC0->RIS & 8) == 0)
            ;                      /* Wait untill sample conversion completed*/
        adc_value = ADC0->SSFIFO3; /* read adc coversion result from SS3 FIFO*/
        ADC0->ISC = 8;             /* clear coversion clear flag bit*/

        if (adc_value >= 2048)
            GPIOF->DATA = 0x08; /* turn on green LED*/
        else if (adc_value < 2048)
            GPIOF->DATA = 0x00; /* turn off green LED*/
    }
}

Interrupt-Driven ADC ​

c
#include "TM4C123.h"
#include <stdio.h>

// Functions Declaration
void delayUs(int); // Delay in Micro Seconds
volatile unsigned int adc_value;

void ADC0SS3_Handler(void)
{
    adc_value = ADC0->SSFIFO3; /* read adc coversion result from SS3 FIFO*/

    if (adc_value >= 2048)
        GPIOF->DATA = 0x08; /* turn on green LED*/
    else if (adc_value < 2048)
        GPIOF->DATA = 0x00; /* turn off green LED*/
    ADC0->ISC = 8;          /* clear coversion clear flag bit*/
    ADC0->PSSI |= (1 << 3); /* Enable SS3 conversion or start sampling data from AN0 */
}

int main(void)
{

    /* Enable Clock to ADC0 and GPIO pins*/
    SYSCTL->RCGCGPIO |= (1 << 4); /* Enable Clock to GPIOE or PE3/AN0 */
    SYSCTL->RCGCADC |= (1 << 0);  /* AD0 clock enable*/

    /* initialize PE3 for AIN0 input  */
    GPIOE->AFSEL |= (1 << 3); /* enable alternate function */
    GPIOE->DEN &= ~(1 << 3);  /* disable digital function */
    GPIOE->AMSEL |= (1 << 3); /* enable analog function */

    /* initialize sample sequencer3 */
    ADC0->ACTSS &= ~(1 << 3);            /* disable SS3 during configuration */
    ADC0->EMUX &= ~0xF000;               /* software trigger conversion */
    ADC0->SSMUX3 = 0;                    /* get input from channel 0 */
    ADC0->SSCTL3 |= (1 << 1) | (1 << 2); /* take one sample at a time, set flag at 1st sample */
    ADC0->ACTSS |= (1 << 3);             /* enable ADC0 sequencer 3 */

    /*Iniitialize PF3 as a digital output pin */

    SYSCTL->RCGCGPIO |= 0x20; // turn on bus clock for GPIOF
    GPIOF->DIR |= 0x08;       // set GREEN pin as a digital output pin
    GPIOF->DEN |= 0x08;       // Enable PF3 pin as a digital pin

    /* Enable ADC Interrupt */
    ADC0->IM |= (1 << 3);        /* Unmask ADC0 sequence 3 interrupt*/
    NVIC->ISER[0] |= 0x00020000; /* enable IRQ17 for ADC0SS3*/
    ADC0->ACTSS |= (1 << 3);     /* enable ADC0 sequencer 3 */
    ADC0->PSSI |= (1 << 3);      /* Enable SS3 conversion or start sampling data from AN0 */

    while (1)
    {
    }
}

Tasks ​

Task 1: LED Control Based on ADC Value ​

Modify the polling example so that:

  • RED LED ON only when ADC value > 1000
  • GREEN LED ON only when ADC value <= 1000

Task 2: Display ADC Value and Voltage on LCD ​

Modify the interrupt-based example so both raw value and computed voltage are displayed on the LCD in the form:

ADC: 767
Voltage: 2.474