๐Ÿ“ Pico Series
Episode 05 ยท Pico Learning Series
// CONCEPT: ADC + PWM

PotentiometerADC โ†’ LED Brightness

12-bit ADC ยท GPIO 26 ยท PWM Duty Cycle ยท Analog World
// What you'll learn
What ADC is โ€” converting analog voltage to a digital number
The RP2040's 12-bit ADC: 0โ€“4095 mapped to 0โ€“3.3V
What PWM is โ€” simulating analog output with digital pulses
How duty cycle controls perceived LED brightness
// Interactive ADC + PWM Simulator
Potentiometer
โ†’
ADC
2048
โ†’
LED
2048
ADC Raw
1.65V
Voltage
50%
PWM Duty
// PWM Signal (simulated)
โ† Drag to rotate potentiometer โ†’
// 01 โ€” Core Concepts

Analog In, Digital Brain

๐Ÿ“Š
ADC โ€” Analog to Digital
The real world is analog โ€” temperature, voltage, pressure all vary continuously. The RP2040's 12-bit ADC samples these voltages and converts them to integers 0โ€“4095. adc_read() returns this number in microseconds.
12-bit = 4096 steps
๐ŸŒŠ
PWM โ€” Pulse Width Modulation
GPIO pins are either ON (3.3V) or OFF (0V) โ€” they can't output 1.65V directly. PWM switches the pin on and off very fast. If it's ON 50% of the time, the LED sees an average of 1.65V and appears half-bright.
Duty cycle = brightness
๐Ÿ”„
The Control Loop
adc_read() โ†’ divide by 64 โ†’ that's the brightness value. Then gpio_put(LED,1), sleep_us(brightness), gpio_put(LED,0), sleep_us(1000-brightness). Higher ADC = longer ON time = brighter LED.
pot_value / 64
๐ŸŽ›๏ธ
Potentiometer
0 โ†’ 3.3V
analog voltage
โ†’
๐Ÿ“ก
GPIO 26
ADC pin
adc_gpio_init(26)
โ†’
๐Ÿ”ข
adc_read()
0 โ†’ 4095
12-bit integer
โ†’
โž—
รท 64
0 โ†’ 63
brightness steps
โ†’
๐Ÿ’ก
PWM LED
GPIO 14
variable brightness
// 02 โ€” Source Code

The ADC Loop

potentiometer.c
#include "hardware/adc.h"
#include "hardware/pwm.h"
#include "pico/stdlib.h"
#include <stdio.h>

#define LED_PIN 14   // LED GPIO
#define POT_PIN 26   // ADC GPIO (ADC channel 0)

int main() {
    stdio_init_all();

    // โ”€โ”€ ADC Setup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    adc_init();                  // init ADC hardware
    adc_gpio_init(POT_PIN);     // enable ADC on GPIO 26
    adc_select_input(0);        // select ADC channel 0

    // โ”€โ”€ LED Setup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);

    while (1) {
        // Read 12-bit ADC value (0โ€“4095)
        uint16_t pot_value = adc_read();

        // Convert to voltage for display
        float voltage = (pot_value / 4096.0) * 3.3;
        printf("Voltage: %.2f V\n", voltage);

        // Map ADC โ†’ brightness (0โ€“63 steps)
        uint16_t brightness = pot_value / 64;

        // Soft-PWM: GPIO ON for 'brightness' ยตs
        //          GPIO OFF for remainder
        gpio_put(LED_PIN, 1);
        sleep_us(brightness);
        gpio_put(LED_PIN, 0);
        sleep_us(1000 - brightness);

        sleep_ms(10); // smooth transition
    }
}
// ADC API Reference
adc_init()
Initialize ADC hardware block
adc_gpio_init(pin)
Enable ADC on GPIO 26/27/28/29
adc_select_input(ch)
Select channel 0โ€“3 (GPIO 26โ€“29)
adc_read()
Returns uint16_t 0โ€“4095
// Connections
Potentiometer wiper โ†’ GPIO 26
(one end = 3.3V, other = GND)
LED anode (+) โ†’ GPIO 14
(cathode โ€“ โ†’ GND via 330ฮฉ)