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 Channel | AN0 | AN1 | AN2 | AN3 | AN4 | AN5 | AN6 | AN7 | AN8 | AN9 | AN10 | AN11 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Pin | PE3 | PE2 | PE1 | PE0 | PD3 | PD2 | PD1 | PD0 | PE5 | PE4 | PB4 | PB5 |
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 ​
- Enable clocks: ADC + GPIO (for analog pin)
- Configure GPIO pin as analog input:
- Disable digital (DEN)
- Enable alternate function & analog mode (AFSEL/AMSEL)
- Disable target sample sequencer
- Set trigger source (processor for simplest)
- Select input channel in SSMUXn
- Configure SSCTLn (END0 | IE0)
- Enable sample sequencer
- Start conversion (PSSI)
- Poll RIS or check FIFO not empty
- Read SSFIFOx
- Clear interrupt (ISC)
- 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
| Mode | Pros | Cons | Use When |
|---|---|---|---|
| Polling | Simple, predictable order | CPU busy-wait | Single slow sensor |
| Interrupt | CPU free between samples | Slight overhead | Periodic sampling / display tasks |
| Timer + ADC | Stable sampling frequency | More setup | Signal 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