Skip to content

Commit

Permalink
feat(adc): spike for ADC reads using DMA w/ circular buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
dobrite committed Jul 29, 2023
1 parent 2d47a4a commit 93c9da5
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 0 deletions.
111 changes: 111 additions & 0 deletions examples/adc_dma_circ.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#![no_main]
#![no_std]

use core::{mem, mem::MaybeUninit};
use log::info;

use cortex_m_rt::entry;

use embedded_hal::adc::Channel;
use stm32h7xx_hal::{
adc,
delay::Delay,
dma::{
dma::{DmaConfig, StreamsTuple},
Transfer,
},
gpio, pac,
prelude::*,
stm32::ADC1,
};

#[macro_use]
mod utilities;

#[entry]
fn main() -> ! {
utilities::logger::init();
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();

// 1 slot because we are only using 1 channel
#[link_section = ".axisram"]
static mut BUFFER: MaybeUninit<[u16; 1]> = MaybeUninit::uninit();

let adc_buffer: &'static mut [u16; 1] = {
// Convert an uninitialised array into an array of uninitialised
let buf: &mut [MaybeUninit<u16>; 1] =
unsafe { mem::transmute(&mut BUFFER) };
// Initialise memory to valid values
for slot in buf.iter_mut() {
// Never create even a _temporary_ reference to uninitialised memory
unsafe {
slot.as_mut_ptr().write(0);
}
}
unsafe { mem::transmute(buf) }
};

// Constrain and Freeze power
info!("Setup PWR... ");
let pwr = dp.PWR.constrain();
let pwrcfg = example_power!(pwr).freeze();

// Constrain and Freeze clock
info!("Setup RCC... ");
let rcc = dp.RCC.constrain();

let ccdr = rcc
.sys_ck(400.MHz())
.pll2_p_ck(40.MHz())
.freeze(pwrcfg, &dp.SYSCFG);

info!("");
info!("stm32h7xx-hal example - ADC to Memory DMA Continuous using Circular Mode");
info!("");

let mut delay = Delay::new(cp.SYST, ccdr.clocks);

// Setup ADC
let mut adc1 = adc::Adc::adc1(
dp.ADC1,
2.MHz(),
&mut delay,
ccdr.peripheral.ADC12,
&ccdr.clocks,
)
.enable();
adc1.set_resolution(adc::Resolution::SixteenBit);
// We can't use ADC2 here because ccdr.peripheral.ADC12 has been
// consumed. See examples/adc12.rs

// Setup GPIOC
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);

// Configure pc4 as an analog input
let mut channel = gpioc.pc4.into_analog(); // ANALOG IN 4

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h743)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h743)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h743v)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h743v)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h753v)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h753v)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h735)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h735)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h753)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h753)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h735)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h735)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h7b0)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h7b0)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h7b3)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h7b3)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h743)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h743)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h747cm7)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (stable, stm32h747cm7)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h747cm7)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h747cm7)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h743v)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h743v)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h7b3)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h7b3)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h753v)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h753v)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h7b0)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h7b0)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / ci (stm32h743v, log-itm)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / ci (stm32h743v, log-itm)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / ci (stm32h743v, log-rtt)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / ci (stm32h743v, log-rtt)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / ci (stm32h743v, log-semihost)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / ci (stm32h743v, log-semihost)

variable does not need to be mutable

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h753)

unused variable: `channel`

Check warning on line 86 in examples/adc_dma_circ.rs

View workflow job for this annotation

GitHub Actions / check (1.65.0, stm32h753)

variable does not need to be mutable

let config = DmaConfig::default()
.circular_buffer(true)
.memory_increment(true);

// Setup the DMA transfer on stream 0
let streams = StreamsTuple::new(dp.DMA1, ccdr.peripheral.DMA1);
let mut transfer: Transfer<_, _, _, _, _> =
Transfer::init(streams.0, adc1, &mut adc_buffer[..], None, config);

