Last active
July 17, 2022 13:57
-
-
Save chmanie/d897d9be6e85c872673b6f010dfff7b0 to your computer and use it in GitHub Desktop.
RP2040 ADC over DMA Round-Robin in Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Configure DMA to copy ADC FIFO round-robin values into memory | |
* | |
* The strategy is as follows: | |
* - Have a static array which is the DMA target address, holding 3 u16 values | |
* - Enable DMA with a data-size of halfword (16bits), increase the write address after each transfer and wrap at 8 bytes | |
* - Start the ADC according to datasheet section 4.9.2.5 (round robin with FIFO enabled and DREQ threshold 1) | |
* | |
* The result will be an array with 16bit values of ADC results where the first bit indicates an error if set | |
*/ | |
use rp2040_hal::{ | |
pac::{ADC, DMA}, | |
}; | |
static ADC_VALS: [u16; 4] = [0; 4]; | |
pub fn setup_adc_dma(adc: ADC, dma: DMA) { | |
// ---- Configure DMA ---- | |
// Set DMA channel 0 read address to the fifo register address | |
dma.ch[0] | |
.ch_read_addr | |
.write(|w| unsafe { w.bits(adc.fifo.as_ptr() as u32) }); | |
// Get raw pointer to ADC_VAL array | |
let dest: *const [u16; 4] = &ADC_VALS; | |
let dest_addr = dest as usize; | |
// Set write address to ADC_VAL address | |
dma.ch[0] | |
.ch_write_addr | |
.write(|w| unsafe { w.bits(dest_addr as u32) }); | |
dma.ch[0].ch_ctrl_trig.write(|w| unsafe { | |
w | |
// Select ADC as Data Request Trigger | |
.treq_sel() | |
.bits(DREQ_ADC) | |
// Set CTRL.DATA_SIZE to 16bit (0x1 -> SIZE_HALFWORD) | |
.data_size() | |
.bits(0x1) | |
// Enable CTRL.INC_WRITE to increase the destination address after each transfer | |
.incr_write() | |
.set_bit() | |
// Set CTRL.RING_SEL to wrap write addresses | |
.ring_sel() | |
.set_bit() | |
// Wrap write addresses at 8 bytes (4 values a 2 bytes) | |
.ring_size() | |
.bits(3) | |
// Enable DMA channel | |
.en() | |
.set_bit() | |
}); | |
// Wait until ADC is read (for good measure) | |
while !adc.cs.read().ready().bit_is_set() { | |
cortex_m::asm::nop(); | |
} | |
// ---- Configure ADC ---- | |
// Set sample rate to 1kS/s | |
adc.div.modify(|_, w| unsafe { w.int().bits(47999) }); | |
adc.fcs.modify(|_, w| unsafe { | |
w | |
// Enable FIFO | |
.en() | |
.set_bit() | |
// Set interrupt threshold to 1 | |
.thresh() | |
.bits(1) | |
// Enable DREQ DMA transfer requests | |
.dreq_en() | |
.set_bit() | |
}); | |
// // Enable Interrupt | |
// adc.inte.modify(|_, w| w.fifo().set_bit()); | |
// | |
// unsafe { | |
// NVIC::unmask(Interrupt::ADC_IRQ_FIFO); | |
// } | |
adc.cs.modify(|_, w| unsafe { | |
w.ainsel() | |
// Set start channel | |
.bits(0) | |
// Sample all four channels (1111) | |
.rrobin() | |
.bits(0b1111) | |
// Start free running conversions | |
.start_many() | |
.set_bit() | |
}); | |
// Wait until ADC is read again (for good measure) | |
while !adc.cs.read().ready().bit_is_set() { | |
cortex_m::asm::nop(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment