Expand description
Analog-Digital Converter (ADC)
See Chapter 4 Section 9 of the datasheet for more details
§Usage
Capture ADC reading from a pin:
// Embedded HAL 1.0.0 doesn't have an ADC trait, so use the one from 0.2
use embedded_hal_0_2::adc::OneShot;
use rp2040_hal::{adc::Adc, adc::AdcPin, gpio::Pins, pac, Sio};
let mut peripherals = pac::Peripherals::take().unwrap();
let sio = Sio::new(peripherals.SIO);
let pins = Pins::new(peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS);
// Enable adc
let mut adc = Adc::new(peripherals.ADC, &mut peripherals.RESETS);
// Configure one of the pins as an ADC input
let mut adc_pin_0 = AdcPin::new(pins.gpio26.into_floating_input()).unwrap();
// Read the ADC counts from the ADC channel
let pin_adc_counts: u16 = adc.read(&mut adc_pin_0).unwrap();
Capture ADC reading from temperature sensor. Note that this needs conversion to be a real-world temperature.
// Embedded HAL 1.0.0 doesn't have an ADC trait, so use the one from 0.2
use embedded_hal_0_2::adc::OneShot;
use rp2040_hal::{adc::Adc, gpio::Pins, pac, Sio};
let mut peripherals = pac::Peripherals::take().unwrap();
let sio = Sio::new(peripherals.SIO);
let pins = Pins::new(peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS);
// Enable adc
let mut adc = Adc::new(peripherals.ADC, &mut peripherals.RESETS);
// Enable the temperature sensor
let mut temperature_sensor = adc.take_temp_sensor().unwrap();
// Read the ADC counts from the ADC channel
let temperature_adc_counts: u16 = adc.read(&mut temperature_sensor).unwrap();
See examples/adc.rs and pimoroni_pico_explorer_showcase.rs for more complete examples
§Free running mode with FIFO
In free-running mode the ADC automatically captures samples in regular intervals. The samples are written to a FIFO, from which they can be retrieved.
use rp2040_hal::{adc::Adc, gpio::Pins, pac, Sio};
let mut peripherals = pac::Peripherals::take().unwrap();
let sio = Sio::new(peripherals.SIO);
let pins = Pins::new(peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS);
// Enable adc
let mut adc = Adc::new(peripherals.ADC, &mut peripherals.RESETS);
// Enable the temperature sensor
let mut temperature_sensor = adc.take_temp_sensor().unwrap();
// Configure & start capturing to the fifo:
let mut fifo = adc.build_fifo()
.clock_divider(0, 0) // sample as fast as possible (500ksps. This is the default)
.set_channel(&mut temperature_sensor)
.start();
loop {
if fifo.len() > 0 {
// Read one captured ADC sample from the FIFO:
let temperature_adc_counts: u16 = fifo.read();
}
}
See examples/adc_fifo_poll.rs for a more complete example.
§Using DMA
When the ADC is in free-running mode, it’s possible to use DMA to transfer data from the FIFO elsewhere, without having to read the FIFO manually.
This requires a number of steps:
- Build an
AdcFifo
, with DMA enabled (AdcFifoBuilder::enable_dma
) - Use
AdcFifoBuilder::prepare
instead ofAdcFifoBuilder::start
, so that the FIFO is created inpaused
state - Start a DMA transfer (
dma::single_buffer::Transfer
,dma::double_buffer::Transfer
, …), using theAdcFifo::dma_read_target
as the source (from
parameter) - Finally unpause the FIFO by calling
AdcFifo::resume
, to start capturing
Example:
use rp2040_hal::{adc::Adc, gpio::Pins, pac, Sio, dma::{single_buffer, DMAExt}};
use cortex_m::singleton;
let mut peripherals = pac::Peripherals::take().unwrap();
let sio = Sio::new(peripherals.SIO);
let pins = Pins::new(peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS);
let dma = peripherals.DMA.split(&mut peripherals.RESETS);
// Enable adc
let mut adc = Adc::new(peripherals.ADC, &mut peripherals.RESETS);
// Enable the temperature sensor
let mut temperature_sensor = adc.take_temp_sensor().unwrap();
// Configure & start capturing to the fifo:
let mut fifo = adc.build_fifo()
.clock_divider(0, 0) // sample as fast as possible (500ksps. This is the default)
.set_channel(&mut temperature_sensor)
.enable_dma()
.prepare();
// Set up a buffer, where the samples should be written:
let buf = singleton!(: [u16; 500] = [0; 500]).unwrap();
// Start DMA transfer
let transfer = single_buffer::Config::new(dma.ch0, fifo.dma_read_target(), buf).start();
// Resume the FIFO to start capturing
fifo.resume();
// Wait for the transfer to complete:
let (ch, adc_read_target, buf) = transfer.wait();
// do something with `buf` (it now contains 500 samples read from the ADC)
//...
//! See examples/adc_fifo_dma.rs for a more complete example.
§Free running mode without FIFO
While free-running mode is usually used in combination with a FIFO, there are use cases where it can be used without. For example, if you want to be able to get the latest available sample at any point in time, and without waiting 96 ADC clock cycles (2µs).
In this case, you can just enable free-running mode on it’s own. The ADC will continuously do ADC conversions. The ones not read will just be discarded, but it’s always possible to read the latest value, without additional delay:
use rp2040_hal::{adc::Adc, adc::AdcPin, gpio::Pins, pac, Sio};
// Embedded HAL 1.0.0 doesn't have an ADC trait, so use the one from 0.2
use embedded_hal_0_2::adc::OneShot;
let mut peripherals = pac::Peripherals::take().unwrap();
let sio = Sio::new(peripherals.SIO);
let pins = Pins::new(peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS);
// Enable adc
let mut adc = Adc::new(peripherals.ADC, &mut peripherals.RESETS);
// Configure one of the pins as an ADC input
let mut adc_pin_0 = AdcPin::new(pins.gpio26.into_floating_input()).unwrap();
// Enable free-running mode
adc.free_running(&adc_pin_0);
// Read the ADC counts from the ADC channel whenever necessary
loop {
let pin_adc_counts: u16 = adc.read_single();
// Do time critical stuff
}
Structs§
- Adc
- Analog to Digital Convertor (ADC).
- AdcFifo
- Represents the ADC fifo
- AdcFifo
Builder - Used to configure & build an
AdcFifo
- AdcPin
- A pin locked in use with the ADC.
- DmaRead
Target - Represents a
dma::ReadTarget
for theAdcFifo
- Invalid
PinError - The pin was invalid for the requested operation
- Round
Robin - Internal struct representing values for the
CS.RROBIN
register. - Temp
Sense - Internal temperature sensor type
Traits§
- AdcChannel
- Trait for entities that can be used as ADC channels.