Skip to content

Commit 16ef975

Browse files
committed
ADC - added continuous conversion and external trigger
1 parent 9b42ebb commit 16ef975

File tree

5 files changed

+277
-4
lines changed

5 files changed

+277
-4
lines changed

examples/adc.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use panic_rtt_target as _;
55

66
use cortex_m_rt::entry;
77
use rtt_target::{rprint, rprintln};
8-
use stm32l4xx_hal::{adc::ADC, delay::Delay, pac, prelude::*};
8+
use stm32l4xx_hal::{adc::config, adc::ADC, delay::Delay, pac, prelude::*};
99

1010
#[entry]
1111
fn main() -> ! {
@@ -28,6 +28,7 @@ fn main() -> ! {
2828
&mut rcc.ahb2,
2929
&mut rcc.ccipr,
3030
&mut delay,
31+
config::ExternalTriggerConfig::default(),
3132
);
3233

3334
let mut gpioc = dp.GPIOC.split(&mut rcc.ahb2);

examples/adc_dma.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use panic_rtt_target as _;
55
use rtt_target::{rprintln, rtt_init_print};
66
use stm32l4xx_hal::{
7-
adc::{DmaMode, SampleTime, Sequence, ADC},
7+
adc::{config, DmaMode, SampleTime, Sequence, ADC},
88
delay::DelayCM,
99
dma::{dma1, RxDma, Transfer, W},
1010
prelude::*,
@@ -60,6 +60,7 @@ const APP: () = {
6060
&mut rcc.ahb2,
6161
&mut rcc.ccipr,
6262
&mut delay,
63+
config::ExternalTriggerConfig::default(),
6364
);
6465

6566
let mut temp_pin = adc.enable_temperature(&mut delay);

examples/adc_dma_cont.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
use panic_rtt_target as _;
5+
use rtt_target::{rprintln, rtt_init_print};
6+
use stm32l4xx_hal::{
7+
adc::{config, DmaMode, SampleTime, Sequence, ADC},
8+
delay::DelayCM,
9+
dma::{dma1, RxDma, Transfer, W},
10+
prelude::*,
11+
};
12+
13+
use rtic::app;
14+
15+
const SEQUENCE_LEN: usize = 8;
16+
17+
#[app(device = stm32l4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
18+
const APP: () = {
19+
// RTIC app is written in here!
20+
21+
struct Resources {
22+
transfer: Option<Transfer<W, &'static mut [u16; SEQUENCE_LEN], RxDma<ADC, dma1::C1>>>,
23+
}
24+
25+
#[init]
26+
fn init(cx: init::Context) -> init::LateResources {
27+
let MEMORY = {
28+
static mut MEMORY: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN];
29+
unsafe { &mut MEMORY }
30+
};
31+
32+
rtt_init_print!();
33+
34+
rprintln!("Hello from init!");
35+
36+
let cp = cx.core;
37+
let mut dcb = cp.DCB;
38+
let mut dwt = cp.DWT;
39+
40+
dcb.enable_trace();
41+
dwt.enable_cycle_counter();
42+
43+
let pac = cx.device;
44+
45+
let mut rcc = pac.RCC.constrain();
46+
let mut flash = pac.FLASH.constrain();
47+
let mut pwr = pac.PWR.constrain(&mut rcc.apb1r1);
48+
let dma_channels = pac.DMA1.split(&mut rcc.ahb1);
49+
50+
//
51+
// Initialize the clocks
52+
//
53+
let clocks = rcc.cfgr.sysclk(80.MHz()).freeze(&mut flash.acr, &mut pwr);
54+
55+
let mut delay = DelayCM::new(clocks);
56+
57+
let mut adc = ADC::new(
58+
pac.ADC1,
59+
pac.ADC_COMMON,
60+
&mut rcc.ahb2,
61+
&mut rcc.ccipr,
62+
&mut delay,
63+
config::ExternalTriggerConfig::default(),
64+
);
65+
66+
let mut temp_pin = adc.enable_temperature(&mut delay);
67+
68+
let dma1_channel = dma_channels.1;
69+
70+
let mut gpioa = pac.GPIOA.split(&mut rcc.ahb2);
71+
let mut a1 = gpioa.pa0.into_analog(&mut gpioa.moder, &mut gpioa.pupdr);
72+
73+
adc.configure_sequence(&mut a1, Sequence::One, SampleTime::Cycles12_5);
74+
75+
// Heapless boxes also work very well as buffers for DMA transfers
76+
let transfer = Transfer::from_adc(adc, dma1_channel, MEMORY, DmaMode::Oneshot, true, true);
77+
78+
init::LateResources {
79+
transfer: Some(transfer),
80+
}
81+
}
82+
83+
#[idle]
84+
fn idle(_cx: idle::Context) -> ! {
85+
loop {
86+
cortex_m::asm::nop();
87+
}
88+
}
89+
90+
#[task(binds = DMA1_CH1, resources = [transfer])]
91+
fn dma1_interrupt(cx: dma1_interrupt::Context) {
92+
let transfer = cx.resources.transfer;
93+
if let Some(transfer_val) = transfer.take() {
94+
let (buffer, rx_dma) = transfer_val.wait();
95+
rprintln!("DMA measurements: {:?}", buffer);
96+
*transfer = Some(Transfer::from_adc_dma(
97+
rx_dma,
98+
buffer,
99+
DmaMode::Oneshot,
100+
true,
101+
true,
102+
));
103+
}
104+
}
105+
};

src/adc.rs

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ impl ADC {
129129
ahb: &mut AHB2,
130130
ccipr: &mut CCIPR,
131131
delay: &mut impl DelayUs<u32>,
132+
external_trigger: config::ExternalTriggerConfig,
132133
) -> Self {
133134
// Enable peripheral
134135
ADC1::enable(ahb);
@@ -183,6 +184,8 @@ impl ADC {
183184

184185
s.calibrate(&mut vref);
185186

187+
s.set_external_trigger(external_trigger);
188+
186189
s.common.ccr.modify(|_, w| w.vrefen().clear_bit());
187190
s
188191
}
@@ -389,6 +392,13 @@ impl ADC {
389392
self.adc.cr.modify(|_, w| w.adstart().set_bit());
390393
}
391394

395+
pub fn start_cont_conversion(&mut self) {
396+
self.enable();
397+
self.enable_continous();
398+
self.clear_end_flags();
399+
self.adc.cr.modify(|_, w| w.adstart().set_bit());
400+
}
401+
392402
pub fn is_converting(&self) -> bool {
393403
self.adc.cr.read().adstart().bit_is_set()
394404
}
@@ -426,13 +436,31 @@ impl ADC {
426436
}
427437
}
428438

439+
pub fn enable_continous(&mut self) {
440+
self.adc.cfgr.modify(|_, w| w.cont().set_bit());
441+
}
442+
443+
pub fn disable_continous(&mut self) {
444+
self.adc.cfgr.modify(|_, w| w.cont().clear_bit());
445+
}
446+
429447
pub fn is_enabled(&self) -> bool {
430448
self.adc.cr.read().aden().bit_is_set()
431449
}
432450

433451
pub fn disable(&mut self) {
434452
self.adc.cr.modify(|_, w| w.addis().set_bit());
435453
}
454+
455+
/// Sets which external trigger to use and if it is disabled, rising, falling or both
456+
pub fn set_external_trigger(&mut self, ext_trg_conf: config::ExternalTriggerConfig) {
457+
self.adc.cfgr.modify(|_, w| unsafe {
458+
w.exten()
459+
.bits(ext_trg_conf.0.into())
460+
.extsel()
461+
.bits(ext_trg_conf.1.into())
462+
});
463+
}
436464
}
437465

