aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/ci/book.sh2
-rwxr-xr-x.github/ci/doc.sh2
-rwxr-xr-xci.sh2
-rw-r--r--cyw43/src/consts.rs4
-rw-r--r--cyw43/src/control.rs74
-rw-r--r--cyw43/src/lib.rs2
-rw-r--r--embassy-mcxa/src/adc.rs784
-rw-r--r--embassy-mcxa/src/clocks/mod.rs3
-rw-r--r--embassy-mcxa/src/clocks/periph_helpers.rs1
-rw-r--r--embassy-mcxa/src/i2c/controller.rs2
-rw-r--r--embassy-mcxa/src/interrupt.rs41
-rw-r--r--embassy-mcxa/src/lib.rs10
-rw-r--r--embassy-mcxa/src/lpuart/mod.rs4
-rw-r--r--embassy-mcxa/src/pins.rs33
-rw-r--r--embassy-mcxa/src/reset_reason.rs106
-rw-r--r--embassy-mcxa/src/rtc.rs78
-rw-r--r--embassy-nrf/src/cracen.rs30
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs1
-rw-r--r--embassy-stm32/src/dma/mod.rs4
-rw-r--r--embassy-stm32/src/dma/util.rs58
-rw-r--r--embassy-stm32/src/i2c/v2.rs93
-rw-r--r--embassy-stm32/src/rcc/n6.rs20
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs1360
-rw-r--r--embassy-stm32/src/sdmmc/sd.rs693
-rw-r--r--embassy-stm32/src/sdmmc/sdio.rs177
-rw-r--r--embassy-stm32/src/spi/mod.rs40
-rw-r--r--embassy-stm32/src/time.rs2
-rw-r--r--examples/mcxa/src/bin/adc_interrupt.rs65
-rw-r--r--examples/mcxa/src/bin/adc_polling.rs58
-rw-r--r--examples/mcxa/src/bin/clkout.rs3
-rw-r--r--examples/mcxa/src/bin/i2c-scan-blocking.rs3
-rw-r--r--examples/mcxa/src/bin/reset-reason.rs15
-rw-r--r--examples/mcxa/src/lib.rs16
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs2
-rw-r--r--examples/rp/src/bin/wifi_webrequest.rs2
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs38
-rw-r--r--examples/stm32f7/src/bin/sdmmc.rs11
-rw-r--r--examples/stm32h7/src/bin/sdmmc.rs13
-rw-r--r--examples/stm32n6/Cargo.toml2
-rw-r--r--examples/stm32n6/src/bin/crc.rs31
-rw-r--r--examples/stm32n6/src/bin/hash.rs78
-rw-r--r--examples/stm32wba/src/bin/rtc.rs62
-rw-r--r--examples/stm32wba6/src/bin/rtc.rs62
-rwxr-xr-xfmtall.sh13
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs2
-rw-r--r--tests/stm32/src/bin/sdmmc.rs92
-rw-r--r--tests/stm32/src/bin/usart.rs44
49 files changed, 2695 insertions, 1548 deletions
diff --git a/.github/ci/book.sh b/.github/ci/book.sh
index 6c300bf09..a39f0dac7 100755
--- a/.github/ci/book.sh
+++ b/.github/ci/book.sh
@@ -9,7 +9,7 @@ set -euxo pipefail
9make -C docs 9make -C docs
10 10
11export KUBECONFIG=/ci/secrets/kubeconfig.yml 11export KUBECONFIG=/ci/secrets/kubeconfig.yml
12POD=$(kubectl -n embassy get po -l app=website -o jsonpath={.items[0].metadata.name}) 12POD=$(kubectl get po -l app=website -o jsonpath={.items[0].metadata.name})
13 13
14mkdir -p build 14mkdir -p build
15mv docs/book build/book 15mv docs/book build/book
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 5a0032d9d..85eed9f80 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -17,6 +17,6 @@ cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked
17cargo embassy-devtool doc -o webroot 17cargo embassy-devtool doc -o webroot
18 18
19export KUBECONFIG=/ci/secrets/kubeconfig.yml 19export KUBECONFIG=/ci/secrets/kubeconfig.yml
20POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 20POD=$(kubectl get po -l app=docserver -o jsonpath={.items[0].metadata.name})
21kubectl cp webroot/crates $POD:/data 21kubectl cp webroot/crates $POD:/data
22kubectl cp webroot/static $POD:/data 22kubectl cp webroot/static $POD:/data
diff --git a/ci.sh b/ci.sh
index cee761500..4f78f70cf 100755
--- a/ci.sh
+++ b/ci.sh
@@ -67,6 +67,8 @@ rm out/tests/rpi-pico/pwm
67rm out/tests/rpi-pico/cyw43-perf 67rm out/tests/rpi-pico/cyw43-perf
68rm out/tests/rpi-pico/uart_buffered 68rm out/tests/rpi-pico/uart_buffered
69 69
70rm out/tests/stm32h563zi/usart_dma
71
70# tests are implemented but the HIL test farm doesn't actually have these boards, yet 72# tests are implemented but the HIL test farm doesn't actually have these boards, yet
71rm -rf out/tests/stm32c071rb 73rm -rf out/tests/stm32c071rb
72rm -rf out/tests/stm32f100rd 74rm -rf out/tests/stm32f100rd
diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs
index c3f0dbfd8..e561d4794 100644
--- a/cyw43/src/consts.rs
+++ b/cyw43/src/consts.rs
@@ -177,9 +177,11 @@ pub(crate) enum Security {
177} 177}
178 178
179#[allow(non_camel_case_types)] 179#[allow(non_camel_case_types)]
180#[derive(Copy, Clone)] 180#[derive(Copy, Clone, PartialEq, num_enum::FromPrimitive)]
181#[repr(u8)] 181#[repr(u8)]
182pub enum EStatus { 182pub enum EStatus {
183 #[num_enum(default)]
184 Unknown = 0xFF,
183 /// operation was successful 185 /// operation was successful
184 SUCCESS = 0, 186 SUCCESS = 0,
185 /// operation failed 187 /// operation failed
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index 07fa1955e..240c0e728 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -12,11 +12,16 @@ use crate::ioctl::{IoctlState, IoctlType};
12use crate::structs::*; 12use crate::structs::*;
13use crate::{PowerManagementMode, countries, events}; 13use crate::{PowerManagementMode, countries, events};
14 14
15/// Control errors. 15/// Join errors.
16#[derive(Debug)] 16#[derive(Debug)]
17pub struct Error { 17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18 /// Status code. 18pub enum JoinError {
19 pub status: u32, 19 /// Network not found.
20 NetworkNotFound,
21 /// Failure to join network. Contains the status code from the SET_SSID event.
22 JoinFailure(u8),
23 /// Authentication failure for a secure network.
24 AuthenticationFailure,
20} 25}
21 26
22/// Multicast errors. 27/// Multicast errors.
@@ -296,7 +301,7 @@ impl<'a> Control<'a> {
296 } 301 }
297 302
298 /// Join a network with the provided SSID using the specified options. 303 /// Join a network with the provided SSID using the specified options.
299 pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> { 304 pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), JoinError> {
300 self.set_iovar_u32("ampdu_ba_wsize", 8).await; 305 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
301 306
302 if options.auth == JoinAuth::Open { 307 if options.auth == JoinAuth::Open {
@@ -367,40 +372,55 @@ impl<'a> Control<'a> {
367 }; 372 };
368 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); 373 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
369 374
370 self.wait_for_join(i).await 375 let secure_network = options.auth != JoinAuth::Open;
376 self.wait_for_join(i, secure_network).await
371 } 377 }
372 378
373 async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { 379 async fn wait_for_join(&mut self, i: SsidInfo, secure_network: bool) -> Result<(), JoinError> {
374 self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); 380 self.events.mask.enable(&[Event::SET_SSID, Event::AUTH, Event::PSK_SUP]);
375 let mut subscriber = self.events.queue.subscriber().unwrap(); 381 let mut subscriber = self.events.queue.subscriber().unwrap();
376 // the actual join operation starts here 382 // the actual join operation starts here
377 // we make sure to enable events before so we don't miss any 383 // we make sure to enable events before so we don't miss any
378 384
379 self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await; 385 self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await;
380 386
381 // to complete the join, we wait for a SET_SSID event 387 // To complete the join on an open network, we wait for a SET_SSID event with status SUCCESS
382 // we also save the AUTH status for the user, it may be interesting 388 // For secured networks, we wait for a PSK_SUP event with status 6 "UNSOLICITED"
383 let mut auth_status = 0; 389 let result = loop {
384 let status = loop {
385 let msg = subscriber.next_message_pure().await; 390 let msg = subscriber.next_message_pure().await;
386 if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS { 391
387 auth_status = msg.header.status; 392 let status = EStatus::from(msg.header.status as u8);
388 } else if msg.header.event_type == Event::SET_SSID { 393 match (msg.header.event_type, status, secure_network) {
389 // join operation ends with SET_SSID event 394 // Join operation ends with SET_SSID event for open networks
390 break msg.header.status; 395 (Event::SET_SSID, EStatus::SUCCESS, false) => break Ok(()),
391 } 396 (Event::SET_SSID, EStatus::NO_NETWORKS, _) => break Err(JoinError::NetworkNotFound),
397 (Event::SET_SSID, status, _) if status != EStatus::SUCCESS => {
398 break Err(JoinError::JoinFailure(status as u8));
399 }
400 // Ignore PSK_SUP "ABORT" which is sometimes sent before successful join
401 (Event::PSK_SUP, EStatus::ABORT, true) => {}
402 // Event PSK_SUP with status 6 "UNSOLICITED" indicates success for secure networks
403 (Event::PSK_SUP, EStatus::UNSOLICITED, true) => break Ok(()),
404 // Events indicating authentication failure, possibly due to incorrect password
405 (Event::PSK_SUP, _, true) | (Event::AUTH, EStatus::FAIL, true) => {
406 break Err(JoinError::AuthenticationFailure);
407 }
408 _ => {}
409 };
392 }; 410 };
393 411
394 self.events.mask.disable_all(); 412 self.events.mask.disable_all();
395 if status == EStatus::SUCCESS { 413 match result {
396 // successful join 414 Ok(()) => {
397 self.state_ch.set_link_state(LinkState::Up); 415 self.state_ch.set_link_state(LinkState::Up);
398 debug!("JOINED"); 416 debug!("JOINED");
399 Ok(()) 417 }
400 } else { 418 Err(JoinError::JoinFailure(status)) => debug!("JOIN failed: status={}", status),
401 warn!("JOIN failed with status={} auth={}", status, auth_status); 419 Err(JoinError::NetworkNotFound) => debug!("JOIN failed: network not found"),
402 Err(Error { status }) 420 Err(JoinError::AuthenticationFailure) => debug!("JOIN failed: authentication failure"),
403 } 421 };
422
423 result
404 } 424 }
405 425
406 /// Set GPIO pin on WiFi chip. 426 /// Set GPIO pin on WiFi chip.
diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs
index 82c636346..73d2830ca 100644
--- a/cyw43/src/lib.rs
+++ b/cyw43/src/lib.rs
@@ -31,7 +31,7 @@ use ioctl::IoctlState;
31use crate::bus::Bus; 31use crate::bus::Bus;
32pub use crate::bus::SpiBusCyw43; 32pub use crate::bus::SpiBusCyw43;
33pub use crate::control::{ 33pub use crate::control::{
34 AddMulticastAddressError, Control, Error as ControlError, JoinAuth, JoinOptions, ScanOptions, ScanType, Scanner, 34 AddMulticastAddressError, Control, JoinAuth, JoinError, JoinOptions, ScanOptions, ScanType, Scanner,
35}; 35};
36pub use crate::runner::Runner; 36pub use crate::runner::Runner;
37pub use crate::structs::BssInfo; 37pub use crate::structs::BssInfo;
diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs
index 7475299ba..f88bb6b37 100644
--- a/embassy-mcxa/src/adc.rs
+++ b/embassy-mcxa/src/adc.rs
@@ -1,42 +1,23 @@
1//! ADC driver 1//! ADC driver
2use core::sync::atomic::{AtomicBool, Ordering}; 2use core::future::Future;
3use core::marker::PhantomData;
3 4
4use embassy_hal_internal::{Peri, PeripheralType}; 5use embassy_hal_internal::{Peri, PeripheralType};
6use maitake_sync::WaitCell;
7use paste::paste;
5 8
6use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; 9use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4};
7use crate::clocks::{Gate, PoweredClock, enable_and_reset}; 10use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset};
11use crate::gpio::{GpioPin, SealedPin};
12use crate::interrupt::typelevel::{Handler, Interrupt};
8use crate::pac; 13use crate::pac;
9use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; 14use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres};
10use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; 15use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts};
11use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; 16use crate::pac::adc1::cmdl1::Mode;
12use crate::pac::adc1::ctrl::CalAvgs; 17use crate::pac::adc1::ctrl::CalAvgs;
13use crate::pac::adc1::tctrl::{Tcmd, Tpri}; 18use crate::pac::adc1::tctrl::{Tcmd, Tpri};
14 19
15type Regs = pac::adc1::RegisterBlock; 20/// Trigger priority policy for ADC conversions.
16
17static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false);
18// Token-based instance pattern like embassy-imxrt
19pub trait Instance: Gate<MrccPeriphConfig = AdcConfig> + PeripheralType {
20 fn ptr() -> *const Regs;
21}
22
23/// Token for ADC1
24pub type Adc1 = crate::peripherals::ADC1;
25impl Instance for crate::peripherals::ADC1 {
26 #[inline(always)]
27 fn ptr() -> *const Regs {
28 pac::Adc1::ptr()
29 }
30}
31
32// Also implement Instance for the Peri wrapper type
33// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> {
34// #[inline(always)]
35// fn ptr() -> *const Regs {
36// pac::Adc1::ptr()
37// }
38// }
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)] 21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41#[repr(u8)] 22#[repr(u8)]
42pub enum TriggerPriorityPolicy { 23pub enum TriggerPriorityPolicy {
@@ -52,20 +33,36 @@ pub enum TriggerPriorityPolicy {
52 TriggerPriorityExceptionDisabled = 16, 33 TriggerPriorityExceptionDisabled = 16,
53} 34}
54 35
36/// Configuration for the LPADC peripheral.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)] 37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct LpadcConfig { 38pub struct LpadcConfig {
39 /// Control system transition to Stop and Wait power modes while ADC is converting.
40 /// When enabled in Doze mode, immediate entries to Wait or Stop are allowed.
41 /// When disabled, the ADC will wait for the current averaging iteration/FIFO storage to complete before acknowledging stop or wait mode entry.
57 pub enable_in_doze_mode: bool, 42 pub enable_in_doze_mode: bool,
43 /// Auto-Calibration Averages.
58 pub conversion_average_mode: CalAvgs, 44 pub conversion_average_mode: CalAvgs,
45 /// ADC analog circuits are pre-enabled and ready to execute conversions without startup delays(at the cost of higher DC current consumption).
59 pub enable_analog_preliminary: bool, 46 pub enable_analog_preliminary: bool,
47 /// Power-up delay value (in ADC clock cycles)
60 pub power_up_delay: u8, 48 pub power_up_delay: u8,
49 /// Reference voltage source selection
61 pub reference_voltage_source: Refsel, 50 pub reference_voltage_source: Refsel,
51 /// Power configuration selection.
62 pub power_level_mode: Pwrsel, 52 pub power_level_mode: Pwrsel,
53 /// Trigger priority policy for handling multiple triggers
63 pub trigger_priority_policy: TriggerPriorityPolicy, 54 pub trigger_priority_policy: TriggerPriorityPolicy,
55 /// Enables the ADC pausing function. When enabled, a programmable delay is inserted during command execution sequencing between LOOP iterations,
56 /// between commands in a sequence, and between conversions when command is executing in "Compare Until True" configuration.
64 pub enable_conv_pause: bool, 57 pub enable_conv_pause: bool,
58 /// Controls the duration of pausing during command execution sequencing. The pause delay is a count of (convPauseDelay*4) ADCK cycles.
59 /// Only available when ADC pausing function is enabled. The available value range is in 9-bit.
65 pub conv_pause_delay: u16, 60 pub conv_pause_delay: u16,
66 pub fifo_watermark: u8, 61 /// Power configuration (normal/deep sleep behavior)
67 pub power: PoweredClock, 62 pub power: PoweredClock,
63 /// ADC clock source selection
68 pub source: AdcClockSel, 64 pub source: AdcClockSel,
65 /// Clock divider for ADC clock
69 pub div: Div4, 66 pub div: Div4,
70} 67}
71 68
@@ -81,7 +78,6 @@ impl Default for LpadcConfig {
81 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, 78 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
82 enable_conv_pause: false, 79 enable_conv_pause: false,
83 conv_pause_delay: 0, 80 conv_pause_delay: 0,
84 fifo_watermark: 0,
85 power: PoweredClock::NormalEnabledDeepSleepDisabled, 81 power: PoweredClock::NormalEnabledDeepSleepDisabled,
86 source: AdcClockSel::FroLfDiv, 82 source: AdcClockSel::FroLfDiv,
87 div: Div4::no_div(), 83 div: Div4::no_div(),
@@ -89,10 +85,11 @@ impl Default for LpadcConfig {
89 } 85 }
90} 86}
91 87
88/// Configuration for a conversion command.
89///
90/// Defines the parameters for a single ADC conversion operation.
92#[derive(Debug, Clone, Copy, PartialEq, Eq)] 91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub struct ConvCommandConfig { 92pub struct ConvCommandConfig {
94 pub sample_channel_mode: Ctype,
95 pub channel_number: Adch,
96 pub chained_next_command_number: Next, 93 pub chained_next_command_number: Next,
97 pub enable_auto_channel_increment: bool, 94 pub enable_auto_channel_increment: bool,
98 pub loop_count: u8, 95 pub loop_count: u8,
@@ -105,6 +102,26 @@ pub struct ConvCommandConfig {
105 pub enable_wait_trigger: bool, 102 pub enable_wait_trigger: bool,
106} 103}
107 104
105impl Default for ConvCommandConfig {
106 fn default() -> Self {
107 ConvCommandConfig {
108 chained_next_command_number: Next::NoNextCmdTerminateOnFinish,
109 enable_auto_channel_increment: false,
110 loop_count: 0,
111 hardware_average_mode: Avgs::NoAverage,
112 sample_time_mode: Sts::Sample3p5,
113 hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult,
114 hardware_compare_value_high: 0,
115 hardware_compare_value_low: 0,
116 conversion_resolution_mode: Mode::Data12Bits,
117 enable_wait_trigger: false,
118 }
119 }
120}
121
122/// Configuration for a conversion trigger.
123///
124/// Defines how a trigger initiates ADC conversions.
108#[derive(Debug, Clone, Copy, PartialEq, Eq)] 125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109pub struct ConvTriggerConfig { 126pub struct ConvTriggerConfig {
110 pub target_command_id: Tcmd, 127 pub target_command_id: Tcmd,
@@ -113,32 +130,298 @@ pub struct ConvTriggerConfig {
113 pub enable_hardware_trigger: bool, 130 pub enable_hardware_trigger: bool,
114} 131}
115 132
133impl Default for ConvTriggerConfig {
134 fn default() -> Self {
135 ConvTriggerConfig {
136 target_command_id: Tcmd::NotValid,
137 delay_power: 0,
138 priority: Tpri::HighestPriority,
139 enable_hardware_trigger: false,
140 }
141 }
142}
143
144/// Shorthand for `Result<T>`.
145pub type Result<T> = core::result::Result<T, Error>;
146
147/// ADC Error types
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149#[cfg_attr(feature = "defmt", derive(defmt::Format))]
150pub enum Error {
151 /// FIFO is empty, no conversion result available
152 FifoEmpty,
153 /// Invalid configuration
154 InvalidConfig,
155 /// Clock configuration error.
156 ClockSetup(ClockError),
157}
158
159/// Result of an ADC conversion.
160///
161/// Contains the conversion value and metadata about the conversion.
116#[derive(Debug, Clone, Copy, PartialEq, Eq)] 162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub struct ConvResult { 163pub struct ConvResult {
118 pub command_id_source: u32, 164 pub command_id_source: u8,
119 pub loop_count_index: u32, 165 pub loop_count_index: u8,
120 pub trigger_id_source: u32, 166 pub trigger_id_source: u8,
121 pub conv_value: u16, 167 pub conv_value: u16,
122} 168}
123 169
124pub struct Adc<'a, I: Instance> { 170/// ADC interrupt handler.
125 _inst: core::marker::PhantomData<&'a mut I>, 171pub struct InterruptHandler<I: Instance> {
172 _phantom: PhantomData<I>,
173}
174
175/// ADC driver instance.
176pub struct Adc<'a, M: ModeAdc> {
177 _inst: PhantomData<&'a mut ()>,
178 mode: M,
179
180 // The channel index of the pin used to create our ADC instance
181 channel_idx: u8,
182
183 // The register block of the ADC instance
184 info: &'static pac::adc0::RegisterBlock,
185}
186
187impl<'a> Adc<'a, Blocking> {
188 /// Create a new blocking instance of the ADC driver.
189 /// # Arguments
190 /// * `_inst` - ADC peripheral instance
191 /// * `pin` - GPIO pin to use for ADC
192 /// * `config` - ADC configuration
193 pub fn new_blocking<I: Instance>(
194 _inst: Peri<'a, I>,
195 pin: Peri<'a, impl AdcPin<I>>,
196 config: LpadcConfig,
197 ) -> Result<Self> {
198 Self::new_inner(_inst, pin, config, Blocking)
199 }
200
201 /// Enable ADC interrupts.
202 ///
203 /// Enables the interrupt sources specified in the bitmask.
204 ///
205 /// # Arguments
206 /// * `mask` - Bitmask of interrupt sources to enable
207 pub fn enable_interrupt(&mut self, mask: u32) {
208 self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) });
209 }
210
211 /// Disable ADC interrupts.
212 ///
213 /// Disables the interrupt sources specified in the bitmask.
214 ///
215 /// # Arguments
216 /// * `mask` - Bitmask of interrupt sources to disable
217 pub fn disable_interrupt(&mut self, mask: u32) {
218 self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) });
219 }
220
221 pub fn set_fifo_watermark(&mut self, watermark: u8) -> Result<()> {
222 if watermark > 0b111 {
223 return Err(Error::InvalidConfig);
224 }
225 self.info.fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(watermark) });
226 Ok(())
227 }
228
229 /// Trigger ADC conversion(s) via software.
230 ///
231 /// Initiates conversion(s) for the trigger(s) specified in the bitmask.
232 /// Each bit in the mask corresponds to a trigger ID (bit 0 = trigger 0, etc.).
233 ///
234 /// # Arguments
235 /// * `trigger_id_mask` - Bitmask of trigger IDs to activate (bit N = trigger N)
236 ///
237 /// # Returns
238 /// * `Ok(())` if the triger mask was valid
239 /// * `Err(Error::InvalidConfig)` if the mask was greater than `0b1111`
240 pub fn do_software_trigger(&self, trigger_id_mask: u8) -> Result<()> {
241 if trigger_id_mask > 0b1111 {
242 return Err(Error::InvalidConfig);
243 }
244 self.info.swtrig().write(|w| unsafe { w.bits(trigger_id_mask as u32) });
245 Ok(())
246 }
247
248 /// Set conversion command configuration.
249 ///
250 /// Configures a conversion command slot with the specified parameters.
251 /// Commands define how conversions are performed (channel, resolution, etc.).
252 ///
253 /// # Arguments
254 /// * `index` - Command index (Must be in range 1..=7)
255 /// * `config` - Command configuration
256 ///
257 /// # Returns
258 /// * `Ok(())` if the command was configured successfully
259 /// * `Err(Error::InvalidConfig)` if the index is out of range
260 pub fn set_conv_command_config(&self, index: usize, config: &ConvCommandConfig) -> Result<()> {
261 self.set_conv_command_config_inner(index, config)
262 }
263
264 /// Set conversion trigger configuration.
265 ///
266 /// Configures a trigger to initiate conversions. Triggers can be
267 /// activated by software or hardware signals.
268 ///
269 /// # Arguments
270 /// * `trigger_id` - Trigger index (0..=3)
271 /// * `config` - Trigger configuration
272 pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> {
273 self.set_conv_trigger_config_inner(trigger_id, config)
274 }
275
276 /// Reset the FIFO buffer.
277 ///
278 /// Clears all pending conversion results from the FIFO.
279 pub fn do_reset_fifo(&self) {
280 self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset());
281 }
282
283 /// Get conversion result from FIFO.
284 ///
285 /// Reads and returns the next conversion result from the FIFO.
286 /// Returns `None` if the FIFO is empty.
287 ///
288 /// # Returns
289 /// - `Some(ConvResult)` if a result is available
290 /// - `Err(Error::FifoEmpty)` if the FIFO is empty
291 pub fn get_conv_result(&self) -> Result<ConvResult> {
292 self.get_conv_result_inner()
293 }
126} 294}
127 295
128impl<'a, I: Instance> Adc<'a, I> { 296impl<'a> Adc<'a, Async> {
129 /// initialize ADC 297 /// Initialize ADC with interrupt support.
130 pub fn new(_inst: Peri<'a, I>, config: LpadcConfig) -> Self { 298 ///
131 let adc = unsafe { &*I::ptr() }; 299 /// # Arguments
300 /// * `_inst` - ADC peripheral instance
301 /// * `pin` - GPIO pin to use for ADC
302 /// * `_irq` - Interrupt binding for this ADC instance
303 /// * `config` - ADC configuration
304 pub fn new_async<I: Instance>(
305 _inst: Peri<'a, I>,
306 pin: Peri<'a, impl AdcPin<I>>,
307 _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a,
308 config: LpadcConfig,
309 ) -> Result<Self> {
310 let adc = Self::new_inner(_inst, pin, config, Async { waiter: I::wait_cell() })?;
311
312 I::Interrupt::unpend();
313 unsafe { I::Interrupt::enable() };
314
315 let cfg = ConvCommandConfig {
316 chained_next_command_number: Next::NoNextCmdTerminateOnFinish,
317 enable_auto_channel_increment: false,
318 loop_count: 0,
319 hardware_average_mode: Avgs::NoAverage,
320 sample_time_mode: Sts::Sample3p5,
321 hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult,
322 hardware_compare_value_high: 0,
323 hardware_compare_value_low: 0,
324 conversion_resolution_mode: Mode::Data16Bits,
325 enable_wait_trigger: false,
326 };
327
328 // We always use command 1, so this cannot fail
329 _ = adc.set_conv_command_config_inner(1, &cfg);
330
331 let cfg = ConvTriggerConfig {
332 target_command_id: Tcmd::ExecuteCmd1,
333 delay_power: 0,
334 priority: Tpri::HighestPriority,
335 enable_hardware_trigger: false,
336 };
337
338 // We always use trigger 0, so this cannot fail
339 _ = adc.set_conv_trigger_config_inner(0, &cfg);
340
341 // We always set the watermark to 0 (trigger when 1 is available)
342 I::ptr().fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(0) });
343
344 Ok(adc)
345 }
346
347 /// Set the number of averages
348 pub fn set_averages(&mut self, avgs: Avgs) {
349 // TODO: we should probably return a result or wait for idle?
350 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior."
351 self.info.cmdh1().modify(|_r, w| w.avgs().variant(avgs));
352 }
132 353
133 let _clock_freq = unsafe { 354 /// Set the sample time
355 pub fn set_sample_time(&mut self, st: Sts) {
356 // TODO: we should probably return a result or wait for idle?
357 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior."
358 self.info.cmdh1().modify(|_r, w| w.sts().variant(st));
359 }
360
361 pub fn set_resolution(&mut self, mode: Mode) {
362 // TODO: we should probably return a result or wait for idle?
363 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior."
364 self.info.cmdl1().modify(|_r, w| w.mode().variant(mode));
365 }
366
367 fn wait_idle(&mut self) -> impl Future<Output = core::result::Result<(), maitake_sync::Closed>> + use<'_> {
368 self.mode
369 .waiter
370 .wait_for(|| self.info.ie().read().fwmie0().bit_is_clear())
371 }
372
373 /// Read ADC value asynchronously.
374 ///
375 /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered.
376 ///
377 /// The function:
378 /// 1. Enables the FIFO watermark interrupt
379 /// 2. Triggers a software conversion on trigger 0
380 /// 3. Waits for the conversion to complete
381 /// 4. Returns the conversion result
382 ///
383 /// # Returns
384 /// 16-bit ADC conversion value
385 pub async fn read(&mut self) -> Result<u16> {
386 // If we cancelled a previous read, we might still be busy, wait
387 // until the interrupt is cleared (done by the interrupt)
388 _ = self.wait_idle().await;
389
390 // Clear the fifo
391 self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset());
392
393 // Trigger a new conversion
394 self.info.ie().modify(|_r, w| w.fwmie0().set_bit());
395 self.info.swtrig().write(|w| w.swt0().set_bit());
396
397 // Wait for completion
398 _ = self.wait_idle().await;
399
400 self.get_conv_result_inner().map(|r| r.conv_value)
401 }
402}
403
404impl<'a, M: ModeAdc> Adc<'a, M> {
405 /// Internal initialization function shared by `new_async` and `new_blocking`.
406 fn new_inner<I: Instance, P: AdcPin<I>>(
407 _inst: Peri<'a, I>,
408 pin: Peri<'a, P>,
409 config: LpadcConfig,
410 mode: M,
411 ) -> Result<Self> {
412 let adc = I::ptr();
413
414 _ = unsafe {
134 enable_and_reset::<I>(&AdcConfig { 415 enable_and_reset::<I>(&AdcConfig {
135 power: config.power, 416 power: config.power,
136 source: config.source, 417 source: config.source,
137 div: config.div, 418 div: config.div,
138 }) 419 })
139 .expect("Adc Init should not fail") 420 .map_err(Error::ClockSetup)?
140 }; 421 };
141 422
423 pin.mux();
424
142 /* Reset the module. */ 425 /* Reset the module. */
143 adc.ctrl().modify(|_, w| w.rst().held_in_reset()); 426 adc.ctrl().modify(|_, w| w.rst().held_in_reset());
144 adc.ctrl().modify(|_, w| w.rst().released_from_reset()); 427 adc.ctrl().modify(|_, w| w.rst().released_from_reset());
@@ -149,22 +432,14 @@ impl<'a, I: Instance> Adc<'a, I> {
149 adc.ctrl().modify(|_, w| w.adcen().disabled()); 432 adc.ctrl().modify(|_, w| w.adcen().disabled());
150 433
151 /* Configure the module generally. */ 434 /* Configure the module generally. */
152 if config.enable_in_doze_mode { 435 adc.ctrl().modify(|_, w| w.dozen().bit(config.enable_in_doze_mode));
153 adc.ctrl().modify(|_, w| w.dozen().enabled());
154 } else {
155 adc.ctrl().modify(|_, w| w.dozen().disabled());
156 }
157 436
158 /* Set calibration average mode. */ 437 /* Set calibration average mode. */
159 adc.ctrl() 438 adc.ctrl()
160 .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode)); 439 .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode));
161 440
162 adc.cfg().write(|w| unsafe { 441 adc.cfg().write(|w| unsafe {
163 let w = if config.enable_analog_preliminary { 442 w.pwren().bit(config.enable_analog_preliminary);
164 w.pwren().pre_enabled()
165 } else {
166 w
167 };
168 443
169 w.pudly() 444 w.pudly()
170 .bits(config.power_up_delay) 445 .bits(config.power_up_delay)
@@ -214,32 +489,38 @@ impl<'a, I: Instance> Adc<'a, I> {
214 adc.pause().write(|w| unsafe { w.bits(0) }); 489 adc.pause().write(|w| unsafe { w.bits(0) });
215 } 490 }
216 491
217 adc.fctrl0() 492 adc.fctrl0().write(|w| unsafe { w.fwmark().bits(0) });
218 .write(|w| unsafe { w.fwmark().bits(config.fifo_watermark) });
219 493
220 // Enable ADC 494 // Enable ADC
221 adc.ctrl().modify(|_, w| w.adcen().enabled()); 495 adc.ctrl().modify(|_, w| w.adcen().enabled());
222 496
223 Self { 497 Ok(Self {
224 _inst: core::marker::PhantomData, 498 _inst: PhantomData,
225 } 499 mode,
226 } 500 channel_idx: P::CHANNEL,
227 501 info: adc,
228 pub fn deinit(&self) { 502 })
229 let adc = unsafe { &*I::ptr() };
230 adc.ctrl().modify(|_, w| w.adcen().disabled());
231 } 503 }
232 504
505 /// Perform offset calibration.
506 /// Waits for calibration to complete before returning.
233 pub fn do_offset_calibration(&self) { 507 pub fn do_offset_calibration(&self) {
234 let adc = unsafe { &*I::ptr() };
235 // Enable calibration mode 508 // Enable calibration mode
236 adc.ctrl() 509 self.info
510 .ctrl()
237 .modify(|_, w| w.calofs().offset_calibration_request_pending()); 511 .modify(|_, w| w.calofs().offset_calibration_request_pending());
238 512
239 // Wait for calibration to complete (polling status register) 513 // Wait for calibration to complete (polling status register)
240 while adc.stat().read().cal_rdy().is_not_set() {} 514 while self.info.stat().read().cal_rdy().is_not_set() {}
241 } 515 }
242 516
517 /// Calculate gain conversion result from gain adjustment factor.
518 ///
519 /// # Arguments
520 /// * `gain_adjustment` - Gain adjustment factor
521 ///
522 /// # Returns
523 /// Gain calibration register value
243 pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 { 524 pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 {
244 let mut gcra_array = [0u32; 17]; 525 let mut gcra_array = [0u32; 17];
245 let mut gcalr: u32 = 0; 526 let mut gcalr: u32 = 0;
@@ -258,102 +539,80 @@ impl<'a, I: Instance> Adc<'a, I> {
258 gcalr 539 gcalr
259 } 540 }
260 541
542 /// Perform automatic gain calibration.
261 pub fn do_auto_calibration(&self) { 543 pub fn do_auto_calibration(&self) {
262 let adc = unsafe { &*I::ptr() }; 544 self.info
263 adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); 545 .ctrl()
546 .modify(|_, w| w.cal_req().calibration_request_pending());
264 547
265 while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} 548 while self.info.gcc0().read().rdy().is_gain_cal_not_valid() {}
266 549
267 let mut gcca = adc.gcc0().read().gain_cal().bits() as u32; 550 let mut gcca = self.info.gcc0().read().gain_cal().bits() as u32;
268 if gcca & ((0xFFFF + 1) >> 1) != 0 { 551 if gcca & 0x8000 != 0 {
269 gcca |= !0xFFFF; 552 gcca |= !0xFFFF;
270 } 553 }
271 554
272 let gcra = 131072.0 / (131072.0 - gcca as f32); 555 let gcra = 131072.0 / (131072.0 - gcca as f32);
273 556
274 // Write to GCR0 557 // Write to GCR0
275 adc.gcr0().write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); 558 self.info
559 .gcr0()
560 .write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) });
276 561
277 adc.gcr0().modify(|_, w| w.rdy().set_bit()); 562 self.info.gcr0().modify(|_, w| w.rdy().set_bit());
278 563
279 // Wait for calibration to complete (polling status register) 564 // Wait for calibration to complete (polling status register)
280 while adc.stat().read().cal_rdy().is_not_set() {} 565 while self.info.stat().read().cal_rdy().is_not_set() {}
281 } 566 }
282 567
283 pub fn do_software_trigger(&self, trigger_id_mask: u32) { 568 fn set_conv_command_config_inner(&self, index: usize, config: &ConvCommandConfig) -> Result<()> {
284 let adc = unsafe { &*I::ptr() }; 569 let (cmdl, cmdh) = match index {
285 adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); 570 1 => (self.info.cmdl1(), self.info.cmdh1()),
286 } 571 2 => (self.info.cmdl2(), self.info.cmdh2()),
572 3 => (self.info.cmdl3(), self.info.cmdh3()),
573 4 => (self.info.cmdl4(), self.info.cmdh4()),
574 5 => (self.info.cmdl5(), self.info.cmdh5()),
575 6 => (self.info.cmdl6(), self.info.cmdh6()),
576 7 => (self.info.cmdl7(), self.info.cmdh7()),
577 _ => return Err(Error::InvalidConfig),
578 };
287 579
288 pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { 580 cmdl.write(|w| {
289 ConvCommandConfig { 581 unsafe {
290 sample_channel_mode: Ctype::SingleEndedASideChannel, 582 w.adch().bits(self.channel_idx);
291 channel_number: Adch::SelectCh0, 583 }
292 chained_next_command_number: Next::NoNextCmdTerminateOnFinish, 584 w.mode().variant(config.conversion_resolution_mode)
293 enable_auto_channel_increment: false, 585 });
294 loop_count: 0,
295 hardware_average_mode: Avgs::NoAverage,
296 sample_time_mode: Sts::Sample3p5,
297 hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult,
298 hardware_compare_value_high: 0,
299 hardware_compare_value_low: 0,
300 conversion_resolution_mode: Mode::Data12Bits,
301 enable_wait_trigger: false,
302 }
303 }
304 586
305 //TBD Need to add cmdlx and cmdhx with x {2..7} 587 cmdh.write(|w| {
306 pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { 588 w.next().variant(config.chained_next_command_number);
307 let adc = unsafe { &*I::ptr() }; 589 unsafe {
308 590 w.loop_().bits(config.loop_count);
309 match index {
310 1 => {
311 adc.cmdl1().write(|w| {
312 w.adch()
313 .variant(config.channel_number)
314 .mode()
315 .variant(config.conversion_resolution_mode)
316 });
317 adc.cmdh1().write(|w| unsafe {
318 w.next()
319 .variant(config.chained_next_command_number)
320 .loop_()
321 .bits(config.loop_count)
322 .avgs()
323 .variant(config.hardware_average_mode)
324 .sts()
325 .variant(config.sample_time_mode)
326 .cmpen()
327 .variant(config.hardware_compare_mode);
328 if config.enable_wait_trigger {
329 w.wait_trig().enabled();
330 }
331 if config.enable_auto_channel_increment {
332 w.lwi().enabled();
333 }
334 w
335 });
336 } 591 }
337 _ => panic!("Invalid command index: must be between 1 and 7"), 592 w.avgs().variant(config.hardware_average_mode);
338 } 593 w.sts().variant(config.sample_time_mode);
594 w.cmpen().variant(config.hardware_compare_mode);
595 w.wait_trig().bit(config.enable_wait_trigger);
596 w.lwi().bit(config.enable_auto_channel_increment);
597 w
598 });
599
600 Ok(())
339 } 601 }
340 602
341 pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig { 603 fn set_conv_trigger_config_inner(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> {
342 ConvTriggerConfig { 604 // 0..4 are valid
343 target_command_id: Tcmd::NotValid, 605 if trigger_id >= 4 {
344 delay_power: 0, 606 return Err(Error::InvalidConfig);
345 priority: Tpri::HighestPriority,
346 enable_hardware_trigger: false,
347 } 607 }
348 }
349 608
350 pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { 609 let tctrl = &self.info.tctrl(trigger_id);
351 let adc = unsafe { &*I::ptr() };
352 let tctrl = &adc.tctrl(trigger_id);
353 610
354 tctrl.write(|w| unsafe { 611 tctrl.write(|w| {
355 let w = w.tcmd().variant(config.target_command_id); 612 w.tcmd().variant(config.target_command_id);
356 let w = w.tdly().bits(config.delay_power); 613 unsafe {
614 w.tdly().bits(config.delay_power);
615 }
357 w.tpri().variant(config.priority); 616 w.tpri().variant(config.priority);
358 if config.enable_hardware_trigger { 617 if config.enable_hardware_trigger {
359 w.hten().enabled() 618 w.hten().enabled()
@@ -361,49 +620,230 @@ impl<'a, I: Instance> Adc<'a, I> {
361 w 620 w
362 } 621 }
363 }); 622 });
364 }
365 623
366 pub fn do_reset_fifo(&self) { 624 Ok(())
367 let adc = unsafe { &*I::ptr() };
368 adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset());
369 } 625 }
370 626
371 pub fn enable_interrupt(&self, mask: u32) { 627 /// Get conversion result from FIFO.
372 let adc = unsafe { &*I::ptr() }; 628 ///
373 adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); 629 /// Reads and returns the next conversion result from the FIFO.
374 INTERRUPT_TRIGGERED.store(false, Ordering::SeqCst); 630 /// Returns `None` if the FIFO is empty.
375 } 631 ///
632 /// # Returns
633 /// - `Some(ConvResult)` if a result is available
634 /// - `Err(Error::FifoEmpty)` if the FIFO is empty
635 fn get_conv_result_inner(&self) -> Result<ConvResult> {
636 let fifo = self.info.resfifo0().read();
637 if !fifo.valid().is_valid() {
638 return Err(Error::FifoEmpty);
639 }
376 640
377 pub fn is_interrupt_triggered(&self) -> bool { 641 Ok(ConvResult {
378 INTERRUPT_TRIGGERED.load(Ordering::Relaxed) 642 command_id_source: fifo.cmdsrc().bits(),
643 loop_count_index: fifo.loopcnt().bits(),
644 trigger_id_source: fifo.tsrc().bits(),
645 conv_value: fifo.d().bits(),
646 })
379 } 647 }
380} 648}
381 649
382pub fn get_conv_result() -> Option<ConvResult> { 650impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> {
383 let adc = unsafe { &*pac::Adc1::ptr() }; 651 unsafe fn on_interrupt() {
384 let fifo = adc.resfifo0().read().bits(); 652 T::ptr().ie().modify(|_r, w| w.fwmie0().clear_bit());
385 const VALID_MASK: u32 = 1 << 31; 653 T::wait_cell().wake();
386 if fifo & VALID_MASK == 0 {
387 return None;
388 } 654 }
655}
389 656
390 Some(ConvResult { 657mod sealed {
391 command_id_source: (fifo >> 24) & 0x0F, 658 /// Seal a trait
392 loop_count_index: (fifo >> 20) & 0x0F, 659 pub trait Sealed {}
393 trigger_id_source: (fifo >> 16) & 0x0F,
394 conv_value: (fifo & 0xFFFF) as u16,
395 })
396} 660}
397 661
398pub fn on_interrupt() { 662impl<I: GpioPin> sealed::Sealed for I {}
399 if get_conv_result().is_some() { 663
400 INTERRUPT_TRIGGERED.store(true, Ordering::SeqCst); 664trait SealedInstance {
401 } 665 fn ptr() -> &'static pac::adc0::RegisterBlock;
666 fn wait_cell() -> &'static WaitCell;
402} 667}
403 668
404pub struct AdcHandler; 669/// ADC Instance
405impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::ADC1> for AdcHandler { 670#[allow(private_bounds)]
406 unsafe fn on_interrupt() { 671pub trait Instance: SealedInstance + PeripheralType + Gate<MrccPeriphConfig = AdcConfig> {
407 on_interrupt(); 672 /// Interrupt for this ADC instance.
408 } 673 type Interrupt: Interrupt;
409} 674}
675
676macro_rules! impl_instance {
677 ($($n:expr),*) => {
678 $(
679 paste!{
680 impl SealedInstance for crate::peripherals::[<ADC $n>] {
681 fn ptr() -> &'static pac::adc0::RegisterBlock {
682 unsafe { &*pac::[<Adc $n>]::ptr() }
683 }
684
685 fn wait_cell() -> &'static WaitCell {
686 static WAIT_CELL: WaitCell = WaitCell::new();
687 &WAIT_CELL
688 }
689
690 }
691
692 impl Instance for crate::peripherals::[<ADC $n>] {
693 type Interrupt = crate::interrupt::typelevel::[<ADC $n>];
694 }
695 }
696 )*
697 };
698}
699
700impl_instance!(0, 1, 2, 3);
701
702pub trait AdcPin<Instance>: GpioPin + sealed::Sealed + PeripheralType {
703 const CHANNEL: u8;
704
705 /// Set the given pin to the correct muxing state
706 fn mux(&self);
707}
708
709/// Driver mode.
710#[allow(private_bounds)]
711pub trait ModeAdc: sealed::Sealed {}
712
713/// Blocking mode.
714pub struct Blocking;
715impl sealed::Sealed for Blocking {}
716impl ModeAdc for Blocking {}
717
718/// Async mode.
719pub struct Async {
720 waiter: &'static WaitCell,
721}
722impl sealed::Sealed for Async {}
723impl ModeAdc for Async {}
724
725macro_rules! impl_pin {
726 ($pin:ident, $peri:ident, $func:ident, $channel:literal) => {
727 impl AdcPin<crate::peripherals::$peri> for crate::peripherals::$pin {
728 const CHANNEL: u8 = $channel;
729
730 fn mux(&self) {
731 self.set_pull(crate::gpio::Pull::Disabled);
732 self.set_slew_rate(crate::gpio::SlewRate::Fast.into());
733 self.set_drive_strength(crate::gpio::DriveStrength::Normal.into());
734 self.set_function(crate::pac::port0::pcr0::Mux::$func);
735 }
736 }
737 };
738}
739
740impl_pin!(P2_0, ADC0, Mux0, 0);
741impl_pin!(P2_4, ADC0, Mux0, 1);
742impl_pin!(P2_15, ADC0, Mux0, 2);
743impl_pin!(P2_3, ADC0, Mux0, 3);
744impl_pin!(P2_2, ADC0, Mux0, 4);
745impl_pin!(P2_12, ADC0, Mux0, 5);
746impl_pin!(P2_16, ADC0, Mux0, 6);
747impl_pin!(P2_7, ADC0, Mux0, 7);
748impl_pin!(P0_18, ADC0, Mux0, 8);
749impl_pin!(P0_19, ADC0, Mux0, 9);
750impl_pin!(P0_20, ADC0, Mux0, 10);
751impl_pin!(P0_21, ADC0, Mux0, 11);
752impl_pin!(P0_22, ADC0, Mux0, 12);
753impl_pin!(P0_23, ADC0, Mux0, 13);
754impl_pin!(P0_3, ADC0, Mux0, 14);
755impl_pin!(P0_6, ADC0, Mux0, 15);
756impl_pin!(P1_0, ADC0, Mux0, 16);
757impl_pin!(P1_1, ADC0, Mux0, 17);
758impl_pin!(P1_2, ADC0, Mux0, 18);
759impl_pin!(P1_3, ADC0, Mux0, 19);
760impl_pin!(P1_4, ADC0, Mux0, 20);
761impl_pin!(P1_5, ADC0, Mux0, 21);
762impl_pin!(P1_6, ADC0, Mux0, 22);
763impl_pin!(P1_7, ADC0, Mux0, 23);
764
765// ???
766// impl_pin!(P1_10, ADC0, Mux0, 255);
767
768impl_pin!(P2_1, ADC1, Mux0, 0);
769impl_pin!(P2_5, ADC1, Mux0, 1);
770impl_pin!(P2_19, ADC1, Mux0, 2);
771impl_pin!(P2_6, ADC1, Mux0, 3);
772impl_pin!(P2_3, ADC1, Mux0, 4);
773impl_pin!(P2_13, ADC1, Mux0, 5);
774impl_pin!(P2_17, ADC1, Mux0, 6);
775impl_pin!(P2_7, ADC1, Mux0, 7);
776impl_pin!(P1_10, ADC1, Mux0, 8);
777impl_pin!(P1_11, ADC1, Mux0, 9);
778impl_pin!(P1_12, ADC1, Mux0, 10);
779impl_pin!(P1_13, ADC1, Mux0, 11);
780impl_pin!(P1_14, ADC1, Mux0, 12);
781impl_pin!(P1_15, ADC1, Mux0, 13);
782// ???
783// impl_pin!(P1_16, ADC1, Mux0, 255);
784// impl_pin!(P1_17, ADC1, Mux0, 255);
785// impl_pin!(P1_18, ADC1, Mux0, 255);
786// impl_pin!(P1_19, ADC1, Mux0, 255);
787// ???
788impl_pin!(P3_31, ADC1, Mux0, 20);
789impl_pin!(P3_30, ADC1, Mux0, 21);
790impl_pin!(P3_29, ADC1, Mux0, 22);
791
792impl_pin!(P2_4, ADC2, Mux0, 0);
793impl_pin!(P2_10, ADC2, Mux0, 1);
794impl_pin!(P4_4, ADC2, Mux0, 2);
795// impl_pin!(P2_24, ADC2, Mux0, 255); ???
796impl_pin!(P2_16, ADC2, Mux0, 4);
797impl_pin!(P2_12, ADC2, Mux0, 5);
798impl_pin!(P2_20, ADC2, Mux0, 6);
799impl_pin!(P2_7, ADC2, Mux0, 7);
800impl_pin!(P0_2, ADC2, Mux0, 8);
801// ???
802// impl_pin!(P0_4, ADC2, Mux0, 255);
803// impl_pin!(P0_5, ADC2, Mux0, 255);
804// impl_pin!(P0_6, ADC2, Mux0, 255);
805// impl_pin!(P0_7, ADC2, Mux0, 255);
806// impl_pin!(P0_12, ADC2, Mux0, 255);
807// impl_pin!(P0_13, ADC2, Mux0, 255);
808// ???
809impl_pin!(P0_14, ADC2, Mux0, 14);
810impl_pin!(P0_15, ADC2, Mux0, 15);
811// ???
812// impl_pin!(P4_0, ADC2, Mux0, 255);
813// impl_pin!(P4_1, ADC2, Mux0, 255);
814// ???
815impl_pin!(P4_2, ADC2, Mux0, 18);
816impl_pin!(P4_3, ADC2, Mux0, 19);
817//impl_pin!(P4_4, ADC2, Mux0, 20); // Conflit with ADC2_A3 and ADC2_A20 using the same pin
818impl_pin!(P4_5, ADC2, Mux0, 21);
819impl_pin!(P4_6, ADC2, Mux0, 22);
820impl_pin!(P4_7, ADC2, Mux0, 23);
821
822impl_pin!(P2_5, ADC3, Mux0, 0);
823impl_pin!(P2_11, ADC3, Mux0, 1);
824impl_pin!(P2_23, ADC3, Mux0, 2);
825// impl_pin!(P2_25, ADC3, Mux0, 255); // ???
826impl_pin!(P2_17, ADC3, Mux0, 4);
827impl_pin!(P2_13, ADC3, Mux0, 5);
828impl_pin!(P2_21, ADC3, Mux0, 6);
829impl_pin!(P2_7, ADC3, Mux0, 7);
830// ???
831// impl_pin!(P3_2, ADC3, Mux0, 255);
832// impl_pin!(P3_3, ADC3, Mux0, 255);
833// impl_pin!(P3_4, ADC3, Mux0, 255);
834// impl_pin!(P3_5, ADC3, Mux0, 255);
835// ???
836impl_pin!(P3_6, ADC3, Mux0, 12);
837impl_pin!(P3_7, ADC3, Mux0, 13);
838impl_pin!(P3_12, ADC3, Mux0, 14);
839impl_pin!(P3_13, ADC3, Mux0, 15);
840impl_pin!(P3_14, ADC3, Mux0, 16);
841impl_pin!(P3_15, ADC3, Mux0, 17);
842impl_pin!(P3_20, ADC3, Mux0, 18);
843impl_pin!(P3_21, ADC3, Mux0, 19);
844impl_pin!(P3_22, ADC3, Mux0, 20);
845// ???
846// impl_pin!(P3_23, ADC3, Mux0, 255);
847// impl_pin!(P3_24, ADC3, Mux0, 255);
848// impl_pin!(P3_25, ADC3, Mux0, 255);
849// ???
diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs
index 9288f5dc1..b96d9612a 100644
--- a/embassy-mcxa/src/clocks/mod.rs
+++ b/embassy-mcxa/src/clocks/mod.rs
@@ -945,7 +945,10 @@ pub(crate) mod gate {
945 impl_cc_gate!(LPUART3, mrcc_glb_cc0, mrcc_glb_rst0, lpuart3, LpuartConfig); 945 impl_cc_gate!(LPUART3, mrcc_glb_cc0, mrcc_glb_rst0, lpuart3, LpuartConfig);
946 impl_cc_gate!(LPUART4, mrcc_glb_cc0, mrcc_glb_rst0, lpuart4, LpuartConfig); 946 impl_cc_gate!(LPUART4, mrcc_glb_cc0, mrcc_glb_rst0, lpuart4, LpuartConfig);
947 impl_cc_gate!(LPUART5, mrcc_glb_cc1, mrcc_glb_rst1, lpuart5, LpuartConfig); 947 impl_cc_gate!(LPUART5, mrcc_glb_cc1, mrcc_glb_rst1, lpuart5, LpuartConfig);
948 impl_cc_gate!(ADC0, mrcc_glb_cc1, mrcc_glb_rst1, adc0, AdcConfig);
948 impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); 949 impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig);
950 impl_cc_gate!(ADC2, mrcc_glb_cc1, mrcc_glb_rst1, adc2, AdcConfig);
951 impl_cc_gate!(ADC3, mrcc_glb_cc1, mrcc_glb_rst1, adc3, AdcConfig);
949 952
950 // DMA0 peripheral - uses NoConfig since it has no selectable clock source 953 // DMA0 peripheral - uses NoConfig since it has no selectable clock source
951 impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig); 954 impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig);
diff --git a/embassy-mcxa/src/clocks/periph_helpers.rs b/embassy-mcxa/src/clocks/periph_helpers.rs
index fed5e558e..f2f51c60c 100644
--- a/embassy-mcxa/src/clocks/periph_helpers.rs
+++ b/embassy-mcxa/src/clocks/periph_helpers.rs
@@ -427,6 +427,7 @@ impl SPConfHelper for OsTimerConfig {
427 427
428/// Selectable clocks for the ADC peripheral 428/// Selectable clocks for the ADC peripheral
429#[derive(Copy, Clone, Debug, PartialEq, Eq)] 429#[derive(Copy, Clone, Debug, PartialEq, Eq)]
430#[cfg_attr(feature = "defmt", derive(defmt::Format))]
430pub enum AdcClockSel { 431pub enum AdcClockSel {
431 /// Divided `fro_lf`/`clk_12m`/FRO12M source 432 /// Divided `fro_lf`/`clk_12m`/FRO12M source
432 FroLfDiv, 433 FroLfDiv,
diff --git a/embassy-mcxa/src/i2c/controller.rs b/embassy-mcxa/src/i2c/controller.rs
index c27d508b0..62789f85f 100644
--- a/embassy-mcxa/src/i2c/controller.rs
+++ b/embassy-mcxa/src/i2c/controller.rs
@@ -8,9 +8,9 @@ use embassy_hal_internal::drop::OnDrop;
8use mcxa_pac::lpi2c0::mtdr::Cmd; 8use mcxa_pac::lpi2c0::mtdr::Cmd;
9 9
10use super::{Async, Blocking, Error, Instance, InterruptHandler, Mode, Result, SclPin, SdaPin}; 10use super::{Async, Blocking, Error, Instance, InterruptHandler, Mode, Result, SclPin, SdaPin};
11use crate::AnyPin;
12use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig}; 11use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig};
13use crate::clocks::{PoweredClock, enable_and_reset}; 12use crate::clocks::{PoweredClock, enable_and_reset};
13use crate::gpio::AnyPin;
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15 15
16/// Bus speed (nominal SCL, no clock stretching) 16/// Bus speed (nominal SCL, no clock stretching)
diff --git a/embassy-mcxa/src/interrupt.rs b/embassy-mcxa/src/interrupt.rs
index be2704454..b662f7ee0 100644
--- a/embassy-mcxa/src/interrupt.rs
+++ b/embassy-mcxa/src/interrupt.rs
@@ -9,7 +9,10 @@
9mod generated { 9mod generated {
10 #[rustfmt::skip] 10 #[rustfmt::skip]
11 embassy_hal_internal::interrupt_mod!( 11 embassy_hal_internal::interrupt_mod!(
12 ADC0,
12 ADC1, 13 ADC1,
14 ADC2,
15 ADC3,
13 DMA_CH0, 16 DMA_CH0,
14 DMA_CH1, 17 DMA_CH1,
15 DMA_CH2, 18 DMA_CH2,
@@ -281,44 +284,6 @@ impl InterruptExt for Rtc {
281 } 284 }
282} 285}
283 286
284pub struct Adc;
285pub const ADC1: Adc = Adc;
286
287impl InterruptExt for Adc {
288 /// Clear any pending ADC1 in NVIC.
289 #[inline]
290 fn unpend(&self) {
291 cortex_m::peripheral::NVIC::unpend(Interrupt::ADC1);
292 }
293
294 /// Set NVIC priority for ADC1.
295 #[inline]
296 fn set_priority(&self, priority: Priority) {
297 unsafe {
298 let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC;
299 nvic.set_priority(Interrupt::ADC1, u8::from(priority));
300 }
301 }
302
303 /// Enable ADC1 in NVIC.
304 #[inline]
305 unsafe fn enable(&self) {
306 cortex_m::peripheral::NVIC::unmask(Interrupt::ADC1);
307 }
308
309 /// Disable ADC1 in NVIC.
310 #[inline]
311 unsafe fn disable(&self) {
312 cortex_m::peripheral::NVIC::mask(Interrupt::ADC1);
313 }
314
315 /// Check if ADC1 is pending in NVIC.
316 #[inline]
317 fn is_pending(&self) -> bool {
318 cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC1)
319 }
320}
321
322pub struct Gpio0; 287pub struct Gpio0;
323pub const GPIO0: Gpio0 = Gpio0; 288pub const GPIO0: Gpio0 = Gpio0;
324 289
diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs
index 12c2708de..6383353db 100644
--- a/embassy-mcxa/src/lib.rs
+++ b/embassy-mcxa/src/lib.rs
@@ -8,7 +8,6 @@
8pub mod clocks; // still provide clock helpers 8pub mod clocks; // still provide clock helpers
9pub mod dma; 9pub mod dma;
10pub mod gpio; 10pub mod gpio;
11pub mod pins; // pin mux helpers
12 11
13pub mod adc; 12pub mod adc;
14pub mod clkout; 13pub mod clkout;
@@ -18,15 +17,19 @@ pub mod i2c;
18pub mod interrupt; 17pub mod interrupt;
19pub mod lpuart; 18pub mod lpuart;
20pub mod ostimer; 19pub mod ostimer;
20pub mod reset_reason;
21pub mod rtc; 21pub mod rtc;
22pub mod trng; 22pub mod trng;
23 23
24use crate::interrupt::InterruptExt;
24pub use crate::pac::NVIC_PRIO_BITS; 25pub use crate::pac::NVIC_PRIO_BITS;
25 26
26#[rustfmt::skip] 27#[rustfmt::skip]
27embassy_hal_internal::peripherals!( 28embassy_hal_internal::peripherals!(
28 ADC0, 29 ADC0,
29 ADC1, 30 ADC1,
31 ADC2,
32 ADC3,
30 33
31 AOI0, 34 AOI0,
32 AOI1, 35 AOI1,
@@ -337,9 +340,6 @@ embassy_hal_internal::peripherals!(
337// Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. 340// Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it.
338 341
339// Re-export interrupt traits and types 342// Re-export interrupt traits and types
340pub use adc::Adc1 as Adc1Token;
341pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output};
342pub use interrupt::InterruptExt;
343#[cfg(feature = "unstable-pac")] 343#[cfg(feature = "unstable-pac")]
344pub use mcxa_pac as pac; 344pub use mcxa_pac as pac;
345#[cfg(not(feature = "unstable-pac"))] 345#[cfg(not(feature = "unstable-pac"))]
@@ -355,8 +355,6 @@ pub fn init(cfg: crate::config::Config) -> Peripherals {
355 // Apply user-configured priority early; enabling is left to examples/apps 355 // Apply user-configured priority early; enabling is left to examples/apps
356 crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); 356 crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority);
357 // Apply user-configured priority early; enabling is left to examples/apps 357 // Apply user-configured priority early; enabling is left to examples/apps
358 crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority);
359 // Apply user-configured priority early; enabling is left to examples/apps
360 crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); 358 crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority);
361 // Apply user-configured priority early; enabling is left to examples/apps 359 // Apply user-configured priority early; enabling is left to examples/apps
362 crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); 360 crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority);
diff --git a/embassy-mcxa/src/lpuart/mod.rs b/embassy-mcxa/src/lpuart/mod.rs
index e59ce8140..bce3986b5 100644
--- a/embassy-mcxa/src/lpuart/mod.rs
+++ b/embassy-mcxa/src/lpuart/mod.rs
@@ -6,12 +6,12 @@ use paste::paste;
6 6
7use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig}; 7use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig};
8use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset}; 8use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset};
9use crate::gpio::SealedPin; 9use crate::gpio::{AnyPin, SealedPin};
10use crate::pac::lpuart0::baud::Sbns as StopBits; 10use crate::pac::lpuart0::baud::Sbns as StopBits;
11use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, M as DataBits, Pt as Parity}; 11use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, M as DataBits, Pt as Parity};
12use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; 12use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource};
13use crate::pac::lpuart0::stat::Msbf as MsbFirst; 13use crate::pac::lpuart0::stat::Msbf as MsbFirst;
14use crate::{AnyPin, interrupt, pac}; 14use crate::{interrupt, pac};
15 15
16pub mod buffered; 16pub mod buffered;
17 17
diff --git a/embassy-mcxa/src/pins.rs b/embassy-mcxa/src/pins.rs
deleted file mode 100644
index 9adbe64c8..000000000
--- a/embassy-mcxa/src/pins.rs
+++ /dev/null
@@ -1,33 +0,0 @@
1//! Pin configuration helpers (separate from peripheral drivers).
2use crate::pac;
3
4/// Configure pins for ADC usage.
5///
6/// # Safety
7///
8/// Must be called after PORT clocks are enabled.
9pub unsafe fn configure_adc_pins() {
10 // P1_10 = ADC1_A8
11 let port1 = &*pac::Port1::ptr();
12 port1.pcr10().write(|w| {
13 w.ps()
14 .ps0()
15 .pe()
16 .pe0()
17 .sre()
18 .sre0()
19 .ode()
20 .ode0()
21 .dse()
22 .dse0()
23 .mux()
24 .mux0()
25 .ibe()
26 .ibe0()
27 .inv()
28 .inv0()
29 .lk()
30 .lk0()
31 });
32 core::arch::asm!("dsb sy; isb sy");
33}
diff --git a/embassy-mcxa/src/reset_reason.rs b/embassy-mcxa/src/reset_reason.rs
new file mode 100644
index 000000000..f9a9ce096
--- /dev/null
+++ b/embassy-mcxa/src/reset_reason.rs
@@ -0,0 +1,106 @@
1//! Reset reason
2//!
3//! MCXA families keep the most recent reset reason in the SRS
4//! register of the CMC block. This lets users understand why the MCU
5//! has reset and take appropriate corrective actions if required.
6
7/// Reads the most recent reset reason from the Core Mode Controller
8/// (CMC).
9pub fn reset_reason() -> ResetReason {
10 let regs = unsafe { &*crate::pac::Cmc::steal() };
11
12 let srs = regs.srs().read();
13
14 if srs.wakeup().is_enabled() {
15 ResetReason::WakeUp
16 } else if srs.por().bit_is_set() {
17 ResetReason::Por
18 } else if srs.vd().bit_is_set() {
19 ResetReason::VoltageDetect
20 } else if srs.warm().bit_is_set() {
21 ResetReason::Warm
22 } else if srs.fatal().bit_is_set() {
23 ResetReason::Fatal
24 } else if srs.pin().bit_is_set() {
25 ResetReason::Pin
26 } else if srs.dap().bit_is_set() {
27 ResetReason::Dap
28 } else if srs.rstack().bit_is_set() {
29 ResetReason::ResetAckTimeout
30 } else if srs.lpack().bit_is_set() {
31 ResetReason::LowPowerAckTimeout
32 } else if srs.scg().bit_is_set() {
33 ResetReason::SystemClockGeneration
34 } else if srs.wwdt0().bit_is_set() {
35 ResetReason::Wwdt0
36 } else if srs.sw().bit_is_set() {
37 ResetReason::Software
38 } else if srs.lockup().bit_is_set() {
39 ResetReason::Lockup
40 } else if srs.cdog0().bit_is_set() {
41 ResetReason::Cdog0
42 } else if srs.cdog1().bit_is_set() {
43 ResetReason::Cdog1
44 } else if srs.jtag().bit_is_set() {
45 ResetReason::Jtag
46 } else {
47 ResetReason::Tamper
48 }
49}
50
51/// Indicates the type and source of the most recent reset.
52#[derive(Clone, Copy, Debug)]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54#[non_exhaustive]
55pub enum ResetReason {
56 /// Tamper reset.
57 Tamper,
58
59 /// JTAG System Reset request.
60 Jtag,
61
62 /// Code Watchdog 0 reset.
63 Cdog0,
64
65 /// Code Watchdog 1 reset.
66 Cdog1,
67
68 /// Lockup reset.
69 Lockup,
70
71 /// Software reset.
72 Software,
73
74 /// Windowed Watchdog 0 reset.
75 Wwdt0,
76
77 /// System clock generation reset.
78 SystemClockGeneration,
79
80 /// Low Power Acknowledge Timeout reset.
81 LowPowerAckTimeout,
82
83 /// Reset Timeout.
84 ResetAckTimeout,
85
86 /// Debug Access Port reset.
87 Dap,
88
89 /// External assertion of RESET_b pin.
90 Pin,
91
92 /// Fatal reset.
93 Fatal,
94
95 /// Warm reset.
96 Warm,
97
98 /// Voltage detect reset.
99 VoltageDetect,
100
101 /// Power-on reset.
102 Por,
103
104 /// Wake-up reset.
105 WakeUp,
106}
diff --git a/embassy-mcxa/src/rtc.rs b/embassy-mcxa/src/rtc.rs
index f975d9c9f..c5474d34a 100644
--- a/embassy-mcxa/src/rtc.rs
+++ b/embassy-mcxa/src/rtc.rs
@@ -9,8 +9,6 @@ use crate::interrupt::typelevel::{Handler, Interrupt};
9use crate::pac; 9use crate::pac;
10use crate::pac::rtc0::cr::Um; 10use crate::pac::rtc0::cr::Um;
11 11
12type Regs = pac::rtc0::RegisterBlock;
13
14/// Global wait cell for alarm notifications 12/// Global wait cell for alarm notifications
15static WAKER: WaitCell = WaitCell::new(); 13static WAKER: WaitCell = WaitCell::new();
16 14
@@ -22,7 +20,7 @@ pub struct InterruptHandler<I: Instance> {
22/// Trait for RTC peripheral instances 20/// Trait for RTC peripheral instances
23pub trait Instance: PeripheralType { 21pub trait Instance: PeripheralType {
24 type Interrupt: Interrupt; 22 type Interrupt: Interrupt;
25 fn ptr() -> *const Regs; 23 fn ptr() -> &'static pac::rtc0::RegisterBlock;
26} 24}
27 25
28/// Token for RTC0 26/// Token for RTC0
@@ -30,8 +28,8 @@ pub type Rtc0 = crate::peripherals::RTC0;
30impl Instance for crate::peripherals::RTC0 { 28impl Instance for crate::peripherals::RTC0 {
31 type Interrupt = crate::interrupt::typelevel::RTC; 29 type Interrupt = crate::interrupt::typelevel::RTC;
32 #[inline(always)] 30 #[inline(always)]
33 fn ptr() -> *const Regs { 31 fn ptr() -> &'static pac::rtc0::RegisterBlock {
34 pac::Rtc0::ptr() 32 unsafe { &*pac::Rtc0::ptr() }
35 } 33 }
36} 34}
37 35
@@ -204,18 +202,19 @@ pub fn get_default_config() -> RtcConfig {
204 } 202 }
205} 203}
206/// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy) 204/// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy)
207pub struct Rtc<'a, I: Instance> { 205pub struct Rtc<'a> {
208 _inst: core::marker::PhantomData<&'a mut I>, 206 _inst: core::marker::PhantomData<&'a mut ()>,
207 info: &'static pac::rtc0::RegisterBlock,
209} 208}
210 209
211impl<'a, I: Instance> Rtc<'a, I> { 210impl<'a> Rtc<'a> {
212 /// Create a new instance of the real time clock. 211 /// Create a new instance of the real time clock.
213 pub fn new( 212 pub fn new<I: Instance>(
214 _inst: Peri<'a, I>, 213 _inst: Peri<'a, I>,
215 _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, 214 _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a,
216 config: RtcConfig, 215 config: RtcConfig,
217 ) -> Self { 216 ) -> Self {
218 let rtc = unsafe { &*I::ptr() }; 217 let info = I::ptr();
219 218
220 // The RTC is NOT gated by the MRCC, but we DO need to make sure the 16k clock 219 // The RTC is NOT gated by the MRCC, but we DO need to make sure the 16k clock
221 // on the vsys domain is active 220 // on the vsys domain is active
@@ -227,13 +226,13 @@ impl<'a, I: Instance> Rtc<'a, I> {
227 } 226 }
228 227
229 // RTC reset 228 // RTC reset
230 rtc.cr().modify(|_, w| w.swr().set_bit()); 229 info.cr().modify(|_, w| w.swr().set_bit());
231 rtc.cr().modify(|_, w| w.swr().clear_bit()); 230 info.cr().modify(|_, w| w.swr().clear_bit());
232 rtc.tsr().write(|w| unsafe { w.bits(1) }); 231 info.tsr().write(|w| unsafe { w.bits(1) });
233 232
234 rtc.cr().modify(|_, w| w.um().variant(config.update_mode)); 233 info.cr().modify(|_, w| w.um().variant(config.update_mode));
235 234
236 rtc.tcr().modify(|_, w| unsafe { 235 info.tcr().modify(|_, w| unsafe {
237 w.cir() 236 w.cir()
238 .bits(config.compensation_interval) 237 .bits(config.compensation_interval)
239 .tcr() 238 .tcr()
@@ -246,6 +245,7 @@ impl<'a, I: Instance> Rtc<'a, I> {
246 245
247 Self { 246 Self {
248 _inst: core::marker::PhantomData, 247 _inst: core::marker::PhantomData,
248 info,
249 } 249 }
250 } 250 }
251 251
@@ -259,9 +259,8 @@ impl<'a, I: Instance> Rtc<'a, I> {
259 /// 259 ///
260 /// The datetime is converted to Unix timestamp and written to the time seconds register. 260 /// The datetime is converted to Unix timestamp and written to the time seconds register.
261 pub fn set_datetime(&self, datetime: RtcDateTime) { 261 pub fn set_datetime(&self, datetime: RtcDateTime) {
262 let rtc = unsafe { &*I::ptr() };
263 let seconds = convert_datetime_to_seconds(&datetime); 262 let seconds = convert_datetime_to_seconds(&datetime);
264 rtc.tsr().write(|w| unsafe { w.bits(seconds) }); 263 self.info.tsr().write(|w| unsafe { w.bits(seconds) });
265 } 264 }
266 265
267 /// Get the current date and time 266 /// Get the current date and time
@@ -274,8 +273,7 @@ impl<'a, I: Instance> Rtc<'a, I> {
274 /// 273 ///
275 /// Reads the current Unix timestamp from the time seconds register and converts it. 274 /// Reads the current Unix timestamp from the time seconds register and converts it.
276 pub fn get_datetime(&self) -> RtcDateTime { 275 pub fn get_datetime(&self) -> RtcDateTime {
277 let rtc = unsafe { &*I::ptr() }; 276 let seconds = self.info.tsr().read().bits();
278 let seconds = rtc.tsr().read().bits();
279 convert_seconds_to_datetime(seconds) 277 convert_seconds_to_datetime(seconds)
280 } 278 }
281 279
@@ -295,19 +293,18 @@ impl<'a, I: Instance> Rtc<'a, I> {
295 /// - Uses timeouts to prevent infinite loops 293 /// - Uses timeouts to prevent infinite loops
296 /// - Enables the alarm interrupt after setting 294 /// - Enables the alarm interrupt after setting
297 pub fn set_alarm(&self, alarm: RtcDateTime) { 295 pub fn set_alarm(&self, alarm: RtcDateTime) {
298 let rtc = unsafe { &*I::ptr() };
299 let seconds = convert_datetime_to_seconds(&alarm); 296 let seconds = convert_datetime_to_seconds(&alarm);
300 297
301 rtc.tar().write(|w| unsafe { w.bits(0) }); 298 self.info.tar().write(|w| unsafe { w.bits(0) });
302 let mut timeout = 10000; 299 let mut timeout = 10000;
303 while rtc.tar().read().bits() != 0 && timeout > 0 { 300 while self.info.tar().read().bits() != 0 && timeout > 0 {
304 timeout -= 1; 301 timeout -= 1;
305 } 302 }
306 303
307 rtc.tar().write(|w| unsafe { w.bits(seconds) }); 304 self.info.tar().write(|w| unsafe { w.bits(seconds) });
308 305
309 let mut timeout = 10000; 306 let mut timeout = 10000;
310 while rtc.tar().read().bits() != seconds && timeout > 0 { 307 while self.info.tar().read().bits() != seconds && timeout > 0 {
311 timeout -= 1; 308 timeout -= 1;
312 } 309 }
313 310
@@ -324,8 +321,7 @@ impl<'a, I: Instance> Rtc<'a, I> {
324 /// 321 ///
325 /// Reads the alarm timestamp from the time alarm register and converts it. 322 /// Reads the alarm timestamp from the time alarm register and converts it.
326 pub fn get_alarm(&self) -> RtcDateTime { 323 pub fn get_alarm(&self) -> RtcDateTime {
327 let rtc = unsafe { &*I::ptr() }; 324 let alarm_seconds = self.info.tar().read().bits();
328 let alarm_seconds = rtc.tar().read().bits();
329 convert_seconds_to_datetime(alarm_seconds) 325 convert_seconds_to_datetime(alarm_seconds)
330 } 326 }
331 327
@@ -335,8 +331,7 @@ impl<'a, I: Instance> Rtc<'a, I> {
335 /// 331 ///
336 /// Sets the Time Counter Enable (TCE) bit in the status register. 332 /// Sets the Time Counter Enable (TCE) bit in the status register.
337 pub fn start(&self) { 333 pub fn start(&self) {
338 let rtc = unsafe { &*I::ptr() }; 334 self.info.sr().modify(|_, w| w.tce().set_bit());
339 rtc.sr().modify(|_, w| w.tce().set_bit());
340 } 335 }
341 336
342 /// Stop the RTC time counter 337 /// Stop the RTC time counter
@@ -345,8 +340,7 @@ impl<'a, I: Instance> Rtc<'a, I> {
345 /// 340 ///
346 /// Clears the Time Counter Enable (TCE) bit in the status register. 341 /// Clears the Time Counter Enable (TCE) bit in the status register.
347 pub fn stop(&self) { 342 pub fn stop(&self) {
348 let rtc = unsafe { &*I::ptr() }; 343 self.info.sr().modify(|_, w| w.tce().clear_bit());
349 rtc.sr().modify(|_, w| w.tce().clear_bit());
350 } 344 }
351 345
352 /// Enable specific RTC interrupts 346 /// Enable specific RTC interrupts
@@ -364,19 +358,17 @@ impl<'a, I: Instance> Rtc<'a, I> {
364 /// - Alarm Interrupt 358 /// - Alarm Interrupt
365 /// - Seconds Interrupt 359 /// - Seconds Interrupt
366 pub fn set_interrupt(&self, mask: u32) { 360 pub fn set_interrupt(&self, mask: u32) {
367 let rtc = unsafe { &*I::ptr() };
368
369 if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 { 361 if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 {
370 rtc.ier().modify(|_, w| w.tiie().tiie_1()); 362 self.info.ier().modify(|_, w| w.tiie().tiie_1());
371 } 363 }
372 if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 { 364 if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 {
373 rtc.ier().modify(|_, w| w.toie().toie_1()); 365 self.info.ier().modify(|_, w| w.toie().toie_1());
374 } 366 }
375 if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 { 367 if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 {
376 rtc.ier().modify(|_, w| w.taie().taie_1()); 368 self.info.ier().modify(|_, w| w.taie().taie_1());
377 } 369 }
378 if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 { 370 if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 {
379 rtc.ier().modify(|_, w| w.tsie().tsie_1()); 371 self.info.ier().modify(|_, w| w.tsie().tsie_1());
380 } 372 }
381 } 373 }
382 374
@@ -390,19 +382,17 @@ impl<'a, I: Instance> Rtc<'a, I> {
390 /// 382 ///
391 /// This function disables the specified interrupt types. 383 /// This function disables the specified interrupt types.
392 pub fn disable_interrupt(&self, mask: u32) { 384 pub fn disable_interrupt(&self, mask: u32) {
393 let rtc = unsafe { &*I::ptr() };
394
395 if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 { 385 if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 {
396 rtc.ier().modify(|_, w| w.tiie().tiie_0()); 386 self.info.ier().modify(|_, w| w.tiie().tiie_0());
397 } 387 }
398 if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 { 388 if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 {
399 rtc.ier().modify(|_, w| w.toie().toie_0()); 389 self.info.ier().modify(|_, w| w.toie().toie_0());
400 } 390 }
401 if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 { 391 if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 {
402 rtc.ier().modify(|_, w| w.taie().taie_0()); 392 self.info.ier().modify(|_, w| w.taie().taie_0());
403 } 393 }
404 if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 { 394 if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 {
405 rtc.ier().modify(|_, w| w.tsie().tsie_0()); 395 self.info.ier().modify(|_, w| w.tsie().tsie_0());
406 } 396 }
407 } 397 }
408 398
@@ -412,8 +402,7 @@ impl<'a, I: Instance> Rtc<'a, I> {
412 /// 402 ///
413 /// This function clears the Time Alarm Interrupt Enable bit. 403 /// This function clears the Time Alarm Interrupt Enable bit.
414 pub fn clear_alarm_flag(&self) { 404 pub fn clear_alarm_flag(&self) {
415 let rtc = unsafe { &*I::ptr() }; 405 self.info.ier().modify(|_, w| w.taie().clear_bit());
416 rtc.ier().modify(|_, w| w.taie().clear_bit());
417 } 406 }
418 407
419 /// Wait for an RTC alarm to trigger. 408 /// Wait for an RTC alarm to trigger.
@@ -421,6 +410,7 @@ impl<'a, I: Instance> Rtc<'a, I> {
421 /// # Arguments 410 /// # Arguments
422 /// 411 ///
423 /// * `alarm` - The date and time when the alarm should trigger 412 /// * `alarm` - The date and time when the alarm should trigger
413 ///
424 /// This function will wait until the RTC alarm is triggered. 414 /// This function will wait until the RTC alarm is triggered.
425 /// If no alarm is scheduled, it will wait indefinitely until one is scheduled and triggered. 415 /// If no alarm is scheduled, it will wait indefinitely until one is scheduled and triggered.
426 pub async fn wait_for_alarm(&mut self, alarm: RtcDateTime) { 416 pub async fn wait_for_alarm(&mut self, alarm: RtcDateTime) {
diff --git a/embassy-nrf/src/cracen.rs b/embassy-nrf/src/cracen.rs
index 47ef1cd87..6381701c0 100644
--- a/embassy-nrf/src/cracen.rs
+++ b/embassy-nrf/src/cracen.rs
@@ -18,10 +18,7 @@ pub struct Cracen<'d, M: Mode> {
18impl<'d> Cracen<'d, Blocking> { 18impl<'d> Cracen<'d, Blocking> {
19 /// Create a new CRACEN driver. 19 /// Create a new CRACEN driver.
20 pub fn new_blocking(_peri: Peri<'d, peripherals::CRACEN>) -> Self { 20 pub fn new_blocking(_peri: Peri<'d, peripherals::CRACEN>) -> Self {
21 let me = Self { _peri, _p: PhantomData }; 21 Self { _peri, _p: PhantomData }
22
23 me.stop();
24 me
25 } 22 }
26} 23}
27 24
@@ -48,7 +45,14 @@ impl<'d, M: Mode> Cracen<'d, M> {
48 while r.rngcontrol().status().read().state() == pac::cracencore::vals::State::STARTUP {} 45 while r.rngcontrol().status().read().state() == pac::cracencore::vals::State::STARTUP {}
49 } 46 }
50 47
51 fn stop(&self) { 48 fn stop_rng(&self) {
49 let r = Self::core();
50 r.rngcontrol().control().write(|w| {
51 w.set_enable(false);
52 });
53
54 while r.rngcontrol().status().read().state() != pac::cracencore::vals::State::RESET {}
55
52 let r = Self::regs(); 56 let r = Self::regs();
53 r.enable().write(|w| { 57 r.enable().write(|w| {
54 w.set_cryptomaster(false); 58 w.set_cryptomaster(false);
@@ -69,7 +73,7 @@ impl<'d, M: Mode> Cracen<'d, M> {
69 chunk[..to_copy].copy_from_slice(&word[..to_copy]); 73 chunk[..to_copy].copy_from_slice(&word[..to_copy]);
70 } 74 }
71 75
72 self.stop(); 76 self.stop_rng();
73 } 77 }
74 78
75 /// Generate a random u32 79 /// Generate a random u32
@@ -90,19 +94,7 @@ impl<'d, M: Mode> Cracen<'d, M> {
90 94
91impl<'d, M: Mode> Drop for Cracen<'d, M> { 95impl<'d, M: Mode> Drop for Cracen<'d, M> {
92 fn drop(&mut self) { 96 fn drop(&mut self) {
93 let r = Self::core(); 97 // nothing to do here, since we stop+disable rng for each operation.
94 r.rngcontrol().control().write(|w| {
95 w.set_enable(false);
96 });
97
98 while r.rngcontrol().status().read().state() != pac::cracencore::vals::State::RESET {}
99
100 let r = Self::regs();
101 r.enable().write(|w| {
102 w.set_cryptomaster(false);
103 w.set_rng(false);
104 w.set_pkeikg(false);
105 });
106 } 98 }
107} 99}
108 100
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 449152485..38f22b1c3 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -90,6 +90,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
90- change: add error messages to can timing calculations ([#4961](https://github.com/embassy-rs/embassy/pull/4961)) 90- change: add error messages to can timing calculations ([#4961](https://github.com/embassy-rs/embassy/pull/4961))
91- feat: stm32/spi bidirectional mode 91- feat: stm32/spi bidirectional mode
92- fix: stm32/i2c v2: add stop flag on stop received 92- fix: stm32/i2c v2: add stop flag on stop received
93- stm32: Add blocking_listen for blocking I2C driver
93- fix: stm32l47*/stm32l48* adc analog pin setup 94- fix: stm32l47*/stm32l48* adc analog pin setup
94- fix: keep stm32/sai: make NODIV independent of MCKDIV 95- fix: keep stm32/sai: make NODIV independent of MCKDIV
95 96
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index e10409112..7989fc5d7 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -200,11 +200,11 @@ aligned = "0.4.1"
200heapless = "0.9.1" 200heapless = "0.9.1"
201 201
202#stm32-metapac = { version = "18" } 202#stm32-metapac = { version = "18" }
203stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f61ed017ef12ec84ff04c49e3147694bda3b29cb" } 203stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-497fb3042b49b765d8974aac87b8ab4fa3566d74" }
204 204
205[build-dependencies] 205[build-dependencies]
206#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} 206#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]}
207stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f61ed017ef12ec84ff04c49e3147694bda3b29cb", default-features = false, features = ["metadata"] } 207stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-497fb3042b49b765d8974aac87b8ab4fa3566d74", default-features = false, features = ["metadata"] }
208 208
209proc-macro2 = "1.0.36" 209proc-macro2 = "1.0.36"
210quote = "1.0.15" 210quote = "1.0.15"
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs
index 51c107cb4..afb18ec1a 100644
--- a/embassy-stm32/src/dma/gpdma/mod.rs
+++ b/embassy-stm32/src/dma/gpdma/mod.rs
@@ -137,7 +137,6 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: c
137 137
138impl AnyChannel { 138impl AnyChannel {
139 /// Safety: Must be called with a matching set of parameters for a valid dma channel 139 /// Safety: Must be called with a matching set of parameters for a valid dma channel
140 #[cfg(not(stm32n6))]
141 pub(crate) unsafe fn on_irq(&self) { 140 pub(crate) unsafe fn on_irq(&self) {
142 let info = self.info(); 141 let info = self.info();
143 #[cfg(feature = "_dual-core")] 142 #[cfg(feature = "_dual-core")]
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 90feab167..05d9c2e51 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -48,11 +48,9 @@ pub type Request = u8;
48pub type Request = (); 48pub type Request = ();
49 49
50pub(crate) trait SealedChannel: StoppablePeripheral { 50pub(crate) trait SealedChannel: StoppablePeripheral {
51 #[cfg(not(stm32n6))]
52 fn id(&self) -> u8; 51 fn id(&self) -> u8;
53} 52}
54 53
55#[cfg(not(stm32n6))]
56pub(crate) trait ChannelInterrupt { 54pub(crate) trait ChannelInterrupt {
57 #[cfg_attr(not(feature = "rt"), allow(unused))] 55 #[cfg_attr(not(feature = "rt"), allow(unused))]
58 unsafe fn on_irq(); 56 unsafe fn on_irq();
@@ -62,7 +60,6 @@ pub(crate) trait ChannelInterrupt {
62#[allow(private_bounds)] 60#[allow(private_bounds)]
63pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {} 61pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {}
64 62
65#[cfg(not(stm32n6))]
66macro_rules! dma_channel_impl { 63macro_rules! dma_channel_impl {
67 ($channel_peri:ident, $index:expr, $stop_mode:ident) => { 64 ($channel_peri:ident, $index:expr, $stop_mode:ident) => {
68 impl crate::rcc::StoppablePeripheral for crate::peripherals::$channel_peri { 65 impl crate::rcc::StoppablePeripheral for crate::peripherals::$channel_peri {
@@ -125,7 +122,6 @@ impl StoppablePeripheral for AnyChannel {
125} 122}
126 123
127impl SealedChannel for AnyChannel { 124impl SealedChannel for AnyChannel {
128 #[cfg(not(stm32n6))]
129 fn id(&self) -> u8 { 125 fn id(&self) -> u8 {
130 self.id 126 self.id
131 } 127 }
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs
index 3245887c1..304268963 100644
--- a/embassy-stm32/src/dma/util.rs
+++ b/embassy-stm32/src/dma/util.rs
@@ -20,6 +20,16 @@ impl<'d> ChannelAndRequest<'d> {
20 Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options) 20 Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options)
21 } 21 }
22 22
23 #[allow(dead_code)]
24 pub unsafe fn read_unchecked<'a, W: Word>(
25 &'a self,
26 peri_addr: *mut W,
27 buf: &'a mut [W],
28 options: TransferOptions,
29 ) -> Transfer<'a> {
30 Transfer::new_read(self.channel.clone_unchecked(), self.request, peri_addr, buf, options)
31 }
32
23 pub unsafe fn read_raw<'a, MW: Word, PW: Word>( 33 pub unsafe fn read_raw<'a, MW: Word, PW: Word>(
24 &'a mut self, 34 &'a mut self,
25 peri_addr: *mut PW, 35 peri_addr: *mut PW,
@@ -29,6 +39,16 @@ impl<'d> ChannelAndRequest<'d> {
29 Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) 39 Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options)
30 } 40 }
31 41
42 #[allow(dead_code)]
43 pub unsafe fn read_raw_unchecked<'a, MW: Word, PW: Word>(
44 &'a self,
45 peri_addr: *mut PW,
46 buf: *mut [MW],
47 options: TransferOptions,
48 ) -> Transfer<'a> {
49 Transfer::new_read_raw(self.channel.clone_unchecked(), self.request, peri_addr, buf, options)
50 }
51
32 pub unsafe fn write<'a, W: Word>( 52 pub unsafe fn write<'a, W: Word>(
33 &'a mut self, 53 &'a mut self,
34 buf: &'a [W], 54 buf: &'a [W],
@@ -38,6 +58,16 @@ impl<'d> ChannelAndRequest<'d> {
38 Transfer::new_write(self.channel.reborrow(), self.request, buf, peri_addr, options) 58 Transfer::new_write(self.channel.reborrow(), self.request, buf, peri_addr, options)
39 } 59 }
40 60
61 #[allow(dead_code)]
62 pub unsafe fn write_unchecked<'a, W: Word>(
63 &'a self,
64 buf: &'a [W],
65 peri_addr: *mut W,
66 options: TransferOptions,
67 ) -> Transfer<'a> {
68 Transfer::new_write(self.channel.clone_unchecked(), self.request, buf, peri_addr, options)
69 }
70
41 pub unsafe fn write_raw<'a, MW: Word, PW: Word>( 71 pub unsafe fn write_raw<'a, MW: Word, PW: Word>(
42 &'a mut self, 72 &'a mut self,
43 buf: *const [MW], 73 buf: *const [MW],
@@ -48,6 +78,16 @@ impl<'d> ChannelAndRequest<'d> {
48 } 78 }
49 79
50 #[allow(dead_code)] 80 #[allow(dead_code)]
81 pub unsafe fn write_raw_unchecked<'a, MW: Word, PW: Word>(
82 &'a self,
83 buf: *const [MW],
84 peri_addr: *mut PW,
85 options: TransferOptions,
86 ) -> Transfer<'a> {
87 Transfer::new_write_raw(self.channel.clone_unchecked(), self.request, buf, peri_addr, options)
88 }
89
90 #[allow(dead_code)]
51 pub unsafe fn write_repeated<'a, W: Word>( 91 pub unsafe fn write_repeated<'a, W: Word>(
52 &'a mut self, 92 &'a mut self,
53 repeated: &'a W, 93 repeated: &'a W,
@@ -64,4 +104,22 @@ impl<'d> ChannelAndRequest<'d> {
64 options, 104 options,
65 ) 105 )
66 } 106 }
107
108 #[allow(dead_code)]
109 pub unsafe fn write_repeated_unchecked<'a, W: Word>(
110 &'a self,
111 repeated: &'a W,
112 count: usize,
113 peri_addr: *mut W,
114 options: TransferOptions,
115 ) -> Transfer<'a> {
116 Transfer::new_write_repeated(
117 self.channel.clone_unchecked(),
118 self.request,
119 repeated,
120 count,
121 peri_addr,
122 options,
123 )
124 }
67} 125}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 32ce83d40..fe7782a7c 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -1680,43 +1680,50 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1680 1680
1681 /// Listen for incoming I2C messages. 1681 /// Listen for incoming I2C messages.
1682 /// 1682 ///
1683 /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. 1683 /// This method blocks until the slave address is matched by a master.
1684 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { 1684 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
1685 let _scoped_block_stop = self.info.rcc.block_stop(); 1685 let timeout = self.timeout();
1686 let state = self.state; 1686
1687 self.info.regs.cr1().modify(|reg| { 1687 self.info.regs.cr1().modify(|reg| {
1688 reg.set_addrie(true); 1688 reg.set_addrie(true);
1689 trace!("Enable ADDRIE"); 1689 trace!("Enable ADDRIE");
1690 }); 1690 });
1691 1691
1692 poll_fn(|cx| { 1692 loop {
1693 state.waker.register(cx.waker());
1694 let isr = self.info.regs.isr().read(); 1693 let isr = self.info.regs.isr().read();
1695 if !isr.addr() { 1694 if isr.addr() {
1696 Poll::Pending 1695 break;
1697 } else {
1698 trace!("ADDR triggered (address match)");
1699 // we do not clear the address flag here as it will be cleared by the dma read/write
1700 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
1701 match isr.dir() {
1702 i2c::vals::Dir::WRITE => {
1703 trace!("DIR: write");
1704 Poll::Ready(Ok(SlaveCommand {
1705 kind: SlaveCommandKind::Write,
1706 address: self.determine_matched_address()?,
1707 }))
1708 }
1709 i2c::vals::Dir::READ => {
1710 trace!("DIR: read");
1711 Poll::Ready(Ok(SlaveCommand {
1712 kind: SlaveCommandKind::Read,
1713 address: self.determine_matched_address()?,
1714 }))
1715 }
1716 }
1717 } 1696 }
1718 }) 1697 timeout.check()?;
1719 .await 1698 }
1699
1700 trace!("ADDR triggered (address match)");
1701
1702 // we do not clear the address flag here as it will be cleared by the dma read/write
1703 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
1704 self.slave_command()
1705 }
1706
1707 /// Determine the received slave command.
1708 fn slave_command(&self) -> Result<SlaveCommand, Error> {
1709 let isr = self.info.regs.isr().read();
1710
1711 match isr.dir() {
1712 i2c::vals::Dir::WRITE => {
1713 trace!("DIR: write");
1714 Ok(SlaveCommand {
1715 kind: SlaveCommandKind::Write,
1716 address: self.determine_matched_address()?,
1717 })
1718 }
1719 i2c::vals::Dir::READ => {
1720 trace!("DIR: read");
1721 Ok(SlaveCommand {
1722 kind: SlaveCommandKind::Read,
1723 address: self.determine_matched_address()?,
1724 })
1725 }
1726 }
1720 } 1727 }
1721 1728
1722 /// Respond to a write command. 1729 /// Respond to a write command.
@@ -1735,6 +1742,32 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1735} 1742}
1736 1743
1737impl<'d> I2c<'d, Async, MultiMaster> { 1744impl<'d> I2c<'d, Async, MultiMaster> {
1745 /// Listen for incoming I2C messages.
1746 ///
1747 /// The listen method is an asynchronous method but it does not require DMA to be asynchronous.
1748 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
1749 let _scoped_block_stop = self.info.rcc.block_stop();
1750 let state = self.state;
1751 self.info.regs.cr1().modify(|reg| {
1752 reg.set_addrie(true);
1753 trace!("Enable ADDRIE");
1754 });
1755
1756 poll_fn(|cx| {
1757 state.waker.register(cx.waker());
1758 let isr = self.info.regs.isr().read();
1759 if !isr.addr() {
1760 Poll::Pending
1761 } else {
1762 trace!("ADDR triggered (address match)");
1763 // we do not clear the address flag here as it will be cleared by the dma read/write
1764 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
1765 Poll::Ready(self.slave_command())
1766 }
1767 })
1768 .await
1769 }
1770
1738 /// Respond to a write command. 1771 /// Respond to a write command.
1739 /// 1772 ///
1740 /// Returns the total number of bytes received. 1773 /// Returns the total number of bytes received.
diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs
index 866851bbd..178ec57d4 100644
--- a/embassy-stm32/src/rcc/n6.rs
+++ b/embassy-stm32/src/rcc/n6.rs
@@ -1003,6 +1003,24 @@ pub(crate) unsafe fn init(config: Config) {
1003 p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); 1003 p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22));
1004 } 1004 }
1005 1005
1006 // TODO: ugly workaround for DMA accesses until RIF is properly implemented
1007 debug!("deactivating RIF");
1008 const RISAF3_BASE_NS: *mut u32 = stm32_metapac::RNG.wrapping_byte_offset(0x8000) as _; // AHB3PERIPH_BASE_NS + 0x8000UL
1009 const RISAF3_REG0_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x40);
1010 const RISAF3_REG0_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x48);
1011 const RISAF3_REG0_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x4C);
1012 const RISAF3_REG1_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x80);
1013 const RISAF3_REG1_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x88);
1014 const RISAF3_REG1_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x8C);
1015 unsafe {
1016 *RISAF3_REG0_CIDCFGR = 0x000F000F; /* RW for everyone */
1017 *RISAF3_REG0_ENDR = 0xFFFFFFFF; /* all-encompassing */
1018 *RISAF3_REG0_CFGR = 0x00000101; /* enabled, secure, unprivileged for everyone */
1019 *RISAF3_REG1_CIDCFGR = 0x00FF00FF; /* RW for everyone */
1020 *RISAF3_REG1_ENDR = 0xFFFFFFFF; /* all-encompassing */
1021 *RISAF3_REG1_CFGR = 0x00000001; /* enabled, non-secure, unprivileged*/
1022 }
1023
1006 debug!("setting power supply config"); 1024 debug!("setting power supply config");
1007 1025
1008 power_supply_config(config.supply_config); 1026 power_supply_config(config.supply_config);
@@ -1039,7 +1057,9 @@ pub(crate) unsafe fn init(config: Config) {
1039 i2s_ckin: None, 1057 i2s_ckin: None,
1040 ic8: None, 1058 ic8: None,
1041 ic9: None, 1059 ic9: None,
1060 ic10: None,
1042 ic14: None, 1061 ic14: None,
1062 ic15: None,
1043 ic17: None, 1063 ic17: None,
1044 ic20: None, 1064 ic20: None,
1045 ); 1065 );
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 37ef7099f..12086cd3a 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -4,16 +4,15 @@
4use core::default::Default; 4use core::default::Default;
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::ops::{Deref, DerefMut}; 7use core::slice;
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{Peri, PeripheralType}; 10use embassy_hal_internal::{Peri, PeripheralType};
12use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
13use sdio_host::common_cmd::{self, Resp, ResponseLen}; 12use sdio_host::Cmd;
14use sdio_host::emmc::{EMMC, ExtCSD}; 13use sdio_host::common_cmd::{self, R1, R2, R3, Resp, ResponseLen, Rz};
15use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; 14use sdio_host::sd::{BusWidth, CardStatus};
16use sdio_host::{Cmd, emmc_cmd, sd_cmd}; 15use sdio_host::sd_cmd::{R6, R7};
17 16
18#[cfg(sdmmc_v1)] 17#[cfg(sdmmc_v1)]
19use crate::dma::ChannelAndRequest; 18use crate::dma::ChannelAndRequest;
@@ -22,37 +21,27 @@ use crate::gpio::Pull;
22use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 21use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
23use crate::interrupt::typelevel::Interrupt; 22use crate::interrupt::typelevel::Interrupt;
24use crate::pac::sdmmc::Sdmmc as RegBlock; 23use crate::pac::sdmmc::Sdmmc as RegBlock;
25use crate::rcc::{self, RccPeripheral}; 24use crate::rcc::{self, RccInfo, RccPeripheral, SealedRccPeripheral};
25use crate::sdmmc::sd::Addressable;
26use crate::time::Hertz; 26use crate::time::Hertz;
27use crate::{interrupt, peripherals}; 27use crate::{interrupt, peripherals};
28 28
29/// Module for SD and EMMC cards
30pub mod sd;
31
32/// Module for SDIO interface
33pub mod sdio;
34
29/// Interrupt handler. 35/// Interrupt handler.
30pub struct InterruptHandler<T: Instance> { 36pub struct InterruptHandler<T: Instance> {
31 _phantom: PhantomData<T>, 37 _phantom: PhantomData<T>,
32} 38}
33 39
34impl<T: Instance> InterruptHandler<T> {
35 fn enable_interrupts() {
36 let regs = T::regs();
37 regs.maskr().write(|w| {
38 w.set_dcrcfailie(true);
39 w.set_dtimeoutie(true);
40 w.set_dataendie(true);
41 w.set_dbckendie(true);
42
43 #[cfg(sdmmc_v1)]
44 w.set_stbiterre(true);
45 #[cfg(sdmmc_v2)]
46 w.set_dabortie(true);
47 });
48 }
49}
50
51impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 40impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
52 unsafe fn on_interrupt() { 41 unsafe fn on_interrupt() {
53 T::state().wake(); 42 T::state().waker.wake();
54 let status = T::regs().star().read(); 43 let status = T::info().regs.star().read();
55 T::regs().maskr().modify(|w| { 44 T::info().regs.maskr().modify(|w| {
56 if status.dcrcfail() { 45 if status.dcrcfail() {
57 w.set_dcrcfailie(false) 46 w.set_dcrcfailie(false)
58 } 47 }
@@ -77,6 +66,57 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
77 } 66 }
78} 67}
79 68
69struct U128(pub u128);
70
71trait TypedResp: Resp {
72 type Word: From<U128>;
73}
74
75impl From<U128> for () {
76 fn from(value: U128) -> Self {
77 match value.0 {
78 0 => (),
79 _ => unreachable!(),
80 }
81 }
82}
83
84impl From<U128> for u32 {
85 fn from(value: U128) -> Self {
86 unwrap!(value.0.try_into())
87 }
88}
89
90impl From<U128> for u128 {
91 fn from(value: U128) -> Self {
92 value.0
93 }
94}
95
96impl TypedResp for Rz {
97 type Word = ();
98}
99
100impl TypedResp for R1 {
101 type Word = u32;
102}
103
104impl TypedResp for R2 {
105 type Word = u128;
106}
107
108impl TypedResp for R3 {
109 type Word = u32;
110}
111
112impl TypedResp for R6 {
113 type Word = u32;
114}
115
116impl TypedResp for R7 {
117 type Word = u32;
118}
119
80/// Frequency used for SD Card initialization. Must be no higher than 400 kHz. 120/// Frequency used for SD Card initialization. Must be no higher than 400 kHz.
81const SD_INIT_FREQ: Hertz = Hertz(400_000); 121const SD_INIT_FREQ: Hertz = Hertz(400_000);
82 122
@@ -99,54 +139,14 @@ impl Default for Signalling {
99 } 139 }
100} 140}
101 141
102/// Aligned data block for SDMMC transfers. 142const fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
103/// 143 let len = x.len() * 4;
104/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements. 144 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
105#[repr(align(4))]
106#[derive(Debug, Clone, PartialEq, Eq)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))]
108pub struct DataBlock(pub [u8; 512]);
109
110impl Deref for DataBlock {
111 type Target = [u8; 512];
112
113 fn deref(&self) -> &Self::Target {
114 &self.0
115 }
116} 145}
117 146
118impl DerefMut for DataBlock { 147const fn slice8_ref(x: &[u32]) -> &[u8] {
119 fn deref_mut(&mut self) -> &mut Self::Target { 148 let len = x.len() * 4;
120 &mut self.0 149 unsafe { slice::from_raw_parts(x.as_ptr() as _, len) }
121 }
122}
123
124/// Command Block buffer for SDMMC command transfers.
125///
126/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required.
127#[derive(Debug, Clone, PartialEq, Eq)]
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub struct CmdBlock(pub [u32; 16]);
130
131impl CmdBlock {
132 /// Creates a new instance of CmdBlock
133 pub const fn new() -> Self {
134 Self([0u32; 16])
135 }
136}
137
138impl Deref for CmdBlock {
139 type Target = [u32; 16];
140
141 fn deref(&self) -> &Self::Target {
142 &self.0
143 }
144}
145
146impl DerefMut for CmdBlock {
147 fn deref_mut(&mut self) -> &mut Self::Target {
148 &mut self.0
149 }
150} 150}
151 151
152/// Errors 152/// Errors
@@ -181,42 +181,6 @@ pub enum Error {
181 StBitErr, 181 StBitErr,
182} 182}
183 183
184#[derive(Clone, Copy, Debug, Default)]
185/// SD Card
186pub struct Card {
187 /// The type of this card
188 pub card_type: CardCapacity,
189 /// Operation Conditions Register
190 pub ocr: OCR<SD>,
191 /// Relative Card Address
192 pub rca: u16,
193 /// Card ID
194 pub cid: CID<SD>,
195 /// Card Specific Data
196 pub csd: CSD<SD>,
197 /// SD CARD Configuration Register
198 pub scr: SCR,
199 /// SD Status
200 pub status: SDStatus,
201}
202
203#[derive(Clone, Copy, Debug, Default)]
204/// eMMC storage
205pub struct Emmc {
206 /// The capacity of this card
207 pub capacity: CardCapacity,
208 /// Operation Conditions Register
209 pub ocr: OCR<EMMC>,
210 /// Relative Card Address
211 pub rca: u16,
212 /// Card ID
213 pub cid: CID<EMMC>,
214 /// Card Specific Data
215 pub csd: CSD<EMMC>,
216 /// Extended Card Specific Data
217 pub ext_csd: ExtCSD,
218}
219
220#[repr(u8)] 184#[repr(u8)]
221enum PowerCtrl { 185enum PowerCtrl {
222 Off = 0b00, 186 Off = 0b00,
@@ -259,6 +223,55 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> {
259 Ok((false, clk_div, clk_f)) 223 Ok((false, clk_div, clk_f))
260} 224}
261 225
226fn bus_width_vals(bus_width: BusWidth) -> (u8, u32) {
227 match bus_width {
228 BusWidth::One => (0, 1u32),
229 BusWidth::Four => (1, 4u32),
230 BusWidth::Eight => (2, 8u32),
231 _ => panic!("Invalid Bus Width"),
232 }
233}
234
235#[repr(u8)]
236enum BlockSize {
237 Size1 = 0b0000,
238 Size2 = 0b0001,
239 Size4 = 0b0010,
240 Size8 = 0b0011,
241 Size16 = 0b0100,
242 Size32 = 0b0101,
243 Size64 = 0b0110,
244 Size128 = 0b0111,
245 Size256 = 0b1000,
246 Size512 = 0b1001,
247 Size1024 = 0b1010,
248 Size2048 = 0b1011,
249 Size4096 = 0b1100,
250 Size8192 = 0b1101,
251 Size16384 = 0b1110,
252}
253
254const fn block_size(bytes: usize) -> BlockSize {
255 match bytes {
256 1 => BlockSize::Size1,
257 2 => BlockSize::Size2,
258 4 => BlockSize::Size4,
259 8 => BlockSize::Size8,
260 16 => BlockSize::Size16,
261 32 => BlockSize::Size32,
262 64 => BlockSize::Size64,
263 128 => BlockSize::Size128,
264 256 => BlockSize::Size256,
265 512 => BlockSize::Size512,
266 1024 => BlockSize::Size1024,
267 2048 => BlockSize::Size2048,
268 4096 => BlockSize::Size4096,
269 8192 => BlockSize::Size8192,
270 16384 => BlockSize::Size16384,
271 _ => core::unreachable!(),
272 }
273}
274
262/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to 275/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
263/// `sdmmc_ck` in Hertz. 276/// `sdmmc_ck` in Hertz.
264/// 277///
@@ -286,6 +299,34 @@ struct Transfer<'a> {
286 _dummy: PhantomData<&'a ()>, 299 _dummy: PhantomData<&'a ()>,
287} 300}
288 301
302struct WrappedTransfer<'a> {
303 _transfer: Transfer<'a>,
304 sdmmc: &'a Sdmmc<'a>,
305 defused: bool,
306}
307
308impl<'a> WrappedTransfer<'a> {
309 pub const fn new(_transfer: Transfer<'a>, sdmmc: &'a Sdmmc) -> Self {
310 Self {
311 _transfer,
312 sdmmc,
313 defused: false,
314 }
315 }
316
317 pub fn defuse(&mut self) {
318 self.defused = true;
319 }
320}
321
322impl<'a> Drop for WrappedTransfer<'a> {
323 fn drop(&mut self) {
324 if !self.defused {
325 self.sdmmc.on_drop();
326 }
327 }
328}
329
289#[cfg(all(sdmmc_v1, dma))] 330#[cfg(all(sdmmc_v1, dma))]
290const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { 331const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {
291 pburst: crate::dma::Burst::Incr4, 332 pburst: crate::dma::Burst::Incr4,
@@ -323,64 +364,11 @@ impl Default for Config {
323 } 364 }
324} 365}
325 366
326/// Peripheral that can be operated over SDMMC
327#[derive(Clone, Copy, Debug)]
328pub enum SdmmcPeripheral {
329 /// SD Card
330 SdCard(Card),
331 /// eMMC memory
332 Emmc(Emmc),
333}
334
335impl SdmmcPeripheral {
336 /// Get this peripheral's address on the SDMMC bus
337 fn get_address(&self) -> u16 {
338 match self {
339 Self::SdCard(c) => c.rca,
340 Self::Emmc(e) => e.rca,
341 }
342 }
343 /// Is this a standard or high capacity peripheral?
344 fn get_capacity(&self) -> CardCapacity {
345 match self {
346 Self::SdCard(c) => c.card_type,
347 Self::Emmc(e) => e.capacity,
348 }
349 }
350 /// Size in bytes
351 fn size(&self) -> u64 {
352 match self {
353 // SDHC / SDXC / SDUC
354 Self::SdCard(c) => u64::from(c.csd.block_count()) * 512,
355 // capacity > 2GB
356 Self::Emmc(e) => u64::from(e.ext_csd.sector_count()) * 512,
357 }
358 }
359
360 /// Get a mutable reference to the SD Card.
361 ///
362 /// Panics if there is another peripheral instead.
363 fn get_sd_card(&mut self) -> &mut Card {
364 match *self {
365 Self::SdCard(ref mut c) => c,
366 _ => unreachable!("SD only"),
367 }
368 }
369
370 /// Get a mutable reference to the eMMC.
371 ///
372 /// Panics if there is another peripheral instead.
373 fn get_emmc(&mut self) -> &mut Emmc {
374 match *self {
375 Self::Emmc(ref mut e) => e,
376 _ => unreachable!("eMMC only"),
377 }
378 }
379}
380
381/// Sdmmc device 367/// Sdmmc device
382pub struct Sdmmc<'d, T: Instance> { 368pub struct Sdmmc<'d> {
383 _peri: Peri<'d, T>, 369 info: &'static Info,
370 state: &'static State,
371 ker_clk: Hertz,
384 #[cfg(sdmmc_v1)] 372 #[cfg(sdmmc_v1)]
385 dma: ChannelAndRequest<'d>, 373 dma: ChannelAndRequest<'d>,
386 374
@@ -400,12 +388,6 @@ pub struct Sdmmc<'d, T: Instance> {
400 clock: Hertz, 388 clock: Hertz,
401 /// Current signalling scheme to card 389 /// Current signalling scheme to card
402 signalling: Signalling, 390 signalling: Signalling,
403 /// Card
404 card: Option<SdmmcPeripheral>,
405
406 /// An optional buffer to be used for commands
407 /// This should be used if there are special memory location requirements for dma
408 cmd_block: Option<&'d mut CmdBlock>,
409} 391}
410 392
411const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); 393const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh);
@@ -416,9 +398,9 @@ const CMD_AF: AfType = AfType::output_pull(OutputType::PushPull, Speed::VeryHigh
416const DATA_AF: AfType = CMD_AF; 398const DATA_AF: AfType = CMD_AF;
417 399
418#[cfg(sdmmc_v1)] 400#[cfg(sdmmc_v1)]
419impl<'d, T: Instance> Sdmmc<'d, T> { 401impl<'d> Sdmmc<'d> {
420 /// Create a new SDMMC driver, with 1 data lane. 402 /// Create a new SDMMC driver, with 1 data lane.
421 pub fn new_1bit( 403 pub fn new_1bit<T: Instance>(
422 sdmmc: Peri<'d, T>, 404 sdmmc: Peri<'d, T>,
423 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 405 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
424 dma: Peri<'d, impl SdmmcDma<T>>, 406 dma: Peri<'d, impl SdmmcDma<T>>,
@@ -451,7 +433,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
451 } 433 }
452 434
453 /// Create a new SDMMC driver, with 4 data lanes. 435 /// Create a new SDMMC driver, with 4 data lanes.
454 pub fn new_4bit( 436 pub fn new_4bit<T: Instance>(
455 sdmmc: Peri<'d, T>, 437 sdmmc: Peri<'d, T>,
456 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 438 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
457 dma: Peri<'d, impl SdmmcDma<T>>, 439 dma: Peri<'d, impl SdmmcDma<T>>,
@@ -491,9 +473,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
491} 473}
492 474
493#[cfg(sdmmc_v1)] 475#[cfg(sdmmc_v1)]
494impl<'d, T: Instance> Sdmmc<'d, T> { 476impl<'d> Sdmmc<'d> {
495 /// Create a new SDMMC driver, with 8 data lanes. 477 /// Create a new SDMMC driver, with 8 data lanes.
496 pub fn new_8bit( 478 pub fn new_8bit<T: Instance>(
497 sdmmc: Peri<'d, T>, 479 sdmmc: Peri<'d, T>,
498 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 480 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
499 dma: Peri<'d, impl SdmmcDma<T>>, 481 dma: Peri<'d, impl SdmmcDma<T>>,
@@ -541,9 +523,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
541} 523}
542 524
543#[cfg(sdmmc_v2)] 525#[cfg(sdmmc_v2)]
544impl<'d, T: Instance> Sdmmc<'d, T> { 526impl<'d> Sdmmc<'d> {
545 /// Create a new SDMMC driver, with 1 data lane. 527 /// Create a new SDMMC driver, with 1 data lane.
546 pub fn new_1bit( 528 pub fn new_1bit<T: Instance>(
547 sdmmc: Peri<'d, T>, 529 sdmmc: Peri<'d, T>,
548 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 530 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
549 clk: Peri<'d, impl CkPin<T>>, 531 clk: Peri<'d, impl CkPin<T>>,
@@ -574,7 +556,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
574 } 556 }
575 557
576 /// Create a new SDMMC driver, with 4 data lanes. 558 /// Create a new SDMMC driver, with 4 data lanes.
577 pub fn new_4bit( 559 pub fn new_4bit<T: Instance>(
578 sdmmc: Peri<'d, T>, 560 sdmmc: Peri<'d, T>,
579 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 561 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
580 clk: Peri<'d, impl CkPin<T>>, 562 clk: Peri<'d, impl CkPin<T>>,
@@ -612,9 +594,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
612} 594}
613 595
614#[cfg(sdmmc_v2)] 596#[cfg(sdmmc_v2)]
615impl<'d, T: Instance> Sdmmc<'d, T> { 597impl<'d> Sdmmc<'d> {
616 /// Create a new SDMMC driver, with 8 data lanes. 598 /// Create a new SDMMC driver, with 8 data lanes.
617 pub fn new_8bit( 599 pub fn new_8bit<T: Instance>(
618 sdmmc: Peri<'d, T>, 600 sdmmc: Peri<'d, T>,
619 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 601 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
620 clk: Peri<'d, impl CkPin<T>>, 602 clk: Peri<'d, impl CkPin<T>>,
@@ -659,9 +641,24 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
659 } 641 }
660} 642}
661 643
662impl<'d, T: Instance> Sdmmc<'d, T> { 644impl<'d> Sdmmc<'d> {
663 fn new_inner( 645 fn enable_interrupts(&self) {
664 sdmmc: Peri<'d, T>, 646 let regs = self.info.regs;
647 regs.maskr().write(|w| {
648 w.set_dcrcfailie(true);
649 w.set_dtimeoutie(true);
650 w.set_dataendie(true);
651 w.set_dbckendie(true);
652
653 #[cfg(sdmmc_v1)]
654 w.set_stbiterre(true);
655 #[cfg(sdmmc_v2)]
656 w.set_dabortie(true);
657 });
658 }
659
660 fn new_inner<T: Instance>(
661 _sdmmc: Peri<'d, T>,
665 #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, 662 #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>,
666 clk: Peri<'d, AnyPin>, 663 clk: Peri<'d, AnyPin>,
667 cmd: Peri<'d, AnyPin>, 664 cmd: Peri<'d, AnyPin>,
@@ -680,8 +677,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
680 T::Interrupt::unpend(); 677 T::Interrupt::unpend();
681 unsafe { T::Interrupt::enable() }; 678 unsafe { T::Interrupt::enable() };
682 679
683 let regs = T::regs(); 680 let info = T::info();
684 regs.clkcr().write(|w| { 681 let state = T::state();
682 let ker_clk = T::frequency();
683
684 info.regs.clkcr().write(|w| {
685 w.set_pwrsav(false); 685 w.set_pwrsav(false);
686 w.set_negedge(false); 686 w.set_negedge(false);
687 687
@@ -698,10 +698,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
698 698
699 // Power off, writen 00: Clock to the card is stopped; 699 // Power off, writen 00: Clock to the card is stopped;
700 // D[7:0], CMD, and CK are driven high. 700 // D[7:0], CMD, and CK are driven high.
701 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); 701 info.regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
702 702
703 Self { 703 Self {
704 _peri: sdmmc, 704 info,
705 state,
706 ker_clk,
705 #[cfg(sdmmc_v1)] 707 #[cfg(sdmmc_v1)]
706 dma, 708 dma,
707 709
@@ -719,15 +721,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
719 config, 721 config,
720 clock: SD_INIT_FREQ, 722 clock: SD_INIT_FREQ,
721 signalling: Default::default(), 723 signalling: Default::default(),
722 card: None,
723 cmd_block: None,
724 } 724 }
725 } 725 }
726 726
727 /// Data transfer is in progress 727 /// Data transfer is in progress
728 #[inline] 728 #[inline]
729 fn data_active() -> bool { 729 fn data_active(&self) -> bool {
730 let regs = T::regs(); 730 let regs = self.info.regs;
731 731
732 let status = regs.star().read(); 732 let status = regs.star().read();
733 #[cfg(sdmmc_v1)] 733 #[cfg(sdmmc_v1)]
@@ -738,8 +738,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
738 738
739 /// Coammand transfer is in progress 739 /// Coammand transfer is in progress
740 #[inline] 740 #[inline]
741 fn cmd_active() -> bool { 741 fn cmd_active(&self) -> bool {
742 let regs = T::regs(); 742 let regs = self.info.regs;
743 743
744 let status = regs.star().read(); 744 let status = regs.star().read();
745 #[cfg(sdmmc_v1)] 745 #[cfg(sdmmc_v1)]
@@ -750,8 +750,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
750 750
751 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) 751 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
752 #[inline] 752 #[inline]
753 fn wait_idle() { 753 fn wait_idle(&self) {
754 while Self::data_active() || Self::cmd_active() {} 754 while self.data_active() || self.cmd_active() {}
755 }
756
757 fn bus_width(&self) -> BusWidth {
758 match (self.d3.is_some(), self.d7.is_some()) {
759 (true, true) => BusWidth::Eight,
760 (true, false) => BusWidth::Four,
761 _ => BusWidth::One,
762 }
755 } 763 }
756 764
757 /// # Safety 765 /// # Safety
@@ -759,23 +767,25 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
759 /// `buffer` must be valid for the whole transfer and word aligned 767 /// `buffer` must be valid for the whole transfer and word aligned
760 #[allow(unused_variables)] 768 #[allow(unused_variables)]
761 fn prepare_datapath_read<'a>( 769 fn prepare_datapath_read<'a>(
762 config: &Config, 770 &'a self,
763 #[cfg(sdmmc_v1)] dma: &'a mut ChannelAndRequest<'d>,
764 buffer: &'a mut [u32], 771 buffer: &'a mut [u32],
765 length_bytes: u32, 772 block_size: BlockSize,
766 block_size: u8, 773 byte_mode: bool,
767 ) -> Transfer<'a> { 774 ) -> WrappedTransfer<'a> {
768 assert!(block_size <= 14, "Block size up to 2^14 bytes"); 775 let regs = self.info.regs;
769 let regs = T::regs();
770 776
771 // Command AND Data state machines must be idle 777 // Command AND Data state machines must be idle
772 Self::wait_idle(); 778 self.wait_idle();
773 Self::clear_interrupt_flags(); 779 self.clear_interrupt_flags();
774 780
775 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 781 regs.dlenr().write(|w| w.set_datalength(size_of_val(buffer) as u32));
776 782
783 // SAFETY: No other functions use the dma
777 #[cfg(sdmmc_v1)] 784 #[cfg(sdmmc_v1)]
778 let transfer = unsafe { dma.read(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) }; 785 let transfer = unsafe {
786 self.dma
787 .read_unchecked(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS)
788 };
779 #[cfg(sdmmc_v2)] 789 #[cfg(sdmmc_v2)]
780 let transfer = { 790 let transfer = {
781 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); 791 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
@@ -785,8 +795,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
785 } 795 }
786 }; 796 };
787 797
798 #[cfg(sdmmc_v2)]
799 let byte_mode = byte_mode as u8;
800
788 regs.dctrl().modify(|w| { 801 regs.dctrl().modify(|w| {
789 w.set_dblocksize(block_size); 802 w.set_dtmode(byte_mode);
803 w.set_dblocksize(block_size as u8);
790 w.set_dtdir(true); 804 w.set_dtdir(true);
791 #[cfg(sdmmc_v1)] 805 #[cfg(sdmmc_v1)]
792 { 806 {
@@ -795,26 +809,33 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
795 } 809 }
796 }); 810 });
797 811
798 transfer 812 self.enable_interrupts();
813
814 WrappedTransfer::new(transfer, &self)
799 } 815 }
800 816
801 /// # Safety 817 /// # Safety
802 /// 818 ///
803 /// `buffer` must be valid for the whole transfer and word aligned 819 /// `buffer` must be valid for the whole transfer and word aligned
804 fn prepare_datapath_write<'a>(&'a mut self, buffer: &'a [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> { 820 fn prepare_datapath_write<'a>(
805 assert!(block_size <= 14, "Block size up to 2^14 bytes"); 821 &'a self,
806 let regs = T::regs(); 822 buffer: &'a [u32],
823 block_size: BlockSize,
824 byte_mode: bool,
825 ) -> WrappedTransfer<'a> {
826 let regs = self.info.regs;
807 827
808 // Command AND Data state machines must be idle 828 // Command AND Data state machines must be idle
809 Self::wait_idle(); 829 self.wait_idle();
810 Self::clear_interrupt_flags(); 830 self.clear_interrupt_flags();
811 831
812 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 832 regs.dlenr().write(|w| w.set_datalength(size_of_val(buffer) as u32));
813 833
834 // SAFETY: No other functions use the dma
814 #[cfg(sdmmc_v1)] 835 #[cfg(sdmmc_v1)]
815 let transfer = unsafe { 836 let transfer = unsafe {
816 self.dma 837 self.dma
817 .write(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) 838 .write_unchecked(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS)
818 }; 839 };
819 #[cfg(sdmmc_v2)] 840 #[cfg(sdmmc_v2)]
820 let transfer = { 841 let transfer = {
@@ -825,8 +846,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
825 } 846 }
826 }; 847 };
827 848
849 #[cfg(sdmmc_v2)]
850 let byte_mode = byte_mode as u8;
851
828 regs.dctrl().modify(|w| { 852 regs.dctrl().modify(|w| {
829 w.set_dblocksize(block_size); 853 w.set_dtmode(byte_mode);
854 w.set_dblocksize(block_size as u8);
830 w.set_dtdir(false); 855 w.set_dtdir(false);
831 #[cfg(sdmmc_v1)] 856 #[cfg(sdmmc_v1)]
832 { 857 {
@@ -835,12 +860,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
835 } 860 }
836 }); 861 });
837 862
838 transfer 863 self.enable_interrupts();
864
865 WrappedTransfer::new(transfer, &self)
839 } 866 }
840 867
841 /// Stops the DMA datapath 868 /// Stops the DMA datapath
842 fn stop_datapath() { 869 fn stop_datapath(&self) {
843 let regs = T::regs(); 870 let regs = self.info.regs;
844 871
845 #[cfg(sdmmc_v1)] 872 #[cfg(sdmmc_v1)]
846 regs.dctrl().modify(|w| { 873 regs.dctrl().modify(|w| {
@@ -851,49 +878,58 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
851 regs.idmactrlr().modify(|w| w.set_idmaen(false)); 878 regs.idmactrlr().modify(|w| w.set_idmaen(false));
852 } 879 }
853 880
881 fn init_idle(&mut self) -> Result<(), Error> {
882 let regs = self.info.regs;
883
884 self.clkcr_set_clkdiv(SD_INIT_FREQ, BusWidth::One)?;
885 regs.dtimer()
886 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
887
888 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
889 self.cmd(common_cmd::idle(), false)
890 }
891
854 /// Sets the CLKDIV field in CLKCR. Updates clock field in self 892 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
855 fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> { 893 fn clkcr_set_clkdiv(&mut self, freq: Hertz, width: BusWidth) -> Result<(), Error> {
856 let regs = T::regs(); 894 let regs = self.info.regs;
857
858 let width_u32 = match width {
859 BusWidth::One => 1u32,
860 BusWidth::Four => 4u32,
861 BusWidth::Eight => 8u32,
862 _ => panic!("Invalid Bus Width"),
863 };
864 895
865 let ker_ck = T::frequency(); 896 let (widbus, width_u32) = bus_width_vals(width);
866 let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; 897 let (_bypass, clkdiv, new_clock) = clk_div(self.ker_clk, freq.0)?;
867 898
868 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 899 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
869 // Section 55.5.8 900 // Section 55.5.8
870 let sdmmc_bus_bandwidth = new_clock.0 * width_u32; 901 let sdmmc_bus_bandwidth = new_clock.0 * width_u32;
871 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); 902 assert!(self.ker_clk.0 > 3 * sdmmc_bus_bandwidth / 32);
872 self.clock = new_clock; 903 self.clock = new_clock;
873 904
874 // CPSMACT and DPSMACT must be 0 to set CLKDIV 905 // CPSMACT and DPSMACT must be 0 to set CLKDIV or WIDBUS
875 Self::wait_idle(); 906 self.wait_idle();
876 regs.clkcr().modify(|w| { 907 regs.clkcr().modify(|w| {
877 w.set_clkdiv(clkdiv); 908 w.set_clkdiv(clkdiv);
878 #[cfg(sdmmc_v1)] 909 #[cfg(sdmmc_v1)]
879 w.set_bypass(_bypass); 910 w.set_bypass(_bypass);
911 w.set_widbus(widbus);
880 }); 912 });
881 913
882 Ok(()) 914 Ok(())
883 } 915 }
884 916
917 fn get_cid(&self) -> Result<u128, Error> {
918 self.cmd(common_cmd::all_send_cid(), false) // CMD2
919 }
920
921 fn get_csd(&self, address: u16) -> Result<u128, Error> {
922 self.cmd(common_cmd::send_csd(address), false)
923 }
924
885 /// Query the card status (CMD13, returns R1) 925 /// Query the card status (CMD13, returns R1)
886 fn read_status<Ext>(&self, card: &SdmmcPeripheral) -> Result<CardStatus<Ext>, Error> 926 fn read_status<A: Addressable>(&self, card: &A) -> Result<CardStatus<A::Ext>, Error>
887 where 927 where
888 CardStatus<Ext>: From<u32>, 928 CardStatus<A::Ext>: From<u32>,
889 { 929 {
890 let regs = T::regs();
891 let rca = card.get_address(); 930 let rca = card.get_address();
892 931
893 Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 932 Ok(self.cmd(common_cmd::card_status(rca, false), false)?.into()) // CMD13
894
895 let r1 = regs.respr(0).read().cardstatus();
896 Ok(r1.into())
897 } 933 }
898 934
899 /// Select one card and place it into the _Tranfer State_ 935 /// Select one card and place it into the _Tranfer State_
@@ -904,17 +940,23 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
904 // Determine Relative Card Address (RCA) of given card 940 // Determine Relative Card Address (RCA) of given card
905 let rca = rca.unwrap_or(0); 941 let rca = rca.unwrap_or(0);
906 942
907 let r = Self::cmd(common_cmd::select_card(rca), false); 943 let resp = self.cmd(common_cmd::select_card(rca), false);
908 match (r, rca) { 944
909 (Err(Error::Timeout), 0) => Ok(()), 945 if let Err(Error::Timeout) = resp
910 _ => r, 946 && rca == 0
947 {
948 return Ok(());
911 } 949 }
950
951 resp?;
952
953 Ok(())
912 } 954 }
913 955
914 /// Clear flags in interrupt clear register 956 /// Clear flags in interrupt clear register
915 #[inline] 957 #[inline]
916 fn clear_interrupt_flags() { 958 fn clear_interrupt_flags(&self) {
917 let regs = T::regs(); 959 let regs = self.info.regs;
918 regs.icr().write(|w| { 960 regs.icr().write(|w| {
919 w.set_ccrcfailc(true); 961 w.set_ccrcfailc(true);
920 w.set_dcrcfailc(true); 962 w.set_dcrcfailc(true);
@@ -947,12 +989,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
947 989
948 /// Send command to card 990 /// Send command to card
949 #[allow(unused_variables)] 991 #[allow(unused_variables)]
950 fn cmd<R: Resp>(cmd: Cmd<R>, data: bool) -> Result<(), Error> { 992 fn cmd<R: TypedResp>(&self, cmd: Cmd<R>, data: bool) -> Result<R::Word, Error> {
951 let regs = T::regs(); 993 let regs = self.info.regs;
952 994
953 Self::clear_interrupt_flags(); 995 self.clear_interrupt_flags();
954 // CP state machine must be idle 996 // CP state machine must be idle
955 while Self::cmd_active() {} 997 while self.cmd_active() {}
956 998
957 // Command arg 999 // Command arg
958 regs.argr().write(|w| w.set_cmdarg(cmd.arg)); 1000 regs.argr().write(|w| w.set_cmdarg(cmd.arg));
@@ -994,16 +1036,29 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
994 } else if status.ccrcfail() { 1036 } else if status.ccrcfail() {
995 return Err(Error::Crc); 1037 return Err(Error::Crc);
996 } 1038 }
997 Ok(()) 1039
1040 Ok(match R::LENGTH {
1041 ResponseLen::Zero => U128(0u128),
1042 ResponseLen::R48 => U128(self.info.regs.respr(0).read().cardstatus() as u128),
1043 ResponseLen::R136 => {
1044 let cid0 = self.info.regs.respr(0).read().cardstatus() as u128;
1045 let cid1 = self.info.regs.respr(1).read().cardstatus() as u128;
1046 let cid2 = self.info.regs.respr(2).read().cardstatus() as u128;
1047 let cid3 = self.info.regs.respr(3).read().cardstatus() as u128;
1048
1049 U128((cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3))
1050 }
1051 }
1052 .into())
998 } 1053 }
999 1054
1000 fn on_drop() { 1055 fn on_drop(&self) {
1001 let regs = T::regs(); 1056 let regs = self.info.regs;
1002 if Self::data_active() { 1057 if self.data_active() {
1003 Self::clear_interrupt_flags(); 1058 self.clear_interrupt_flags();
1004 // Send abort 1059 // Send abort
1005 // CP state machine must be idle 1060 // CP state machine must be idle
1006 while Self::cmd_active() {} 1061 while self.cmd_active() {}
1007 1062
1008 // Command arg 1063 // Command arg
1009 regs.argr().write(|w| w.set_cmdarg(0)); 1064 regs.argr().write(|w| w.set_cmdarg(0));
@@ -1023,22 +1078,22 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1023 }); 1078 });
1024 1079
1025 // Wait for the abort 1080 // Wait for the abort
1026 while Self::data_active() {} 1081 while self.data_active() {}
1027 } 1082 }
1028 regs.maskr().write(|_| ()); // disable irqs 1083 regs.maskr().write(|_| ()); // disable irqs
1029 Self::clear_interrupt_flags(); 1084 self.clear_interrupt_flags();
1030 Self::stop_datapath(); 1085 self.stop_datapath();
1031 } 1086 }
1032 1087
1033 /// Wait for a previously started datapath transfer to complete from an interrupt. 1088 /// Wait for a previously started datapath transfer to complete from an interrupt.
1034 #[inline] 1089 #[inline]
1035 #[allow(unused)] 1090 #[allow(unused)]
1036 async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { 1091 async fn complete_datapath_transfer(&self, mut transfer: WrappedTransfer<'_>, block: bool) -> Result<(), Error> {
1037 let res = poll_fn(|cx| { 1092 let res = poll_fn(|cx| {
1038 // Compiler might not be sufficiently constrained here 1093 // Compiler might not be sufficiently constrained here
1039 // https://github.com/embassy-rs/embassy/issues/4723 1094 // https://github.com/embassy-rs/embassy/issues/4723
1040 T::state().register(cx.waker()); 1095 self.state.waker.register(cx.waker());
1041 let status = T::regs().star().read(); 1096 let status = self.info.regs.star().read();
1042 1097
1043 if status.dcrcfail() { 1098 if status.dcrcfail() {
1044 return Poll::Ready(Err(Error::Crc)); 1099 return Poll::Ready(Err(Error::Crc));
@@ -1067,706 +1122,25 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1067 }) 1122 })
1068 .await; 1123 .await;
1069 1124
1070 Self::clear_interrupt_flags(); 1125 self.clear_interrupt_flags();
1071 1126 self.stop_datapath();
1072 res
1073 }
1074
1075 /// Read a data block.
1076 #[inline]
1077 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
1078 let _scoped_block_stop = T::RCC_INFO.block_stop();
1079 let card_capacity = self.card()?.get_capacity();
1080
1081 // NOTE(unsafe) DataBlock uses align 4
1082 let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
1083
1084 // Always read 1 block of 512 bytes
1085 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1086 let address = match card_capacity {
1087 CardCapacity::StandardCapacity => block_idx * 512,
1088 _ => block_idx,
1089 };
1090 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1091 1127
1092 let on_drop = OnDrop::new(|| Self::on_drop()); 1128 transfer.defuse();
1129 drop(transfer);
1093 1130
1094 let transfer = Self::prepare_datapath_read(
1095 &self.config,
1096 #[cfg(sdmmc_v1)]
1097 &mut self.dma,
1098 buffer,
1099 512,
1100 9,
1101 );
1102 InterruptHandler::<T>::enable_interrupts();
1103 Self::cmd(common_cmd::read_single_block(address), true)?;
1104
1105 let res = Self::complete_datapath_transfer(true).await;
1106
1107 if res.is_ok() {
1108 on_drop.defuse();
1109 Self::stop_datapath();
1110 drop(transfer);
1111 }
1112 res 1131 res
1113 } 1132 }
1114 1133
1115 /// Read multiple data blocks.
1116 #[inline]
1117 pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
1118 let _scoped_block_stop = T::RCC_INFO.block_stop();
1119 let card_capacity = self.card()?.get_capacity();
1120
1121 // NOTE(unsafe) reinterpret buffer as &mut [u32]
1122 let buffer = unsafe {
1123 let ptr = blocks.as_mut_ptr() as *mut u32;
1124 let len = blocks.len() * 128;
1125 core::slice::from_raw_parts_mut(ptr, len)
1126 };
1127
1128 // Always read 1 block of 512 bytes
1129 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1130 let address = match card_capacity {
1131 CardCapacity::StandardCapacity => block_idx * 512,
1132 _ => block_idx,
1133 };
1134 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1135
1136 let on_drop = OnDrop::new(|| Self::on_drop());
1137
1138 let transfer = Self::prepare_datapath_read(
1139 &self.config,
1140 #[cfg(sdmmc_v1)]
1141 &mut self.dma,
1142 buffer,
1143 512 * blocks.len() as u32,
1144 9,
1145 );
1146 InterruptHandler::<T>::enable_interrupts();
1147
1148 Self::cmd(common_cmd::read_multiple_blocks(address), true)?;
1149
1150 let res = Self::complete_datapath_transfer(false).await;
1151
1152 Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
1153 Self::clear_interrupt_flags();
1154
1155 if res.is_ok() {
1156 on_drop.defuse();
1157 Self::stop_datapath();
1158 drop(transfer);
1159 }
1160 res
1161 }
1162
1163 /// Write a data block.
1164 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
1165 let _scoped_block_stop = T::RCC_INFO.block_stop();
1166 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1167
1168 // NOTE(unsafe) DataBlock uses align 4
1169 let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
1170
1171 // Always read 1 block of 512 bytes
1172 // cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1173 let address = match card.get_capacity() {
1174 CardCapacity::StandardCapacity => block_idx * 512,
1175 _ => block_idx,
1176 };
1177 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1178
1179 let on_drop = OnDrop::new(|| Self::on_drop());
1180
1181 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
1182 #[cfg(sdmmc_v1)]
1183 Self::cmd(common_cmd::write_single_block(address), true)?;
1184
1185 let transfer = self.prepare_datapath_write(buffer, 512, 9);
1186 InterruptHandler::<T>::enable_interrupts();
1187
1188 #[cfg(sdmmc_v2)]
1189 Self::cmd(common_cmd::write_single_block(address), true)?;
1190
1191 let res = Self::complete_datapath_transfer(true).await;
1192
1193 match res {
1194 Ok(_) => {
1195 on_drop.defuse();
1196 Self::stop_datapath();
1197 drop(transfer);
1198
1199 // TODO: Make this configurable
1200 let mut timeout: u32 = 0x00FF_FFFF;
1201
1202 let card = self.card.as_ref().unwrap();
1203 while timeout > 0 {
1204 let ready_for_data = match card {
1205 SdmmcPeripheral::Emmc(_) => self.read_status::<EMMC>(card)?.ready_for_data(),
1206 SdmmcPeripheral::SdCard(_) => self.read_status::<SD>(card)?.ready_for_data(),
1207 };
1208
1209 if ready_for_data {
1210 return Ok(());
1211 }
1212 timeout -= 1;
1213 }
1214 Err(Error::SoftwareTimeout)
1215 }
1216 Err(e) => Err(e),
1217 }
1218 }
1219
1220 /// Write multiple data blocks.
1221 pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> {
1222 let _scoped_block_stop = T::RCC_INFO.block_stop();
1223 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1224
1225 // NOTE(unsafe) reinterpret buffer as &[u32]
1226 let buffer = unsafe {
1227 let ptr = blocks.as_ptr() as *const u32;
1228 let len = blocks.len() * 128;
1229 core::slice::from_raw_parts(ptr, len)
1230 };
1231
1232 // Always read 1 block of 512 bytes
1233 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1234 let address = match card.get_capacity() {
1235 CardCapacity::StandardCapacity => block_idx * 512,
1236 _ => block_idx,
1237 };
1238
1239 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1240
1241 let block_count = blocks.len();
1242
1243 let on_drop = OnDrop::new(|| Self::on_drop());
1244
1245 #[cfg(sdmmc_v1)]
1246 Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
1247
1248 // Setup write command
1249 let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9);
1250 InterruptHandler::<T>::enable_interrupts();
1251
1252 #[cfg(sdmmc_v2)]
1253 Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
1254
1255 let res = Self::complete_datapath_transfer(false).await;
1256
1257 Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
1258 Self::clear_interrupt_flags();
1259
1260 match res {
1261 Ok(_) => {
1262 on_drop.defuse();
1263 Self::stop_datapath();
1264 drop(transfer);
1265
1266 // TODO: Make this configurable
1267 let mut timeout: u32 = 0x00FF_FFFF;
1268
1269 // Try to read card status (ACMD13)
1270 while timeout > 0 {
1271 match self.read_sd_status().await {
1272 Ok(_) => return Ok(()),
1273 Err(Error::Timeout) => (), // Try again
1274 Err(e) => return Err(e),
1275 }
1276 timeout -= 1;
1277 }
1278 Err(Error::SoftwareTimeout)
1279 }
1280 Err(e) => Err(e),
1281 }
1282 }
1283
1284 /// Get a reference to the initialized card
1285 ///
1286 /// # Errors
1287 ///
1288 /// Returns Error::NoCard if [`init_sd_card`](#method.init_sd_card) or
1289 /// [`init_emmc`](#method.init_emmc) has not previously succeeded
1290 #[inline]
1291 pub fn card(&self) -> Result<&SdmmcPeripheral, Error> {
1292 self.card.as_ref().ok_or(Error::NoCard)
1293 }
1294
1295 /// Get the current SDMMC bus clock 1134 /// Get the current SDMMC bus clock
1296 pub fn clock(&self) -> Hertz { 1135 pub fn clock(&self) -> Hertz {
1297 self.clock 1136 self.clock
1298 } 1137 }
1299
1300 /// Set a specific cmd buffer rather than using the default stack allocated one.
1301 /// This is required if stack RAM cannot be used with DMA and usually manifests
1302 /// itself as an indefinite wait on a dma transfer because the dma peripheral
1303 /// cannot access the memory.
1304 pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) {
1305 self.cmd_block = Some(cmd_block)
1306 }
1307
1308 async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> {
1309 let regs = T::regs();
1310 let ker_ck = T::frequency();
1311
1312 let bus_width = match (self.d3.is_some(), self.d7.is_some()) {
1313 (true, true) => {
1314 if matches!(card, SdmmcPeripheral::SdCard(_)) {
1315 return Err(Error::BusWidth);
1316 }
1317 BusWidth::Eight
1318 }
1319 (true, false) => BusWidth::Four,
1320 _ => BusWidth::One,
1321 };
1322
1323 // While the SD/SDIO card or eMMC is in identification mode,
1324 // the SDMMC_CK frequency must be no more than 400 kHz.
1325 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1326 self.clock = init_clock;
1327
1328 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1329 Self::wait_idle();
1330
1331 regs.clkcr().modify(|w| {
1332 w.set_widbus(0);
1333 w.set_clkdiv(clkdiv);
1334 #[cfg(sdmmc_v1)]
1335 w.set_bypass(_bypass);
1336 });
1337 regs.dtimer()
1338 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
1339
1340 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
1341 Self::cmd(common_cmd::idle(), false)?;
1342
1343 match card {
1344 SdmmcPeripheral::SdCard(ref mut card) => {
1345 // Check if cards supports CMD8 (with pattern)
1346 Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?;
1347 let cic = CIC::from(regs.respr(0).read().cardstatus());
1348
1349 if cic.pattern() != 0xAA {
1350 return Err(Error::UnsupportedCardVersion);
1351 }
1352
1353 if cic.voltage_accepted() & 1 == 0 {
1354 return Err(Error::UnsupportedVoltage);
1355 }
1356
1357 let ocr = loop {
1358 // Signal that next command is a app command
1359 Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55
1360
1361 // 3.2-3.3V
1362 let voltage_window = 1 << 5;
1363 // Initialize card
1364 match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) {
1365 // ACMD41
1366 Ok(_) => (),
1367 Err(Error::Crc) => (),
1368 Err(err) => return Err(err),
1369 }
1370 let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into();
1371 if !ocr.is_busy() {
1372 // Power up done
1373 break ocr;
1374 }
1375 };
1376
1377 if ocr.high_capacity() {
1378 // Card is SDHC or SDXC or SDUC
1379 card.card_type = CardCapacity::HighCapacity;
1380 } else {
1381 card.card_type = CardCapacity::StandardCapacity;
1382 }
1383 card.ocr = ocr;
1384 }
1385 SdmmcPeripheral::Emmc(ref mut emmc) => {
1386 let ocr = loop {
1387 let high_voltage = 0b0 << 7;
1388 let access_mode = 0b10 << 29;
1389 let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15;
1390 // Initialize card
1391 match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) {
1392 Ok(_) => (),
1393 Err(Error::Crc) => (),
1394 Err(err) => return Err(err),
1395 }
1396 let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into();
1397 if !ocr.is_busy() {
1398 // Power up done
1399 break ocr;
1400 }
1401 };
1402
1403 emmc.capacity = if ocr.access_mode() == 0b10 {
1404 // Card is SDHC or SDXC or SDUC
1405 CardCapacity::HighCapacity
1406 } else {
1407 CardCapacity::StandardCapacity
1408 };
1409 emmc.ocr = ocr;
1410 }
1411 }
1412
1413 Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2
1414 let cid0 = regs.respr(0).read().cardstatus() as u128;
1415 let cid1 = regs.respr(1).read().cardstatus() as u128;
1416 let cid2 = regs.respr(2).read().cardstatus() as u128;
1417 let cid3 = regs.respr(3).read().cardstatus() as u128;
1418 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1419
1420 match card {
1421 SdmmcPeripheral::SdCard(ref mut card) => {
1422 card.cid = cid.into();
1423
1424 Self::cmd(sd_cmd::send_relative_address(), false)?;
1425 let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus());
1426 card.rca = rca.address();
1427 }
1428 SdmmcPeripheral::Emmc(ref mut emmc) => {
1429 emmc.cid = cid.into();
1430
1431 emmc.rca = 1u16.into();
1432 Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?;
1433 }
1434 }
1435
1436 Self::cmd(common_cmd::send_csd(card.get_address()), false)?;
1437 let csd0 = regs.respr(0).read().cardstatus() as u128;
1438 let csd1 = regs.respr(1).read().cardstatus() as u128;
1439 let csd2 = regs.respr(2).read().cardstatus() as u128;
1440 let csd3 = regs.respr(3).read().cardstatus() as u128;
1441 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1442
1443 self.select_card(Some(card.get_address()))?;
1444
1445 let bus_width = match card {
1446 SdmmcPeripheral::SdCard(ref mut card) => {
1447 card.csd = csd.into();
1448
1449 self.get_scr(card).await?;
1450
1451 if !card.scr.bus_width_four() {
1452 BusWidth::One
1453 } else {
1454 BusWidth::Four
1455 }
1456 }
1457 SdmmcPeripheral::Emmc(ref mut emmc) => {
1458 emmc.csd = csd.into();
1459
1460 bus_width
1461 }
1462 };
1463
1464 // Set bus width
1465 let widbus = match bus_width {
1466 BusWidth::Eight => 2,
1467 BusWidth::Four => 1,
1468 BusWidth::One => 0,
1469 _ => unreachable!(),
1470 };
1471
1472 match card {
1473 SdmmcPeripheral::SdCard(ref mut card) => {
1474 let acmd_arg = match bus_width {
1475 BusWidth::Four if card.scr.bus_width_four() => 2,
1476 _ => 0,
1477 };
1478 Self::cmd(common_cmd::app_cmd(card.rca), false)?;
1479 Self::cmd(sd_cmd::cmd6(acmd_arg), false)?;
1480 }
1481 SdmmcPeripheral::Emmc(_) => {
1482 // Write bus width to ExtCSD byte 183
1483 Self::cmd(
1484 emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus),
1485 false,
1486 )?;
1487
1488 // Wait for ready after R1b response
1489 loop {
1490 let status = self.read_status::<EMMC>(&card)?;
1491
1492 if status.ready_for_data() {
1493 break;
1494 }
1495 }
1496 }
1497 }
1498
1499 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1500 Self::wait_idle();
1501
1502 regs.clkcr().modify(|w| w.set_widbus(widbus));
1503
1504 // Set Clock
1505 if freq.0 <= 25_000_000 {
1506 // Final clock frequency
1507 self.clkcr_set_clkdiv(freq.0, bus_width)?;
1508 } else {
1509 // Switch to max clock for SDR12
1510 self.clkcr_set_clkdiv(25_000_000, bus_width)?;
1511 }
1512
1513 self.card = Some(card);
1514
1515 match card {
1516 SdmmcPeripheral::SdCard(_) => {
1517 // Read status
1518 self.read_sd_status().await?;
1519
1520 if freq.0 > 25_000_000 {
1521 // Switch to SDR25
1522 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1523
1524 if self.signalling == Signalling::SDR25 {
1525 // Set final clock frequency
1526 self.clkcr_set_clkdiv(freq.0, bus_width)?;
1527
1528 if self.read_status::<SD>(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer {
1529 return Err(Error::SignalingSwitchFailed);
1530 }
1531 }
1532 }
1533
1534 // Read status after signalling change
1535 self.read_sd_status().await?;
1536 }
1537 SdmmcPeripheral::Emmc(_) => {
1538 self.read_ext_csd().await?;
1539 }
1540 }
1541
1542 Ok(())
1543 }
1544
1545 /// Initializes card (if present) and sets the bus at the specified frequency.
1546 ///
1547 /// SD only.
1548 pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> {
1549 let _scoped_block_stop = T::RCC_INFO.block_stop();
1550
1551 self.init_internal(freq, SdmmcPeripheral::SdCard(Card::default())).await
1552 }
1553
1554 /// Switch mode using CMD6.
1555 ///
1556 /// Attempt to set a new signalling mode. The selected
1557 /// signalling mode is returned. Expects the current clock
1558 /// frequency to be > 12.5MHz.
1559 ///
1560 /// SD only.
1561 async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> {
1562 let _ = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card();
1563 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
1564 // necessary"
1565
1566 let set_function = 0x8000_0000
1567 | match signalling {
1568 // See PLSS v7_10 Table 4-11
1569 Signalling::DDR50 => 0xFF_FF04,
1570 Signalling::SDR104 => 0xFF_1F03,
1571 Signalling::SDR50 => 0xFF_1F02,
1572 Signalling::SDR25 => 0xFF_FF01,
1573 Signalling::SDR12 => 0xFF_FF00,
1574 };
1575
1576 let status = match self.cmd_block.as_deref_mut() {
1577 Some(x) => x,
1578 None => &mut CmdBlock::new(),
1579 };
1580
1581 // Arm `OnDrop` after the buffer, so it will be dropped first
1582 let on_drop = OnDrop::new(|| Self::on_drop());
1583
1584 let transfer = Self::prepare_datapath_read(
1585 &self.config,
1586 #[cfg(sdmmc_v1)]
1587 &mut self.dma,
1588 status.as_mut(),
1589 64,
1590 6,
1591 );
1592 InterruptHandler::<T>::enable_interrupts();
1593 Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6
1594
1595 let res = Self::complete_datapath_transfer(true).await;
1596
1597 // Host is allowed to use the new functions at least 8
1598 // clocks after the end of the switch command
1599 // transaction. We know the current clock period is < 80ns,
1600 // so a total delay of 640ns is required here
1601 for _ in 0..300 {
1602 cortex_m::asm::nop();
1603 }
1604
1605 match res {
1606 Ok(_) => {
1607 on_drop.defuse();
1608 Self::stop_datapath();
1609 drop(transfer);
1610
1611 // Function Selection of Function Group 1
1612 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
1613
1614 match selection {
1615 0 => Ok(Signalling::SDR12),
1616 1 => Ok(Signalling::SDR25),
1617 2 => Ok(Signalling::SDR50),
1618 3 => Ok(Signalling::SDR104),
1619 4 => Ok(Signalling::DDR50),
1620 _ => Err(Error::UnsupportedCardType),
1621 }
1622 }
1623 Err(e) => Err(e),
1624 }
1625 }
1626
1627 /// Reads the SCR register.
1628 ///
1629 /// SD only.
1630 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
1631 // Read the 64-bit SCR register
1632 Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16
1633 Self::cmd(common_cmd::app_cmd(card.rca), false)?;
1634
1635 let cmd_block = match self.cmd_block.as_deref_mut() {
1636 Some(x) => x,
1637 None => &mut CmdBlock::new(),
1638 };
1639 let scr = &mut cmd_block.0[..2];
1640
1641 // Arm `OnDrop` after the buffer, so it will be dropped first
1642 let on_drop = OnDrop::new(|| Self::on_drop());
1643
1644 let transfer = Self::prepare_datapath_read(
1645 &self.config,
1646 #[cfg(sdmmc_v1)]
1647 &mut self.dma,
1648 scr,
1649 8,
1650 3,
1651 );
1652 InterruptHandler::<T>::enable_interrupts();
1653 Self::cmd(sd_cmd::send_scr(), true)?;
1654
1655 let res = Self::complete_datapath_transfer(true).await;
1656
1657 if res.is_ok() {
1658 on_drop.defuse();
1659 Self::stop_datapath();
1660 drop(transfer);
1661
1662 unsafe {
1663 let scr_bytes = &*(&scr as *const _ as *const [u8; 8]);
1664 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
1665 }
1666 }
1667 res
1668 }
1669
1670 /// Reads the SD Status (ACMD13)
1671 ///
1672 /// SD only.
1673 async fn read_sd_status(&mut self) -> Result<(), Error> {
1674 let card = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card();
1675 let rca = card.rca;
1676
1677 let cmd_block = match self.cmd_block.as_deref_mut() {
1678 Some(x) => x,
1679 None => &mut CmdBlock::new(),
1680 };
1681
1682 Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16
1683 Self::cmd(common_cmd::app_cmd(rca), false)?; // APP
1684
1685 let status = cmd_block;
1686
1687 // Arm `OnDrop` after the buffer, so it will be dropped first
1688 let on_drop = OnDrop::new(|| Self::on_drop());
1689
1690 let transfer = Self::prepare_datapath_read(
1691 &self.config,
1692 #[cfg(sdmmc_v1)]
1693 &mut self.dma,
1694 status.as_mut(),
1695 64,
1696 6,
1697 );
1698 InterruptHandler::<T>::enable_interrupts();
1699 Self::cmd(sd_cmd::sd_status(), true)?;
1700
1701 let res = Self::complete_datapath_transfer(true).await;
1702
1703 if res.is_ok() {
1704 on_drop.defuse();
1705 Self::stop_datapath();
1706 drop(transfer);
1707
1708 for byte in status.iter_mut() {
1709 *byte = u32::from_be(*byte);
1710 }
1711 card.status = status.0.into();
1712 }
1713 res
1714 }
1715
1716 /// Initializes eMMC and sets the bus at the specified frequency.
1717 ///
1718 /// eMMC only.
1719 pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> {
1720 let _scoped_block_stop = T::RCC_INFO.block_stop();
1721
1722 self.init_internal(freq, SdmmcPeripheral::Emmc(Emmc::default())).await
1723 }
1724
1725 /// Gets the EXT_CSD register.
1726 ///
1727 /// eMMC only.
1728 async fn read_ext_csd(&mut self) -> Result<(), Error> {
1729 let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc();
1730
1731 // Note: cmd_block can't be used because ExtCSD is too long to fit.
1732 let mut data_block = DataBlock([0u8; 512]);
1733
1734 // NOTE(unsafe) DataBlock uses align 4
1735 let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) };
1736
1737 Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16
1738
1739 // Arm `OnDrop` after the buffer, so it will be dropped first
1740 let on_drop = OnDrop::new(|| Self::on_drop());
1741
1742 let transfer = Self::prepare_datapath_read(
1743 &self.config,
1744 #[cfg(sdmmc_v1)]
1745 &mut self.dma,
1746 buffer,
1747 512,
1748 9,
1749 );
1750 InterruptHandler::<T>::enable_interrupts();
1751 Self::cmd(emmc_cmd::send_ext_csd(), true)?;
1752
1753 let res = Self::complete_datapath_transfer(true).await;
1754
1755 if res.is_ok() {
1756 on_drop.defuse();
1757 Self::stop_datapath();
1758 drop(transfer);
1759
1760 card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into();
1761 }
1762 res
1763 }
1764} 1138}
1765 1139
1766impl<'d, T: Instance> Drop for Sdmmc<'d, T> { 1140impl<'d> Drop for Sdmmc<'d> {
1767 fn drop(&mut self) { 1141 fn drop(&mut self) {
1768 T::Interrupt::disable(); 1142 // T::Interrupt::disable();
1769 Self::on_drop(); 1143 self.on_drop();
1770 1144
1771 critical_section::with(|_| { 1145 critical_section::with(|_| {
1772 self.clk.set_as_disconnected(); 1146 self.clk.set_as_disconnected();
@@ -1799,9 +1173,28 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> {
1799 1173
1800////////////////////////////////////////////////////// 1174//////////////////////////////////////////////////////
1801 1175
1176type Regs = RegBlock;
1177
1178struct Info {
1179 regs: Regs,
1180 rcc: RccInfo,
1181}
1182
1183struct State {
1184 waker: AtomicWaker,
1185}
1186
1187impl State {
1188 const fn new() -> Self {
1189 Self {
1190 waker: AtomicWaker::new(),
1191 }
1192 }
1193}
1194
1802trait SealedInstance { 1195trait SealedInstance {
1803 fn regs() -> RegBlock; 1196 fn info() -> &'static Info;
1804 fn state() -> &'static AtomicWaker; 1197 fn state() -> &'static State;
1805} 1198}
1806 1199
1807/// SDMMC instance trait. 1200/// SDMMC instance trait.
@@ -1828,13 +1221,17 @@ dma_trait!(SdmmcDma, Instance);
1828foreach_peripheral!( 1221foreach_peripheral!(
1829 (sdmmc, $inst:ident) => { 1222 (sdmmc, $inst:ident) => {
1830 impl SealedInstance for peripherals::$inst { 1223 impl SealedInstance for peripherals::$inst {
1831 fn regs() -> RegBlock { 1224 fn info() -> &'static Info {
1832 crate::pac::$inst 1225 static INFO: Info = Info {
1226 regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) },
1227 rcc: crate::peripherals::$inst::RCC_INFO,
1228 };
1229 &INFO
1833 } 1230 }
1834 1231
1835 fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker { 1232 fn state() -> &'static State {
1836 static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new(); 1233 static STATE: State = State::new();
1837 &WAKER 1234 &STATE
1838 } 1235 }
1839 } 1236 }
1840 1237
@@ -1843,48 +1240,3 @@ foreach_peripheral!(
1843 } 1240 }
1844 }; 1241 };
1845); 1242);
1846
1847impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> {
1848 type Error = Error;
1849 type Align = aligned::A4;
1850
1851 async fn read(
1852 &mut self,
1853 block_address: u32,
1854 buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>],
1855 ) -> Result<(), Self::Error> {
1856 let _scoped_block_stop = T::RCC_INFO.block_stop();
1857 // TODO: I think block_address needs to be adjusted by the partition start offset
1858 if buf.len() == 1 {
1859 let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) };
1860 self.read_block(block_address, block).await?;
1861 } else {
1862 let blocks: &mut [DataBlock] =
1863 unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) };
1864 self.read_blocks(block_address, blocks).await?;
1865 }
1866 Ok(())
1867 }
1868
1869 async fn write(
1870 &mut self,
1871 block_address: u32,
1872 buf: &[aligned::Aligned<Self::Align, [u8; 512]>],
1873 ) -> Result<(), Self::Error> {
1874 let _scoped_block_stop = T::RCC_INFO.block_stop();
1875 // TODO: I think block_address needs to be adjusted by the partition start offset
1876 if buf.len() == 1 {
1877 let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) };
1878 self.write_block(block_address, block).await?;
1879 } else {
1880 let blocks: &[DataBlock] =
1881 unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) };
1882 self.write_blocks(block_address, blocks).await?;
1883 }
1884 Ok(())
1885 }
1886
1887 async fn size(&mut self) -> Result<u64, Self::Error> {
1888 Ok(self.card()?.size())
1889 }
1890}
diff --git a/embassy-stm32/src/sdmmc/sd.rs b/embassy-stm32/src/sdmmc/sd.rs
new file mode 100644
index 000000000..6190226b8
--- /dev/null
+++ b/embassy-stm32/src/sdmmc/sd.rs
@@ -0,0 +1,693 @@
1use core::default::Default;
2use core::ops::{Deref, DerefMut};
3
4use sdio_host::emmc::{EMMC, ExtCSD};
5use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus};
6use sdio_host::{common_cmd, emmc_cmd, sd_cmd};
7
8use crate::sdmmc::{BlockSize, Error, Sdmmc, Signalling, block_size, bus_width_vals, slice8_mut, slice8_ref};
9use crate::time::{Hertz, mhz};
10
11/// Aligned data block for SDMMC transfers.
12///
13/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements.
14#[repr(align(4))]
15#[derive(Debug, Clone, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct DataBlock(pub [u32; 128]);
18
19impl DataBlock {
20 /// Create a new DataBlock
21 pub const fn new() -> Self {
22 DataBlock([0u32; 128])
23 }
24}
25
26impl Deref for DataBlock {
27 type Target = [u8; 512];
28
29 fn deref(&self) -> &Self::Target {
30 unwrap!(slice8_ref(&self.0[..]).try_into())
31 }
32}
33
34impl DerefMut for DataBlock {
35 fn deref_mut(&mut self) -> &mut Self::Target {
36 unwrap!(slice8_mut(&mut self.0[..]).try_into())
37 }
38}
39
40/// Command Block buffer for SDMMC command transfers.
41///
42/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required.
43#[derive(Debug, Clone, PartialEq, Eq)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub struct CmdBlock(pub [u32; 16]);
46
47impl CmdBlock {
48 /// Creates a new instance of CmdBlock
49 pub const fn new() -> Self {
50 Self([0u32; 16])
51 }
52}
53
54impl Deref for CmdBlock {
55 type Target = [u32; 16];
56
57 fn deref(&self) -> &Self::Target {
58 &self.0
59 }
60}
61
62impl DerefMut for CmdBlock {
63 fn deref_mut(&mut self) -> &mut Self::Target {
64 &mut self.0
65 }
66}
67
68/// Represents either an SD or EMMC card
69pub trait Addressable: Sized + Clone {
70 /// Associated type
71 type Ext;
72
73 /// Get this peripheral's address on the SDMMC bus
74 fn get_address(&self) -> u16;
75
76 /// Is this a standard or high capacity peripheral?
77 fn get_capacity(&self) -> CardCapacity;
78
79 /// Size in bytes
80 fn size(&self) -> u64;
81}
82
83/// Storage Device
84pub struct StorageDevice<'a, 'b, T: Addressable> {
85 info: T,
86 /// Inner member
87 pub sdmmc: &'a mut Sdmmc<'b>,
88}
89
90/// Card Storage Device
91impl<'a, 'b> StorageDevice<'a, 'b, Card> {
92 /// Create a new SD card
93 pub async fn new_sd_card(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> {
94 let mut s = Self {
95 info: Card::default(),
96 sdmmc,
97 };
98
99 s.acquire(cmd_block, freq).await?;
100
101 Ok(s)
102 }
103
104 /// Initializes the card into a known state (or at least tries to).
105 async fn acquire(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> {
106 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
107 let regs = self.sdmmc.info.regs;
108
109 let _bus_width = match self.sdmmc.bus_width() {
110 BusWidth::Eight => return Err(Error::BusWidth),
111 bus_width => bus_width,
112 };
113
114 // While the SD/SDIO card or eMMC is in identification mode,
115 // the SDMMC_CK frequency must be no more than 400 kHz.
116 self.sdmmc.init_idle()?;
117
118 // Check if cards supports CMD8 (with pattern)
119 self.sdmmc.cmd(sd_cmd::send_if_cond(1, 0xAA), false)?;
120 let cic = CIC::from(regs.respr(0).read().cardstatus());
121
122 if cic.pattern() != 0xAA {
123 return Err(Error::UnsupportedCardVersion);
124 }
125
126 if cic.voltage_accepted() & 1 == 0 {
127 return Err(Error::UnsupportedVoltage);
128 }
129
130 let ocr = loop {
131 // Signal that next command is a app command
132 self.sdmmc.cmd(common_cmd::app_cmd(0), false)?; // CMD55
133
134 // 3.2-3.3V
135 let voltage_window = 1 << 5;
136 // Initialize card
137 match self
138 .sdmmc
139 .cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false)
140 {
141 // ACMD41
142 Ok(_) => (),
143 Err(Error::Crc) => (),
144 Err(err) => return Err(err),
145 }
146
147 let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into();
148 if !ocr.is_busy() {
149 // Power up done
150 break ocr;
151 }
152 };
153
154 if ocr.high_capacity() {
155 // Card is SDHC or SDXC or SDUC
156 self.info.card_type = CardCapacity::HighCapacity;
157 } else {
158 self.info.card_type = CardCapacity::StandardCapacity;
159 }
160 self.info.ocr = ocr;
161
162 self.info.cid = self.sdmmc.get_cid()?.into();
163
164 self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?;
165 let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus());
166 self.info.rca = rca.address();
167
168 self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into();
169 self.sdmmc.select_card(Some(self.info.get_address()))?;
170
171 self.info.scr = self.get_scr(cmd_block).await?;
172
173 let (bus_width, acmd_arg) = if !self.info.scr.bus_width_four() {
174 (BusWidth::One, 0)
175 } else {
176 (BusWidth::Four, 2)
177 };
178
179 self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?;
180 self.sdmmc.cmd(sd_cmd::cmd6(acmd_arg), false)?;
181
182 self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?;
183
184 // Read status
185 self.info.status = self.read_sd_status(cmd_block).await?;
186
187 if freq > mhz(25) {
188 // Switch to SDR25
189 self.sdmmc.signalling = self.switch_signalling_mode(cmd_block, Signalling::SDR25).await?;
190
191 if self.sdmmc.signalling == Signalling::SDR25 {
192 // Set final clock frequency
193 self.sdmmc.clkcr_set_clkdiv(freq, bus_width)?;
194
195 if self.sdmmc.read_status(&self.info)?.state() != CurrentState::Transfer {
196 return Err(Error::SignalingSwitchFailed);
197 }
198 }
199
200 // Read status after signalling change
201 self.read_sd_status(cmd_block).await?;
202 }
203
204 Ok(())
205 }
206
207 /// Switch mode using CMD6.
208 ///
209 /// Attempt to set a new signalling mode. The selected
210 /// signalling mode is returned. Expects the current clock
211 /// frequency to be > 12.5MHz.
212 ///
213 /// SD only.
214 async fn switch_signalling_mode(
215 &self,
216 cmd_block: &mut CmdBlock,
217 signalling: Signalling,
218 ) -> Result<Signalling, Error> {
219 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
220 // necessary"
221
222 let set_function = 0x8000_0000
223 | match signalling {
224 // See PLSS v7_10 Table 4-11
225 Signalling::DDR50 => 0xFF_FF04,
226 Signalling::SDR104 => 0xFF_1F03,
227 Signalling::SDR50 => 0xFF_1F02,
228 Signalling::SDR25 => 0xFF_FF01,
229 Signalling::SDR12 => 0xFF_FF00,
230 };
231
232 let buffer = &mut cmd_block.0[..64 / 4];
233
234 let transfer = self
235 .sdmmc
236 .prepare_datapath_read(buffer, block_size(size_of_val(buffer)), false);
237
238 self.sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6
239
240 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
241
242 // Host is allowed to use the new functions at least 8
243 // clocks after the end of the switch command
244 // transaction. We know the current clock period is < 80ns,
245 // so a total delay of 640ns is required here
246 for _ in 0..300 {
247 cortex_m::asm::nop();
248 }
249
250 // Function Selection of Function Group 1
251 let selection = (u32::from_be(cmd_block[4]) >> 24) & 0xF;
252
253 match selection {
254 0 => Ok(Signalling::SDR12),
255 1 => Ok(Signalling::SDR25),
256 2 => Ok(Signalling::SDR50),
257 3 => Ok(Signalling::SDR104),
258 4 => Ok(Signalling::DDR50),
259 _ => Err(Error::UnsupportedCardType),
260 }
261 }
262
263 /// Reads the SCR register.
264 ///
265 /// SD only.
266 async fn get_scr(&self, cmd_block: &mut CmdBlock) -> Result<SCR, Error> {
267 // Read the 64-bit SCR register
268 self.sdmmc.cmd(common_cmd::set_block_length(8), false)?; // CMD16
269 self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?;
270
271 let scr = &mut cmd_block.0[..2];
272
273 // Arm `OnDrop` after the buffer, so it will be dropped first
274
275 let transfer = self.sdmmc.prepare_datapath_read(scr, BlockSize::Size8, false);
276 self.sdmmc.cmd(sd_cmd::send_scr(), true)?;
277
278 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
279
280 Ok(SCR(u64::from_be_bytes(unwrap!(slice8_mut(scr).try_into()))))
281 }
282
283 /// Reads the SD Status (ACMD13)
284 ///
285 /// SD only.
286 async fn read_sd_status(&self, cmd_block: &mut CmdBlock) -> Result<SDStatus, Error> {
287 let rca = self.info.rca;
288
289 self.sdmmc.cmd(common_cmd::set_block_length(64), false)?; // CMD16
290 self.sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP
291
292 let buffer = &mut cmd_block.as_mut()[..64 / 4];
293
294 let transfer = self
295 .sdmmc
296 .prepare_datapath_read(buffer, block_size(size_of_val(buffer)), false);
297 self.sdmmc.cmd(sd_cmd::sd_status(), true)?;
298
299 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
300
301 for byte in cmd_block.iter_mut() {
302 *byte = u32::from_be(*byte);
303 }
304
305 Ok(cmd_block.0.into())
306 }
307}
308
309/// Emmc storage device
310impl<'a, 'b> StorageDevice<'a, 'b, Emmc> {
311 /// Create a new EMMC card
312 pub async fn new_emmc(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> {
313 let mut s = Self {
314 info: Emmc::default(),
315 sdmmc,
316 };
317
318 s.acquire(cmd_block, freq).await?;
319
320 Ok(s)
321 }
322
323 async fn acquire(&mut self, _cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> {
324 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
325 let regs = self.sdmmc.info.regs;
326
327 let bus_width = self.sdmmc.bus_width();
328
329 // While the SD/SDIO card or eMMC is in identification mode,
330 // the SDMMC_CK frequency must be no more than 400 kHz.
331 self.sdmmc.init_idle()?;
332
333 let ocr = loop {
334 let high_voltage = 0b0 << 7;
335 let access_mode = 0b10 << 29;
336 let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15;
337 // Initialize card
338 match self.sdmmc.cmd(emmc_cmd::send_op_cond(op_cond), false) {
339 Ok(_) => (),
340 Err(Error::Crc) => (),
341 Err(err) => return Err(err),
342 }
343 let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into();
344 if !ocr.is_busy() {
345 // Power up done
346 break ocr;
347 }
348 };
349
350 self.info.capacity = if ocr.access_mode() == 0b10 {
351 // Card is SDHC or SDXC or SDUC
352 CardCapacity::HighCapacity
353 } else {
354 CardCapacity::StandardCapacity
355 };
356 self.info.ocr = ocr;
357
358 self.info.cid = self.sdmmc.get_cid()?.into();
359
360 self.info.rca = 1u16.into();
361 self.sdmmc
362 .cmd(emmc_cmd::assign_relative_address(self.info.rca), false)?;
363
364 self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into();
365 self.sdmmc.select_card(Some(self.info.get_address()))?;
366
367 let (widbus, _) = bus_width_vals(bus_width);
368
369 // Write bus width to ExtCSD byte 183
370 self.sdmmc.cmd(
371 emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus),
372 false,
373 )?;
374
375 // Wait for ready after R1b response
376 loop {
377 let status = self.sdmmc.read_status(&self.info)?;
378
379 if status.ready_for_data() {
380 break;
381 }
382 }
383
384 self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?;
385 self.info.ext_csd = self.read_ext_csd().await?;
386
387 Ok(())
388 }
389
390 /// Gets the EXT_CSD register.
391 ///
392 /// eMMC only.
393 async fn read_ext_csd(&self) -> Result<ExtCSD, Error> {
394 // Note: cmd_block can't be used because ExtCSD is too long to fit.
395 let mut data_block = DataBlock::new();
396
397 self.sdmmc
398 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)
399 .unwrap(); // CMD16
400
401 let transfer = self
402 .sdmmc
403 .prepare_datapath_read(&mut data_block.0, block_size(size_of::<DataBlock>()), false);
404 self.sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?;
405
406 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
407
408 Ok(data_block.0.into())
409 }
410}
411
412/// Card or Emmc storage device
413impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> {
414 /// Write a block
415 pub fn card(&self) -> A {
416 self.info.clone()
417 }
418
419 /// Read a data block.
420 #[inline]
421 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
422 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
423 let card_capacity = self.info.get_capacity();
424
425 // Always read 1 block of 512 bytes
426 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
427 let address = match card_capacity {
428 CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32,
429 _ => block_idx,
430 };
431 self.sdmmc
432 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
433
434 let transfer = self
435 .sdmmc
436 .prepare_datapath_read(&mut buffer.0, block_size(size_of::<DataBlock>()), false);
437 self.sdmmc.cmd(common_cmd::read_single_block(address), true)?;
438
439 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
440
441 Ok(())
442 }
443
444 /// Read multiple data blocks.
445 #[inline]
446 pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
447 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
448 let card_capacity = self.info.get_capacity();
449
450 // NOTE(unsafe) reinterpret buffer as &mut [u32]
451 let buffer = unsafe {
452 core::slice::from_raw_parts_mut(
453 blocks.as_mut_ptr() as *mut u32,
454 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
455 )
456 };
457
458 // Always read 1 block of 512 bytes
459 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
460 let address = match card_capacity {
461 CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32,
462 _ => block_idx,
463 };
464 self.sdmmc
465 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
466
467 let transfer = self
468 .sdmmc
469 .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false);
470 self.sdmmc.cmd(common_cmd::read_multiple_blocks(address), true)?;
471
472 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
473
474 self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12
475 self.sdmmc.clear_interrupt_flags();
476
477 Ok(())
478 }
479
480 /// Write a data block.
481 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error>
482 where
483 CardStatus<A::Ext>: From<u32>,
484 {
485 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
486
487 // Always read 1 block of 512 bytes
488 // cards are byte addressed hence the blockaddress is in multiples of 512 bytes
489 let address = match self.info.get_capacity() {
490 CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32,
491 _ => block_idx,
492 };
493 self.sdmmc
494 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
495
496 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
497 #[cfg(sdmmc_v1)]
498 self.sdmmc.cmd(common_cmd::write_single_block(address), true)?;
499
500 let transfer = self
501 .sdmmc
502 .prepare_datapath_write(&buffer.0, block_size(size_of::<DataBlock>()), false);
503
504 #[cfg(sdmmc_v2)]
505 self.sdmmc.cmd(common_cmd::write_single_block(address), true)?;
506
507 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
508
509 // TODO: Make this configurable
510 let mut timeout: u32 = 0x00FF_FFFF;
511
512 while timeout > 0 {
513 let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data();
514 if ready_for_data {
515 return Ok(());
516 }
517 timeout -= 1;
518 }
519
520 Err(Error::SoftwareTimeout)
521 }
522
523 /// Write multiple data blocks.
524 pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error>
525 where
526 CardStatus<A::Ext>: From<u32>,
527 {
528 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
529
530 // NOTE(unsafe) reinterpret buffer as &[u32]
531 let buffer = unsafe {
532 core::slice::from_raw_parts(
533 blocks.as_ptr() as *const u32,
534 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
535 )
536 };
537 // Always read 1 block of 512 bytes
538 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
539 let address = match self.info.get_capacity() {
540 CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32,
541 _ => block_idx,
542 };
543
544 self.sdmmc
545 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
546
547 #[cfg(sdmmc_v1)]
548 self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
549
550 // Setup write command
551 let transfer = self
552 .sdmmc
553 .prepare_datapath_write(buffer, block_size(size_of::<DataBlock>()), false);
554
555 #[cfg(sdmmc_v2)]
556 self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
557
558 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
559
560 self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12
561 self.sdmmc.clear_interrupt_flags();
562
563 // TODO: Make this configurable
564 let mut timeout: u32 = 0x00FF_FFFF;
565
566 while timeout > 0 {
567 let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data();
568
569 if ready_for_data {
570 return Ok(());
571 }
572 timeout -= 1;
573 }
574 Err(Error::SoftwareTimeout)
575 }
576}
577
578#[derive(Clone, Copy, Debug, Default)]
579/// SD Card
580pub struct Card {
581 /// The type of this card
582 pub card_type: CardCapacity,
583 /// Operation Conditions Register
584 pub ocr: OCR<SD>,
585 /// Relative Card Address
586 pub rca: u16,
587 /// Card ID
588 pub cid: CID<SD>,
589 /// Card Specific Data
590 pub csd: CSD<SD>,
591 /// SD CARD Configuration Register
592 pub scr: SCR,
593 /// SD Status
594 pub status: SDStatus,
595}
596
597impl Addressable for Card {
598 type Ext = SD;
599
600 /// Get this peripheral's address on the SDMMC bus
601 fn get_address(&self) -> u16 {
602 self.rca
603 }
604
605 /// Is this a standard or high capacity peripheral?
606 fn get_capacity(&self) -> CardCapacity {
607 self.card_type
608 }
609
610 /// Size in bytes
611 fn size(&self) -> u64 {
612 u64::from(self.csd.block_count()) * 512
613 }
614}
615
616#[derive(Clone, Copy, Debug, Default)]
617/// eMMC storage
618pub struct Emmc {
619 /// The capacity of this card
620 pub capacity: CardCapacity,
621 /// Operation Conditions Register
622 pub ocr: OCR<EMMC>,
623 /// Relative Card Address
624 pub rca: u16,
625 /// Card ID
626 pub cid: CID<EMMC>,
627 /// Card Specific Data
628 pub csd: CSD<EMMC>,
629 /// Extended Card Specific Data
630 pub ext_csd: ExtCSD,
631}
632
633impl Addressable for Emmc {
634 type Ext = EMMC;
635
636 /// Get this peripheral's address on the SDMMC bus
637 fn get_address(&self) -> u16 {
638 self.rca
639 }
640
641 /// Is this a standard or high capacity peripheral?
642 fn get_capacity(&self) -> CardCapacity {
643 self.capacity
644 }
645
646 /// Size in bytes
647 fn size(&self) -> u64 {
648 u64::from(self.ext_csd.sector_count()) * 512
649 }
650}
651
652impl<'d, 'e, A: Addressable> block_device_driver::BlockDevice<512> for StorageDevice<'d, 'e, A> {
653 type Error = Error;
654 type Align = aligned::A4;
655
656 async fn read(
657 &mut self,
658 block_address: u32,
659 buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>],
660 ) -> Result<(), Self::Error> {
661 // TODO: I think block_address needs to be adjusted by the partition start offset
662 if buf.len() == 1 {
663 let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut DataBlock) };
664 self.read_block(block_address, block).await?;
665 } else {
666 let blocks: &mut [DataBlock] =
667 unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) };
668 self.read_blocks(block_address, blocks).await?;
669 }
670 Ok(())
671 }
672
673 async fn write(
674 &mut self,
675 block_address: u32,
676 buf: &[aligned::Aligned<Self::Align, [u8; 512]>],
677 ) -> Result<(), Self::Error> {
678 // TODO: I think block_address needs to be adjusted by the partition start offset
679 if buf.len() == 1 {
680 let block = unsafe { &*(&buf[0] as *const _ as *const DataBlock) };
681 self.write_block(block_address, block).await?;
682 } else {
683 let blocks: &[DataBlock] =
684 unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) };
685 self.write_blocks(block_address, blocks).await?;
686 }
687 Ok(())
688 }
689
690 async fn size(&mut self) -> Result<u64, Self::Error> {
691 Ok(self.info.size())
692 }
693}
diff --git a/embassy-stm32/src/sdmmc/sdio.rs b/embassy-stm32/src/sdmmc/sdio.rs
new file mode 100644
index 000000000..1412b21fc
--- /dev/null
+++ b/embassy-stm32/src/sdmmc/sdio.rs
@@ -0,0 +1,177 @@
1use core::ops::{Deref, DerefMut};
2
3use sdio_host::common_cmd::{R1, Rz, cmd};
4use sdio_host::sd::BusWidth;
5use sdio_host::sd_cmd;
6
7use crate::sdmmc::{Error, Sdmmc, block_size, slice8_mut, slice8_ref};
8use crate::time::Hertz;
9
10/// Aligned data block for SDMMC transfers.
11///
12/// This is a 64-byte array, aligned to 4 bytes to satisfy DMA requirements.
13#[repr(align(4))]
14#[derive(Debug, Clone, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub struct DataBlock(pub [u32; 16]);
17
18impl DataBlock {
19 /// Create a new DataBlock
20 pub const fn new() -> Self {
21 DataBlock([0u32; 16])
22 }
23}
24
25impl Deref for DataBlock {
26 type Target = [u8; 64];
27
28 fn deref(&self) -> &Self::Target {
29 unwrap!(slice8_ref(&self.0[..]).try_into())
30 }
31}
32
33impl DerefMut for DataBlock {
34 fn deref_mut(&mut self) -> &mut Self::Target {
35 unwrap!(slice8_mut(&mut self.0[..]).try_into())
36 }
37}
38
39/// Storage Device
40pub struct SerialDataInterface<'a, 'b> {
41 /// Inner member
42 pub sdmmc: &'a mut Sdmmc<'b>,
43}
44
45/// Card Storage Device
46impl<'a, 'b> SerialDataInterface<'a, 'b> {
47 /// Create a new SD card
48 pub async fn new(sdmmc: &'a mut Sdmmc<'b>, freq: Hertz) -> Result<Self, Error> {
49 let mut s = Self { sdmmc };
50
51 s.acquire(freq).await?;
52
53 Ok(s)
54 }
55
56 /// Initializes the card into a known state (or at least tries to).
57 async fn acquire(&mut self, _freq: Hertz) -> Result<(), Error> {
58 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
59
60 let _bus_width = match self.sdmmc.bus_width() {
61 BusWidth::Eight => return Err(Error::BusWidth),
62 bus_width => bus_width,
63 };
64
65 // While the SD/SDIO card or eMMC is in identification mode,
66 // the SDMMC_CK frequency must be no more than 400 kHz.
67 self.sdmmc.init_idle()?;
68
69 self.sdmmc.cmd(cmd::<Rz>(5, 0), false)?;
70
71 // Get RCA
72 let rca = self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?;
73
74 // Select the card with RCA
75 self.sdmmc.select_card(Some(rca.try_into().unwrap()))?;
76
77 Ok(())
78 }
79
80 /// Set the bus to the 4-bit high-speed frequency
81 pub fn set_bus_to_high_speed(&mut self, frequency: Hertz) -> Result<(), Error> {
82 self.sdmmc.clkcr_set_clkdiv(frequency, BusWidth::Four)?;
83
84 Ok(())
85 }
86
87 /// Run cmd52
88 pub async fn cmd52(&mut self, arg: u32) -> Result<u32, Error> {
89 self.sdmmc.cmd(cmd::<R1>(52, arg), false)
90 }
91
92 /// Read in block mode using cmd53
93 pub async fn cmd53_block_read(&mut self, arg: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
94 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
95
96 // NOTE(unsafe) reinterpret buffer as &mut [u32]
97 let buffer = unsafe {
98 core::slice::from_raw_parts_mut(
99 blocks.as_mut_ptr() as *mut u32,
100 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
101 )
102 };
103
104 let transfer = self
105 .sdmmc
106 .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false);
107 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
108
109 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
110 self.sdmmc.clear_interrupt_flags();
111
112 Ok(())
113 }
114
115 /// Read in multibyte mode using cmd53
116 pub async fn cmd53_byte_read(&mut self, arg: u32, buffer: &mut [u32]) -> Result<(), Error> {
117 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
118
119 let transfer = self
120 .sdmmc
121 .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), true);
122 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
123
124 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
125 self.sdmmc.clear_interrupt_flags();
126
127 Ok(())
128 }
129
130 /// Write in block mode using cmd53
131 pub async fn cmd53_block_write(&mut self, arg: u32, blocks: &[DataBlock]) -> Result<(), Error> {
132 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
133
134 // NOTE(unsafe) reinterpret buffer as &mut [u32]
135 let buffer = unsafe {
136 core::slice::from_raw_parts_mut(
137 blocks.as_ptr() as *mut u32,
138 blocks.len() * size_of::<DataBlock>() / size_of::<u32>(),
139 )
140 };
141
142 #[cfg(sdmmc_v1)]
143 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
144
145 let transfer = self
146 .sdmmc
147 .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false);
148
149 #[cfg(sdmmc_v2)]
150 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
151
152 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
153 self.sdmmc.clear_interrupt_flags();
154
155 Ok(())
156 }
157
158 /// Write in multibyte mode using cmd53
159 pub async fn cmd53_byte_write(&mut self, arg: u32, buffer: &[u32]) -> Result<(), Error> {
160 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
161
162 #[cfg(sdmmc_v1)]
163 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
164
165 let transfer = self
166 .sdmmc
167 .prepare_datapath_write(buffer, block_size(size_of::<DataBlock>()), true);
168
169 #[cfg(sdmmc_v2)]
170 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
171
172 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
173 self.sdmmc.clear_interrupt_flags();
174
175 Ok(())
176 }
177}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c90e0cef4..af51b79b4 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -64,6 +64,16 @@ pub enum Direction {
64 Receive, 64 Receive,
65} 65}
66 66
67/// Slave Select (SS) pin polarity.
68#[derive(Debug, PartialEq, Eq, Clone, Copy)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum SlaveSelectPolarity {
71 /// SS active high
72 ActiveHigh,
73 /// SS active low
74 ActiveLow,
75}
76
67/// SPI configuration. 77/// SPI configuration.
68#[non_exhaustive] 78#[non_exhaustive]
69#[derive(Copy, Clone)] 79#[derive(Copy, Clone)]
@@ -86,6 +96,9 @@ pub struct Config {
86 /// NSS output enabled (SSM = 0, SSOE = 1): The NSS signal is driven low when the master starts the communication and is kept low until the SPI is disabled. 96 /// NSS output enabled (SSM = 0, SSOE = 1): The NSS signal is driven low when the master starts the communication and is kept low until the SPI is disabled.
87 /// NSS output disabled (SSM = 0, SSOE = 0): For devices set as slave, the NSS pin acts as a classical NSS input: the slave is selected when NSS is low and deselected when NSS high. 97 /// NSS output disabled (SSM = 0, SSOE = 0): For devices set as slave, the NSS pin acts as a classical NSS input: the slave is selected when NSS is low and deselected when NSS high.
88 pub nss_output_disable: bool, 98 pub nss_output_disable: bool,
99 /// Slave Select (SS) pin polarity.
100 #[cfg(any(spi_v4, spi_v5, spi_v6))]
101 pub nss_polarity: SlaveSelectPolarity,
89} 102}
90 103
91impl Default for Config { 104impl Default for Config {
@@ -97,6 +110,8 @@ impl Default for Config {
97 miso_pull: Pull::None, 110 miso_pull: Pull::None,
98 gpio_speed: Speed::VeryHigh, 111 gpio_speed: Speed::VeryHigh,
99 nss_output_disable: false, 112 nss_output_disable: false,
113 #[cfg(any(spi_v4, spi_v5, spi_v6))]
114 nss_polarity: SlaveSelectPolarity::ActiveHigh,
100 } 115 }
101 } 116 }
102} 117}
@@ -123,6 +138,14 @@ impl Config {
123 } 138 }
124 } 139 }
125 140
141 #[cfg(any(spi_v4, spi_v5, spi_v6))]
142 fn raw_nss_polarity(&self) -> vals::Ssiop {
143 match self.nss_polarity {
144 SlaveSelectPolarity::ActiveHigh => vals::Ssiop::ACTIVE_HIGH,
145 SlaveSelectPolarity::ActiveLow => vals::Ssiop::ACTIVE_LOW,
146 }
147 }
148
126 #[cfg(gpio_v1)] 149 #[cfg(gpio_v1)]
127 fn sck_af(&self) -> AfType { 150 fn sck_af(&self) -> AfType {
128 AfType::output(OutputType::PushPull, self.gpio_speed) 151 AfType::output(OutputType::PushPull, self.gpio_speed)
@@ -305,6 +328,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
305 #[cfg(any(spi_v4, spi_v5, spi_v6))] 328 #[cfg(any(spi_v4, spi_v5, spi_v6))]
306 { 329 {
307 let ssoe = CM::MASTER == vals::Master::MASTER && !config.nss_output_disable; 330 let ssoe = CM::MASTER == vals::Master::MASTER && !config.nss_output_disable;
331 let ssiop = config.raw_nss_polarity();
308 regs.ifcr().write(|w| w.0 = 0xffff_ffff); 332 regs.ifcr().write(|w| w.0 = 0xffff_ffff);
309 regs.cfg2().modify(|w| { 333 regs.cfg2().modify(|w| {
310 w.set_ssoe(ssoe); 334 w.set_ssoe(ssoe);
@@ -318,7 +342,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
318 w.set_midi(0); 342 w.set_midi(0);
319 w.set_mssi(0); 343 w.set_mssi(0);
320 w.set_afcntr(true); 344 w.set_afcntr(true);
321 w.set_ssiop(vals::Ssiop::ACTIVE_HIGH); 345 w.set_ssiop(ssiop);
322 }); 346 });
323 regs.cfg1().modify(|w| { 347 regs.cfg1().modify(|w| {
324 w.set_crcen(false); 348 w.set_crcen(false);
@@ -366,6 +390,8 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
366 390
367 #[cfg(any(spi_v4, spi_v5, spi_v6))] 391 #[cfg(any(spi_v4, spi_v5, spi_v6))]
368 { 392 {
393 let ssiop = config.raw_nss_polarity();
394
369 self.info.regs.cr1().modify(|w| { 395 self.info.regs.cr1().modify(|w| {
370 w.set_spe(false); 396 w.set_spe(false);
371 }); 397 });
@@ -374,6 +400,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
374 w.set_cpha(cpha); 400 w.set_cpha(cpha);
375 w.set_cpol(cpol); 401 w.set_cpol(cpol);
376 w.set_lsbfirst(lsbfirst); 402 w.set_lsbfirst(lsbfirst);
403 w.set_ssiop(ssiop);
377 }); 404 });
378 self.info.regs.cfg1().modify(|w| { 405 self.info.regs.cfg1().modify(|w| {
379 w.set_mbr(br); 406 w.set_mbr(br);
@@ -446,6 +473,13 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
446 // NSS output disabled if SSOE=0 or if SSM=1 software slave management enabled 473 // NSS output disabled if SSOE=0 or if SSM=1 software slave management enabled
447 let nss_output_disable = !ssoe || cfg.ssm(); 474 let nss_output_disable = !ssoe || cfg.ssm();
448 475
476 #[cfg(any(spi_v4, spi_v5, spi_v6))]
477 let nss_polarity = if cfg.ssiop() == vals::Ssiop::ACTIVE_LOW {
478 SlaveSelectPolarity::ActiveLow
479 } else {
480 SlaveSelectPolarity::ActiveHigh
481 };
482
449 Config { 483 Config {
450 mode: Mode { polarity, phase }, 484 mode: Mode { polarity, phase },
451 bit_order, 485 bit_order,
@@ -453,6 +487,8 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
453 miso_pull, 487 miso_pull,
454 gpio_speed: self.gpio_speed, 488 gpio_speed: self.gpio_speed,
455 nss_output_disable, 489 nss_output_disable,
490 #[cfg(any(spi_v4, spi_v5, spi_v6))]
491 nss_polarity,
456 } 492 }
457 } 493 }
458 494
@@ -769,7 +805,7 @@ impl<'d> Spi<'d, Async, Master> {
769 ) 805 )
770 } 806 }
771 807
772 /// Create a new SPI driver, in bidirectional mode, specifically in tranmit mode 808 /// Create a new SPI driver, in bidirectional mode, specifically in tranmit mode
773 #[cfg(any(spi_v1, spi_v2, spi_v3))] 809 #[cfg(any(spi_v1, spi_v2, spi_v3))]
774 pub fn new_bidi<T: Instance, #[cfg(afio)] A>( 810 pub fn new_bidi<T: Instance, #[cfg(afio)] A>(
775 peri: Peri<'d, T>, 811 peri: Peri<'d, T>,
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index 532877f70..88a28ee3d 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -4,7 +4,7 @@ use core::fmt::Display;
4use core::ops::{Div, Mul}; 4use core::ops::{Div, Mul};
5 5
6/// Hertz 6/// Hertz
7#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] 7#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default)]
8pub struct Hertz(pub u32); 8pub struct Hertz(pub u32);
9 9
10impl Display for Hertz { 10impl Display for Hertz {
diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs
index c88b1fe8d..d2cda631c 100644
--- a/examples/mcxa/src/bin/adc_interrupt.rs
+++ b/examples/mcxa/src/bin/adc_interrupt.rs
@@ -2,34 +2,31 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa_examples::init_adc_pins; 5use embassy_time::{Duration, Ticker};
6use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; 6use hal::adc::{Adc, InterruptHandler, LpadcConfig, TriggerPriorityPolicy};
7use hal::bind_interrupts;
7use hal::clocks::PoweredClock; 8use hal::clocks::PoweredClock;
9use hal::clocks::config::Div8;
8use hal::clocks::periph_helpers::{AdcClockSel, Div4}; 10use hal::clocks::periph_helpers::{AdcClockSel, Div4};
11use hal::config::Config;
9use hal::pac::adc1::cfg::{Pwrsel, Refsel}; 12use hal::pac::adc1::cfg::{Pwrsel, Refsel};
10use hal::pac::adc1::cmdl1::{Adch, Mode}; 13use hal::pac::adc1::cmdl1::Mode;
11use hal::pac::adc1::ctrl::CalAvgs; 14use hal::pac::adc1::ctrl::CalAvgs;
12use hal::pac::adc1::tctrl::Tcmd; 15use hal::peripherals::ADC1;
13use hal::{InterruptExt, bind_interrupts};
14use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 16use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
15 17
16bind_interrupts!(struct Irqs { 18bind_interrupts!(struct Irqs {
17 ADC1 => hal::adc::AdcHandler; 19 ADC1 => InterruptHandler<ADC1>;
18}); 20});
19 21
20#[used]
21#[no_mangle]
22static KEEP_ADC: unsafe extern "C" fn() = ADC1;
23
24#[embassy_executor::main] 22#[embassy_executor::main]
25async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
26 let p = hal::init(hal::config::Config::default()); 24 let mut config = Config::default();
25 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
27 26
28 defmt::info!("ADC interrupt Example"); 27 let p = hal::init(config);
29 28
30 unsafe { 29 defmt::info!("ADC interrupt Example");
31 init_adc_pins();
32 }
33 30
34 let adc_config = LpadcConfig { 31 let adc_config = LpadcConfig {
35 enable_in_doze_mode: true, 32 enable_in_doze_mode: true,
@@ -41,44 +38,28 @@ async fn main(_spawner: Spawner) {
41 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, 38 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
42 enable_conv_pause: false, 39 enable_conv_pause: false,
43 conv_pause_delay: 0, 40 conv_pause_delay: 0,
44 fifo_watermark: 0,
45 power: PoweredClock::NormalEnabledDeepSleepDisabled, 41 power: PoweredClock::NormalEnabledDeepSleepDisabled,
46 source: AdcClockSel::FroLfDiv, 42 source: AdcClockSel::FroLfDiv,
47 div: Div4::no_div(), 43 div: Div4::no_div(),
48 }; 44 };
49 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); 45 let mut adc = Adc::new_async(p.ADC1, p.P1_10, Irqs, adc_config).unwrap();
50 46
51 adc.do_offset_calibration(); 47 adc.do_offset_calibration();
52 adc.do_auto_calibration(); 48 adc.do_auto_calibration();
53 49 adc.set_resolution(Mode::Data16Bits);
54 let mut conv_command_config = adc.get_default_conv_command_config();
55 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8;
56 conv_command_config.conversion_resolution_mode = Mode::Data16Bits;
57 adc.set_conv_command_config(1, &conv_command_config);
58
59 let mut conv_trigger_config = adc.get_default_conv_trigger_config();
60 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1;
61 conv_trigger_config.enable_hardware_trigger = false;
62 adc.set_conv_trigger_config(0, &conv_trigger_config);
63 50
64 defmt::info!("ADC configuration done..."); 51 defmt::info!("ADC configuration done...");
65 52 let mut ticker = Ticker::every(Duration::from_millis(100));
66 adc.enable_interrupt(0x1);
67
68 unsafe {
69 hal::interrupt::ADC1.enable();
70 }
71
72 unsafe {
73 cortex_m::interrupt::enable();
74 }
75 53
76 loop { 54 loop {
77 adc.do_software_trigger(1); 55 ticker.next().await;
78 while !adc.is_interrupt_triggered() { 56 match adc.read().await {
79 // Wait until the interrupt is triggered 57 Ok(value) => {
58 defmt::info!("ADC value: {}", value);
59 }
60 Err(e) => {
61 defmt::error!("ADC read error: {:?}", e);
62 }
80 } 63 }
81 defmt::info!("*** ADC interrupt TRIGGERED! ***");
82 //TBD need to print the value
83 } 64 }
84} 65}
diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs
index 07c50f224..5c4d5524c 100644
--- a/examples/mcxa/src/bin/adc_polling.rs
+++ b/examples/mcxa/src/bin/adc_polling.rs
@@ -2,12 +2,15 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa_examples::init_adc_pins; 5use embassy_mcxa::adc::{ConvCommandConfig, ConvTriggerConfig};
6use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; 6use embassy_time::{Duration, Ticker};
7use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy};
7use hal::clocks::PoweredClock; 8use hal::clocks::PoweredClock;
9use hal::clocks::config::Div8;
8use hal::clocks::periph_helpers::{AdcClockSel, Div4}; 10use hal::clocks::periph_helpers::{AdcClockSel, Div4};
11use hal::config::Config;
9use hal::pac::adc1::cfg::{Pwrsel, Refsel}; 12use hal::pac::adc1::cfg::{Pwrsel, Refsel};
10use hal::pac::adc1::cmdl1::{Adch, Mode}; 13use hal::pac::adc1::cmdl1::Mode;
11use hal::pac::adc1::ctrl::CalAvgs; 14use hal::pac::adc1::ctrl::CalAvgs;
12use hal::pac::adc1::tctrl::Tcmd; 15use hal::pac::adc1::tctrl::Tcmd;
13use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 16use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -16,11 +19,10 @@ const G_LPADC_RESULT_SHIFT: u32 = 0;
16 19
17#[embassy_executor::main] 20#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
19 let p = hal::init(hal::config::Config::default()); 22 let mut config = Config::default();
23 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
20 24
21 unsafe { 25 let p = hal::init(config);
22 init_adc_pins();
23 }
24 26
25 defmt::info!("=== ADC polling Example ==="); 27 defmt::info!("=== ADC polling Example ===");
26 28
@@ -34,35 +36,43 @@ async fn main(_spawner: Spawner) {
34 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, 36 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
35 enable_conv_pause: false, 37 enable_conv_pause: false,
36 conv_pause_delay: 0, 38 conv_pause_delay: 0,
37 fifo_watermark: 0,
38 power: PoweredClock::NormalEnabledDeepSleepDisabled, 39 power: PoweredClock::NormalEnabledDeepSleepDisabled,
39 source: AdcClockSel::FroLfDiv, 40 source: AdcClockSel::FroLfDiv,
40 div: Div4::no_div(), 41 div: Div4::no_div(),
41 }; 42 };
42 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); 43 let adc = Adc::new_blocking(p.ADC1, p.P1_10, adc_config).unwrap();
43 44
44 adc.do_offset_calibration(); 45 adc.do_offset_calibration();
45 adc.do_auto_calibration(); 46 adc.do_auto_calibration();
46 47
47 let mut conv_command_config = adc.get_default_conv_command_config(); 48 let conv_command_config = ConvCommandConfig {
48 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; 49 conversion_resolution_mode: Mode::Data16Bits,
49 conv_command_config.conversion_resolution_mode = Mode::Data16Bits; 50 ..ConvCommandConfig::default()
50 adc.set_conv_command_config(1, &conv_command_config); 51 };
52 adc.set_conv_command_config(1, &conv_command_config).unwrap();
51 53
52 let mut conv_trigger_config = adc.get_default_conv_trigger_config(); 54 let conv_trigger_config = ConvTriggerConfig {
53 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; 55 target_command_id: Tcmd::ExecuteCmd1,
54 conv_trigger_config.enable_hardware_trigger = false; 56 enable_hardware_trigger: false,
55 adc.set_conv_trigger_config(0, &conv_trigger_config); 57 ..Default::default()
58 };
59 adc.set_conv_trigger_config(0, &conv_trigger_config).unwrap();
56 60
57 defmt::info!("=== ADC configuration done... ==="); 61 defmt::info!("=== ADC configuration done... ===");
62 let mut tick = Ticker::every(Duration::from_millis(100));
58 63
59 loop { 64 loop {
60 adc.do_software_trigger(1); 65 tick.next().await;
61 let mut result: Option<ConvResult> = None; 66 adc.do_software_trigger(1).unwrap();
62 while result.is_none() { 67 let result = loop {
63 result = hal::adc::get_conv_result(); 68 match adc.get_conv_result() {
64 } 69 Ok(res) => break res,
65 let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; 70 Err(_) => {
66 defmt::info!("value: {=u16}", value); 71 // Conversion not ready, continue polling
72 }
73 }
74 };
75 let value = result.conv_value >> G_LPADC_RESULT_SHIFT;
76 defmt::info!("ADC value: {=u16}", value);
67 } 77 }
68} 78}
diff --git a/examples/mcxa/src/bin/clkout.rs b/examples/mcxa/src/bin/clkout.rs
index bfd963540..1e52912d3 100644
--- a/examples/mcxa/src/bin/clkout.rs
+++ b/examples/mcxa/src/bin/clkout.rs
@@ -4,8 +4,7 @@
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4}; 5use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4};
6use embassy_mcxa::clocks::PoweredClock; 6use embassy_mcxa::clocks::PoweredClock;
7use embassy_mcxa::gpio::{DriveStrength, SlewRate}; 7use embassy_mcxa::gpio::{DriveStrength, Level, Output, SlewRate};
8use embassy_mcxa::{Level, Output};
9use embassy_time::Timer; 8use embassy_time::Timer;
10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11 10
diff --git a/examples/mcxa/src/bin/i2c-scan-blocking.rs b/examples/mcxa/src/bin/i2c-scan-blocking.rs
index 0197f9b1d..bd706d712 100644
--- a/examples/mcxa/src/bin/i2c-scan-blocking.rs
+++ b/examples/mcxa/src/bin/i2c-scan-blocking.rs
@@ -2,8 +2,7 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa::Input; 5use embassy_mcxa::gpio::{Input, Pull};
6use embassy_mcxa::gpio::Pull;
7use embassy_time::Timer; 6use embassy_time::Timer;
8use hal::clocks::config::Div8; 7use hal::clocks::config::Div8;
9use hal::config::Config; 8use hal::config::Config;
diff --git a/examples/mcxa/src/bin/reset-reason.rs b/examples/mcxa/src/bin/reset-reason.rs
new file mode 100644
index 000000000..c244fbe04
--- /dev/null
+++ b/examples/mcxa/src/bin/reset-reason.rs
@@ -0,0 +1,15 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use hal::config::Config;
6use hal::reset_reason::reset_reason;
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let config = Config::default();
12 let _p = hal::init(config);
13
14 defmt::info!("Reset Reason: '{}'", reset_reason());
15}
diff --git a/examples/mcxa/src/lib.rs b/examples/mcxa/src/lib.rs
deleted file mode 100644
index 2573a6adc..000000000
--- a/examples/mcxa/src/lib.rs
+++ /dev/null
@@ -1,16 +0,0 @@
1#![no_std]
2#![allow(clippy::missing_safety_doc)]
3
4//! Shared board-specific helpers for the FRDM-MCXA276 examples.
5//! These live with the examples so the HAL stays generic.
6
7use hal::{clocks, pins};
8use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
9
10/// Initialize clocks and pin muxing for ADC.
11pub unsafe fn init_adc_pins() {
12 // NOTE: Lpuart has been updated to properly enable + reset its own clocks.
13 // GPIO has not.
14 _ = clocks::enable_and_reset::<hal::peripherals::PORT1>(&clocks::periph_helpers::NoConfig);
15 pins::configure_adc_pins();
16}
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index e39de4902..ef8d08b76 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -101,7 +101,7 @@ async fn main(spawner: Spawner) {
101 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) 101 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
102 .await 102 .await
103 { 103 {
104 info!("join failed with status={}", err.status); 104 info!("join failed: {:?}", err);
105 } 105 }
106 106
107 info!("waiting for link..."); 107 info!("waiting for link...");
diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs
index ce85f4b9a..069afc794 100644
--- a/examples/rp/src/bin/wifi_webrequest.rs
+++ b/examples/rp/src/bin/wifi_webrequest.rs
@@ -106,7 +106,7 @@ async fn main(spawner: Spawner) {
106 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) 106 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
107 .await 107 .await
108 { 108 {
109 info!("join failed with status={}", err.status); 109 info!("join failed: {:?}", err);
110 } 110 }
111 111
112 info!("waiting for link..."); 112 info!("waiting for link...");
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
index fe0f887bf..098fd6986 100644
--- a/examples/stm32f4/src/bin/sdmmc.rs
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -3,7 +3,8 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; 6use embassy_stm32::sdmmc::Sdmmc;
7use embassy_stm32::sdmmc::sd::{CmdBlock, DataBlock, StorageDevice};
7use embassy_stm32::time::{Hertz, mhz}; 8use embassy_stm32::time::{Hertz, mhz};
8use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; 9use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -57,31 +58,24 @@ async fn main(_spawner: Spawner) {
57 // Should print 400kHz for initialization 58 // Should print 400kHz for initialization
58 info!("Configured clock: {}", sdmmc.clock().0); 59 info!("Configured clock: {}", sdmmc.clock().0);
59 60
60 let mut err = None; 61 let mut cmd_block = CmdBlock::new();
61 loop { 62
62 match sdmmc.init_sd_card(mhz(24)).await { 63 let mut storage = StorageDevice::new_sd_card(&mut sdmmc, &mut cmd_block, mhz(24))
63 Ok(_) => break, 64 .await
64 Err(e) => { 65 .unwrap();
65 if err != Some(e) {
66 info!("waiting for card error, retrying: {:?}", e);
67 err = Some(e);
68 }
69 }
70 }
71 }
72 66
73 let card = unwrap!(sdmmc.card()); 67 let card = storage.card();
74 68
75 info!("Card: {:#?}", Debug2Format(card)); 69 info!("Card: {:#?}", Debug2Format(&card));
76 info!("Clock: {}", sdmmc.clock()); 70 info!("Clock: {}", storage.sdmmc.clock());
77 71
78 // Arbitrary block index 72 // Arbitrary block index
79 let block_idx = 16; 73 let block_idx = 16;
80 74
81 // SDMMC uses `DataBlock` instead of `&[u8]` to ensure 4 byte alignment required by the hardware. 75 // SDMMC uses `DataBlock` instead of `&[u8]` to ensure 4 byte alignment required by the hardware.
82 let mut block = DataBlock([0u8; 512]); 76 let mut block = DataBlock::new();
83 77
84 sdmmc.read_block(block_idx, &mut block).await.unwrap(); 78 storage.read_block(block_idx, &mut block).await.unwrap();
85 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); 79 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
86 80
87 if !ALLOW_WRITES { 81 if !ALLOW_WRITES {
@@ -91,17 +85,17 @@ async fn main(_spawner: Spawner) {
91 85
92 info!("Filling block with 0x55"); 86 info!("Filling block with 0x55");
93 block.fill(0x55); 87 block.fill(0x55);
94 sdmmc.write_block(block_idx, &block).await.unwrap(); 88 storage.write_block(block_idx, &block).await.unwrap();
95 info!("Write done"); 89 info!("Write done");
96 90
97 sdmmc.read_block(block_idx, &mut block).await.unwrap(); 91 storage.read_block(block_idx, &mut block).await.unwrap();
98 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); 92 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
99 93
100 info!("Filling block with 0xAA"); 94 info!("Filling block with 0xAA");
101 block.fill(0xAA); 95 block.fill(0xAA);
102 sdmmc.write_block(block_idx, &block).await.unwrap(); 96 storage.write_block(block_idx, &block).await.unwrap();
103 info!("Write done"); 97 info!("Write done");
104 98
105 sdmmc.read_block(block_idx, &mut block).await.unwrap(); 99 storage.read_block(block_idx, &mut block).await.unwrap();
106 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); 100 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
107} 101}
diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs
index 8809b5d0c..e5d261d89 100644
--- a/examples/stm32f7/src/bin/sdmmc.rs
+++ b/examples/stm32f7/src/bin/sdmmc.rs
@@ -4,6 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::sdmmc::Sdmmc; 6use embassy_stm32::sdmmc::Sdmmc;
7use embassy_stm32::sdmmc::sd::{CmdBlock, StorageDevice};
7use embassy_stm32::time::{Hertz, mhz}; 8use embassy_stm32::time::{Hertz, mhz};
8use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; 9use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -54,9 +55,13 @@ async fn main(_spawner: Spawner) {
54 // Should print 400kHz for initialization 55 // Should print 400kHz for initialization
55 info!("Configured clock: {}", sdmmc.clock().0); 56 info!("Configured clock: {}", sdmmc.clock().0);
56 57
57 unwrap!(sdmmc.init_sd_card(mhz(25)).await); 58 let mut cmd_block = CmdBlock::new();
58 59
59 let card = unwrap!(sdmmc.card()); 60 let storage = StorageDevice::new_sd_card(&mut sdmmc, &mut cmd_block, mhz(25))
61 .await
62 .unwrap();
60 63
61 info!("Card: {:#?}", Debug2Format(card)); 64 let card = storage.card();
65
66 info!("Card: {:#?}", Debug2Format(&card));
62} 67}
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs
index 4977fec79..f2e5bedeb 100644
--- a/examples/stm32h7/src/bin/sdmmc.rs
+++ b/examples/stm32h7/src/bin/sdmmc.rs
@@ -4,6 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::sdmmc::Sdmmc; 6use embassy_stm32::sdmmc::Sdmmc;
7use embassy_stm32::sdmmc::sd::{CmdBlock, StorageDevice};
7use embassy_stm32::time::mhz; 8use embassy_stm32::time::mhz;
8use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; 9use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -13,7 +14,7 @@ bind_interrupts!(struct Irqs {
13}); 14});
14 15
15#[embassy_executor::main] 16#[embassy_executor::main]
16async fn main(_spawner: Spawner) -> ! { 17async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 18 let mut config = Config::default();
18 { 19 {
19 use embassy_stm32::rcc::*; 20 use embassy_stm32::rcc::*;
@@ -53,11 +54,13 @@ async fn main(_spawner: Spawner) -> ! {
53 // Should print 400kHz for initialization 54 // Should print 400kHz for initialization
54 info!("Configured clock: {}", sdmmc.clock().0); 55 info!("Configured clock: {}", sdmmc.clock().0);
55 56
56 unwrap!(sdmmc.init_sd_card(mhz(25)).await); 57 let mut cmd_block = CmdBlock::new();
57 58
58 let card = unwrap!(sdmmc.card()); 59 let storage = StorageDevice::new_sd_card(&mut sdmmc, &mut cmd_block, mhz(25))
60 .await
61 .unwrap();
59 62
60 info!("Card: {:#?}", Debug2Format(card)); 63 let card = storage.card();
61 64
62 loop {} 65 info!("Card: {:#?}", Debug2Format(&card));
63} 66}
diff --git a/examples/stm32n6/Cargo.toml b/examples/stm32n6/Cargo.toml
index 5ed28eed1..5ad5b97ce 100644
--- a/examples/stm32n6/Cargo.toml
+++ b/examples/stm32n6/Cargo.toml
@@ -32,6 +32,8 @@ micromath = "2.0.0"
32stm32-fmc = "0.3.0" 32stm32-fmc = "0.3.0"
33embedded-storage = "0.3.1" 33embedded-storage = "0.3.1"
34static_cell = "2" 34static_cell = "2"
35hmac = "0.12.1"
36sha2 = { version = "0.10.9", default-features = false }
35 37
36 38
37# cargo build/run 39# cargo build/run
diff --git a/examples/stm32n6/src/bin/crc.rs b/examples/stm32n6/src/bin/crc.rs
new file mode 100644
index 000000000..d1b545d5b
--- /dev/null
+++ b/examples/stm32n6/src/bin/crc.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::crc::{Config, Crc, InputReverseConfig, PolySize};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12 info!("Hello World!");
13
14 // Setup for: https://crccalc.com/?crc=Life, it never dieWomen are my favorite guy&method=crc32&datatype=ascii&outtype=0
15 let mut crc = Crc::new(
16 p.CRC,
17 unwrap!(Config::new(
18 InputReverseConfig::Byte,
19 true,
20 PolySize::Width32,
21 0xFFFFFFFF,
22 0x04C11DB7
23 )),
24 );
25
26 let output = crc.feed_bytes(b"Life, it never die\nWomen are my favorite guy") ^ 0xFFFFFFFF;
27
28 defmt::assert_eq!(output, 0x33F0E26B);
29
30 cortex_m::asm::bkpt();
31}
diff --git a/examples/stm32n6/src/bin/hash.rs b/examples/stm32n6/src/bin/hash.rs
new file mode 100644
index 000000000..9f248318f
--- /dev/null
+++ b/examples/stm32n6/src/bin/hash.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_stm32::hash::*;
7use embassy_stm32::{Config, bind_interrupts, hash, peripherals};
8use embassy_time::Instant;
9use hmac::{Hmac, Mac};
10use sha2::{Digest, Sha256};
11use {defmt_rtt as _, panic_probe as _};
12
13type HmacSha256 = Hmac<Sha256>;
14
15bind_interrupts!(struct Irqs {
16 HASH => hash::InterruptHandler<peripherals::HASH>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) -> ! {
21 let config = Config::default();
22 let p = embassy_stm32::init(config);
23
24 let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh";
25 let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr";
26
27 let mut hw_hasher = Hash::new_blocking(p.HASH, Irqs);
28
29 let hw_start_time = Instant::now();
30
31 // Compute a digest in hardware.
32 let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, None);
33 hw_hasher.update_blocking(&mut context, test_1);
34 hw_hasher.update_blocking(&mut context, test_2);
35 let mut hw_digest: [u8; 32] = [0; 32];
36 hw_hasher.finish_blocking(context, &mut hw_digest);
37
38 let hw_end_time = Instant::now();
39 let hw_execution_time = hw_end_time - hw_start_time;
40
41 let sw_start_time = Instant::now();
42
43 // Compute a digest in software.
44 let mut sw_hasher = Sha256::new();
45 sw_hasher.update(test_1);
46 sw_hasher.update(test_2);
47 let sw_digest = sw_hasher.finalize();
48
49 let sw_end_time = Instant::now();
50 let sw_execution_time = sw_end_time - sw_start_time;
51
52 info!("Hardware Digest: {:?}", hw_digest);
53 info!("Software Digest: {:?}", sw_digest[..]);
54 info!("Hardware Execution Time: {:?}", hw_execution_time);
55 info!("Software Execution Time: {:?}", sw_execution_time);
56 assert_eq!(hw_digest, sw_digest[..]);
57
58 let hmac_key: [u8; 64] = [0x55; 64];
59
60 // Compute HMAC in hardware.
61 let mut sha256hmac_context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, Some(&hmac_key));
62 hw_hasher.update_blocking(&mut sha256hmac_context, test_1);
63 hw_hasher.update_blocking(&mut sha256hmac_context, test_2);
64 let mut hw_hmac: [u8; 32] = [0; 32];
65 hw_hasher.finish_blocking(sha256hmac_context, &mut hw_hmac);
66
67 // Compute HMAC in software.
68 let mut sw_mac = HmacSha256::new_from_slice(&hmac_key).unwrap();
69 sw_mac.update(test_1);
70 sw_mac.update(test_2);
71 let sw_hmac = sw_mac.finalize().into_bytes();
72
73 info!("Hardware HMAC: {:?}", hw_hmac);
74 info!("Software HMAC: {:?}", sw_hmac[..]);
75 assert_eq!(hw_hmac, sw_hmac[..]);
76
77 loop {}
78}
diff --git a/examples/stm32wba/src/bin/rtc.rs b/examples/stm32wba/src/bin/rtc.rs
new file mode 100644
index 000000000..cef8501e0
--- /dev/null
+++ b/examples/stm32wba/src/bin/rtc.rs
@@ -0,0 +1,62 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::Config;
7use embassy_stm32::rcc::*;
8use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig};
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12pub fn pll_init(config: &mut Config) {
13 config.rcc.pll1 = Some(embassy_stm32::rcc::Pll {
14 source: PllSource::HSI,
15 prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz
16 mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO
17 divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk)
18 // divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED)
19 divq: None,
20 divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG)
21 frac: Some(0), // Fractional part (enabled)
22 });
23
24 config.rcc.ahb_pre = AHBPrescaler::DIV1;
25 config.rcc.apb1_pre = APBPrescaler::DIV1;
26 config.rcc.apb2_pre = APBPrescaler::DIV1;
27 config.rcc.apb7_pre = APBPrescaler::DIV1;
28 config.rcc.ahb5_pre = AHB5Prescaler::DIV4;
29
30 // voltage scale for max performance
31 config.rcc.voltage_scale = VoltageScale::RANGE1;
32 // route PLL1_P into the USB‐OTG‐HS block
33 config.rcc.sys = Sysclk::PLL1_R;
34}
35
36#[embassy_executor::main]
37async fn main(_spawner: Spawner) {
38 let mut config = Config::default();
39
40 pll_init(&mut config);
41
42 let p = embassy_stm32::init(config);
43
44 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
45
46 // Setting datetime
47 let initial_datetime = DateTime::from(1970, 1, 1, DayOfWeek::Thursday, 0, 00, 00, 0).unwrap();
48 match rtc.0.set_datetime(initial_datetime) {
49 Ok(()) => info!("RTC set successfully."),
50 Err(e) => error!("Failed to set RTC date/time: {:?}", e),
51 }
52
53 // Reading datetime every 1s
54 loop {
55 match rtc.1.now() {
56 Ok(result) => info!("{}", result),
57 Err(e) => error!("Failed to set RTC date/time: {:?}", e),
58 }
59
60 Timer::after_millis(1000).await;
61 }
62}
diff --git a/examples/stm32wba6/src/bin/rtc.rs b/examples/stm32wba6/src/bin/rtc.rs
new file mode 100644
index 000000000..cef8501e0
--- /dev/null
+++ b/examples/stm32wba6/src/bin/rtc.rs
@@ -0,0 +1,62 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::Config;
7use embassy_stm32::rcc::*;
8use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig};
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12pub fn pll_init(config: &mut Config) {
13 config.rcc.pll1 = Some(embassy_stm32::rcc::Pll {
14 source: PllSource::HSI,
15 prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz
16 mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO
17 divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk)
18 // divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED)
19 divq: None,
20 divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG)
21 frac: Some(0), // Fractional part (enabled)
22 });
23
24 config.rcc.ahb_pre = AHBPrescaler::DIV1;
25 config.rcc.apb1_pre = APBPrescaler::DIV1;
26 config.rcc.apb2_pre = APBPrescaler::DIV1;
27 config.rcc.apb7_pre = APBPrescaler::DIV1;
28 config.rcc.ahb5_pre = AHB5Prescaler::DIV4;
29
30 // voltage scale for max performance
31 config.rcc.voltage_scale = VoltageScale::RANGE1;
32 // route PLL1_P into the USB‐OTG‐HS block
33 config.rcc.sys = Sysclk::PLL1_R;
34}
35
36#[embassy_executor::main]
37async fn main(_spawner: Spawner) {
38 let mut config = Config::default();
39
40 pll_init(&mut config);
41
42 let p = embassy_stm32::init(config);
43
44 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
45
46 // Setting datetime
47 let initial_datetime = DateTime::from(1970, 1, 1, DayOfWeek::Thursday, 0, 00, 00, 0).unwrap();
48 match rtc.0.set_datetime(initial_datetime) {
49 Ok(()) => info!("RTC set successfully."),
50 Err(e) => error!("Failed to set RTC date/time: {:?}", e),
51 }
52
53 // Reading datetime every 1s
54 loop {
55 match rtc.1.now() {
56 Ok(result) => info!("{}", result),
57 Err(e) => error!("Failed to set RTC date/time: {:?}", e),
58 }
59
60 Timer::after_millis(1000).await;
61 }
62}
diff --git a/fmtall.sh b/fmtall.sh
new file mode 100755
index 000000000..9cadcdbe9
--- /dev/null
+++ b/fmtall.sh
@@ -0,0 +1,13 @@
1#!/bin/bash
2
3set -euo pipefail
4
5# We need the nightly toolchain for this
6mv rust-toolchain-nightly.toml rust-toolchain.toml
7
8# Similar to the CI workflow, but don't just CHECK, actualy DO the formatting
9find . -name '*.rs' -not -path '*target*' | xargs rustfmt --skip-children --unstable-features --edition 2024
10
11# Put the toolchains back, copy back to nightly and do a clean checkout of rust-toolchain
12mv rust-toolchain.toml rust-toolchain-nightly.toml
13git checkout -- rust-toolchain.toml
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index 9487f5e1a..1ef9cf066 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -98,7 +98,7 @@ async fn main(spawner: Spawner) {
98 { 98 {
99 Ok(_) => break, 99 Ok(_) => break,
100 Err(err) => { 100 Err(err) => {
101 panic!("join failed with status={}", err.status); 101 panic!("join failed: {:?}", err);
102 } 102 }
103 } 103 }
104 } 104 }
diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs
index 9f9c526e1..07422c42e 100644
--- a/tests/stm32/src/bin/sdmmc.rs
+++ b/tests/stm32/src/bin/sdmmc.rs
@@ -7,7 +7,8 @@ mod common;
7use common::*; 7use common::*;
8use defmt::assert_eq; 8use defmt::assert_eq;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; 10use embassy_stm32::sdmmc::Sdmmc;
11use embassy_stm32::sdmmc::sd::{CmdBlock, DataBlock, StorageDevice};
11use embassy_stm32::time::mhz; 12use embassy_stm32::time::mhz;
12use embassy_stm32::{bind_interrupts, peripherals, sdmmc}; 13use embassy_stm32::{bind_interrupts, peripherals, sdmmc};
13use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
@@ -28,16 +29,16 @@ async fn main(_spawner: Spawner) {
28 // Arbitrary block index 29 // Arbitrary block index
29 let block_idx = 16; 30 let block_idx = 16;
30 31
31 let mut pattern1 = DataBlock([0u8; 512]); 32 let mut pattern1 = DataBlock::new();
32 let mut pattern2 = DataBlock([0u8; 512]); 33 let mut pattern2 = DataBlock::new();
33 for i in 0..512 { 34 for i in 0..512 {
34 pattern1[i] = i as u8; 35 pattern1[i] = i as u8;
35 pattern2[i] = !i as u8; 36 pattern2[i] = !i as u8;
36 } 37 }
37 let patterns = [pattern1.clone(), pattern2.clone()]; 38 let patterns = [pattern1.clone(), pattern2.clone()];
38 39
39 let mut block = DataBlock([0u8; 512]); 40 let mut block = DataBlock::new();
40 let mut blocks = [DataBlock([0u8; 512]), DataBlock([0u8; 512])]; 41 let mut blocks = [DataBlock::new(), DataBlock::new()];
41 42
42 // ======== Try 4bit. ============== 43 // ======== Try 4bit. ==============
43 info!("initializing in 4-bit mode..."); 44 info!("initializing in 4-bit mode...");
@@ -54,43 +55,80 @@ async fn main(_spawner: Spawner) {
54 Default::default(), 55 Default::default(),
55 ); 56 );
56 57
57 let mut err = None; 58 let mut cmd_block = CmdBlock::new();
58 loop {
59 match s.init_sd_card(mhz(24)).await {
60 Ok(_) => break,
61 Err(e) => {
62 if err != Some(e) {
63 info!("waiting for card: {:?}", e);
64 err = Some(e);
65 }
66 }
67 }
68 }
69 59
70 let card = unwrap!(s.card()); 60 let mut storage = loop {
71 61 if let Ok(storage) = StorageDevice::new_sd_card(&mut s, &mut cmd_block, mhz(24)).await {
72 info!("Card: {:#?}", Debug2Format(card)); 62 break storage;
73 info!("Clock: {}", s.clock()); 63 }
64 };
65
66 let card = storage.card();
67
68 info!("Card: {:#?}", Debug2Format(&card));
69 info!("Clock: {}", storage.sdmmc.clock());
70
71 // card_type: HighCapacity,
72 // ocr: OCR: Operation Conditions Register {
73 // Voltage Window (mV): (2700, 3600),
74 // S18A (UHS-I only): true,
75 // Over 2TB flag (SDUC only): false,
76 // UHS-II Card: false,
77 // Card Capacity Status (CSS): \"SDHC/SDXC/SDUC\",
78 // Busy: false },
79 // rca: 43690,
80 // cid: CID: Card Identification { Manufacturer ID: 3,
81 // OEM ID: \"SD\",
82 // Product Name: \"SL08G\",
83 // Product Revision: 128,
84 // Product Serial Number: 701445767,
85 // Manufacturing Date: (9,
86 // 2015) },
87 // csd: CSD: Card Specific Data { Transfer Rate: 50,
88 // Block Count: 15523840,
89 // Card Size (bytes): 7948206080,
90 // Read I (@min VDD): 100 mA,
91 // Write I (@min VDD): 10 mA,
92 // Read I (@max VDD): 5 mA,
93 // Write I (@max VDD): 45 mA,
94 // Erase Size (Blocks): 1 },
95 // scr: SCR: SD CARD Configuration Register { Version: Unknown,
96 // 1-bit width: false,
97 // 4-bit width: true },
98 // status: SD Status { Bus Width: One,
99 // Secured Mode: false,
100 // SD Memory Card Type: 0,
101 // Protected Area Size (B): 0,
102 // Speed Class: 0,
103 // Video Speed Class: 0,
104 // Application Performance Class: 0,
105 // Move Performance (MB/s): 0,
106 // AU Size: 0,
107 // Erase Size (units of AU): 0,
108 // Erase Timeout (s): 0,
109 // Discard Support: false } }
110
111 defmt::assert!(card.scr.bus_width_four());
74 112
75 info!("writing pattern1..."); 113 info!("writing pattern1...");
76 s.write_block(block_idx, &pattern1).await.unwrap(); 114 storage.write_block(block_idx, &pattern1).await.unwrap();
77 115
78 info!("reading..."); 116 info!("reading...");
79 s.read_block(block_idx, &mut block).await.unwrap(); 117 storage.read_block(block_idx, &mut block).await.unwrap();
80 assert_eq!(block, pattern1); 118 assert_eq!(block, pattern1);
81 119
82 info!("writing pattern2..."); 120 info!("writing pattern2...");
83 s.write_block(block_idx, &pattern2).await.unwrap(); 121 storage.write_block(block_idx, &pattern2).await.unwrap();
84 122
85 info!("reading..."); 123 info!("reading...");
86 s.read_block(block_idx, &mut block).await.unwrap(); 124 storage.read_block(block_idx, &mut block).await.unwrap();
87 assert_eq!(block, pattern2); 125 assert_eq!(block, pattern2);
88 126
89 info!("writing blocks [pattern1, pattern2]..."); 127 info!("writing blocks [pattern1, pattern2]...");
90 s.write_blocks(block_idx, &patterns).await.unwrap(); 128 storage.write_blocks(block_idx, &patterns).await.unwrap();
91 129
92 info!("reading blocks..."); 130 info!("reading blocks...");
93 s.read_blocks(block_idx, &mut blocks).await.unwrap(); 131 storage.read_blocks(block_idx, &mut blocks).await.unwrap();
94 assert_eq!(&blocks, &patterns); 132 assert_eq!(&blocks, &patterns);
95 133
96 drop(s); 134 drop(s);
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index 0b98d3eeb..ef7efe96a 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -6,6 +6,7 @@ mod common;
6use common::*; 6use common::*;
7use defmt::{assert, assert_eq, unreachable}; 7use defmt::{assert, assert_eq, unreachable};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::mode::Blocking;
9use embassy_stm32::usart::{Config, ConfigError, Error, Uart}; 10use embassy_stm32::usart::{Config, ConfigError, Error, Uart};
10use embassy_time::{Duration, Instant, block_for}; 11use embassy_time::{Duration, Instant, block_for};
11 12
@@ -24,22 +25,41 @@ async fn main(_spawner: Spawner) {
24 let config = Config::default(); 25 let config = Config::default();
25 let mut usart = Uart::new_blocking(usart.reborrow(), rx.reborrow(), tx.reborrow(), config).unwrap(); 26 let mut usart = Uart::new_blocking(usart.reborrow(), rx.reborrow(), tx.reborrow(), config).unwrap();
26 27
27 // We can't send too many bytes, they have to fit in the FIFO. 28 let test_usart = async |usart: &mut Uart<'_, Blocking>| -> Result<(), Error> {
28 // This is because we aren't sending+receiving at the same time. 29 // We can't send too many bytes, they have to fit in the FIFO.
30 // This is because we aren't sending+receiving at the same time.
29 31
30 let data = [0xC0, 0xDE]; 32 let data = [0xC0, 0xDE];
31 usart.blocking_write(&data).unwrap(); 33 usart.blocking_write(&data)?;
32 34
33 let mut buf = [0; 2]; 35 let mut buf = [0; 2];
34 usart.blocking_read(&mut buf).unwrap(); 36 usart.blocking_read(&mut buf)?;
35 assert_eq!(buf, data); 37 assert_eq!(buf, data);
36 38
37 // Test flush doesn't hang. 39 // Test flush doesn't hang.
38 usart.blocking_write(&data).unwrap(); 40 usart.blocking_write(&data)?;
39 usart.blocking_flush().unwrap(); 41 usart.blocking_flush()?;
40 42
41 // Test flush doesn't hang if there's nothing to flush 43 // Test flush doesn't hang if there's nothing to flush
42 usart.blocking_flush().unwrap(); 44 usart.blocking_flush()?;
45
46 Ok(())
47 };
48
49 let mut is_ok = false;
50 for _ in 0..3 {
51 match test_usart(&mut usart).await {
52 Ok(()) => is_ok = true,
53 Err(Error::Noise) => is_ok = false,
54 Err(e) => defmt::panic!("{}", e),
55 }
56
57 if is_ok {
58 break;
59 }
60 }
61
62 assert!(is_ok);
43 } 63 }
44 64
45 // Test error handling with with an overflow error 65 // Test error handling with with an overflow error