RPi Pico 2W — Using ADC
Pico 2 ADC overview can be found in the datasheet on page 1067.
The ADC runs on a 48 MHz clock and a conversion takes 96 cycles. This gives a maximum of 500000 samples per second.
On the Pico 2, the ADC has 5 channels, which can sample inputs from GPIO-26, GPIO-27, GPIO-28, GPIO-29 and from the built-in temperature sensor.
| Channel | Connection |
|---|---|
| 0 | GPIO[26] |
| 1 | GPIO[27] |
| 2 | GPIO[28] |
| 3 | GPIO[29] |
| 4 | Temperature Sensor |
First, add the hardware_adc library to CMakeLists.txt for ADC support.
target_link_libraries(my_project pico_stdlib hardware_adc)Now the steps are:
- Initialize the ADC.
- Configure the GPIO pin to sample.
- Configure the ADC to sample the correct GPIO.
- Configure the sample rate.
adc_init();
// Make sure GPIO is high-impedance, no pullups etc adc_gpio_init(26);
// Select ADC input 0 (GPIO26) adc_select_input(0);And then continuously read from the ADC, with code similar to the code in the Pico examples repository:
// 12-bit conversion, assume max value == ADC_VREF == 3.3 V const float conversion_factor = 3.3f / (1 << 12); uint16_t result = adc_read(); // Trigger conversion and wait for result printf("Raw value: 0x%03x, voltage: %f V\n", result, result * conversion_factor);Interrupts, FIFO, and freerunning mode
Section titled “Interrupts, FIFO, and freerunning mode”The ADC has a DIV register, which can be used to control how often to
initiate a new sampling. From the datasheet:
Set DIV.INT to a positive value n to trigger the ADC once per n + 1 cycles. The ADC ignores this if a conversion is currently in progress, so generally n will be ≥ 96. For example, setting DIV.INT to 47999 runs the ADC at 1 kS/s, if running from a 48 MHz clock. The pacing timer supports fractional-rate division (first order delta sigma). When setting DIV.FRAC to a non-zero value, the ADC starts a new conversion once per
1 + INT + FRAC/256cycles on average, by changing the sample interval betweenINT + 1andINT + 2.
The function void adc_set_clkdiv(float clkdiv) from adc.h can be used
to set the DIV register. The function void adc_run(bool run) from
adc.h starts the ADC as “freerunning”, which means that it keeps
sampling and placing the sampled value in its result register. However,
there is no function in the SDK that can read the result register (except
for adc_read(), which starts a new conversion). An option would be to
configure use of the FIFO, but it looks like the FIFO would have to be
polled from application code, because there doesn’t seem to be an option
to configure a callback or interrupt on the FIFO. The ADC can also sample
the 5 channels in round-robin mode, but it will place the results in the
same FIFO with no indication of which channel the result came from.
So, the hardware seems very capable, but the SDK is currently lacking features to use it fully.