Skip to content

Commit 88a45af

Browse files
committed
adc: check buffer length on DMA
1 parent 72e96ff commit 88a45af

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1818
- Add `QeiOptions` struct to configure slave mode and auto reload value of QEI interface
1919
- Implement multiplication and division for frequency wrappers (#193)
2020
- Add support for CRC
21+
- ADC multichannel continuous conversion
2122

2223
### Changed
2324

examples/adc-dma-rx.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![no_main]
44
#![no_std]
55

6-
use panic_halt as _;
6+
use panic_semihosting as _;
77

88
use cortex_m::singleton;
99
use cortex_m_semihosting::hprintln;
@@ -72,11 +72,21 @@ fn main() -> ! {
7272
let pins = AdcPins(adc_ch0, adc_ch2);
7373
let adc_dma = adc1.with_scan_dma::<_, adc::Single>(pins, dma_ch1);
7474

75-
// TODO: should match with # of conversions specified by AdcPins
7675
let buf = singleton!(: [u16; 4] = [0; 4]).unwrap();
76+
let (_buf, adc_dma) = adc_dma.read(buf).wait();
77+
hprintln!(
78+
"multi-channel single-shot conversion, exact buffer={:?}",
79+
_buf
80+
)
81+
.ok();
7782

83+
let buf = singleton!(: [u16; 8] = [0; 8]).unwrap();
7884
let (_buf, adc_dma) = adc_dma.read(buf).wait();
79-
hprintln!("multi-channel single-shot conversion={:?}", _buf).ok();
85+
hprintln!(
86+
"multi-channel single-shot conversion, larger buffer={:?}",
87+
_buf
88+
)
89+
.ok();
8090

8191
adc_dma.split()
8292
};

src/adc.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@ pub struct Continuous;
2121
/// Single conversion mode
2222
pub struct Single;
2323

24+
pub trait ConversionMode {
25+
fn is_continuous() -> bool;
26+
}
27+
28+
impl ConversionMode for Continuous {
29+
fn is_continuous() -> bool {
30+
true
31+
}
32+
}
33+
34+
impl ConversionMode for Single {
35+
fn is_continuous() -> bool {
36+
false
37+
}
38+
}
39+
2440
/// ADC configuration
2541
pub struct Adc<ADC> {
2642
rb: ADC,
@@ -344,6 +360,11 @@ macro_rules! adc_hal {
344360
self.rb.sqr1.modify(|_, w| w.l().bits((len-1) as u8));
345361
}
346362

363+
#[allow(unused)]
364+
fn sequence_len(&self) -> usize {
365+
self.rb.sqr1.read().l().bits() as usize + 1
366+
}
367+
347368
/**
348369
Performs an ADC conversion
349370
@@ -709,15 +730,29 @@ impl<B, PINS, MODE> crate::dma::ReadDma<B, u16> for AdcDma<PINS, MODE>
709730
where
710731
Self: TransferPayload,
711732
B: as_slice::AsMutSlice<Element = u16>,
733+
MODE: ConversionMode,
712734
{
713735
fn read(mut self, buffer: &'static mut B) -> Transfer<W, &'static mut B, Self> {
714736
{
715737
let buffer = buffer.as_mut_slice();
738+
739+
let conversion_len = if MODE::is_continuous() {
740+
buffer.len()
741+
} else {
742+
// for non-continous conversion, conversion sequence length should match with DMA
743+
// transfer length, to prevent DMA from waiting for a conversion indefinitely
744+
let sequence_len = self.payload.adc.sequence_len();
745+
if buffer.len() < sequence_len {
746+
panic!("short buffer on ADC conversion: buffer.len()={:?}, adc.seqeuence_len()={:?}", buffer.len(), sequence_len);
747+
}
748+
sequence_len
749+
};
750+
716751
self.channel
717752
.set_peripheral_address(unsafe { &(*ADC1::ptr()).dr as *const _ as u32 }, false);
718753
self.channel
719754
.set_memory_address(buffer.as_ptr() as u32, true);
720-
self.channel.set_transfer_length(buffer.len());
755+
self.channel.set_transfer_length(conversion_len);
721756
}
722757
atomic::compiler_fence(Ordering::Release);
723758
self.channel.ch().cr.modify(|_, w| {

0 commit comments

Comments
 (0)