438466
impl<C> OneShot<ADC, u16, C> for ADC
@@ -491,9 +519,17 @@ where
491519
buffer: BUFFER,
492520
dma_mode: DmaMode,
493521
transfer_complete_interrupt: bool,
522+
continuous_conversion: bool,
494523
) -> Self {
495524
let (adc, channel) = dma.split();
496-
Transfer::from_adc(adc, channel, buffer, dma_mode, transfer_complete_interrupt)
525+
Transfer::from_adc(
526+
adc,
527+
channel,
528+
buffer,
529+
dma_mode,
530+
transfer_complete_interrupt,
531+
continuous_conversion,
532+
)
497533
}
498534

499535
/// Initiate a new DMA transfer from an ADC.
@@ -508,6 +544,7 @@ where
508544
buffer: BUFFER,
509545
dma_mode: DmaMode,
510546
transfer_complete_interrupt: bool,
547+
continuous_conversion: bool,
511548
) -> Self {
512549
assert!(dma_mode != DmaMode::Disabled);
513550

@@ -555,7 +592,11 @@ where
555592
atomic::compiler_fence(Ordering::Release);
556593

557594
channel.start();
558-
adc.start_conversion();
595+
if continuous_conversion == false {
596+
adc.start_conversion();
597+
} else {
598+
adc.start_cont_conversion();
599+
}
559600

560601
Transfer::w(
561602
buffer,
@@ -643,6 +684,87 @@ pub trait Channel: EmbeddedHalChannel<ADC, ID = u8> {
643684
fn set_sample_time(&mut self, adc: &ADC1, sample_time: SampleTime);
644685
}
645686

687+
/// Contains types related to ADC configuration
688+
pub mod config {
689+
/// Possible external triggers the ADC can listen to
690+
#[derive(Debug, Clone, Copy)]
691+
pub enum ExternalTrigger {
692+
/// TIM1 compare channel 1
693+
Tim_1_cc_1,
694+
/// TIM1 compare channel 2
695+
Tim_1_cc_2,
696+
/// TIM1 compare channel 3
697+
Tim_1_cc_3,
698+
/// TIM2 compare channel 2
699+
Tim_2_cc_2,
700+
/// TIM3 trigger out
701+
Tim_3_trgo,
702+
/// External interupt line 11
703+
Exti_11,
704+
/// TIM1 trigger out
705+
Tim_1_trgo,
706+
/// TIM1 trigger out 2
707+
Tim_1_trgo2,
708+
/// TIM2 trigger out
709+
Tim_2_trgo,
710+
/// TIM6 trigger out
711+
Tim_6_trgo,
712+
/// TIM15 trigger out
713+
Tim_15_trgo,
714+
}
715+
716+
impl From<ExternalTrigger> for u8 {
717+
fn from(et: ExternalTrigger) -> u8 {
718+
match et {
719+
ExternalTrigger::Tim_1_cc_1 => 0b0000, // EXT0
720+
ExternalTrigger::Tim_1_cc_2 => 0b0001, // EXT1
721+
ExternalTrigger::Tim_1_cc_3 => 0b0010, // EXT2
722+
ExternalTrigger::Tim_2_cc_2 => 0b0011, // EXT3
723+
ExternalTrigger::Tim_3_trgo => 0b0100, // EXT4
724+
ExternalTrigger::Exti_11 => 0b0110, // EXT6
725+
ExternalTrigger::Tim_1_trgo => 0b1001, // EXT9
726+
ExternalTrigger::Tim_1_trgo2 => 0b1010, // EXT10
727+
ExternalTrigger::Tim_2_trgo => 0b1011, // EXT11
728+
ExternalTrigger::Tim_6_trgo => 0b1101, // EXT13
729+
ExternalTrigger::Tim_15_trgo => 0b1110, // EXT14
730+
}
731+
}
732+
}
733+
734+
/// Possible trigger modes
735+
#[derive(Debug, Clone, Copy)]
736+
pub enum TriggerMode {
737+
/// Don't listen to external trigger
738+
Disabled,
739+
/// Listen for rising edges of external trigger
740+
RisingEdge,
741+
/// Listen for falling edges of external trigger
742+
FallingEdge,
743+
/// Listen for both rising and falling edges of external trigger
744+
BothEdges,
745+
}
746+
747+
impl From<TriggerMode> for u8 {
748+
fn from(tm: TriggerMode) -> u8 {
749+
match tm {
750+
TriggerMode::Disabled => 0b00,
751+
TriggerMode::RisingEdge => 0b01,
752+
TriggerMode::FallingEdge => 0b10,
753+
TriggerMode::BothEdges => 0b11,
754+
}
755+
}
756+
}
757+
758+
#[derive(Debug)]
759+
pub struct ExternalTriggerConfig(pub TriggerMode, pub ExternalTrigger);
760+
761+
impl Default for ExternalTriggerConfig {
762+
fn default() -> Self {
763+
Self(TriggerMode::Disabled, ExternalTrigger::Tim_1_cc_1)
764+
}
765+
}
766+
}
767+
646768
macro_rules! adc_pins {
647769
(
648770
$(

src/timer.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,33 @@ pub enum Event {
8080
TimeOut,
8181
}
8282

83+
/// Master mode types
84+
pub enum MasterMode {
85+
Reset = 0,
86+
Enable = 1,
87+
Update = 2,
88+
ComparePulse = 3,
89+
CompareOC1REF = 4,
90+
CompareOC2REF = 5,
91+
CompareOC3REF = 6,
92+
CompareOC4REF = 7,
93+
}
94+
95+
impl Into<u8> for MasterMode {
96+
fn into(self) -> u8 {
97+
match self {
98+
MasterMode::Reset => 0,
99+
MasterMode::Enable => 1,
100+
MasterMode::Update => 2,
101+
MasterMode::ComparePulse => 3,
102+
MasterMode::CompareOC1REF => 4,
103+
MasterMode::CompareOC2REF => 5,
104+
MasterMode::CompareOC3REF => 6,
105+
MasterMode::CompareOC4REF => 7
106+
}
107+
}
108+
}
109+
83110
macro_rules! hal {
84111
($($TIM:ident: ($tim:ident, $frname:ident, $apb:ident, $width:ident, $timclk:ident),)+) => {
85112
$(
@@ -275,6 +302,20 @@ macro_rules! hal {
275302
self.pause();
276303
self.tim
277304
}
305+
}
306+
)+
307+
}
308+
}
309+
310+
macro_rules! master_mode {
311+
($($TIM:ident,)+) => {
312+
$(
313+
impl Timer<$TIM> {
314+
pub fn master_mode(&mut self, mode: MasterMode) {
315+
unsafe {
316+
self.tim.cr2.modify(|_, w| w.mms().bits(mode.into()));
317+
}
318+
}
278319
}
279320
)+
280321
}
@@ -288,6 +329,9 @@ hal! {
288329
TIM16: (tim16, free_running_tim16, APB2, u16, timclk2),
289330
}
290331

332+
// no impl for TIM1, TIM7, TIM8, TIM15
333+
master_mode!(TIM2, TIM6, );
334+
291335
#[cfg(any(
292336
// feature = "stm32l451",
293337
feature = "stm32l452",

0 commit comments

Comments
 (0)