diff options
| author | xoviat <[email protected]> | 2025-12-10 01:39:17 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-10 01:39:17 +0000 |
| commit | b1798e14d202a28ade6b9f2e985d4aaa0ad7c758 (patch) | |
| tree | ef69a8d6fc5bd1be2acca11f70b355e0d5d5a854 /embassy-stm32 | |
| parent | cf069b3e4e6a02660893ef8014e4ab69df6d46e0 (diff) | |
| parent | c5c7a2143b15530b0c8f08d1dd6e24a6985318f9 (diff) | |
Merge pull request #5018 from xoviat/sdio
stm32: refactor sdmmc module
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/dma/util.rs | 58 | ||||
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 1005 | ||||
| -rw-r--r-- | embassy-stm32/src/time.rs | 2 |
3 files changed, 591 insertions, 474 deletions
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/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 37ef7099f..ad00b4398 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -22,7 +22,7 @@ use crate::gpio::Pull; | |||
| 22 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; | 22 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; |
| 23 | use crate::interrupt::typelevel::Interrupt; | 23 | use crate::interrupt::typelevel::Interrupt; |
| 24 | use crate::pac::sdmmc::Sdmmc as RegBlock; | 24 | use crate::pac::sdmmc::Sdmmc as RegBlock; |
| 25 | use crate::rcc::{self, RccPeripheral}; | 25 | use crate::rcc::{self, RccInfo, RccPeripheral, SealedRccPeripheral}; |
| 26 | use crate::time::Hertz; | 26 | use crate::time::Hertz; |
| 27 | use crate::{interrupt, peripherals}; | 27 | use crate::{interrupt, peripherals}; |
| 28 | 28 | ||
| @@ -31,28 +31,11 @@ pub struct InterruptHandler<T: Instance> { | |||
| 31 | _phantom: PhantomData<T>, | 31 | _phantom: PhantomData<T>, |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | impl<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 | |||
| 51 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | 34 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 52 | unsafe fn on_interrupt() { | 35 | unsafe fn on_interrupt() { |
| 53 | T::state().wake(); | 36 | T::state().waker.wake(); |
| 54 | let status = T::regs().star().read(); | 37 | let status = T::info().regs.star().read(); |
| 55 | T::regs().maskr().modify(|w| { | 38 | T::info().regs.maskr().modify(|w| { |
| 56 | if status.dcrcfail() { | 39 | if status.dcrcfail() { |
| 57 | w.set_dcrcfailie(false) | 40 | w.set_dcrcfailie(false) |
| 58 | } | 41 | } |
| @@ -181,6 +164,76 @@ pub enum Error { | |||
| 181 | StBitErr, | 164 | StBitErr, |
| 182 | } | 165 | } |
| 183 | 166 | ||
| 167 | /// Represents either an SD or EMMC card | ||
| 168 | pub trait Addressable: Sized + Clone { | ||
| 169 | /// Associated type | ||
| 170 | type Ext; | ||
| 171 | |||
| 172 | /// Get this peripheral's address on the SDMMC bus | ||
| 173 | fn get_address(&self) -> u16; | ||
| 174 | |||
| 175 | /// Is this a standard or high capacity peripheral? | ||
| 176 | fn get_capacity(&self) -> CardCapacity; | ||
| 177 | |||
| 178 | /// Size in bytes | ||
| 179 | fn size(&self) -> u64; | ||
| 180 | } | ||
| 181 | |||
| 182 | /// Storage Device | ||
| 183 | pub struct StorageDevice<'a, 'b, T: Addressable> { | ||
| 184 | info: T, | ||
| 185 | /// Inner member | ||
| 186 | pub sdmmc: &'a mut Sdmmc<'b>, | ||
| 187 | } | ||
| 188 | |||
| 189 | /// Card Storage Device | ||
| 190 | impl<'a, 'b> StorageDevice<'a, 'b, Card> { | ||
| 191 | /// Create a new SD card | ||
| 192 | pub async fn new_sd_card(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | ||
| 193 | let info = sdmmc.init_sd_card(cmd_block, freq).await?; | ||
| 194 | |||
| 195 | Ok(Self { info, sdmmc }) | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | /// Emmc storage device | ||
| 200 | impl<'a, 'b> StorageDevice<'a, 'b, Emmc> { | ||
| 201 | /// Create a new EMMC card | ||
| 202 | pub async fn new_emmc(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | ||
| 203 | let info = sdmmc.init_emmc(cmd_block, freq).await?; | ||
| 204 | |||
| 205 | Ok(Self { info, sdmmc }) | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | /// Card or Emmc storage device | ||
| 210 | impl<'a, 'b, T: Addressable> StorageDevice<'a, 'b, T> { | ||
| 211 | /// Write a block | ||
| 212 | pub fn card(&self) -> T { | ||
| 213 | self.info.clone() | ||
| 214 | } | ||
| 215 | |||
| 216 | /// Write a block | ||
| 217 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | ||
| 218 | self.sdmmc.write_block(&mut self.info, block_idx, buffer).await | ||
| 219 | } | ||
| 220 | |||
| 221 | /// Write a block | ||
| 222 | pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> { | ||
| 223 | self.sdmmc.write_blocks(&mut self.info, block_idx, blocks).await | ||
| 224 | } | ||
| 225 | |||
| 226 | /// Read a block | ||
| 227 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 228 | self.sdmmc.read_block(&mut self.info, block_idx, buffer).await | ||
| 229 | } | ||
| 230 | |||
| 231 | /// Read a block | ||
| 232 | pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { | ||
| 233 | self.sdmmc.read_blocks(&mut self.info, block_idx, blocks).await | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 184 | #[derive(Clone, Copy, Debug, Default)] | 237 | #[derive(Clone, Copy, Debug, Default)] |
| 185 | /// SD Card | 238 | /// SD Card |
| 186 | pub struct Card { | 239 | pub struct Card { |
| @@ -200,6 +253,157 @@ pub struct Card { | |||
| 200 | pub status: SDStatus, | 253 | pub status: SDStatus, |
| 201 | } | 254 | } |
| 202 | 255 | ||
| 256 | impl Card { | ||
| 257 | /// Switch mode using CMD6. | ||
| 258 | /// | ||
| 259 | /// Attempt to set a new signalling mode. The selected | ||
| 260 | /// signalling mode is returned. Expects the current clock | ||
| 261 | /// frequency to be > 12.5MHz. | ||
| 262 | /// | ||
| 263 | /// SD only. | ||
| 264 | async fn switch_signalling_mode<'a>( | ||
| 265 | &mut self, | ||
| 266 | sdmmc: &mut Sdmmc<'a>, | ||
| 267 | cmd_block: &mut CmdBlock, | ||
| 268 | signalling: Signalling, | ||
| 269 | ) -> Result<Signalling, Error> { | ||
| 270 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | ||
| 271 | // necessary" | ||
| 272 | |||
| 273 | let set_function = 0x8000_0000 | ||
| 274 | | match signalling { | ||
| 275 | // See PLSS v7_10 Table 4-11 | ||
| 276 | Signalling::DDR50 => 0xFF_FF04, | ||
| 277 | Signalling::SDR104 => 0xFF_1F03, | ||
| 278 | Signalling::SDR50 => 0xFF_1F02, | ||
| 279 | Signalling::SDR25 => 0xFF_FF01, | ||
| 280 | Signalling::SDR12 => 0xFF_FF00, | ||
| 281 | }; | ||
| 282 | |||
| 283 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 284 | let on_drop = OnDrop::new(|| sdmmc.on_drop()); | ||
| 285 | |||
| 286 | let transfer = sdmmc.prepare_datapath_read(&sdmmc.config, cmd_block.as_mut(), 64, 6); | ||
| 287 | sdmmc.enable_interrupts(); | ||
| 288 | sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 | ||
| 289 | |||
| 290 | let res = sdmmc.complete_datapath_transfer(true).await; | ||
| 291 | |||
| 292 | // Host is allowed to use the new functions at least 8 | ||
| 293 | // clocks after the end of the switch command | ||
| 294 | // transaction. We know the current clock period is < 80ns, | ||
| 295 | // so a total delay of 640ns is required here | ||
| 296 | for _ in 0..300 { | ||
| 297 | cortex_m::asm::nop(); | ||
| 298 | } | ||
| 299 | |||
| 300 | match res { | ||
| 301 | Ok(_) => { | ||
| 302 | on_drop.defuse(); | ||
| 303 | sdmmc.stop_datapath(); | ||
| 304 | drop(transfer); | ||
| 305 | |||
| 306 | // Function Selection of Function Group 1 | ||
| 307 | let selection = (u32::from_be(cmd_block[4]) >> 24) & 0xF; | ||
| 308 | |||
| 309 | match selection { | ||
| 310 | 0 => Ok(Signalling::SDR12), | ||
| 311 | 1 => Ok(Signalling::SDR25), | ||
| 312 | 2 => Ok(Signalling::SDR50), | ||
| 313 | 3 => Ok(Signalling::SDR104), | ||
| 314 | 4 => Ok(Signalling::DDR50), | ||
| 315 | _ => Err(Error::UnsupportedCardType), | ||
| 316 | } | ||
| 317 | } | ||
| 318 | Err(e) => Err(e), | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | /// Reads the SCR register. | ||
| 323 | /// | ||
| 324 | /// SD only. | ||
| 325 | async fn get_scr<'a>(&mut self, sdmmc: &mut Sdmmc<'a>, cmd_block: &mut CmdBlock) -> Result<(), Error> { | ||
| 326 | // Read the 64-bit SCR register | ||
| 327 | sdmmc.cmd(common_cmd::set_block_length(8), false)?; // CMD16 | ||
| 328 | sdmmc.cmd(common_cmd::app_cmd(self.rca), false)?; | ||
| 329 | |||
| 330 | let scr = &mut cmd_block.0[..2]; | ||
| 331 | |||
| 332 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 333 | let on_drop = OnDrop::new(|| sdmmc.on_drop()); | ||
| 334 | |||
| 335 | let transfer = sdmmc.prepare_datapath_read(&sdmmc.config, scr, 8, 3); | ||
| 336 | sdmmc.enable_interrupts(); | ||
| 337 | sdmmc.cmd(sd_cmd::send_scr(), true)?; | ||
| 338 | |||
| 339 | let res = sdmmc.complete_datapath_transfer(true).await; | ||
| 340 | |||
| 341 | if res.is_ok() { | ||
| 342 | on_drop.defuse(); | ||
| 343 | sdmmc.stop_datapath(); | ||
| 344 | drop(transfer); | ||
| 345 | |||
| 346 | unsafe { | ||
| 347 | let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); | ||
| 348 | self.scr = SCR(u64::from_be_bytes(*scr_bytes)); | ||
| 349 | } | ||
| 350 | } | ||
| 351 | res | ||
| 352 | } | ||
| 353 | |||
| 354 | /// Reads the SD Status (ACMD13) | ||
| 355 | /// | ||
| 356 | /// SD only. | ||
| 357 | async fn read_sd_status<'a>(&mut self, sdmmc: &mut Sdmmc<'a>, cmd_block: &mut CmdBlock) -> Result<(), Error> { | ||
| 358 | let rca = self.rca; | ||
| 359 | |||
| 360 | sdmmc.cmd(common_cmd::set_block_length(64), false)?; // CMD16 | ||
| 361 | sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP | ||
| 362 | |||
| 363 | let status = cmd_block; | ||
| 364 | |||
| 365 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 366 | let on_drop = OnDrop::new(|| sdmmc.on_drop()); | ||
| 367 | |||
| 368 | let transfer = sdmmc.prepare_datapath_read(&sdmmc.config, status.as_mut(), 64, 6); | ||
| 369 | sdmmc.enable_interrupts(); | ||
| 370 | sdmmc.cmd(sd_cmd::sd_status(), true)?; | ||
| 371 | |||
| 372 | let res = sdmmc.complete_datapath_transfer(true).await; | ||
| 373 | |||
| 374 | if res.is_ok() { | ||
| 375 | on_drop.defuse(); | ||
| 376 | sdmmc.stop_datapath(); | ||
| 377 | drop(transfer); | ||
| 378 | |||
| 379 | for byte in status.iter_mut() { | ||
| 380 | *byte = u32::from_be(*byte); | ||
| 381 | } | ||
| 382 | self.status = status.0.into(); | ||
| 383 | } | ||
| 384 | res | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | impl Addressable for Card { | ||
| 389 | type Ext = SD; | ||
| 390 | |||
| 391 | /// Get this peripheral's address on the SDMMC bus | ||
| 392 | fn get_address(&self) -> u16 { | ||
| 393 | self.rca | ||
| 394 | } | ||
| 395 | |||
| 396 | /// Is this a standard or high capacity peripheral? | ||
| 397 | fn get_capacity(&self) -> CardCapacity { | ||
| 398 | self.card_type | ||
| 399 | } | ||
| 400 | |||
| 401 | /// Size in bytes | ||
| 402 | fn size(&self) -> u64 { | ||
| 403 | u64::from(self.csd.block_count()) * 512 | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 203 | #[derive(Clone, Copy, Debug, Default)] | 407 | #[derive(Clone, Copy, Debug, Default)] |
| 204 | /// eMMC storage | 408 | /// eMMC storage |
| 205 | pub struct Emmc { | 409 | pub struct Emmc { |
| @@ -217,6 +421,59 @@ pub struct Emmc { | |||
| 217 | pub ext_csd: ExtCSD, | 421 | pub ext_csd: ExtCSD, |
| 218 | } | 422 | } |
| 219 | 423 | ||
| 424 | impl Emmc { | ||
| 425 | /// Gets the EXT_CSD register. | ||
| 426 | /// | ||
| 427 | /// eMMC only. | ||
| 428 | async fn read_ext_csd<'a>(&mut self, sdmmc: &mut Sdmmc<'a>) -> Result<(), Error> { | ||
| 429 | // Note: cmd_block can't be used because ExtCSD is too long to fit. | ||
| 430 | let mut data_block = DataBlock([0u8; 512]); | ||
| 431 | |||
| 432 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 433 | let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 434 | |||
| 435 | sdmmc.cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 | ||
| 436 | |||
| 437 | let transfer = sdmmc.prepare_datapath_read(&sdmmc.config, buffer, 512, 9); | ||
| 438 | sdmmc.enable_interrupts(); | ||
| 439 | sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?; | ||
| 440 | |||
| 441 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 442 | let on_drop = OnDrop::new(|| sdmmc.on_drop()); | ||
| 443 | |||
| 444 | let res = sdmmc.complete_datapath_transfer(true).await; | ||
| 445 | |||
| 446 | if res.is_ok() { | ||
| 447 | on_drop.defuse(); | ||
| 448 | sdmmc.stop_datapath(); | ||
| 449 | drop(transfer); | ||
| 450 | |||
| 451 | self.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); | ||
| 452 | } | ||
| 453 | |||
| 454 | res | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | impl Addressable for Emmc { | ||
| 459 | type Ext = EMMC; | ||
| 460 | |||
| 461 | /// Get this peripheral's address on the SDMMC bus | ||
| 462 | fn get_address(&self) -> u16 { | ||
| 463 | self.rca | ||
| 464 | } | ||
| 465 | |||
| 466 | /// Is this a standard or high capacity peripheral? | ||
| 467 | fn get_capacity(&self) -> CardCapacity { | ||
| 468 | self.capacity | ||
| 469 | } | ||
| 470 | |||
| 471 | /// Size in bytes | ||
| 472 | fn size(&self) -> u64 { | ||
| 473 | u64::from(self.ext_csd.sector_count()) * 512 | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 220 | #[repr(u8)] | 477 | #[repr(u8)] |
| 221 | enum PowerCtrl { | 478 | enum PowerCtrl { |
| 222 | Off = 0b00, | 479 | Off = 0b00, |
| @@ -340,47 +597,13 @@ impl SdmmcPeripheral { | |||
| 340 | Self::Emmc(e) => e.rca, | 597 | Self::Emmc(e) => e.rca, |
| 341 | } | 598 | } |
| 342 | } | 599 | } |
| 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 | } | 600 | } |
| 380 | 601 | ||
| 381 | /// Sdmmc device | 602 | /// Sdmmc device |
| 382 | pub struct Sdmmc<'d, T: Instance> { | 603 | pub struct Sdmmc<'d> { |
| 383 | _peri: Peri<'d, T>, | 604 | info: &'static Info, |
| 605 | state: &'static State, | ||
| 606 | ker_clk: Hertz, | ||
| 384 | #[cfg(sdmmc_v1)] | 607 | #[cfg(sdmmc_v1)] |
| 385 | dma: ChannelAndRequest<'d>, | 608 | dma: ChannelAndRequest<'d>, |
| 386 | 609 | ||
| @@ -400,12 +623,6 @@ pub struct Sdmmc<'d, T: Instance> { | |||
| 400 | clock: Hertz, | 623 | clock: Hertz, |
| 401 | /// Current signalling scheme to card | 624 | /// Current signalling scheme to card |
| 402 | signalling: Signalling, | 625 | 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 | } | 626 | } |
| 410 | 627 | ||
| 411 | const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); | 628 | const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); |
| @@ -416,9 +633,9 @@ const CMD_AF: AfType = AfType::output_pull(OutputType::PushPull, Speed::VeryHigh | |||
| 416 | const DATA_AF: AfType = CMD_AF; | 633 | const DATA_AF: AfType = CMD_AF; |
| 417 | 634 | ||
| 418 | #[cfg(sdmmc_v1)] | 635 | #[cfg(sdmmc_v1)] |
| 419 | impl<'d, T: Instance> Sdmmc<'d, T> { | 636 | impl<'d> Sdmmc<'d> { |
| 420 | /// Create a new SDMMC driver, with 1 data lane. | 637 | /// Create a new SDMMC driver, with 1 data lane. |
| 421 | pub fn new_1bit( | 638 | pub fn new_1bit<T: Instance>( |
| 422 | sdmmc: Peri<'d, T>, | 639 | sdmmc: Peri<'d, T>, |
| 423 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 640 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 424 | dma: Peri<'d, impl SdmmcDma<T>>, | 641 | dma: Peri<'d, impl SdmmcDma<T>>, |
| @@ -451,7 +668,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 451 | } | 668 | } |
| 452 | 669 | ||
| 453 | /// Create a new SDMMC driver, with 4 data lanes. | 670 | /// Create a new SDMMC driver, with 4 data lanes. |
| 454 | pub fn new_4bit( | 671 | pub fn new_4bit<T: Instance>( |
| 455 | sdmmc: Peri<'d, T>, | 672 | sdmmc: Peri<'d, T>, |
| 456 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 673 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 457 | dma: Peri<'d, impl SdmmcDma<T>>, | 674 | dma: Peri<'d, impl SdmmcDma<T>>, |
| @@ -491,9 +708,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 491 | } | 708 | } |
| 492 | 709 | ||
| 493 | #[cfg(sdmmc_v1)] | 710 | #[cfg(sdmmc_v1)] |
| 494 | impl<'d, T: Instance> Sdmmc<'d, T> { | 711 | impl<'d> Sdmmc<'d> { |
| 495 | /// Create a new SDMMC driver, with 8 data lanes. | 712 | /// Create a new SDMMC driver, with 8 data lanes. |
| 496 | pub fn new_8bit( | 713 | pub fn new_8bit<T: Instance>( |
| 497 | sdmmc: Peri<'d, T>, | 714 | sdmmc: Peri<'d, T>, |
| 498 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 715 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 499 | dma: Peri<'d, impl SdmmcDma<T>>, | 716 | dma: Peri<'d, impl SdmmcDma<T>>, |
| @@ -541,9 +758,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 541 | } | 758 | } |
| 542 | 759 | ||
| 543 | #[cfg(sdmmc_v2)] | 760 | #[cfg(sdmmc_v2)] |
| 544 | impl<'d, T: Instance> Sdmmc<'d, T> { | 761 | impl<'d> Sdmmc<'d> { |
| 545 | /// Create a new SDMMC driver, with 1 data lane. | 762 | /// Create a new SDMMC driver, with 1 data lane. |
| 546 | pub fn new_1bit( | 763 | pub fn new_1bit<T: Instance>( |
| 547 | sdmmc: Peri<'d, T>, | 764 | sdmmc: Peri<'d, T>, |
| 548 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 765 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 549 | clk: Peri<'d, impl CkPin<T>>, | 766 | clk: Peri<'d, impl CkPin<T>>, |
| @@ -574,7 +791,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 574 | } | 791 | } |
| 575 | 792 | ||
| 576 | /// Create a new SDMMC driver, with 4 data lanes. | 793 | /// Create a new SDMMC driver, with 4 data lanes. |
| 577 | pub fn new_4bit( | 794 | pub fn new_4bit<T: Instance>( |
| 578 | sdmmc: Peri<'d, T>, | 795 | sdmmc: Peri<'d, T>, |
| 579 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 796 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 580 | clk: Peri<'d, impl CkPin<T>>, | 797 | clk: Peri<'d, impl CkPin<T>>, |
| @@ -612,9 +829,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 612 | } | 829 | } |
| 613 | 830 | ||
| 614 | #[cfg(sdmmc_v2)] | 831 | #[cfg(sdmmc_v2)] |
| 615 | impl<'d, T: Instance> Sdmmc<'d, T> { | 832 | impl<'d> Sdmmc<'d> { |
| 616 | /// Create a new SDMMC driver, with 8 data lanes. | 833 | /// Create a new SDMMC driver, with 8 data lanes. |
| 617 | pub fn new_8bit( | 834 | pub fn new_8bit<T: Instance>( |
| 618 | sdmmc: Peri<'d, T>, | 835 | sdmmc: Peri<'d, T>, |
| 619 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 836 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 620 | clk: Peri<'d, impl CkPin<T>>, | 837 | clk: Peri<'d, impl CkPin<T>>, |
| @@ -659,9 +876,24 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 659 | } | 876 | } |
| 660 | } | 877 | } |
| 661 | 878 | ||
| 662 | impl<'d, T: Instance> Sdmmc<'d, T> { | 879 | impl<'d> Sdmmc<'d> { |
| 663 | fn new_inner( | 880 | fn enable_interrupts(&self) { |
| 664 | sdmmc: Peri<'d, T>, | 881 | let regs = self.info.regs; |
| 882 | regs.maskr().write(|w| { | ||
| 883 | w.set_dcrcfailie(true); | ||
| 884 | w.set_dtimeoutie(true); | ||
| 885 | w.set_dataendie(true); | ||
| 886 | w.set_dbckendie(true); | ||
| 887 | |||
| 888 | #[cfg(sdmmc_v1)] | ||
| 889 | w.set_stbiterre(true); | ||
| 890 | #[cfg(sdmmc_v2)] | ||
| 891 | w.set_dabortie(true); | ||
| 892 | }); | ||
| 893 | } | ||
| 894 | |||
| 895 | fn new_inner<T: Instance>( | ||
| 896 | _sdmmc: Peri<'d, T>, | ||
| 665 | #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, | 897 | #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, |
| 666 | clk: Peri<'d, AnyPin>, | 898 | clk: Peri<'d, AnyPin>, |
| 667 | cmd: Peri<'d, AnyPin>, | 899 | cmd: Peri<'d, AnyPin>, |
| @@ -680,8 +912,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 680 | T::Interrupt::unpend(); | 912 | T::Interrupt::unpend(); |
| 681 | unsafe { T::Interrupt::enable() }; | 913 | unsafe { T::Interrupt::enable() }; |
| 682 | 914 | ||
| 683 | let regs = T::regs(); | 915 | let info = T::info(); |
| 684 | regs.clkcr().write(|w| { | 916 | let state = T::state(); |
| 917 | let ker_clk = T::frequency(); | ||
| 918 | |||
| 919 | info.regs.clkcr().write(|w| { | ||
| 685 | w.set_pwrsav(false); | 920 | w.set_pwrsav(false); |
| 686 | w.set_negedge(false); | 921 | w.set_negedge(false); |
| 687 | 922 | ||
| @@ -698,10 +933,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 698 | 933 | ||
| 699 | // Power off, writen 00: Clock to the card is stopped; | 934 | // Power off, writen 00: Clock to the card is stopped; |
| 700 | // D[7:0], CMD, and CK are driven high. | 935 | // D[7:0], CMD, and CK are driven high. |
| 701 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); | 936 | info.regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); |
| 702 | 937 | ||
| 703 | Self { | 938 | Self { |
| 704 | _peri: sdmmc, | 939 | info, |
| 940 | state, | ||
| 941 | ker_clk, | ||
| 705 | #[cfg(sdmmc_v1)] | 942 | #[cfg(sdmmc_v1)] |
| 706 | dma, | 943 | dma, |
| 707 | 944 | ||
| @@ -719,15 +956,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 719 | config, | 956 | config, |
| 720 | clock: SD_INIT_FREQ, | 957 | clock: SD_INIT_FREQ, |
| 721 | signalling: Default::default(), | 958 | signalling: Default::default(), |
| 722 | card: None, | ||
| 723 | cmd_block: None, | ||
| 724 | } | 959 | } |
| 725 | } | 960 | } |
| 726 | 961 | ||
| 727 | /// Data transfer is in progress | 962 | /// Data transfer is in progress |
| 728 | #[inline] | 963 | #[inline] |
| 729 | fn data_active() -> bool { | 964 | fn data_active(&self) -> bool { |
| 730 | let regs = T::regs(); | 965 | let regs = self.info.regs; |
| 731 | 966 | ||
| 732 | let status = regs.star().read(); | 967 | let status = regs.star().read(); |
| 733 | #[cfg(sdmmc_v1)] | 968 | #[cfg(sdmmc_v1)] |
| @@ -738,8 +973,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 738 | 973 | ||
| 739 | /// Coammand transfer is in progress | 974 | /// Coammand transfer is in progress |
| 740 | #[inline] | 975 | #[inline] |
| 741 | fn cmd_active() -> bool { | 976 | fn cmd_active(&self) -> bool { |
| 742 | let regs = T::regs(); | 977 | let regs = self.info.regs; |
| 743 | 978 | ||
| 744 | let status = regs.star().read(); | 979 | let status = regs.star().read(); |
| 745 | #[cfg(sdmmc_v1)] | 980 | #[cfg(sdmmc_v1)] |
| @@ -750,8 +985,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 750 | 985 | ||
| 751 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) | 986 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) |
| 752 | #[inline] | 987 | #[inline] |
| 753 | fn wait_idle() { | 988 | fn wait_idle(&self) { |
| 754 | while Self::data_active() || Self::cmd_active() {} | 989 | while self.data_active() || self.cmd_active() {} |
| 755 | } | 990 | } |
| 756 | 991 | ||
| 757 | /// # Safety | 992 | /// # Safety |
| @@ -759,23 +994,27 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 759 | /// `buffer` must be valid for the whole transfer and word aligned | 994 | /// `buffer` must be valid for the whole transfer and word aligned |
| 760 | #[allow(unused_variables)] | 995 | #[allow(unused_variables)] |
| 761 | fn prepare_datapath_read<'a>( | 996 | fn prepare_datapath_read<'a>( |
| 997 | &'a self, | ||
| 762 | config: &Config, | 998 | config: &Config, |
| 763 | #[cfg(sdmmc_v1)] dma: &'a mut ChannelAndRequest<'d>, | ||
| 764 | buffer: &'a mut [u32], | 999 | buffer: &'a mut [u32], |
| 765 | length_bytes: u32, | 1000 | length_bytes: u32, |
| 766 | block_size: u8, | 1001 | block_size: u8, |
| 767 | ) -> Transfer<'a> { | 1002 | ) -> Transfer<'a> { |
| 768 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 1003 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 769 | let regs = T::regs(); | 1004 | let regs = self.info.regs; |
| 770 | 1005 | ||
| 771 | // Command AND Data state machines must be idle | 1006 | // Command AND Data state machines must be idle |
| 772 | Self::wait_idle(); | 1007 | self.wait_idle(); |
| 773 | Self::clear_interrupt_flags(); | 1008 | self.clear_interrupt_flags(); |
| 774 | 1009 | ||
| 775 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 1010 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); |
| 776 | 1011 | ||
| 1012 | // SAFETY: No other functions use the dma | ||
| 777 | #[cfg(sdmmc_v1)] | 1013 | #[cfg(sdmmc_v1)] |
| 778 | let transfer = unsafe { dma.read(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) }; | 1014 | let transfer = unsafe { |
| 1015 | self.dma | ||
| 1016 | .read_unchecked(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) | ||
| 1017 | }; | ||
| 779 | #[cfg(sdmmc_v2)] | 1018 | #[cfg(sdmmc_v2)] |
| 780 | let transfer = { | 1019 | let transfer = { |
| 781 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); | 1020 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); |
| @@ -801,20 +1040,21 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 801 | /// # Safety | 1040 | /// # Safety |
| 802 | /// | 1041 | /// |
| 803 | /// `buffer` must be valid for the whole transfer and word aligned | 1042 | /// `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> { | 1043 | fn prepare_datapath_write<'a>(&'a self, buffer: &'a [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> { |
| 805 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 1044 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 806 | let regs = T::regs(); | 1045 | let regs = self.info.regs; |
| 807 | 1046 | ||
| 808 | // Command AND Data state machines must be idle | 1047 | // Command AND Data state machines must be idle |
| 809 | Self::wait_idle(); | 1048 | self.wait_idle(); |
| 810 | Self::clear_interrupt_flags(); | 1049 | self.clear_interrupt_flags(); |
| 811 | 1050 | ||
| 812 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 1051 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); |
| 813 | 1052 | ||
| 1053 | // SAFETY: No other functions use the dma | ||
| 814 | #[cfg(sdmmc_v1)] | 1054 | #[cfg(sdmmc_v1)] |
| 815 | let transfer = unsafe { | 1055 | let transfer = unsafe { |
| 816 | self.dma | 1056 | self.dma |
| 817 | .write(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) | 1057 | .write_unchecked(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) |
| 818 | }; | 1058 | }; |
| 819 | #[cfg(sdmmc_v2)] | 1059 | #[cfg(sdmmc_v2)] |
| 820 | let transfer = { | 1060 | let transfer = { |
| @@ -839,8 +1079,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 839 | } | 1079 | } |
| 840 | 1080 | ||
| 841 | /// Stops the DMA datapath | 1081 | /// Stops the DMA datapath |
| 842 | fn stop_datapath() { | 1082 | fn stop_datapath(&self) { |
| 843 | let regs = T::regs(); | 1083 | let regs = self.info.regs; |
| 844 | 1084 | ||
| 845 | #[cfg(sdmmc_v1)] | 1085 | #[cfg(sdmmc_v1)] |
| 846 | regs.dctrl().modify(|w| { | 1086 | regs.dctrl().modify(|w| { |
| @@ -853,7 +1093,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 853 | 1093 | ||
| 854 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self | 1094 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self |
| 855 | fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> { | 1095 | fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> { |
| 856 | let regs = T::regs(); | 1096 | let regs = self.info.regs; |
| 857 | 1097 | ||
| 858 | let width_u32 = match width { | 1098 | let width_u32 = match width { |
| 859 | BusWidth::One => 1u32, | 1099 | BusWidth::One => 1u32, |
| @@ -862,17 +1102,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 862 | _ => panic!("Invalid Bus Width"), | 1102 | _ => panic!("Invalid Bus Width"), |
| 863 | }; | 1103 | }; |
| 864 | 1104 | ||
| 865 | let ker_ck = T::frequency(); | 1105 | let (_bypass, clkdiv, new_clock) = clk_div(self.ker_clk, freq)?; |
| 866 | let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; | ||
| 867 | 1106 | ||
| 868 | // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 | 1107 | // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 |
| 869 | // Section 55.5.8 | 1108 | // Section 55.5.8 |
| 870 | let sdmmc_bus_bandwidth = new_clock.0 * width_u32; | 1109 | let sdmmc_bus_bandwidth = new_clock.0 * width_u32; |
| 871 | assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); | 1110 | assert!(self.ker_clk.0 > 3 * sdmmc_bus_bandwidth / 32); |
| 872 | self.clock = new_clock; | 1111 | self.clock = new_clock; |
| 873 | 1112 | ||
| 874 | // CPSMACT and DPSMACT must be 0 to set CLKDIV | 1113 | // CPSMACT and DPSMACT must be 0 to set CLKDIV |
| 875 | Self::wait_idle(); | 1114 | self.wait_idle(); |
| 876 | regs.clkcr().modify(|w| { | 1115 | regs.clkcr().modify(|w| { |
| 877 | w.set_clkdiv(clkdiv); | 1116 | w.set_clkdiv(clkdiv); |
| 878 | #[cfg(sdmmc_v1)] | 1117 | #[cfg(sdmmc_v1)] |
| @@ -883,14 +1122,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 883 | } | 1122 | } |
| 884 | 1123 | ||
| 885 | /// Query the card status (CMD13, returns R1) | 1124 | /// Query the card status (CMD13, returns R1) |
| 886 | fn read_status<Ext>(&self, card: &SdmmcPeripheral) -> Result<CardStatus<Ext>, Error> | 1125 | fn read_status<A: Addressable>(&self, card: &A) -> Result<CardStatus<A::Ext>, Error> |
| 887 | where | 1126 | where |
| 888 | CardStatus<Ext>: From<u32>, | 1127 | CardStatus<A::Ext>: From<u32>, |
| 889 | { | 1128 | { |
| 890 | let regs = T::regs(); | 1129 | let regs = self.info.regs; |
| 891 | let rca = card.get_address(); | 1130 | let rca = card.get_address(); |
| 892 | 1131 | ||
| 893 | Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 | 1132 | self.cmd(common_cmd::card_status(rca, false), false)?; // CMD13 |
| 894 | 1133 | ||
| 895 | let r1 = regs.respr(0).read().cardstatus(); | 1134 | let r1 = regs.respr(0).read().cardstatus(); |
| 896 | Ok(r1.into()) | 1135 | Ok(r1.into()) |
| @@ -904,7 +1143,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 904 | // Determine Relative Card Address (RCA) of given card | 1143 | // Determine Relative Card Address (RCA) of given card |
| 905 | let rca = rca.unwrap_or(0); | 1144 | let rca = rca.unwrap_or(0); |
| 906 | 1145 | ||
| 907 | let r = Self::cmd(common_cmd::select_card(rca), false); | 1146 | let r = self.cmd(common_cmd::select_card(rca), false); |
| 908 | match (r, rca) { | 1147 | match (r, rca) { |
| 909 | (Err(Error::Timeout), 0) => Ok(()), | 1148 | (Err(Error::Timeout), 0) => Ok(()), |
| 910 | _ => r, | 1149 | _ => r, |
| @@ -913,8 +1152,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 913 | 1152 | ||
| 914 | /// Clear flags in interrupt clear register | 1153 | /// Clear flags in interrupt clear register |
| 915 | #[inline] | 1154 | #[inline] |
| 916 | fn clear_interrupt_flags() { | 1155 | fn clear_interrupt_flags(&self) { |
| 917 | let regs = T::regs(); | 1156 | let regs = self.info.regs; |
| 918 | regs.icr().write(|w| { | 1157 | regs.icr().write(|w| { |
| 919 | w.set_ccrcfailc(true); | 1158 | w.set_ccrcfailc(true); |
| 920 | w.set_dcrcfailc(true); | 1159 | w.set_dcrcfailc(true); |
| @@ -947,12 +1186,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 947 | 1186 | ||
| 948 | /// Send command to card | 1187 | /// Send command to card |
| 949 | #[allow(unused_variables)] | 1188 | #[allow(unused_variables)] |
| 950 | fn cmd<R: Resp>(cmd: Cmd<R>, data: bool) -> Result<(), Error> { | 1189 | fn cmd<R: Resp>(&self, cmd: Cmd<R>, data: bool) -> Result<(), Error> { |
| 951 | let regs = T::regs(); | 1190 | let regs = self.info.regs; |
| 952 | 1191 | ||
| 953 | Self::clear_interrupt_flags(); | 1192 | self.clear_interrupt_flags(); |
| 954 | // CP state machine must be idle | 1193 | // CP state machine must be idle |
| 955 | while Self::cmd_active() {} | 1194 | while self.cmd_active() {} |
| 956 | 1195 | ||
| 957 | // Command arg | 1196 | // Command arg |
| 958 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); | 1197 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); |
| @@ -997,13 +1236,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 997 | Ok(()) | 1236 | Ok(()) |
| 998 | } | 1237 | } |
| 999 | 1238 | ||
| 1000 | fn on_drop() { | 1239 | fn on_drop(&self) { |
| 1001 | let regs = T::regs(); | 1240 | let regs = self.info.regs; |
| 1002 | if Self::data_active() { | 1241 | if self.data_active() { |
| 1003 | Self::clear_interrupt_flags(); | 1242 | self.clear_interrupt_flags(); |
| 1004 | // Send abort | 1243 | // Send abort |
| 1005 | // CP state machine must be idle | 1244 | // CP state machine must be idle |
| 1006 | while Self::cmd_active() {} | 1245 | while self.cmd_active() {} |
| 1007 | 1246 | ||
| 1008 | // Command arg | 1247 | // Command arg |
| 1009 | regs.argr().write(|w| w.set_cmdarg(0)); | 1248 | regs.argr().write(|w| w.set_cmdarg(0)); |
| @@ -1023,22 +1262,22 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1023 | }); | 1262 | }); |
| 1024 | 1263 | ||
| 1025 | // Wait for the abort | 1264 | // Wait for the abort |
| 1026 | while Self::data_active() {} | 1265 | while self.data_active() {} |
| 1027 | } | 1266 | } |
| 1028 | regs.maskr().write(|_| ()); // disable irqs | 1267 | regs.maskr().write(|_| ()); // disable irqs |
| 1029 | Self::clear_interrupt_flags(); | 1268 | self.clear_interrupt_flags(); |
| 1030 | Self::stop_datapath(); | 1269 | self.stop_datapath(); |
| 1031 | } | 1270 | } |
| 1032 | 1271 | ||
| 1033 | /// Wait for a previously started datapath transfer to complete from an interrupt. | 1272 | /// Wait for a previously started datapath transfer to complete from an interrupt. |
| 1034 | #[inline] | 1273 | #[inline] |
| 1035 | #[allow(unused)] | 1274 | #[allow(unused)] |
| 1036 | async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { | 1275 | async fn complete_datapath_transfer(&self, block: bool) -> Result<(), Error> { |
| 1037 | let res = poll_fn(|cx| { | 1276 | let res = poll_fn(|cx| { |
| 1038 | // Compiler might not be sufficiently constrained here | 1277 | // Compiler might not be sufficiently constrained here |
| 1039 | // https://github.com/embassy-rs/embassy/issues/4723 | 1278 | // https://github.com/embassy-rs/embassy/issues/4723 |
| 1040 | T::state().register(cx.waker()); | 1279 | self.state.waker.register(cx.waker()); |
| 1041 | let status = T::regs().star().read(); | 1280 | let status = self.info.regs.star().read(); |
| 1042 | 1281 | ||
| 1043 | if status.dcrcfail() { | 1282 | if status.dcrcfail() { |
| 1044 | return Poll::Ready(Err(Error::Crc)); | 1283 | return Poll::Ready(Err(Error::Crc)); |
| @@ -1067,16 +1306,21 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1067 | }) | 1306 | }) |
| 1068 | .await; | 1307 | .await; |
| 1069 | 1308 | ||
| 1070 | Self::clear_interrupt_flags(); | 1309 | self.clear_interrupt_flags(); |
| 1071 | 1310 | ||
| 1072 | res | 1311 | res |
| 1073 | } | 1312 | } |
| 1074 | 1313 | ||
| 1075 | /// Read a data block. | 1314 | /// Read a data block. |
| 1076 | #[inline] | 1315 | #[inline] |
| 1077 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | 1316 | pub async fn read_block( |
| 1078 | let _scoped_block_stop = T::RCC_INFO.block_stop(); | 1317 | &mut self, |
| 1079 | let card_capacity = self.card()?.get_capacity(); | 1318 | card: &mut impl Addressable, |
| 1319 | block_idx: u32, | ||
| 1320 | buffer: &mut DataBlock, | ||
| 1321 | ) -> Result<(), Error> { | ||
| 1322 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1323 | let card_capacity = card.get_capacity(); | ||
| 1080 | 1324 | ||
| 1081 | // NOTE(unsafe) DataBlock uses align 4 | 1325 | // NOTE(unsafe) DataBlock uses align 4 |
| 1082 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | 1326 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; |
| @@ -1087,26 +1331,19 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1087 | CardCapacity::StandardCapacity => block_idx * 512, | 1331 | CardCapacity::StandardCapacity => block_idx * 512, |
| 1088 | _ => block_idx, | 1332 | _ => block_idx, |
| 1089 | }; | 1333 | }; |
| 1090 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | 1334 | self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 |
| 1091 | 1335 | ||
| 1092 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1336 | let on_drop = OnDrop::new(|| self.on_drop()); |
| 1093 | 1337 | ||
| 1094 | let transfer = Self::prepare_datapath_read( | 1338 | let transfer = self.prepare_datapath_read(&self.config, buffer, 512, 9); |
| 1095 | &self.config, | 1339 | self.enable_interrupts(); |
| 1096 | #[cfg(sdmmc_v1)] | 1340 | self.cmd(common_cmd::read_single_block(address), true)?; |
| 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 | 1341 | ||
| 1105 | let res = Self::complete_datapath_transfer(true).await; | 1342 | let res = self.complete_datapath_transfer(true).await; |
| 1106 | 1343 | ||
| 1107 | if res.is_ok() { | 1344 | if res.is_ok() { |
| 1108 | on_drop.defuse(); | 1345 | on_drop.defuse(); |
| 1109 | Self::stop_datapath(); | 1346 | self.stop_datapath(); |
| 1110 | drop(transfer); | 1347 | drop(transfer); |
| 1111 | } | 1348 | } |
| 1112 | res | 1349 | res |
| @@ -1114,9 +1351,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1114 | 1351 | ||
| 1115 | /// Read multiple data blocks. | 1352 | /// Read multiple data blocks. |
| 1116 | #[inline] | 1353 | #[inline] |
| 1117 | pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { | 1354 | pub async fn read_blocks( |
| 1118 | let _scoped_block_stop = T::RCC_INFO.block_stop(); | 1355 | &mut self, |
| 1119 | let card_capacity = self.card()?.get_capacity(); | 1356 | card: &mut impl Addressable, |
| 1357 | block_idx: u32, | ||
| 1358 | blocks: &mut [DataBlock], | ||
| 1359 | ) -> Result<(), Error> { | ||
| 1360 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1361 | let card_capacity = card.get_capacity(); | ||
| 1120 | 1362 | ||
| 1121 | // NOTE(unsafe) reinterpret buffer as &mut [u32] | 1363 | // NOTE(unsafe) reinterpret buffer as &mut [u32] |
| 1122 | let buffer = unsafe { | 1364 | let buffer = unsafe { |
| @@ -1131,39 +1373,39 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1131 | CardCapacity::StandardCapacity => block_idx * 512, | 1373 | CardCapacity::StandardCapacity => block_idx * 512, |
| 1132 | _ => block_idx, | 1374 | _ => block_idx, |
| 1133 | }; | 1375 | }; |
| 1134 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | 1376 | self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 |
| 1135 | 1377 | ||
| 1136 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1378 | let on_drop = OnDrop::new(|| self.on_drop()); |
| 1137 | 1379 | ||
| 1138 | let transfer = Self::prepare_datapath_read( | 1380 | let transfer = self.prepare_datapath_read(&self.config, buffer, 512 * blocks.len() as u32, 9); |
| 1139 | &self.config, | 1381 | self.enable_interrupts(); |
| 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 | 1382 | ||
| 1148 | Self::cmd(common_cmd::read_multiple_blocks(address), true)?; | 1383 | self.cmd(common_cmd::read_multiple_blocks(address), true)?; |
| 1149 | 1384 | ||
| 1150 | let res = Self::complete_datapath_transfer(false).await; | 1385 | let res = self.complete_datapath_transfer(false).await; |
| 1151 | 1386 | ||
| 1152 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 | 1387 | self.cmd(common_cmd::stop_transmission(), false)?; // CMD12 |
| 1153 | Self::clear_interrupt_flags(); | 1388 | self.clear_interrupt_flags(); |
| 1154 | 1389 | ||
| 1155 | if res.is_ok() { | 1390 | if res.is_ok() { |
| 1156 | on_drop.defuse(); | 1391 | on_drop.defuse(); |
| 1157 | Self::stop_datapath(); | 1392 | self.stop_datapath(); |
| 1158 | drop(transfer); | 1393 | drop(transfer); |
| 1159 | } | 1394 | } |
| 1160 | res | 1395 | res |
| 1161 | } | 1396 | } |
| 1162 | 1397 | ||
| 1163 | /// Write a data block. | 1398 | /// Write a data block. |
| 1164 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | 1399 | pub async fn write_block<A: Addressable>( |
| 1165 | let _scoped_block_stop = T::RCC_INFO.block_stop(); | 1400 | &mut self, |
| 1166 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | 1401 | card: &mut A, |
| 1402 | block_idx: u32, | ||
| 1403 | buffer: &DataBlock, | ||
| 1404 | ) -> Result<(), Error> | ||
| 1405 | where | ||
| 1406 | CardStatus<A::Ext>: From<u32>, | ||
| 1407 | { | ||
| 1408 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1167 | 1409 | ||
| 1168 | // NOTE(unsafe) DataBlock uses align 4 | 1410 | // NOTE(unsafe) DataBlock uses align 4 |
| 1169 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | 1411 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; |
| @@ -1174,38 +1416,33 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1174 | CardCapacity::StandardCapacity => block_idx * 512, | 1416 | CardCapacity::StandardCapacity => block_idx * 512, |
| 1175 | _ => block_idx, | 1417 | _ => block_idx, |
| 1176 | }; | 1418 | }; |
| 1177 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | 1419 | self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 |
| 1178 | 1420 | ||
| 1179 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1421 | let on_drop = OnDrop::new(|| self.on_drop()); |
| 1180 | 1422 | ||
| 1181 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | 1423 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes |
| 1182 | #[cfg(sdmmc_v1)] | 1424 | #[cfg(sdmmc_v1)] |
| 1183 | Self::cmd(common_cmd::write_single_block(address), true)?; | 1425 | self.cmd(common_cmd::write_single_block(address), true)?; |
| 1184 | 1426 | ||
| 1185 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | 1427 | let transfer = self.prepare_datapath_write(buffer, 512, 9); |
| 1186 | InterruptHandler::<T>::enable_interrupts(); | 1428 | self.enable_interrupts(); |
| 1187 | 1429 | ||
| 1188 | #[cfg(sdmmc_v2)] | 1430 | #[cfg(sdmmc_v2)] |
| 1189 | Self::cmd(common_cmd::write_single_block(address), true)?; | 1431 | self.cmd(common_cmd::write_single_block(address), true)?; |
| 1190 | 1432 | ||
| 1191 | let res = Self::complete_datapath_transfer(true).await; | 1433 | let res = self.complete_datapath_transfer(true).await; |
| 1192 | 1434 | ||
| 1193 | match res { | 1435 | match res { |
| 1194 | Ok(_) => { | 1436 | Ok(_) => { |
| 1195 | on_drop.defuse(); | 1437 | on_drop.defuse(); |
| 1196 | Self::stop_datapath(); | 1438 | self.stop_datapath(); |
| 1197 | drop(transfer); | 1439 | drop(transfer); |
| 1198 | 1440 | ||
| 1199 | // TODO: Make this configurable | 1441 | // TODO: Make this configurable |
| 1200 | let mut timeout: u32 = 0x00FF_FFFF; | 1442 | let mut timeout: u32 = 0x00FF_FFFF; |
| 1201 | 1443 | ||
| 1202 | let card = self.card.as_ref().unwrap(); | ||
| 1203 | while timeout > 0 { | 1444 | while timeout > 0 { |
| 1204 | let ready_for_data = match card { | 1445 | let ready_for_data = self.read_status(card)?.ready_for_data(); |
| 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 { | 1446 | if ready_for_data { |
| 1210 | return Ok(()); | 1447 | return Ok(()); |
| 1211 | } | 1448 | } |
| @@ -1218,9 +1455,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1218 | } | 1455 | } |
| 1219 | 1456 | ||
| 1220 | /// Write multiple data blocks. | 1457 | /// Write multiple data blocks. |
| 1221 | pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> { | 1458 | pub async fn write_blocks<A: Addressable>( |
| 1222 | let _scoped_block_stop = T::RCC_INFO.block_stop(); | 1459 | &mut self, |
| 1223 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | 1460 | card: &mut A, |
| 1461 | block_idx: u32, | ||
| 1462 | blocks: &[DataBlock], | ||
| 1463 | ) -> Result<(), Error> | ||
| 1464 | where | ||
| 1465 | CardStatus<A::Ext>: From<u32>, | ||
| 1466 | { | ||
| 1467 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1224 | 1468 | ||
| 1225 | // NOTE(unsafe) reinterpret buffer as &[u32] | 1469 | // NOTE(unsafe) reinterpret buffer as &[u32] |
| 1226 | let buffer = unsafe { | 1470 | let buffer = unsafe { |
| @@ -1236,42 +1480,41 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1236 | _ => block_idx, | 1480 | _ => block_idx, |
| 1237 | }; | 1481 | }; |
| 1238 | 1482 | ||
| 1239 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | 1483 | self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 |
| 1240 | 1484 | ||
| 1241 | let block_count = blocks.len(); | 1485 | let block_count = blocks.len(); |
| 1242 | 1486 | ||
| 1243 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1487 | let on_drop = OnDrop::new(|| self.on_drop()); |
| 1244 | 1488 | ||
| 1245 | #[cfg(sdmmc_v1)] | 1489 | #[cfg(sdmmc_v1)] |
| 1246 | Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | 1490 | self.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 |
| 1247 | 1491 | ||
| 1248 | // Setup write command | 1492 | // Setup write command |
| 1249 | let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); | 1493 | let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); |
| 1250 | InterruptHandler::<T>::enable_interrupts(); | 1494 | self.enable_interrupts(); |
| 1251 | 1495 | ||
| 1252 | #[cfg(sdmmc_v2)] | 1496 | #[cfg(sdmmc_v2)] |
| 1253 | Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | 1497 | self.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 |
| 1254 | 1498 | ||
| 1255 | let res = Self::complete_datapath_transfer(false).await; | 1499 | let res = self.complete_datapath_transfer(false).await; |
| 1256 | 1500 | ||
| 1257 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 | 1501 | self.cmd(common_cmd::stop_transmission(), false)?; // CMD12 |
| 1258 | Self::clear_interrupt_flags(); | 1502 | self.clear_interrupt_flags(); |
| 1259 | 1503 | ||
| 1260 | match res { | 1504 | match res { |
| 1261 | Ok(_) => { | 1505 | Ok(_) => { |
| 1262 | on_drop.defuse(); | 1506 | on_drop.defuse(); |
| 1263 | Self::stop_datapath(); | 1507 | self.stop_datapath(); |
| 1264 | drop(transfer); | 1508 | drop(transfer); |
| 1265 | 1509 | ||
| 1266 | // TODO: Make this configurable | 1510 | // TODO: Make this configurable |
| 1267 | let mut timeout: u32 = 0x00FF_FFFF; | 1511 | let mut timeout: u32 = 0x00FF_FFFF; |
| 1268 | 1512 | ||
| 1269 | // Try to read card status (ACMD13) | ||
| 1270 | while timeout > 0 { | 1513 | while timeout > 0 { |
| 1271 | match self.read_sd_status().await { | 1514 | let ready_for_data = self.read_status(card)?.ready_for_data(); |
| 1272 | Ok(_) => return Ok(()), | 1515 | |
| 1273 | Err(Error::Timeout) => (), // Try again | 1516 | if ready_for_data { |
| 1274 | Err(e) => return Err(e), | 1517 | return Ok(()); |
| 1275 | } | 1518 | } |
| 1276 | timeout -= 1; | 1519 | timeout -= 1; |
| 1277 | } | 1520 | } |
| @@ -1281,33 +1524,20 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1281 | } | 1524 | } |
| 1282 | } | 1525 | } |
| 1283 | 1526 | ||
| 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 | 1527 | /// Get the current SDMMC bus clock |
| 1296 | pub fn clock(&self) -> Hertz { | 1528 | pub fn clock(&self) -> Hertz { |
| 1297 | self.clock | 1529 | self.clock |
| 1298 | } | 1530 | } |
| 1299 | 1531 | ||
| 1300 | /// Set a specific cmd buffer rather than using the default stack allocated one. | 1532 | async fn init_internal( |
| 1301 | /// This is required if stack RAM cannot be used with DMA and usually manifests | 1533 | &mut self, |
| 1302 | /// itself as an indefinite wait on a dma transfer because the dma peripheral | 1534 | cmd_block: &mut CmdBlock, |
| 1303 | /// cannot access the memory. | 1535 | freq: Hertz, |
| 1304 | pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { | 1536 | card: &mut SdmmcPeripheral, |
| 1305 | self.cmd_block = Some(cmd_block) | 1537 | ) -> Result<(), Error> { |
| 1306 | } | 1538 | let _scoped_block_stop = self.info.rcc.block_stop(); |
| 1307 | 1539 | ||
| 1308 | async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> { | 1540 | let regs = self.info.regs; |
| 1309 | let regs = T::regs(); | ||
| 1310 | let ker_ck = T::frequency(); | ||
| 1311 | 1541 | ||
| 1312 | let bus_width = match (self.d3.is_some(), self.d7.is_some()) { | 1542 | let bus_width = match (self.d3.is_some(), self.d7.is_some()) { |
| 1313 | (true, true) => { | 1543 | (true, true) => { |
| @@ -1322,11 +1552,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1322 | 1552 | ||
| 1323 | // While the SD/SDIO card or eMMC is in identification mode, | 1553 | // While the SD/SDIO card or eMMC is in identification mode, |
| 1324 | // the SDMMC_CK frequency must be no more than 400 kHz. | 1554 | // 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)); | 1555 | let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(self.ker_clk, SD_INIT_FREQ.0)); |
| 1326 | self.clock = init_clock; | 1556 | self.clock = init_clock; |
| 1327 | 1557 | ||
| 1328 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | 1558 | // CPSMACT and DPSMACT must be 0 to set WIDBUS |
| 1329 | Self::wait_idle(); | 1559 | self.wait_idle(); |
| 1330 | 1560 | ||
| 1331 | regs.clkcr().modify(|w| { | 1561 | regs.clkcr().modify(|w| { |
| 1332 | w.set_widbus(0); | 1562 | w.set_widbus(0); |
| @@ -1338,12 +1568,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1338 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | 1568 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); |
| 1339 | 1569 | ||
| 1340 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | 1570 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); |
| 1341 | Self::cmd(common_cmd::idle(), false)?; | 1571 | self.cmd(common_cmd::idle(), false)?; |
| 1342 | 1572 | ||
| 1343 | match card { | 1573 | match card { |
| 1344 | SdmmcPeripheral::SdCard(ref mut card) => { | 1574 | SdmmcPeripheral::SdCard(card) => { |
| 1345 | // Check if cards supports CMD8 (with pattern) | 1575 | // Check if cards supports CMD8 (with pattern) |
| 1346 | Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; | 1576 | self.cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; |
| 1347 | let cic = CIC::from(regs.respr(0).read().cardstatus()); | 1577 | let cic = CIC::from(regs.respr(0).read().cardstatus()); |
| 1348 | 1578 | ||
| 1349 | if cic.pattern() != 0xAA { | 1579 | if cic.pattern() != 0xAA { |
| @@ -1356,12 +1586,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1356 | 1586 | ||
| 1357 | let ocr = loop { | 1587 | let ocr = loop { |
| 1358 | // Signal that next command is a app command | 1588 | // Signal that next command is a app command |
| 1359 | Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55 | 1589 | self.cmd(common_cmd::app_cmd(0), false)?; // CMD55 |
| 1360 | 1590 | ||
| 1361 | // 3.2-3.3V | 1591 | // 3.2-3.3V |
| 1362 | let voltage_window = 1 << 5; | 1592 | let voltage_window = 1 << 5; |
| 1363 | // Initialize card | 1593 | // Initialize card |
| 1364 | match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { | 1594 | match self.cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { |
| 1365 | // ACMD41 | 1595 | // ACMD41 |
| 1366 | Ok(_) => (), | 1596 | Ok(_) => (), |
| 1367 | Err(Error::Crc) => (), | 1597 | Err(Error::Crc) => (), |
| @@ -1382,13 +1612,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1382 | } | 1612 | } |
| 1383 | card.ocr = ocr; | 1613 | card.ocr = ocr; |
| 1384 | } | 1614 | } |
| 1385 | SdmmcPeripheral::Emmc(ref mut emmc) => { | 1615 | SdmmcPeripheral::Emmc(emmc) => { |
| 1386 | let ocr = loop { | 1616 | let ocr = loop { |
| 1387 | let high_voltage = 0b0 << 7; | 1617 | let high_voltage = 0b0 << 7; |
| 1388 | let access_mode = 0b10 << 29; | 1618 | let access_mode = 0b10 << 29; |
| 1389 | let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; | 1619 | let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; |
| 1390 | // Initialize card | 1620 | // Initialize card |
| 1391 | match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) { | 1621 | match self.cmd(emmc_cmd::send_op_cond(op_cond), false) { |
| 1392 | Ok(_) => (), | 1622 | Ok(_) => (), |
| 1393 | Err(Error::Crc) => (), | 1623 | Err(Error::Crc) => (), |
| 1394 | Err(err) => return Err(err), | 1624 | Err(err) => return Err(err), |
| @@ -1410,7 +1640,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1410 | } | 1640 | } |
| 1411 | } | 1641 | } |
| 1412 | 1642 | ||
| 1413 | Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 | 1643 | self.cmd(common_cmd::all_send_cid(), false)?; // CMD2 |
| 1414 | let cid0 = regs.respr(0).read().cardstatus() as u128; | 1644 | let cid0 = regs.respr(0).read().cardstatus() as u128; |
| 1415 | let cid1 = regs.respr(1).read().cardstatus() as u128; | 1645 | let cid1 = regs.respr(1).read().cardstatus() as u128; |
| 1416 | let cid2 = regs.respr(2).read().cardstatus() as u128; | 1646 | let cid2 = regs.respr(2).read().cardstatus() as u128; |
| @@ -1418,22 +1648,22 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1418 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | 1648 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); |
| 1419 | 1649 | ||
| 1420 | match card { | 1650 | match card { |
| 1421 | SdmmcPeripheral::SdCard(ref mut card) => { | 1651 | SdmmcPeripheral::SdCard(card) => { |
| 1422 | card.cid = cid.into(); | 1652 | card.cid = cid.into(); |
| 1423 | 1653 | ||
| 1424 | Self::cmd(sd_cmd::send_relative_address(), false)?; | 1654 | self.cmd(sd_cmd::send_relative_address(), false)?; |
| 1425 | let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus()); | 1655 | let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus()); |
| 1426 | card.rca = rca.address(); | 1656 | card.rca = rca.address(); |
| 1427 | } | 1657 | } |
| 1428 | SdmmcPeripheral::Emmc(ref mut emmc) => { | 1658 | SdmmcPeripheral::Emmc(emmc) => { |
| 1429 | emmc.cid = cid.into(); | 1659 | emmc.cid = cid.into(); |
| 1430 | 1660 | ||
| 1431 | emmc.rca = 1u16.into(); | 1661 | emmc.rca = 1u16.into(); |
| 1432 | Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; | 1662 | self.cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; |
| 1433 | } | 1663 | } |
| 1434 | } | 1664 | } |
| 1435 | 1665 | ||
| 1436 | Self::cmd(common_cmd::send_csd(card.get_address()), false)?; | 1666 | self.cmd(common_cmd::send_csd(card.get_address()), false)?; |
| 1437 | let csd0 = regs.respr(0).read().cardstatus() as u128; | 1667 | let csd0 = regs.respr(0).read().cardstatus() as u128; |
| 1438 | let csd1 = regs.respr(1).read().cardstatus() as u128; | 1668 | let csd1 = regs.respr(1).read().cardstatus() as u128; |
| 1439 | let csd2 = regs.respr(2).read().cardstatus() as u128; | 1669 | let csd2 = regs.respr(2).read().cardstatus() as u128; |
| @@ -1443,10 +1673,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1443 | self.select_card(Some(card.get_address()))?; | 1673 | self.select_card(Some(card.get_address()))?; |
| 1444 | 1674 | ||
| 1445 | let bus_width = match card { | 1675 | let bus_width = match card { |
| 1446 | SdmmcPeripheral::SdCard(ref mut card) => { | 1676 | SdmmcPeripheral::SdCard(card) => { |
| 1447 | card.csd = csd.into(); | 1677 | card.csd = csd.into(); |
| 1448 | 1678 | ||
| 1449 | self.get_scr(card).await?; | 1679 | card.get_scr(self, cmd_block).await?; |
| 1450 | 1680 | ||
| 1451 | if !card.scr.bus_width_four() { | 1681 | if !card.scr.bus_width_four() { |
| 1452 | BusWidth::One | 1682 | BusWidth::One |
| @@ -1454,7 +1684,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1454 | BusWidth::Four | 1684 | BusWidth::Four |
| 1455 | } | 1685 | } |
| 1456 | } | 1686 | } |
| 1457 | SdmmcPeripheral::Emmc(ref mut emmc) => { | 1687 | SdmmcPeripheral::Emmc(emmc) => { |
| 1458 | emmc.csd = csd.into(); | 1688 | emmc.csd = csd.into(); |
| 1459 | 1689 | ||
| 1460 | bus_width | 1690 | bus_width |
| @@ -1470,24 +1700,24 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1470 | }; | 1700 | }; |
| 1471 | 1701 | ||
| 1472 | match card { | 1702 | match card { |
| 1473 | SdmmcPeripheral::SdCard(ref mut card) => { | 1703 | SdmmcPeripheral::SdCard(card) => { |
| 1474 | let acmd_arg = match bus_width { | 1704 | let acmd_arg = match bus_width { |
| 1475 | BusWidth::Four if card.scr.bus_width_four() => 2, | 1705 | BusWidth::Four if card.scr.bus_width_four() => 2, |
| 1476 | _ => 0, | 1706 | _ => 0, |
| 1477 | }; | 1707 | }; |
| 1478 | Self::cmd(common_cmd::app_cmd(card.rca), false)?; | 1708 | self.cmd(common_cmd::app_cmd(card.rca), false)?; |
| 1479 | Self::cmd(sd_cmd::cmd6(acmd_arg), false)?; | 1709 | self.cmd(sd_cmd::cmd6(acmd_arg), false)?; |
| 1480 | } | 1710 | } |
| 1481 | SdmmcPeripheral::Emmc(_) => { | 1711 | SdmmcPeripheral::Emmc(emmc) => { |
| 1482 | // Write bus width to ExtCSD byte 183 | 1712 | // Write bus width to ExtCSD byte 183 |
| 1483 | Self::cmd( | 1713 | self.cmd( |
| 1484 | emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), | 1714 | emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), |
| 1485 | false, | 1715 | false, |
| 1486 | )?; | 1716 | )?; |
| 1487 | 1717 | ||
| 1488 | // Wait for ready after R1b response | 1718 | // Wait for ready after R1b response |
| 1489 | loop { | 1719 | loop { |
| 1490 | let status = self.read_status::<EMMC>(&card)?; | 1720 | let status = self.read_status(emmc)?; |
| 1491 | 1721 | ||
| 1492 | if status.ready_for_data() { | 1722 | if status.ready_for_data() { |
| 1493 | break; | 1723 | break; |
| @@ -1497,7 +1727,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1497 | } | 1727 | } |
| 1498 | 1728 | ||
| 1499 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | 1729 | // CPSMACT and DPSMACT must be 0 to set WIDBUS |
| 1500 | Self::wait_idle(); | 1730 | self.wait_idle(); |
| 1501 | 1731 | ||
| 1502 | regs.clkcr().modify(|w| w.set_widbus(widbus)); | 1732 | regs.clkcr().modify(|w| w.set_widbus(widbus)); |
| 1503 | 1733 | ||
| @@ -1510,32 +1740,30 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1510 | self.clkcr_set_clkdiv(25_000_000, bus_width)?; | 1740 | self.clkcr_set_clkdiv(25_000_000, bus_width)?; |
| 1511 | } | 1741 | } |
| 1512 | 1742 | ||
| 1513 | self.card = Some(card); | ||
| 1514 | |||
| 1515 | match card { | 1743 | match card { |
| 1516 | SdmmcPeripheral::SdCard(_) => { | 1744 | SdmmcPeripheral::SdCard(card) => { |
| 1517 | // Read status | 1745 | // Read status |
| 1518 | self.read_sd_status().await?; | 1746 | card.read_sd_status(self, cmd_block).await?; |
| 1519 | 1747 | ||
| 1520 | if freq.0 > 25_000_000 { | 1748 | if freq.0 > 25_000_000 { |
| 1521 | // Switch to SDR25 | 1749 | // Switch to SDR25 |
| 1522 | self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; | 1750 | self.signalling = card.switch_signalling_mode(self, cmd_block, Signalling::SDR25).await?; |
| 1523 | 1751 | ||
| 1524 | if self.signalling == Signalling::SDR25 { | 1752 | if self.signalling == Signalling::SDR25 { |
| 1525 | // Set final clock frequency | 1753 | // Set final clock frequency |
| 1526 | self.clkcr_set_clkdiv(freq.0, bus_width)?; | 1754 | self.clkcr_set_clkdiv(freq.0, bus_width)?; |
| 1527 | 1755 | ||
| 1528 | if self.read_status::<SD>(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { | 1756 | if self.read_status(card)?.state() != CurrentState::Transfer { |
| 1529 | return Err(Error::SignalingSwitchFailed); | 1757 | return Err(Error::SignalingSwitchFailed); |
| 1530 | } | 1758 | } |
| 1531 | } | 1759 | } |
| 1532 | } | 1760 | } |
| 1533 | 1761 | ||
| 1534 | // Read status after signalling change | 1762 | // Read status after signalling change |
| 1535 | self.read_sd_status().await?; | 1763 | card.read_sd_status(self, cmd_block).await?; |
| 1536 | } | 1764 | } |
| 1537 | SdmmcPeripheral::Emmc(_) => { | 1765 | SdmmcPeripheral::Emmc(emmc) => { |
| 1538 | self.read_ext_csd().await?; | 1766 | emmc.read_ext_csd(self).await?; |
| 1539 | } | 1767 | } |
| 1540 | } | 1768 | } |
| 1541 | 1769 | ||
| @@ -1545,228 +1773,38 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1545 | /// Initializes card (if present) and sets the bus at the specified frequency. | 1773 | /// Initializes card (if present) and sets the bus at the specified frequency. |
| 1546 | /// | 1774 | /// |
| 1547 | /// SD only. | 1775 | /// SD only. |
| 1548 | pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> { | 1776 | async fn init_sd_card(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Card, Error> { |
| 1549 | let _scoped_block_stop = T::RCC_INFO.block_stop(); | 1777 | let mut card = SdmmcPeripheral::SdCard(Card::default()); |
| 1550 | 1778 | self.init_internal(cmd_block, freq, &mut card).await?; | |
| 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 | 1779 | ||
| 1595 | let res = Self::complete_datapath_transfer(true).await; | 1780 | let card = match card { |
| 1596 | 1781 | SdmmcPeripheral::SdCard(card) => card, | |
| 1597 | // Host is allowed to use the new functions at least 8 | 1782 | _ => unreachable!(), |
| 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 | }; | 1783 | }; |
| 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 | 1784 | ||
| 1657 | if res.is_ok() { | 1785 | Ok(card) |
| 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 | } | 1786 | } |
| 1715 | 1787 | ||
| 1716 | /// Initializes eMMC and sets the bus at the specified frequency. | 1788 | /// Initializes eMMC and sets the bus at the specified frequency. |
| 1717 | /// | 1789 | /// |
| 1718 | /// eMMC only. | 1790 | /// eMMC only. |
| 1719 | pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> { | 1791 | async fn init_emmc(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Emmc, Error> { |
| 1720 | let _scoped_block_stop = T::RCC_INFO.block_stop(); | 1792 | let mut card = SdmmcPeripheral::Emmc(Emmc::default()); |
| 1721 | 1793 | self.init_internal(cmd_block, freq, &mut card).await?; | |
| 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 | 1794 | ||
| 1737 | Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 | 1795 | let card = match card { |
| 1738 | 1796 | SdmmcPeripheral::Emmc(card) => card, | |
| 1739 | // Arm `OnDrop` after the buffer, so it will be dropped first | 1797 | _ => unreachable!(), |
| 1740 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1798 | }; |
| 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 | 1799 | ||
| 1760 | card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); | 1800 | Ok(card) |
| 1761 | } | ||
| 1762 | res | ||
| 1763 | } | 1801 | } |
| 1764 | } | 1802 | } |
| 1765 | 1803 | ||
| 1766 | impl<'d, T: Instance> Drop for Sdmmc<'d, T> { | 1804 | impl<'d> Drop for Sdmmc<'d> { |
| 1767 | fn drop(&mut self) { | 1805 | fn drop(&mut self) { |
| 1768 | T::Interrupt::disable(); | 1806 | // T::Interrupt::disable(); |
| 1769 | Self::on_drop(); | 1807 | self.on_drop(); |
| 1770 | 1808 | ||
| 1771 | critical_section::with(|_| { | 1809 | critical_section::with(|_| { |
| 1772 | self.clk.set_as_disconnected(); | 1810 | self.clk.set_as_disconnected(); |
| @@ -1799,9 +1837,28 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> { | |||
| 1799 | 1837 | ||
| 1800 | ////////////////////////////////////////////////////// | 1838 | ////////////////////////////////////////////////////// |
| 1801 | 1839 | ||
| 1840 | type Regs = RegBlock; | ||
| 1841 | |||
| 1842 | struct Info { | ||
| 1843 | regs: Regs, | ||
| 1844 | rcc: RccInfo, | ||
| 1845 | } | ||
| 1846 | |||
| 1847 | struct State { | ||
| 1848 | waker: AtomicWaker, | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | impl State { | ||
| 1852 | const fn new() -> Self { | ||
| 1853 | Self { | ||
| 1854 | waker: AtomicWaker::new(), | ||
| 1855 | } | ||
| 1856 | } | ||
| 1857 | } | ||
| 1858 | |||
| 1802 | trait SealedInstance { | 1859 | trait SealedInstance { |
| 1803 | fn regs() -> RegBlock; | 1860 | fn info() -> &'static Info; |
| 1804 | fn state() -> &'static AtomicWaker; | 1861 | fn state() -> &'static State; |
| 1805 | } | 1862 | } |
| 1806 | 1863 | ||
| 1807 | /// SDMMC instance trait. | 1864 | /// SDMMC instance trait. |
| @@ -1828,13 +1885,17 @@ dma_trait!(SdmmcDma, Instance); | |||
| 1828 | foreach_peripheral!( | 1885 | foreach_peripheral!( |
| 1829 | (sdmmc, $inst:ident) => { | 1886 | (sdmmc, $inst:ident) => { |
| 1830 | impl SealedInstance for peripherals::$inst { | 1887 | impl SealedInstance for peripherals::$inst { |
| 1831 | fn regs() -> RegBlock { | 1888 | fn info() -> &'static Info { |
| 1832 | crate::pac::$inst | 1889 | static INFO: Info = Info { |
| 1890 | regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }, | ||
| 1891 | rcc: crate::peripherals::$inst::RCC_INFO, | ||
| 1892 | }; | ||
| 1893 | &INFO | ||
| 1833 | } | 1894 | } |
| 1834 | 1895 | ||
| 1835 | fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker { | 1896 | fn state() -> &'static State { |
| 1836 | static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new(); | 1897 | static STATE: State = State::new(); |
| 1837 | &WAKER | 1898 | &STATE |
| 1838 | } | 1899 | } |
| 1839 | } | 1900 | } |
| 1840 | 1901 | ||
| @@ -1844,7 +1905,7 @@ foreach_peripheral!( | |||
| 1844 | }; | 1905 | }; |
| 1845 | ); | 1906 | ); |
| 1846 | 1907 | ||
| 1847 | impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { | 1908 | impl<'d, 'e, A: Addressable> block_device_driver::BlockDevice<512> for StorageDevice<'d, 'e, A> { |
| 1848 | type Error = Error; | 1909 | type Error = Error; |
| 1849 | type Align = aligned::A4; | 1910 | type Align = aligned::A4; |
| 1850 | 1911 | ||
| @@ -1853,7 +1914,6 @@ impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { | |||
| 1853 | block_address: u32, | 1914 | block_address: u32, |
| 1854 | buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>], | 1915 | buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>], |
| 1855 | ) -> Result<(), Self::Error> { | 1916 | ) -> 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 | 1917 | // TODO: I think block_address needs to be adjusted by the partition start offset |
| 1858 | if buf.len() == 1 { | 1918 | if buf.len() == 1 { |
| 1859 | let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) }; | 1919 | let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) }; |
| @@ -1871,7 +1931,6 @@ impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { | |||
| 1871 | block_address: u32, | 1931 | block_address: u32, |
| 1872 | buf: &[aligned::Aligned<Self::Align, [u8; 512]>], | 1932 | buf: &[aligned::Aligned<Self::Align, [u8; 512]>], |
| 1873 | ) -> Result<(), Self::Error> { | 1933 | ) -> 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 | 1934 | // TODO: I think block_address needs to be adjusted by the partition start offset |
| 1876 | if buf.len() == 1 { | 1935 | if buf.len() == 1 { |
| 1877 | let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) }; | 1936 | let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) }; |
| @@ -1885,6 +1944,6 @@ impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { | |||
| 1885 | } | 1944 | } |
| 1886 | 1945 | ||
| 1887 | async fn size(&mut self) -> Result<u64, Self::Error> { | 1946 | async fn size(&mut self) -> Result<u64, Self::Error> { |
| 1888 | Ok(self.card()?.size()) | 1947 | Ok(self.info.size()) |
| 1889 | } | 1948 | } |
| 1890 | } | 1949 | } |
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; | |||
| 4 | use core::ops::{Div, Mul}; | 4 | use 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)] |
| 8 | pub struct Hertz(pub u32); | 8 | pub struct Hertz(pub u32); |
| 9 | 9 | ||
| 10 | impl Display for Hertz { | 10 | impl Display for Hertz { |
