1use crate::spi::{InnerDelay, SpiBusWrapper, SpiInitError};
2use esp_hal::gpio::{Level, Output, OutputConfig};
3use esp_hal::peripherals::GPIO16;
4
5use embedded_timers::{clock::Clock, instant::TimespecInstant};
6use sdmmc;
7
8pub struct SdDelay(pub InnerDelay);
17
18#[cfg(feature = "blocking")]
19impl embedded_hal::delay::DelayNs for SdDelay {
20 fn delay_ns(&mut self, ns: u32) {
21 self.0.delay_ns(ns)
22 }
23}
24
25#[cfg(feature = "async")]
26impl sdmmc::delay::Delay for SdDelay {
27 type Future = embassy_time::Timer;
28
29 fn delay_ms(&mut self, ms: u32) -> Self::Future {
30 let _ = &mut self.0;
31 embassy_time::Timer::after_millis(ms as u64)
32 }
33}
34
35pub struct SdClock;
43
44impl Clock for SdClock {
45 type Instant = TimespecInstant;
46
47 fn now(&self) -> Self::Instant {
48 #[cfg(feature = "async")]
49 let now = embassy_time::Instant::now().as_millis();
50 #[cfg(feature = "blocking")]
51 let now = esp_hal::time::Instant::now()
52 .duration_since_epoch()
53 .as_millis();
54 TimespecInstant::new((now / 1000) as u32, ((now % 1000) * 1_000_000) as u32)
55 }
56}
57
58pub struct SdSpi<'a>(pub &'a SpiBusWrapper);
63
64pub type SdBus<'a> = sdmmc::bus::spi::Bus<SdSpi<'a>, SdChipSelect<'a>, SdClock>;
66
67pub struct SdChipSelect<'a>(Output<'a>);
69impl<'a> SdChipSelect<'a> {
70 pub fn new(pin: GPIO16<'a>) -> Self {
71 Self(Output::new(pin, Level::High, OutputConfig::default()))
72 }
73}
74impl embedded_hal::digital::ErrorType for SdChipSelect<'_> {
75 type Error = core::convert::Infallible;
76}
77impl embedded_hal::digital::OutputPin for SdChipSelect<'_> {
78 fn set_low(&mut self) -> Result<(), Self::Error> {
79 self.0.set_low();
80 Ok(())
81 }
82 fn set_high(&mut self) -> Result<(), Self::Error> {
83 self.0.set_high();
84 Ok(())
85 }
86}
87impl Drop for SdChipSelect<'_> {
88 fn drop(&mut self) {
89 self.0.set_high();
90 }
91}
92
93pub type SDC<'a> = sdmmc::SD<SdBus<'a>>;
113pub type SdVolMgr<'a> = SDC<'a>;
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum SdInitError {
123 SpiDevice(SpiInitError),
125 CardInitFailed,
127}
128
129#[cfg(feature = "AtomicBus")]
130compile_error!("AtomicBus is not supported with async-sdmmc");
131
132impl SdInitError {
133 pub const fn as_str(self) -> &'static str {
135 match self {
136 Self::SpiDevice(err) => err.as_str(),
137 Self::CardInitFailed => "SD card init failed",
138 }
139 }
140}
141
142#[cfg(feature = "blocking")]
144fn transfer_blocking(
145 bus: &mut crate::spi::SpiBusInner,
146 tx: &[u8],
147 rx: &mut [u8],
148) -> Result<(), SpiInitError> {
149 let tail = crate::sd_wire::prepare_read(tx, rx);
150 if !rx.is_empty() {
151 embedded_hal::spi::SpiBus::transfer_in_place(bus, rx)
152 .map_err(|_| SpiInitError::DeviceInitFailed)?;
153 }
154 if !tail.is_empty() {
155 embedded_hal::spi::SpiBus::write(bus, tail).map_err(|_| SpiInitError::DeviceInitFailed)?;
156 }
157 Ok(())
158}
159
160#[cfg(feature = "blocking")]
161impl<'a> sdmmc::bus::spi::Transfer for SdSpi<'a> {
162 type Error = SpiInitError;
163 fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
164 #[cfg(feature = "RefCellBus")]
165 {
166 transfer_blocking(&mut self.0.borrow_mut(), tx, rx)
167 }
168 #[cfg(feature = "CriticalSectionBus")]
169 {
170 critical_section::with(|cs| {
171 transfer_blocking(&mut self.0.borrow(cs).borrow_mut(), tx, rx)
172 })
173 }
174 }
175}
176
177#[cfg(feature = "async")]
178impl<'a> sdmmc::bus::spi::Transfer for SdSpi<'a> {
179 type Error = SpiInitError;
180 async fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
181 let mut bus = self.0.lock().await;
182 let tail = crate::sd_wire::prepare_read(tx, rx);
183 if !rx.is_empty() {
184 embedded_hal_async::spi::SpiBus::transfer_in_place(&mut *bus, rx)
185 .await
186 .map_err(|_| SpiInitError::DeviceInitFailed)?;
187 }
188 if !tail.is_empty() {
189 embedded_hal_async::spi::SpiBus::write(&mut *bus, tail)
190 .await
191 .map_err(|_| SpiInitError::DeviceInitFailed)?;
192 }
193 Ok(())
194 }
195}
196
197#[cfg_attr(not(feature = "async"), deasync::deasync)]
198async fn set_frequency(
199 bus: &SpiBusWrapper,
200 frequency: esp_hal::time::Rate,
201) -> Result<(), SdInitError> {
202 let config = esp_hal::spi::master::Config::default().with_frequency(frequency);
203 #[cfg(all(feature = "blocking", feature = "RefCellBus"))]
204 let result = bus.borrow_mut().apply_config(&config);
205 #[cfg(all(feature = "blocking", feature = "CriticalSectionBus"))]
206 let result = critical_section::with(|cs| bus.borrow(cs).borrow_mut().apply_config(&config));
207 #[cfg(feature = "async")]
208 let result = bus.lock().await.apply_config(&config);
209 result.map_err(|_| SdInitError::SpiDevice(SpiInitError::BusInitFailed))
210}
211
212#[cfg_attr(not(feature = "async"), deasync::deasync)]
239pub async fn init_sd<'a>(
240 spi_bus: &'a SpiBusWrapper,
241 sd_cs: SdChipSelect<'a>,
242 delay: SdDelay,
243 frequency: fugit::HertzU32,
244) -> Result<SDC<'a>, SdInitError> {
245 use esp_hal::time::Rate;
246 set_frequency(spi_bus, Rate::from_khz(400)).await?;
249 let mut bus = SdBus::new(SdSpi(spi_bus), sd_cs, SdClock);
250 let card = match bus.init(delay).await {
251 Ok(card) => card,
252 Err(error) => {
253 esp_println::println!("SD identification failed at 400 kHz: {:?}", error);
254 set_frequency(spi_bus, Rate::from_hz(frequency.raw())).await?;
255 return Err(SdInitError::CardInitFailed);
256 }
257 };
258 let result = sdmmc::SD::init(bus, card).await.map_err(|error| {
259 esp_println::println!("SD card registers could not be read: {:?}", error);
260 SdInitError::CardInitFailed
261 });
262 set_frequency(spi_bus, Rate::from_hz(frequency.raw())).await?;
264 result
265}