// This closure runs right after enabling the stream
transfer.start(|adc| {
let channel = <gpio::PC4 as Channel<ADC1>>::channel();
adc.start_conversion_dma_circ(&[channel]); // more channels can be added to the list
});

loop {
info!("{}", unsafe {
core::ptr::read_volatile(0x2400_0000 as *const u16)
// if more channels are used, each address will be offset by 2
});

delay.delay_ms(10_u16); // slow down the loop a bit
}
}
60 changes: 60 additions & 0 deletions src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,66 @@ macro_rules! adc_hal {
self.start_conversion_common(chan);
}

pub fn start_conversion_dma_circ(&mut self, chans: &[u8])
{
for chan in chans.iter() {
assert!(*chan <= 19);
}

self.rb.cfgr.modify(|_, w| unsafe { w.res().bits(self.get_resolution().into()) }); // set resolution
self.rb.cfgr.modify(|_, w| w.dmngt().bits(0b11)); // circular mode enabled
self.rb.cfgr.modify(|_, w| w.cont().set_bit().discen().clear_bit() ); // set continuous mode, unset discontinuous mode
self.rb.cfgr.modify(|_, w| w.ovrmod().overwrite()); // overwrite on overrun
self.check_conversion_conditions();
self.rb.cfgr2.modify(|_, w| w.lshift().bits(self.get_lshift().value())); // set LSHIFT[3:0]

// preselect channels
for chan in chans.iter() {
self.rb.pcsel.modify(|r, w| unsafe { w.pcsel().bits(r.pcsel().bits() | (1 << chan)) });
self.set_chan_smp(*chan);
}

// set sequence order and length
let mut seq_len = 0;
for (i, ch) in chans.iter().enumerate() {
self.set_sequence(*ch, i as u8 + 1);
seq_len += 1;
}
self.set_sequence_len(seq_len);

self.rb.cr.modify(|_, w| w.adstart().set_bit()); // start circ conversions
}

/// Select a sequence to sample, by inputting a single channel and position.
pub fn set_sequence(&mut self, chan: u8, position: u8) {
match position {
1 => self.rb.sqr1.modify(|_, w| unsafe { w.sq1().bits(chan) }),
2 => self.rb.sqr1.modify(|_, w| unsafe { w.sq2().bits(chan) }),
3 => self.rb.sqr1.modify(|_, w| unsafe { w.sq3().bits(chan) }),
4 => self.rb.sqr1.modify(|_, w| unsafe { w.sq4().bits(chan) }),
5 => self.rb.sqr2.modify(|_, w| unsafe { w.sq5().bits(chan) }),
6 => self.rb.sqr2.modify(|_, w| unsafe { w.sq6().bits(chan) }),
7 => self.rb.sqr2.modify(|_, w| unsafe { w.sq7().bits(chan) }),
8 => self.rb.sqr2.modify(|_, w| unsafe { w.sq8().bits(chan) }),
9 => self.rb.sqr2.modify(|_, w| unsafe { w.sq9().bits(chan) }),
10 => self.rb.sqr3.modify(|_, w| unsafe { w.sq10().bits(chan) }),
11 => self.rb.sqr3.modify(|_, w| unsafe { w.sq11().bits(chan) }),
12 => self.rb.sqr3.modify(|_, w| unsafe { w.sq12().bits(chan) }),
13 => self.rb.sqr3.modify(|_, w| unsafe { w.sq13().bits(chan) }),
14 => self.rb.sqr3.modify(|_, w| unsafe { w.sq14().bits(chan) }),
15 => self.rb.sqr4.modify(|_, w| unsafe { w.sq15().bits(chan) }),
16 => self.rb.sqr4.modify(|_, w| unsafe { w.sq16().bits(chan) }),
_ => panic!("Sequence out of bounds. Only 16 positions are available."),
}
}

pub fn set_sequence_len(&mut self, len: u8) {
if len - 1 >= 16 {
panic!("ADC sequence length must be in 1..=16")
}

self.rb.sqr1.modify(|_, w| w.l().bits(len - 1));
}

/// Read sample
///
Expand Down

0 comments on commit 93c9da5

Please sign in to comment.