aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/Cargo.toml8
-rw-r--r--embassy-stm32/build.rs2
-rw-r--r--embassy-stm32/src/adc/c0.rs468
-rw-r--r--embassy-stm32/src/adc/mod.rs20
-rw-r--r--embassy-stm32/src/flash/f4.rs5
-rw-r--r--embassy-stm32/src/flash/h5.rs1
-rw-r--r--embassy-stm32/src/flash/h50.rs2
-rw-r--r--embassy-stm32/src/flash/mod.rs2
-rw-r--r--embassy-stm32/src/flash/u5.rs2
-rw-r--r--embassy-stm32/src/ospi/mod.rs4
-rw-r--r--embassy-stm32/src/rcc/c0.rs3
-rw-r--r--examples/stm32c0/src/bin/adc.rs57
12 files changed, 562 insertions, 12 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 068c5e230..8204a0fea 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -72,8 +72,8 @@ futures-util = { version = "0.3.30", default-features = false }
72rand_core = "0.6.3" 72rand_core = "0.6.3"
73sdio-host = "0.5.0" 73sdio-host = "0.5.0"
74critical-section = "1.1" 74critical-section = "1.1"
75stm32-metapac = { version = "16" } 75#stm32-metapac = { version = "16" }
76#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c" } 76stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609" }
77 77
78vcell = "0.1.3" 78vcell = "0.1.3"
79nb = "1.0.0" 79nb = "1.0.0"
@@ -101,8 +101,8 @@ proptest-state-machine = "0.3.0"
101proc-macro2 = "1.0.36" 101proc-macro2 = "1.0.36"
102quote = "1.0.15" 102quote = "1.0.15"
103 103
104stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} 104#stm32-metapac = { version = "16", default-features = false, features = ["metadata"]}
105#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c", default-features = false, features = ["metadata"] } 105stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609", default-features = false, features = ["metadata"] }
106 106
107[features] 107[features]
108default = ["rt"] 108default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index b35fd0300..eb0437bc2 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -296,6 +296,8 @@ fn main() {
296 "Bank1" 296 "Bank1"
297 } else if region.name.starts_with("BANK_2") { 297 } else if region.name.starts_with("BANK_2") {
298 "Bank2" 298 "Bank2"
299 } else if region.name == "OTP" {
300 "Otp"
299 } else { 301 } else {
300 continue; 302 continue;
301 } 303 }
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
new file mode 100644
index 000000000..84763ad4f
--- /dev/null
+++ b/embassy-stm32/src/adc/c0.rs
@@ -0,0 +1,468 @@
1use pac::adc::vals::Scandir;
2#[allow(unused)]
3use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr};
4use pac::adccommon::vals::Presc;
5
6use super::{
7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel,
8};
9use crate::dma::Transfer;
10use crate::time::Hertz;
11use crate::{pac, rcc, Peripheral};
12
13/// Default VREF voltage used for sample conversion to millivolts.
14pub const VREF_DEFAULT_MV: u32 = 3300;
15/// VREF voltage used for factory calibration of VREFINTCAL register.
16pub const VREF_CALIB_MV: u32 = 3300;
17
18const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25);
19
20const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20;
21
22const TEMP_CHANNEL: u8 = 9;
23const VREF_CHANNEL: u8 = 10;
24
25const NUM_HW_CHANNELS: u8 = 22;
26const CHSELR_SQ_SIZE: usize = 8;
27const CHSELR_SQ_MAX_CHANNEL: u8 = 14;
28const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111;
29
30// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs,
31// this currently cannot be modeled with stm32-data,
32// so these are available from the software on all ADCs.
33/// Internal voltage reference channel.
34pub struct VrefInt;
35impl<T: Instance> AdcChannel<T> for VrefInt {}
36impl<T: Instance> SealedAdcChannel<T> for VrefInt {
37 fn channel(&self) -> u8 {
38 VREF_CHANNEL
39 }
40}
41
42/// Internal temperature channel.
43pub struct Temperature;
44impl<T: Instance> AdcChannel<T> for Temperature {}
45impl<T: Instance> SealedAdcChannel<T> for Temperature {
46 fn channel(&self) -> u8 {
47 TEMP_CHANNEL
48 }
49}
50
51#[derive(Debug)]
52pub enum Prescaler {
53 NotDivided,
54 DividedBy2,
55 DividedBy4,
56 DividedBy6,
57 DividedBy8,
58 DividedBy10,
59 DividedBy12,
60 DividedBy16,
61 DividedBy32,
62 DividedBy64,
63 DividedBy128,
64 DividedBy256,
65}
66
67impl Prescaler {
68 fn from_ker_ck(frequency: Hertz) -> Self {
69 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
70 match raw_prescaler {
71 0 => Self::NotDivided,
72 1 => Self::DividedBy2,
73 2..=3 => Self::DividedBy4,
74 4..=5 => Self::DividedBy6,
75 6..=7 => Self::DividedBy8,
76 8..=9 => Self::DividedBy10,
77 10..=11 => Self::DividedBy12,
78 _ => unimplemented!(),
79 }
80 }
81
82 #[allow(unused)]
83 fn divisor(&self) -> u32 {
84 match self {
85 Prescaler::NotDivided => 1,
86 Prescaler::DividedBy2 => 2,
87 Prescaler::DividedBy4 => 4,
88 Prescaler::DividedBy6 => 6,
89 Prescaler::DividedBy8 => 8,
90 Prescaler::DividedBy10 => 10,
91 Prescaler::DividedBy12 => 12,
92 Prescaler::DividedBy16 => 16,
93 Prescaler::DividedBy32 => 32,
94 Prescaler::DividedBy64 => 64,
95 Prescaler::DividedBy128 => 128,
96 Prescaler::DividedBy256 => 256,
97 }
98 }
99
100 fn presc(&self) -> Presc {
101 match self {
102 Prescaler::NotDivided => Presc::DIV1,
103 Prescaler::DividedBy2 => Presc::DIV2,
104 Prescaler::DividedBy4 => Presc::DIV4,
105 Prescaler::DividedBy6 => Presc::DIV6,
106 Prescaler::DividedBy8 => Presc::DIV8,
107 Prescaler::DividedBy10 => Presc::DIV10,
108 Prescaler::DividedBy12 => Presc::DIV12,
109 Prescaler::DividedBy16 => Presc::DIV16,
110 Prescaler::DividedBy32 => Presc::DIV32,
111 Prescaler::DividedBy64 => Presc::DIV64,
112 Prescaler::DividedBy128 => Presc::DIV128,
113 Prescaler::DividedBy256 => Presc::DIV256,
114 }
115 }
116}
117
118#[cfg(feature = "defmt")]
119impl<'a> defmt::Format for Prescaler {
120 fn format(&self, fmt: defmt::Formatter) {
121 match self {
122 Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"),
123 Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"),
124 Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"),
125 Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"),
126 Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"),
127 Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"),
128 Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"),
129 Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"),
130 Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"),
131 Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"),
132 Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"),
133 Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"),
134 }
135 }
136}
137
138/// Number of samples used for averaging.
139/// TODO: Implement hardware averaging setting.
140#[allow(unused)]
141pub enum Averaging {
142 Disabled,
143 Samples2,
144 Samples4,
145 Samples8,
146 Samples16,
147 Samples32,
148 Samples64,
149 Samples128,
150 Samples256,
151 Samples512,
152 Samples1024,
153}
154
155impl<'d, T: Instance> Adc<'d, T> {
156 /// Create a new ADC driver.
157 pub fn new(adc: impl Peripheral<P = T> + 'd, sample_time: SampleTime, resolution: Resolution) -> Self {
158 embassy_hal_internal::into_ref!(adc);
159 rcc::enable_and_reset::<T>();
160
161 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
162
163 let prescaler = Prescaler::from_ker_ck(T::frequency());
164 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
165
166 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
167 debug!("ADC frequency set to {} Hz", frequency.0);
168
169 if frequency > MAX_ADC_CLK_FREQ {
170 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
171 }
172
173 let mut s = Self {
174 adc,
175 sample_time: SampleTime::from_bits(0),
176 };
177
178 s.power_up();
179
180 s.set_resolution(resolution);
181
182 s.calibrate();
183
184 s.enable();
185
186 s.configure_default();
187
188 s.set_sample_time_all_channels(sample_time);
189
190 s
191 }
192
193 fn power_up(&mut self) {
194 T::regs().cr().modify(|reg| {
195 reg.set_advregen(true);
196 });
197
198 // "The software must wait for the ADC voltage regulator startup time."
199 // See datasheet for the value.
200 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1);
201 }
202
203 fn calibrate(&mut self) {
204 // We have to make sure AUTOFF is OFF, but keep its value after calibration.
205 let autoff_value = T::regs().cfgr1().read().autoff();
206 T::regs().cfgr1().modify(|w| w.set_autoff(false));
207
208 T::regs().cr().modify(|w| w.set_adcal(true));
209
210 // "ADCAL bit stays at 1 during all the calibration sequence."
211 // "It is then cleared by hardware as soon the calibration completes."
212 while T::regs().cr().read().adcal() {}
213
214 debug!("ADC calibration value: {}.", T::regs().dr().read().data());
215
216 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value));
217 }
218
219 fn enable(&mut self) {
220 T::regs().isr().modify(|w| w.set_adrdy(true));
221 T::regs().cr().modify(|w| w.set_aden(true));
222 // ADRDY is "ADC ready". Wait until it will be True.
223 while !T::regs().isr().read().adrdy() {}
224 }
225
226 fn configure_default(&mut self) {
227 // single conversion mode, software trigger
228 T::regs().cfgr1().modify(|w| {
229 w.set_cont(false);
230 w.set_exten(Exten::DISABLED);
231 w.set_align(Align::RIGHT);
232 });
233 }
234
235 /// Enable reading the voltage reference internal channel.
236 pub fn enable_vrefint(&self) -> VrefInt {
237 T::common_regs().ccr().modify(|reg| {
238 reg.set_vrefen(true);
239 });
240
241 VrefInt {}
242 }
243
244 /// Enable reading the temperature internal channel.
245 pub fn enable_temperature(&self) -> Temperature {
246 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!");
247 T::common_regs().ccr().modify(|reg| {
248 reg.set_tsen(true);
249 });
250
251 Temperature {}
252 }
253
254 /// Set the ADC sample time.
255 /// Shall only be called when ADC is not converting.
256 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
257 self.sample_time = sample_time;
258
259 // Set all channels to use SMP1 field as source.
260 T::regs().smpr().modify(|w| {
261 w.smpsel(0);
262 w.set_smp1(sample_time);
263 });
264 }
265
266 /// Set the ADC resolution.
267 pub fn set_resolution(&mut self, resolution: Resolution) {
268 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
269 }
270
271 /// Perform a single conversion.
272 fn convert(&mut self) -> u16 {
273 // Set single conversion mode.
274 T::regs().cfgr1().modify(|w| w.set_cont(false));
275
276 // Start conversion
277 T::regs().cr().modify(|reg| {
278 reg.set_adstart(true);
279 });
280
281 // Waiting for End Of Conversion (EOC).
282 while !T::regs().isr().read().eoc() {}
283
284 T::regs().dr().read().data() as u16
285 }
286
287 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
288 Self::configure_channel(channel);
289 T::regs().cfgr1().write(|reg| {
290 reg.set_chselrmod(false);
291 reg.set_align(Align::RIGHT);
292 });
293 self.convert()
294 }
295
296 fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) {
297 assert!(
298 channel_sequence.len() <= CHSELR_SQ_SIZE,
299 "Seqenced read set cannot be more than {} in size.",
300 CHSELR_SQ_SIZE
301 );
302 let mut last_sq_set: usize = 0;
303 T::regs().chselr_sq().write(|w| {
304 for (i, channel) in channel_sequence.enumerate() {
305 assert!(
306 channel.channel() <= CHSELR_SQ_MAX_CHANNEL,
307 "Sequencer only support HW channels smaller than {}.",
308 CHSELR_SQ_MAX_CHANNEL
309 );
310 w.set_sq(i, channel.channel());
311 last_sq_set = i;
312 }
313
314 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
315 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
316 }
317 });
318
319 Self::apply_channel_conf()
320 }
321
322 async fn dma_convert(&mut self, rx_dma: &mut impl RxDma<T>, readings: &mut [u16]) {
323 // Enable overrun control, so no new DMA requests will be generated until
324 // previous DR values is read.
325 T::regs().isr().modify(|reg| {
326 reg.set_ovr(true);
327 });
328
329 // Set continuous mode with oneshot dma.
330 T::regs().cfgr1().modify(|reg| {
331 reg.set_discen(false);
332 reg.set_cont(true);
333 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
334 reg.set_dmaen(true);
335 reg.set_ovrmod(Ovrmod::PRESERVE);
336 });
337
338 let request = rx_dma.request();
339 let transfer = unsafe {
340 Transfer::new_read(
341 rx_dma,
342 request,
343 T::regs().dr().as_ptr() as *mut u16,
344 readings,
345 Default::default(),
346 )
347 };
348
349 // Start conversion.
350 T::regs().cr().modify(|reg| {
351 reg.set_adstart(true);
352 });
353
354 // Wait for conversion sequence to finish.
355 transfer.await;
356
357 // Ensure conversions are finished.
358 Self::cancel_conversions();
359
360 // Reset configuration.
361 T::regs().cfgr1().modify(|reg| {
362 reg.set_cont(false);
363 reg.set_dmacfg(Dmacfg::from_bits(0));
364 reg.set_dmaen(false);
365 });
366 }
367
368 /// Read one or multiple ADC channels using DMA in hardware order.
369 /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting.
370 /// Readings won't be in the same order as in the `set`!
371 ///
372 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
373 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
374 /// TODO(chudsaviet): externalize generic code and merge with read().
375 pub async fn read_in_hw_order(
376 &mut self,
377 rx_dma: &mut impl RxDma<T>,
378 hw_channel_selection: u32,
379 scandir: Scandir,
380 readings: &mut [u16],
381 ) {
382 assert!(
383 hw_channel_selection != 0,
384 "Some bits in `hw_channel_selection` shall be set."
385 );
386 assert!(
387 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
388 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
389 NUM_HW_CHANNELS
390 );
391 // To check for correct readings slice size, we shall solve Hamming weight problem,
392 // which is either slow or memory consuming.
393 // Since we have limited resources, we don't do it here.
394 // Not doing this have a great potential for a bug through.
395
396 // Ensure no conversions are ongoing.
397 Self::cancel_conversions();
398
399 T::regs().cfgr1().modify(|reg| {
400 reg.set_chselrmod(false);
401 reg.set_scandir(scandir);
402 reg.set_align(Align::RIGHT);
403 });
404
405 // Set required channels for multi-convert.
406 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
407
408 Self::apply_channel_conf();
409
410 self.dma_convert(rx_dma, readings).await
411 }
412
413 // Read ADC channels in specified order using DMA (CHSELRMOD = 1).
414 // In STM32C0, only lower 14 ADC channels can be read this way.
415 // For other channels, use `read_in_hw_order()` or blocking read.
416 pub async fn read(
417 &mut self,
418 rx_dma: &mut impl RxDma<T>,
419 channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
420 readings: &mut [u16],
421 ) {
422 assert!(
423 channel_sequence.len() != 0,
424 "Asynchronous read channel sequence cannot be empty."
425 );
426 assert!(
427 channel_sequence.len() == readings.len(),
428 "Channel sequence length must be equal to readings length."
429 );
430
431 // Ensure no conversions are ongoing.
432 Self::cancel_conversions();
433
434 T::regs().cfgr1().modify(|reg| {
435 reg.set_chselrmod(true);
436 reg.set_align(Align::RIGHT);
437 });
438
439 Self::setup_channel_sequencer(channel_sequence);
440
441 self.dma_convert(rx_dma, readings).await
442 }
443
444 fn configure_channel(channel: &mut impl AdcChannel<T>) {
445 channel.setup();
446 // write() because we want all other bits to be set to 0.
447 T::regs()
448 .chselr()
449 .write(|w| w.set_chsel(channel.channel().into(), true));
450
451 Self::apply_channel_conf();
452 }
453
454 fn apply_channel_conf() {
455 // Trigger and wait for the channel selection procedure to complete.
456 T::regs().isr().modify(|w| w.set_ccrdy(false));
457 while !T::regs().isr().read().ccrdy() {}
458 }
459
460 fn cancel_conversions() {
461 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
462 T::regs().cr().modify(|reg| {
463 reg.set_adstp(Adstp::STOP);
464 });
465 while T::regs().cr().read().adstart() {}
466 }
467 }
468}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 36898b8f9..31a08b6eb 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -14,6 +14,7 @@
14#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] 14#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")]
15#[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")] 15#[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")]
16#[cfg_attr(adc_g4, path = "g4.rs")] 16#[cfg_attr(adc_g4, path = "g4.rs")]
17#[cfg_attr(adc_c0, path = "c0.rs")]
17mod _version; 18mod _version;
18 19
19use core::marker::PhantomData; 20use core::marker::PhantomData;
@@ -71,7 +72,7 @@ trait SealedInstance {
71} 72}
72 73
73pub(crate) trait SealedAdcChannel<T> { 74pub(crate) trait SealedAdcChannel<T> {
74 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] 75 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
75 fn setup(&mut self) {} 76 fn setup(&mut self) {}
76 77
77 #[allow(unused)] 78 #[allow(unused)]
@@ -106,7 +107,8 @@ pub(crate) fn blocking_delay_us(us: u32) {
106 adc_g0, 107 adc_g0,
107 adc_u0, 108 adc_u0,
108 adc_h5, 109 adc_h5,
109 adc_u5 110 adc_u5,
111 adc_c0
110)))] 112)))]
111#[allow(private_bounds)] 113#[allow(private_bounds)]
112pub trait Instance: SealedInstance + crate::Peripheral<P = Self> { 114pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
@@ -126,7 +128,8 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
126 adc_g0, 128 adc_g0,
127 adc_u0, 129 adc_u0,
128 adc_h5, 130 adc_h5,
129 adc_u5 131 adc_u5,
132 adc_c0
130))] 133))]
131#[allow(private_bounds)] 134#[allow(private_bounds)]
132pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral { 135pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {
@@ -164,6 +167,13 @@ impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
164 } 167 }
165} 168}
166 169
170impl<T> AnyAdcChannel<T> {
171 #[allow(unused)]
172 pub fn get_hw_channel(&self) -> u8 {
173 self.channel
174 }
175}
176
167#[cfg(adc_u5)] 177#[cfg(adc_u5)]
168foreach_adc!( 178foreach_adc!(
169 (ADC4, $common_inst:ident, $clock:ident) => { 179 (ADC4, $common_inst:ident, $clock:ident) => {
@@ -225,7 +235,7 @@ macro_rules! impl_adc_pin {
225 ($inst:ident, $pin:ident, $ch:expr) => { 235 ($inst:ident, $pin:ident, $ch:expr) => {
226 impl crate::adc::AdcChannel<peripherals::$inst> for crate::peripherals::$pin {} 236 impl crate::adc::AdcChannel<peripherals::$inst> for crate::peripherals::$pin {}
227 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::peripherals::$pin { 237 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::peripherals::$pin {
228 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] 238 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
229 fn setup(&mut self) { 239 fn setup(&mut self) {
230 <Self as crate::gpio::SealedPin>::set_as_analog(self); 240 <Self as crate::gpio::SealedPin>::set_as_analog(self);
231 } 241 }
@@ -254,7 +264,7 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 {
254 Resolution::BITS12 => (1 << 12) - 1, 264 Resolution::BITS12 => (1 << 12) - 1,
255 Resolution::BITS10 => (1 << 10) - 1, 265 Resolution::BITS10 => (1 << 10) - 1,
256 Resolution::BITS8 => (1 << 8) - 1, 266 Resolution::BITS8 => (1 << 8) - 1,
257 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] 267 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_c0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))]
258 Resolution::BITS6 => (1 << 6) - 1, 268 Resolution::BITS6 => (1 << 6) - 1,
259 #[allow(unreachable_patterns)] 269 #[allow(unreachable_patterns)]
260 _ => core::unreachable!(), 270 _ => core::unreachable!(),
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index d818c77d0..86afdce8a 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -15,7 +15,7 @@ mod alt_regions {
15 15
16 use embassy_hal_internal::PeripheralRef; 16 use embassy_hal_internal::PeripheralRef;
17 17
18 use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3}; 18 use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
19 use crate::_generated::FLASH_SIZE; 19 use crate::_generated::FLASH_SIZE;
20 use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; 20 use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion};
21 use crate::peripherals::FLASH; 21 use crate::peripherals::FLASH;
@@ -62,6 +62,7 @@ mod alt_regions {
62 pub bank2_region1: AltBank2Region1<'d, MODE>, 62 pub bank2_region1: AltBank2Region1<'d, MODE>,
63 pub bank2_region2: AltBank2Region2<'d, MODE>, 63 pub bank2_region2: AltBank2Region2<'d, MODE>,
64 pub bank2_region3: AltBank2Region3<'d, MODE>, 64 pub bank2_region3: AltBank2Region3<'d, MODE>,
65 pub otp_region: OTPRegion<'d, MODE>,
65 } 66 }
66 67
67 impl<'d> Flash<'d> { 68 impl<'d> Flash<'d> {
@@ -78,6 +79,7 @@ mod alt_regions {
78 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), 79 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
79 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), 80 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
80 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), 81 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
82 otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
81 } 83 }
82 } 84 }
83 85
@@ -94,6 +96,7 @@ mod alt_regions {
94 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), 96 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
95 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), 97 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
96 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), 98 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
99 otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
97 } 100 }
98 } 101 }
99 } 102 }
diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs
index 9e131ca2b..d95de2e38 100644
--- a/embassy-stm32/src/flash/h5.rs
+++ b/embassy-stm32/src/flash/h5.rs
@@ -114,6 +114,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
114 r.set_bksel(match sector.bank { 114 r.set_bksel(match sector.bank {
115 crate::flash::FlashBank::Bank1 => stm32_metapac::flash::vals::NscrBksel::B_0X0, 115 crate::flash::FlashBank::Bank1 => stm32_metapac::flash::vals::NscrBksel::B_0X0,
116 crate::flash::FlashBank::Bank2 => stm32_metapac::flash::vals::NscrBksel::B_0X1, 116 crate::flash::FlashBank::Bank2 => stm32_metapac::flash::vals::NscrBksel::B_0X1,
117 _ => unreachable!(),
117 }); 118 });
118 r.set_snb(sector.index_in_bank); 119 r.set_snb(sector.index_in_bank);
119 r.set_ser(true); 120 r.set_ser(true);
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index 82e77d130..74cd6cc03 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -55,6 +55,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
55} 55}
56 56
57pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 57pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
58 assert!(sector.bank != FlashBank::Otp);
58 assert!(sector.index_in_bank < 8); 59 assert!(sector.index_in_bank < 8);
59 60
60 while busy() {} 61 while busy() {}
@@ -67,6 +68,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
67 (FlashBank::Bank2, true) => Bksel::BANK1, 68 (FlashBank::Bank2, true) => Bksel::BANK1,
68 (FlashBank::Bank2, false) => Bksel::BANK2, 69 (FlashBank::Bank2, false) => Bksel::BANK2,
69 (FlashBank::Bank1, true) => Bksel::BANK2, 70 (FlashBank::Bank1, true) => Bksel::BANK2,
71 _ => unreachable!(),
70 }); 72 });
71 w.set_snb(sector.index_in_bank); 73 w.set_snb(sector.index_in_bank);
72 w.set_ser(true); 74 w.set_ser(true);
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index b564de093..c7488c8ef 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -88,6 +88,8 @@ pub enum FlashBank {
88 Bank1 = 0, 88 Bank1 = 0,
89 /// Bank 2 89 /// Bank 2
90 Bank2 = 1, 90 Bank2 = 1,
91 /// OTP region,
92 Otp,
91} 93}
92 94
93#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb), path = "l.rs")] 95#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb), path = "l.rs")]
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
index e5af4f1f7..dad698316 100644
--- a/embassy-stm32/src/flash/u5.rs
+++ b/embassy-stm32/src/flash/u5.rs
@@ -75,6 +75,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
75 w.set_bker(match sector.bank { 75 w.set_bker(match sector.bank {
76 FlashBank::Bank1 => pac::flash::vals::SeccrBker::B_0X0, 76 FlashBank::Bank1 => pac::flash::vals::SeccrBker::B_0X0,
77 FlashBank::Bank2 => pac::flash::vals::SeccrBker::B_0X1, 77 FlashBank::Bank2 => pac::flash::vals::SeccrBker::B_0X1,
78 _ => unreachable!(),
78 }); 79 });
79 }); 80 });
80 #[cfg(not(feature = "trustzone-secure"))] 81 #[cfg(not(feature = "trustzone-secure"))]
@@ -85,6 +86,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
85 w.set_bker(match sector.bank { 86 w.set_bker(match sector.bank {
86 FlashBank::Bank1 => pac::flash::vals::NscrBker::B_0X0, 87 FlashBank::Bank1 => pac::flash::vals::NscrBker::B_0X0,
87 FlashBank::Bank2 => pac::flash::vals::NscrBker::B_0X1, 88 FlashBank::Bank2 => pac::flash::vals::NscrBker::B_0X1,
89 _ => unreachable!(),
88 }); 90 });
89 }); 91 });
90 92
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index e35d51c91..5dff3c4c3 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -372,7 +372,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
372 }); 372 });
373 373
374 T::REGS.cr().modify(|w| { 374 T::REGS.cr().modify(|w| {
375 w.set_fthres(vals::Threshold(config.fifo_threshold.into())); 375 w.set_fthres(vals::Threshold::from_bits(config.fifo_threshold.into()));
376 }); 376 });
377 377
378 // Wait for busy flag to clear 378 // Wait for busy flag to clear
@@ -643,7 +643,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
643 }); 643 });
644 644
645 T::REGS.cr().modify(|w| { 645 T::REGS.cr().modify(|w| {
646 w.set_fthres(vals::Threshold(config.fifo_threshold.into())); 646 w.set_fthres(vals::Threshold::from_bits(config.fifo_threshold.into()));
647 }); 647 });
648 648
649 // Wait for busy flag to clear 649 // Wait for busy flag to clear
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 977b2e7a2..04cbe83ed 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -180,6 +180,9 @@ pub(crate) unsafe fn init(config: Config) {
180 lsi: None, 180 lsi: None,
181 lse: None, 181 lse: None,
182 ); 182 );
183
184 RCC.ccipr()
185 .modify(|w| w.set_adc1sel(stm32_metapac::rcc::vals::Adcsel::SYS));
183} 186}
184 187
185mod max { 188mod max {
diff --git a/examples/stm32c0/src/bin/adc.rs b/examples/stm32c0/src/bin/adc.rs
new file mode 100644
index 000000000..10481f4d2
--- /dev/null
+++ b/examples/stm32c0/src/bin/adc.rs
@@ -0,0 +1,57 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::vals::Scandir;
7use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime};
8use embassy_stm32::peripherals::ADC1;
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let config = Default::default();
15 let p = embassy_stm32::init(config);
16
17 info!("ADC STM32C0 example.");
18
19 // We need to set certain sample time to be able to read temp sensor.
20 let mut adc = Adc::new(p.ADC1, SampleTime::CYCLES12_5, Resolution::BITS12);
21 let mut temp = adc.enable_temperature().degrade_adc();
22 let mut vref = adc.enable_vrefint().degrade_adc();
23 let mut pin0 = p.PA0.degrade_adc();
24
25 let mut dma = p.DMA1_CH1;
26 let mut read_buffer: [u16; 3] = [0; 3];
27
28 loop {
29 info!("============================");
30 let blocking_temp = adc.blocking_read(&mut temp);
31 let blocking_vref = adc.blocking_read(&mut vref);
32 let blocing_pin0 = adc.blocking_read(&mut pin0);
33 info!(
34 "Blocking ADC read: vref = {}, temp = {}, pin0 = {}.",
35 blocking_vref, blocking_temp, blocing_pin0
36 );
37
38 let channels_seqence: [&mut AnyAdcChannel<ADC1>; 3] = [&mut vref, &mut temp, &mut pin0];
39 adc.read(&mut dma, channels_seqence.into_iter(), &mut read_buffer).await;
40 // Values are ordered according to hardware ADC channel number!
41 info!(
42 "DMA ADC read in set: vref = {}, temp = {}, pin0 = {}.",
43 read_buffer[0], read_buffer[1], read_buffer[2]
44 );
45
46 let hw_channel_selection: u32 =
47 (1 << temp.get_hw_channel()) + (1 << vref.get_hw_channel()) + (1 << pin0.get_hw_channel());
48 adc.read_in_hw_order(&mut dma, hw_channel_selection, Scandir::UP, &mut read_buffer)
49 .await;
50 info!(
51 "DMA ADC read in hardware order: vref = {}, temp = {}, pin0 = {}.",
52 read_buffer[2], read_buffer[1], read_buffer[0]
53 );
54
55 Timer::after_millis(2000).await;
56 }
57}