aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32g4/src/bin
diff options
context:
space:
mode:
authorJakob <[email protected]>2025-11-04 19:55:09 +0100
committerJakob <[email protected]>2025-11-04 19:55:09 +0100
commit8184bb809b65281cfcf0035e40c7c215d6b9aeda (patch)
tree46fbc20ff00150a6eb40ac0c87a214e5fac63b6a /examples/stm32g4/src/bin
parentdda429ce6642deaa490f8737e1373e2e2ba79655 (diff)
Implement into_ring_buffered for g4. Add methods for configuring injected sampling for g4.
Diffstat (limited to 'examples/stm32g4/src/bin')
-rw-r--r--examples/stm32g4/src/bin/adc_dma.rs4
-rw-r--r--examples/stm32g4/src/bin/adc_injected_and_regular.rs144
2 files changed, 146 insertions, 2 deletions
diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs
index a82067049..ef8b0c3c2 100644
--- a/examples/stm32g4/src/bin/adc_dma.rs
+++ b/examples/stm32g4/src/bin/adc_dma.rs
@@ -12,7 +12,7 @@ static mut DMA_BUF: [u16; 2] = [0; 2];
12 12
13#[embassy_executor::main] 13#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
15 let mut read_buffer = unsafe { &mut DMA_BUF[..] }; 15 let read_buffer = unsafe { &mut DMA_BUF[..] };
16 16
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 { 18 {
@@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) {
47 (&mut pa0, SampleTime::CYCLES247_5), 47 (&mut pa0, SampleTime::CYCLES247_5),
48 ] 48 ]
49 .into_iter(), 49 .into_iter(),
50 &mut read_buffer, 50 read_buffer,
51 ) 51 )
52 .await; 52 .await;
53 53
diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs
new file mode 100644
index 000000000..5db1a4fa0
--- /dev/null
+++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs
@@ -0,0 +1,144 @@
1//! adc injected and regular conversions
2//!
3//! This example both regular and injected ADC conversions at the same time
4//! p:pa0 n:pa2
5
6#![no_std]
7#![no_main]
8
9use core::cell::RefCell;
10
11use defmt::info;
12use embassy_stm32::adc::{Adc, AdcChannel as _, Exten, RxDma, SampleTime};
13use embassy_stm32::interrupt::typelevel::{ADC1_2, Interrupt};
14use embassy_stm32::peripherals::ADC1;
15use embassy_stm32::time::Hertz;
16use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, Mms2};
17use embassy_stm32::timer::low_level::CountingMode;
18use embassy_stm32::{Config, interrupt};
19use embassy_sync::blocking_mutex::CriticalSectionMutex;
20use {critical_section, defmt_rtt as _, panic_probe as _};
21
22static ADC1_HANDLE: CriticalSectionMutex<RefCell<Option<Adc<'static, ADC1>>>> =
23 CriticalSectionMutex::new(RefCell::new(None));
24
25/// This example showcases how to use both regular ADC conversions with DMA and injected ADC
26/// conversions with ADC interrupt simultaneously. Both conversion types can be configured with
27/// different triggers and thanks to DMA it is possible to use the measurements in different task
28/// without needing to access the ADC peripheral.
29///
30/// If you don't need both regular and injected conversions the example code can easily be reworked
31/// to only include one of the ADC conversion types.
32#[embassy_executor::main]
33async fn main(_spawner: embassy_executor::Spawner) {
34 // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers
35 // Note: Regular and Injected channels use different tables!!
36 const ADC1_INJECTED_TRIGGER_TIM1_TRGO2: u8 = 8;
37 const ADC1_REGULAR_TRIGGER_TIM1_TRGO2: u8 = 10;
38
39 // --- RCC config ---
40 let mut config = Config::default();
41 {
42 use embassy_stm32::rcc::*;
43 config.rcc.pll = Some(Pll {
44 source: PllSource::HSI,
45 prediv: PllPreDiv::DIV4,
46 mul: PllMul::MUL85,
47 divp: None,
48 divq: None,
49 divr: Some(PllRDiv::DIV2),
50 });
51 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
52 config.rcc.sys = Sysclk::PLL1_R;
53 }
54 let p = embassy_stm32::init(config);
55
56 // In this example we use tim1_trgo2 event to trigger the ADC conversions
57 let tim1 = p.TIM1;
58 let pwm_freq = 1;
59 let mut pwm = ComplementaryPwm::new(
60 tim1,
61 None,
62 None,
63 None,
64 None,
65 None,
66 None,
67 None,
68 None,
69 Hertz::hz(pwm_freq),
70 CountingMode::EdgeAlignedUp,
71 );
72 pwm.set_master_output_enable(false);
73 // Mms2 is used to configure which timer event that is connected to tim1_trgo2.
74 // In this case we use the update event of the timer.
75 pwm.set_mms2(Mms2::UPDATE);
76
77 // Configure regular conversions with DMA
78 let mut adc1 = Adc::new(p.ADC1);
79
80 let mut vrefint_channel = adc1.enable_vrefint().degrade_adc();
81 let mut pa0 = p.PC1.degrade_adc();
82 let regular_sequence = [
83 (&mut vrefint_channel, SampleTime::CYCLES247_5),
84 (&mut pa0, SampleTime::CYCLES247_5),
85 ]
86 .into_iter();
87
88 // Configure DMA for retrieving regular ADC measurements
89 let dma1_ch1 = p.DMA1_CH1;
90 // Using buffer of double size means the half-full interrupts will generate at the expected rate
91 let mut readings = [0u16; 4];
92 let mut ring_buffered_adc = adc1.into_ring_buffered(dma1_ch1, &mut readings, regular_sequence);
93
94 // Configurations of Injected ADC measurements
95 let mut pa2 = p.PA2.degrade_adc();
96 let injected_seq = [(&mut pa2, SampleTime::CYCLES247_5)].into_iter();
97 adc1.configure_injected_sequence(injected_seq);
98
99 adc1.set_regular_conversion_trigger(ADC1_REGULAR_TRIGGER_TIM1_TRGO2, Exten::RISING_EDGE);
100 adc1.set_injected_conversion_trigger(ADC1_INJECTED_TRIGGER_TIM1_TRGO2, Exten::RISING_EDGE);
101
102 // ADC must be started after all configurations are completed
103 adc1.start_injected_conversion();
104
105 // Enable interrupt at end of injected ADC conversion
106 adc1.enable_injected_eos_interrupt(true);
107
108 // Store ADC globally to allow access from ADC interrupt
109 critical_section::with(|cs| {
110 ADC1_HANDLE.borrow(cs).replace(Some(adc1));
111 });
112 // Enable interrupt for ADC1_2
113 unsafe { ADC1_2::enable() };
114
115 // Main loop for reading regular ADC measurements periodically
116 let mut data = [0u16; 2];
117 loop {
118 {
119 match ring_buffered_adc.read(&mut data).await {
120 Ok(n) => {
121 defmt::info!("Regular ADC reading, VrefInt: {}, PA0: {}", data[0], data[1]);
122 defmt::info!("Remaining samples: {}", n,);
123 }
124 Err(e) => {
125 defmt::error!("DMA error: {:?}", e);
126 ring_buffered_adc.clear();
127 }
128 }
129 }
130 }
131}
132
133/// Use ADC1_2 interrupt to retrieve injected ADC measurements
134/// Interrupt must be unsafe as hardware can invoke it any-time. Critical sections ensure safety
135/// within the interrupt.
136#[interrupt]
137unsafe fn ADC1_2() {
138 critical_section::with(|cs| {
139 if let Some(adc) = ADC1_HANDLE.borrow(cs).borrow_mut().as_mut() {
140 let injected_data = adc.clear_injected_eos();
141 info!("Injected reading of PA2: {}", injected_data[0]);
142 }
143 });
144}