diff options
| -rw-r--r-- | embassy-stm32/Cargo.toml | 2 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 1274 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/sdmmc.rs | 2 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/sdmmc.rs | 2 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/sdmmc.rs | 2 | ||||
| -rw-r--r-- | tests/stm32/src/bin/sdmmc.rs | 4 |
7 files changed, 742 insertions, 546 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4d0555d4a..d15ac4823 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -70,7 +70,7 @@ cortex-m-rt = ">=0.6.15,<0.8" | |||
| 70 | cortex-m = "0.7.6" | 70 | cortex-m = "0.7.6" |
| 71 | futures-util = { version = "0.3.30", default-features = false } | 71 | futures-util = { version = "0.3.30", default-features = false } |
| 72 | rand_core = "0.6.3" | 72 | rand_core = "0.6.3" |
| 73 | sdio-host = "0.5.0" | 73 | sdio-host = "0.9.0" |
| 74 | critical-section = "1.1" | 74 | critical-section = "1.1" |
| 75 | #stm32-metapac = { version = "16" } | 75 | #stm32-metapac = { version = "16" } |
| 76 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db" } | 76 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db" } |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index b4e61878c..d965d8732 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -1056,7 +1056,7 @@ fn main() { | |||
| 1056 | (("sdmmc", "D4"), quote!(crate::sdmmc::D4Pin)), | 1056 | (("sdmmc", "D4"), quote!(crate::sdmmc::D4Pin)), |
| 1057 | (("sdmmc", "D5"), quote!(crate::sdmmc::D5Pin)), | 1057 | (("sdmmc", "D5"), quote!(crate::sdmmc::D5Pin)), |
| 1058 | (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), | 1058 | (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), |
| 1059 | (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), | 1059 | (("sdmmc", "D7"), quote!(crate::sdmmc::D7Pin)), |
| 1060 | (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), | 1060 | (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), |
| 1061 | (("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)), | 1061 | (("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)), |
| 1062 | (("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)), | 1062 | (("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)), |
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 8f3c45f50..63868e5ae 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -10,7 +10,10 @@ use core::task::Poll; | |||
| 10 | use embassy_hal_internal::drop::OnDrop; | 10 | use embassy_hal_internal::drop::OnDrop; |
| 11 | use embassy_hal_internal::{Peri, PeripheralType}; | 11 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | 12 | use embassy_sync::waitqueue::AtomicWaker; |
| 13 | use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; | 13 | use sdio_host::common_cmd::{self, Resp, ResponseLen}; |
| 14 | use sdio_host::emmc::{ExtCSD, EMMC}; | ||
| 15 | use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; | ||
| 16 | use sdio_host::{emmc_cmd, sd_cmd, Cmd}; | ||
| 14 | 17 | ||
| 15 | #[cfg(sdmmc_v1)] | 18 | #[cfg(sdmmc_v1)] |
| 16 | use crate::dma::ChannelAndRequest; | 19 | use crate::dma::ChannelAndRequest; |
| @@ -136,10 +139,14 @@ pub enum Error { | |||
| 136 | UnsupportedCardVersion, | 139 | UnsupportedCardVersion, |
| 137 | /// Unsupported card type. | 140 | /// Unsupported card type. |
| 138 | UnsupportedCardType, | 141 | UnsupportedCardType, |
| 142 | /// Unsupported voltage. | ||
| 143 | UnsupportedVoltage, | ||
| 139 | /// CRC error. | 144 | /// CRC error. |
| 140 | Crc, | 145 | Crc, |
| 141 | /// No card inserted. | 146 | /// No card inserted. |
| 142 | NoCard, | 147 | NoCard, |
| 148 | /// 8-lane buses are not supported for SD cards. | ||
| 149 | BusWidth, | ||
| 143 | /// Bad clock supplied to the SDMMC peripheral. | 150 | /// Bad clock supplied to the SDMMC peripheral. |
| 144 | BadClock, | 151 | BadClock, |
| 145 | /// Signaling switch failed. | 152 | /// Signaling switch failed. |
| @@ -149,38 +156,40 @@ pub enum Error { | |||
| 149 | StBitErr, | 156 | StBitErr, |
| 150 | } | 157 | } |
| 151 | 158 | ||
| 152 | /// A SD command | ||
| 153 | struct Cmd { | ||
| 154 | cmd: u8, | ||
| 155 | arg: u32, | ||
| 156 | resp: Response, | ||
| 157 | } | ||
| 158 | |||
| 159 | #[derive(Clone, Copy, Debug, Default)] | 159 | #[derive(Clone, Copy, Debug, Default)] |
| 160 | /// SD Card | 160 | /// SD Card |
| 161 | pub struct Card { | 161 | pub struct Card { |
| 162 | /// The type of this card | 162 | /// The type of this card |
| 163 | pub card_type: CardCapacity, | 163 | pub card_type: CardCapacity, |
| 164 | /// Operation Conditions Register | 164 | /// Operation Conditions Register |
| 165 | pub ocr: OCR, | 165 | pub ocr: OCR<SD>, |
| 166 | /// Relative Card Address | 166 | /// Relative Card Address |
| 167 | pub rca: u32, | 167 | pub rca: u16, |
| 168 | /// Card ID | 168 | /// Card ID |
| 169 | pub cid: CID, | 169 | pub cid: CID<SD>, |
| 170 | /// Card Specific Data | 170 | /// Card Specific Data |
| 171 | pub csd: CSD, | 171 | pub csd: CSD<SD>, |
| 172 | /// SD CARD Configuration Register | 172 | /// SD CARD Configuration Register |
| 173 | pub scr: SCR, | 173 | pub scr: SCR, |
| 174 | /// SD Status | 174 | /// SD Status |
| 175 | pub status: SDStatus, | 175 | pub status: SDStatus, |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | impl Card { | 178 | #[derive(Clone, Copy, Debug, Default)] |
| 179 | /// Size in bytes | 179 | /// eMMC storage |
| 180 | pub fn size(&self) -> u64 { | 180 | pub struct Emmc { |
| 181 | // SDHC / SDXC / SDUC | 181 | /// The capacity of this card |
| 182 | u64::from(self.csd.block_count()) * 512 | 182 | pub capacity: CardCapacity, |
| 183 | } | 183 | /// Operation Conditions Register |
| 184 | pub ocr: OCR<EMMC>, | ||
| 185 | /// Relative Card Address | ||
| 186 | pub rca: u16, | ||
| 187 | /// Card ID | ||
| 188 | pub cid: CID<EMMC>, | ||
| 189 | /// Card Specific Data | ||
| 190 | pub csd: CSD<EMMC>, | ||
| 191 | /// Extended Card Specific Data | ||
| 192 | pub ext_csd: ExtCSD, | ||
| 184 | } | 193 | } |
| 185 | 194 | ||
| 186 | #[repr(u8)] | 195 | #[repr(u8)] |
| @@ -189,22 +198,12 @@ enum PowerCtrl { | |||
| 189 | On = 0b11, | 198 | On = 0b11, |
| 190 | } | 199 | } |
| 191 | 200 | ||
| 192 | #[repr(u32)] | 201 | fn get_waitresp_val(rlen: ResponseLen) -> u8 { |
| 193 | #[allow(dead_code)] | 202 | match rlen { |
| 194 | #[allow(non_camel_case_types)] | 203 | common_cmd::ResponseLen::Zero => 0, |
| 195 | enum CmdAppOper { | 204 | common_cmd::ResponseLen::R48 => 1, |
| 196 | VOLTAGE_WINDOW_SD = 0x8010_0000, | 205 | common_cmd::ResponseLen::R136 => 3, |
| 197 | HIGH_CAPACITY = 0x4000_0000, | 206 | } |
| 198 | SDMMC_STD_CAPACITY = 0x0000_0000, | ||
| 199 | SDMMC_CHECK_PATTERN = 0x0000_01AA, | ||
| 200 | SD_SWITCH_1_8V_CAPACITY = 0x0100_0000, | ||
| 201 | } | ||
| 202 | |||
| 203 | #[derive(Eq, PartialEq, Copy, Clone)] | ||
| 204 | enum Response { | ||
| 205 | None = 0, | ||
| 206 | Short = 1, | ||
| 207 | Long = 3, | ||
| 208 | } | 207 | } |
| 209 | 208 | ||
| 210 | /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to | 209 | /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to |
| @@ -301,6 +300,61 @@ impl Default for Config { | |||
| 301 | } | 300 | } |
| 302 | } | 301 | } |
| 303 | 302 | ||
| 303 | /// Peripheral that can be operated over SDMMC | ||
| 304 | #[derive(Clone, Copy, Debug)] | ||
| 305 | pub enum SdmmcPeripheral { | ||
| 306 | /// SD Card | ||
| 307 | SdCard(Card), | ||
| 308 | /// eMMC memory | ||
| 309 | Emmc(Emmc), | ||
| 310 | } | ||
| 311 | |||
| 312 | impl SdmmcPeripheral { | ||
| 313 | /// Get this peripheral's address on the SDMMC bus | ||
| 314 | fn get_address(&self) -> u16 { | ||
| 315 | match self { | ||
| 316 | Self::SdCard(c) => c.rca, | ||
| 317 | Self::Emmc(e) => e.rca, | ||
| 318 | } | ||
| 319 | } | ||
| 320 | /// Is this a standard or high capacity peripheral? | ||
| 321 | fn get_capacity(&self) -> CardCapacity { | ||
| 322 | match self { | ||
| 323 | Self::SdCard(c) => c.card_type, | ||
| 324 | Self::Emmc(e) => e.capacity, | ||
| 325 | } | ||
| 326 | } | ||
| 327 | /// Size in bytes | ||
| 328 | fn size(&self) -> u64 { | ||
| 329 | match self { | ||
| 330 | // SDHC / SDXC / SDUC | ||
| 331 | Self::SdCard(c) => u64::from(c.csd.block_count()) * 512, | ||
| 332 | // capacity > 2GB | ||
| 333 | Self::Emmc(e) => u64::from(e.ext_csd.sector_count()) * 512, | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | /// Get a mutable reference to the SD Card. | ||
| 338 | /// | ||
| 339 | /// Panics if there is another peripheral instead. | ||
| 340 | fn get_sd_card(&mut self) -> &mut Card { | ||
| 341 | match *self { | ||
| 342 | Self::SdCard(ref mut c) => c, | ||
| 343 | _ => unreachable!("SD only"), | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | /// Get a mutable reference to the eMMC. | ||
| 348 | /// | ||
| 349 | /// Panics if there is another peripheral instead. | ||
| 350 | fn get_emmc(&mut self) -> &mut Emmc { | ||
| 351 | match *self { | ||
| 352 | Self::Emmc(ref mut e) => e, | ||
| 353 | _ => unreachable!("eMMC only"), | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 304 | /// Sdmmc device | 358 | /// Sdmmc device |
| 305 | pub struct Sdmmc<'d, T: Instance> { | 359 | pub struct Sdmmc<'d, T: Instance> { |
| 306 | _peri: Peri<'d, T>, | 360 | _peri: Peri<'d, T>, |
| @@ -313,6 +367,10 @@ pub struct Sdmmc<'d, T: Instance> { | |||
| 313 | d1: Option<Peri<'d, AnyPin>>, | 367 | d1: Option<Peri<'d, AnyPin>>, |
| 314 | d2: Option<Peri<'d, AnyPin>>, | 368 | d2: Option<Peri<'d, AnyPin>>, |
| 315 | d3: Option<Peri<'d, AnyPin>>, | 369 | d3: Option<Peri<'d, AnyPin>>, |
| 370 | d4: Option<Peri<'d, AnyPin>>, | ||
| 371 | d5: Option<Peri<'d, AnyPin>>, | ||
| 372 | d6: Option<Peri<'d, AnyPin>>, | ||
| 373 | d7: Option<Peri<'d, AnyPin>>, | ||
| 316 | 374 | ||
| 317 | config: Config, | 375 | config: Config, |
| 318 | /// Current clock to card | 376 | /// Current clock to card |
| @@ -320,7 +378,7 @@ pub struct Sdmmc<'d, T: Instance> { | |||
| 320 | /// Current signalling scheme to card | 378 | /// Current signalling scheme to card |
| 321 | signalling: Signalling, | 379 | signalling: Signalling, |
| 322 | /// Card | 380 | /// Card |
| 323 | card: Option<Card>, | 381 | card: Option<SdmmcPeripheral>, |
| 324 | 382 | ||
| 325 | /// An optional buffer to be used for commands | 383 | /// An optional buffer to be used for commands |
| 326 | /// This should be used if there are special memory location requirements for dma | 384 | /// This should be used if there are special memory location requirements for dma |
| @@ -361,6 +419,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 361 | None, | 419 | None, |
| 362 | None, | 420 | None, |
| 363 | None, | 421 | None, |
| 422 | None, | ||
| 423 | None, | ||
| 424 | None, | ||
| 425 | None, | ||
| 364 | config, | 426 | config, |
| 365 | ) | 427 | ) |
| 366 | } | 428 | } |
| @@ -396,6 +458,60 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 396 | Some(d1.into()), | 458 | Some(d1.into()), |
| 397 | Some(d2.into()), | 459 | Some(d2.into()), |
| 398 | Some(d3.into()), | 460 | Some(d3.into()), |
| 461 | None, | ||
| 462 | None, | ||
| 463 | None, | ||
| 464 | None, | ||
| 465 | config, | ||
| 466 | ) | ||
| 467 | } | ||
| 468 | } | ||
| 469 | |||
| 470 | #[cfg(sdmmc_v1)] | ||
| 471 | impl<'d, T: Instance> Sdmmc<'d, T> { | ||
| 472 | /// Create a new SDMMC driver, with 8 data lanes. | ||
| 473 | pub fn new_8bit( | ||
| 474 | sdmmc: Peri<'d, T>, | ||
| 475 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 476 | dma: Peri<'d, impl SdmmcDma<T>>, | ||
| 477 | clk: Peri<'d, impl CkPin<T>>, | ||
| 478 | cmd: Peri<'d, impl CmdPin<T>>, | ||
| 479 | d0: Peri<'d, impl D0Pin<T>>, | ||
| 480 | d1: Peri<'d, impl D1Pin<T>>, | ||
| 481 | d2: Peri<'d, impl D2Pin<T>>, | ||
| 482 | d3: Peri<'d, impl D3Pin<T>>, | ||
| 483 | d4: Peri<'d, impl D4Pin<T>>, | ||
| 484 | d5: Peri<'d, impl D5Pin<T>>, | ||
| 485 | d6: Peri<'d, impl D6Pin<T>>, | ||
| 486 | d7: Peri<'d, impl D7Pin<T>>, | ||
| 487 | config: Config, | ||
| 488 | ) -> Self { | ||
| 489 | critical_section::with(|_| { | ||
| 490 | clk.set_as_af(clk.af_num(), CLK_AF); | ||
| 491 | cmd.set_as_af(cmd.af_num(), CMD_AF); | ||
| 492 | d0.set_as_af(d0.af_num(), DATA_AF); | ||
| 493 | d1.set_as_af(d1.af_num(), DATA_AF); | ||
| 494 | d2.set_as_af(d2.af_num(), DATA_AF); | ||
| 495 | d3.set_as_af(d3.af_num(), DATA_AF); | ||
| 496 | d4.set_as_af(d4.af_num(), DATA_AF); | ||
| 497 | d5.set_as_af(d5.af_num(), DATA_AF); | ||
| 498 | d6.set_as_af(d6.af_num(), DATA_AF); | ||
| 499 | d7.set_as_af(d7.af_num(), DATA_AF); | ||
| 500 | }); | ||
| 501 | |||
| 502 | Self::new_inner( | ||
| 503 | sdmmc, | ||
| 504 | new_dma_nonopt!(dma), | ||
| 505 | clk.into(), | ||
| 506 | cmd.into(), | ||
| 507 | d0.into(), | ||
| 508 | Some(d1.into()), | ||
| 509 | Some(d2.into()), | ||
| 510 | Some(d3.into()), | ||
| 511 | Some(d4.into()), | ||
| 512 | Some(d5.into()), | ||
| 513 | Some(d6.into()), | ||
| 514 | Some(d7.into()), | ||
| 399 | config, | 515 | config, |
| 400 | ) | 516 | ) |
| 401 | } | 517 | } |
| @@ -418,7 +534,20 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 418 | d0.set_as_af(d0.af_num(), DATA_AF); | 534 | d0.set_as_af(d0.af_num(), DATA_AF); |
| 419 | }); | 535 | }); |
| 420 | 536 | ||
| 421 | Self::new_inner(sdmmc, clk.into(), cmd.into(), d0.into(), None, None, None, config) | 537 | Self::new_inner( |
| 538 | sdmmc, | ||
| 539 | clk.into(), | ||
| 540 | cmd.into(), | ||
| 541 | d0.into(), | ||
| 542 | None, | ||
| 543 | None, | ||
| 544 | None, | ||
| 545 | None, | ||
| 546 | None, | ||
| 547 | None, | ||
| 548 | None, | ||
| 549 | config, | ||
| 550 | ) | ||
| 422 | } | 551 | } |
| 423 | 552 | ||
| 424 | /// Create a new SDMMC driver, with 4 data lanes. | 553 | /// Create a new SDMMC driver, with 4 data lanes. |
| @@ -450,6 +579,58 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 450 | Some(d1.into()), | 579 | Some(d1.into()), |
| 451 | Some(d2.into()), | 580 | Some(d2.into()), |
| 452 | Some(d3.into()), | 581 | Some(d3.into()), |
| 582 | None, | ||
| 583 | None, | ||
| 584 | None, | ||
| 585 | None, | ||
| 586 | config, | ||
| 587 | ) | ||
| 588 | } | ||
| 589 | } | ||
| 590 | |||
| 591 | #[cfg(sdmmc_v2)] | ||
| 592 | impl<'d, T: Instance> Sdmmc<'d, T> { | ||
| 593 | /// Create a new SDMMC driver, with 8 data lanes. | ||
| 594 | pub fn new_8bit( | ||
| 595 | sdmmc: Peri<'d, T>, | ||
| 596 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 597 | clk: Peri<'d, impl CkPin<T>>, | ||
| 598 | cmd: Peri<'d, impl CmdPin<T>>, | ||
| 599 | d0: Peri<'d, impl D0Pin<T>>, | ||
| 600 | d1: Peri<'d, impl D1Pin<T>>, | ||
| 601 | d2: Peri<'d, impl D2Pin<T>>, | ||
| 602 | d3: Peri<'d, impl D3Pin<T>>, | ||
| 603 | d4: Peri<'d, impl D4Pin<T>>, | ||
| 604 | d5: Peri<'d, impl D5Pin<T>>, | ||
| 605 | d6: Peri<'d, impl D6Pin<T>>, | ||
| 606 | d7: Peri<'d, impl D7Pin<T>>, | ||
| 607 | config: Config, | ||
| 608 | ) -> Self { | ||
| 609 | critical_section::with(|_| { | ||
| 610 | clk.set_as_af(clk.af_num(), CLK_AF); | ||
| 611 | cmd.set_as_af(cmd.af_num(), CMD_AF); | ||
| 612 | d0.set_as_af(d0.af_num(), DATA_AF); | ||
| 613 | d1.set_as_af(d1.af_num(), DATA_AF); | ||
| 614 | d2.set_as_af(d2.af_num(), DATA_AF); | ||
| 615 | d3.set_as_af(d3.af_num(), DATA_AF); | ||
| 616 | d4.set_as_af(d4.af_num(), DATA_AF); | ||
| 617 | d5.set_as_af(d5.af_num(), DATA_AF); | ||
| 618 | d6.set_as_af(d6.af_num(), DATA_AF); | ||
| 619 | d7.set_as_af(d7.af_num(), DATA_AF); | ||
| 620 | }); | ||
| 621 | |||
| 622 | Self::new_inner( | ||
| 623 | sdmmc, | ||
| 624 | clk.into(), | ||
| 625 | cmd.into(), | ||
| 626 | d0.into(), | ||
| 627 | Some(d1.into()), | ||
| 628 | Some(d2.into()), | ||
| 629 | Some(d3.into()), | ||
| 630 | Some(d4.into()), | ||
| 631 | Some(d5.into()), | ||
| 632 | Some(d6.into()), | ||
| 633 | Some(d7.into()), | ||
| 453 | config, | 634 | config, |
| 454 | ) | 635 | ) |
| 455 | } | 636 | } |
| @@ -465,6 +646,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 465 | d1: Option<Peri<'d, AnyPin>>, | 646 | d1: Option<Peri<'d, AnyPin>>, |
| 466 | d2: Option<Peri<'d, AnyPin>>, | 647 | d2: Option<Peri<'d, AnyPin>>, |
| 467 | d3: Option<Peri<'d, AnyPin>>, | 648 | d3: Option<Peri<'d, AnyPin>>, |
| 649 | d4: Option<Peri<'d, AnyPin>>, | ||
| 650 | d5: Option<Peri<'d, AnyPin>>, | ||
| 651 | d6: Option<Peri<'d, AnyPin>>, | ||
| 652 | d7: Option<Peri<'d, AnyPin>>, | ||
| 468 | config: Config, | 653 | config: Config, |
| 469 | ) -> Self { | 654 | ) -> Self { |
| 470 | rcc::enable_and_reset::<T>(); | 655 | rcc::enable_and_reset::<T>(); |
| @@ -503,6 +688,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 503 | d1, | 688 | d1, |
| 504 | d2, | 689 | d2, |
| 505 | d3, | 690 | d3, |
| 691 | d4, | ||
| 692 | d5, | ||
| 693 | d6, | ||
| 694 | d7, | ||
| 506 | 695 | ||
| 507 | config, | 696 | config, |
| 508 | clock: SD_INIT_FREQ, | 697 | clock: SD_INIT_FREQ, |
| @@ -673,182 +862,29 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 673 | Ok(()) | 862 | Ok(()) |
| 674 | } | 863 | } |
| 675 | 864 | ||
| 676 | /// Switch mode using CMD6. | ||
| 677 | /// | ||
| 678 | /// Attempt to set a new signalling mode. The selected | ||
| 679 | /// signalling mode is returned. Expects the current clock | ||
| 680 | /// frequency to be > 12.5MHz. | ||
| 681 | async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> { | ||
| 682 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | ||
| 683 | // necessary" | ||
| 684 | |||
| 685 | let set_function = 0x8000_0000 | ||
| 686 | | match signalling { | ||
| 687 | // See PLSS v7_10 Table 4-11 | ||
| 688 | Signalling::DDR50 => 0xFF_FF04, | ||
| 689 | Signalling::SDR104 => 0xFF_1F03, | ||
| 690 | Signalling::SDR50 => 0xFF_1F02, | ||
| 691 | Signalling::SDR25 => 0xFF_FF01, | ||
| 692 | Signalling::SDR12 => 0xFF_FF00, | ||
| 693 | }; | ||
| 694 | |||
| 695 | let status = match self.cmd_block.as_deref_mut() { | ||
| 696 | Some(x) => x, | ||
| 697 | None => &mut CmdBlock::new(), | ||
| 698 | }; | ||
| 699 | |||
| 700 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 701 | let regs = T::regs(); | ||
| 702 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 703 | |||
| 704 | let transfer = Self::prepare_datapath_read( | ||
| 705 | &self.config, | ||
| 706 | #[cfg(sdmmc_v1)] | ||
| 707 | &mut self.dma, | ||
| 708 | status.as_mut(), | ||
| 709 | 64, | ||
| 710 | 6, | ||
| 711 | ); | ||
| 712 | InterruptHandler::<T>::data_interrupts(true); | ||
| 713 | Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 | ||
| 714 | |||
| 715 | let res = poll_fn(|cx| { | ||
| 716 | T::state().register(cx.waker()); | ||
| 717 | let status = regs.star().read(); | ||
| 718 | |||
| 719 | if status.dcrcfail() { | ||
| 720 | return Poll::Ready(Err(Error::Crc)); | ||
| 721 | } | ||
| 722 | if status.dtimeout() { | ||
| 723 | return Poll::Ready(Err(Error::Timeout)); | ||
| 724 | } | ||
| 725 | #[cfg(sdmmc_v1)] | ||
| 726 | if status.stbiterr() { | ||
| 727 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 728 | } | ||
| 729 | if status.dataend() { | ||
| 730 | return Poll::Ready(Ok(())); | ||
| 731 | } | ||
| 732 | Poll::Pending | ||
| 733 | }) | ||
| 734 | .await; | ||
| 735 | Self::clear_interrupt_flags(); | ||
| 736 | |||
| 737 | // Host is allowed to use the new functions at least 8 | ||
| 738 | // clocks after the end of the switch command | ||
| 739 | // transaction. We know the current clock period is < 80ns, | ||
| 740 | // so a total delay of 640ns is required here | ||
| 741 | for _ in 0..300 { | ||
| 742 | cortex_m::asm::nop(); | ||
| 743 | } | ||
| 744 | |||
| 745 | match res { | ||
| 746 | Ok(_) => { | ||
| 747 | on_drop.defuse(); | ||
| 748 | Self::stop_datapath(); | ||
| 749 | drop(transfer); | ||
| 750 | |||
| 751 | // Function Selection of Function Group 1 | ||
| 752 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; | ||
| 753 | |||
| 754 | match selection { | ||
| 755 | 0 => Ok(Signalling::SDR12), | ||
| 756 | 1 => Ok(Signalling::SDR25), | ||
| 757 | 2 => Ok(Signalling::SDR50), | ||
| 758 | 3 => Ok(Signalling::SDR104), | ||
| 759 | 4 => Ok(Signalling::DDR50), | ||
| 760 | _ => Err(Error::UnsupportedCardType), | ||
| 761 | } | ||
| 762 | } | ||
| 763 | Err(e) => Err(e), | ||
| 764 | } | ||
| 765 | } | ||
| 766 | |||
| 767 | /// Query the card status (CMD13, returns R1) | 865 | /// Query the card status (CMD13, returns R1) |
| 768 | fn read_status(&self, card: &Card) -> Result<CardStatus, Error> { | 866 | fn read_status<Ext>(&self, card: &SdmmcPeripheral) -> Result<CardStatus<Ext>, Error> |
| 867 | where | ||
| 868 | CardStatus<Ext>: From<u32>, | ||
| 869 | { | ||
| 769 | let regs = T::regs(); | 870 | let regs = T::regs(); |
| 770 | let rca = card.rca; | 871 | let rca = card.get_address(); |
| 771 | 872 | ||
| 772 | Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 | 873 | Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 |
| 773 | 874 | ||
| 774 | let r1 = regs.respr(0).read().cardstatus(); | 875 | let r1 = regs.respr(0).read().cardstatus(); |
| 775 | Ok(r1.into()) | 876 | Ok(r1.into()) |
| 776 | } | 877 | } |
| 777 | 878 | ||
| 778 | /// Reads the SD Status (ACMD13) | ||
| 779 | async fn read_sd_status(&mut self) -> Result<(), Error> { | ||
| 780 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | ||
| 781 | let rca = card.rca; | ||
| 782 | |||
| 783 | let cmd_block = match self.cmd_block.as_deref_mut() { | ||
| 784 | Some(x) => x, | ||
| 785 | None => &mut CmdBlock::new(), | ||
| 786 | }; | ||
| 787 | |||
| 788 | Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 | ||
| 789 | Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP | ||
| 790 | |||
| 791 | let status = cmd_block; | ||
| 792 | |||
| 793 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 794 | let regs = T::regs(); | ||
| 795 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 796 | |||
| 797 | let transfer = Self::prepare_datapath_read( | ||
| 798 | &self.config, | ||
| 799 | #[cfg(sdmmc_v1)] | ||
| 800 | &mut self.dma, | ||
| 801 | status.as_mut(), | ||
| 802 | 64, | ||
| 803 | 6, | ||
| 804 | ); | ||
| 805 | InterruptHandler::<T>::data_interrupts(true); | ||
| 806 | Self::cmd(Cmd::card_status(0), true)?; | ||
| 807 | |||
| 808 | let res = poll_fn(|cx| { | ||
| 809 | T::state().register(cx.waker()); | ||
| 810 | let status = regs.star().read(); | ||
| 811 | |||
| 812 | if status.dcrcfail() { | ||
| 813 | return Poll::Ready(Err(Error::Crc)); | ||
| 814 | } | ||
| 815 | if status.dtimeout() { | ||
| 816 | return Poll::Ready(Err(Error::Timeout)); | ||
| 817 | } | ||
| 818 | #[cfg(sdmmc_v1)] | ||
| 819 | if status.stbiterr() { | ||
| 820 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 821 | } | ||
| 822 | if status.dataend() { | ||
| 823 | return Poll::Ready(Ok(())); | ||
| 824 | } | ||
| 825 | Poll::Pending | ||
| 826 | }) | ||
| 827 | .await; | ||
| 828 | Self::clear_interrupt_flags(); | ||
| 829 | |||
| 830 | if res.is_ok() { | ||
| 831 | on_drop.defuse(); | ||
| 832 | Self::stop_datapath(); | ||
| 833 | drop(transfer); | ||
| 834 | |||
| 835 | for byte in status.iter_mut() { | ||
| 836 | *byte = u32::from_be(*byte); | ||
| 837 | } | ||
| 838 | self.card.as_mut().unwrap().status = status.0.into(); | ||
| 839 | } | ||
| 840 | res | ||
| 841 | } | ||
| 842 | |||
| 843 | /// Select one card and place it into the _Tranfer State_ | 879 | /// Select one card and place it into the _Tranfer State_ |
| 844 | /// | 880 | /// |
| 845 | /// If `None` is specifed for `card`, all cards are put back into | 881 | /// If `None` is specifed for `card`, all cards are put back into |
| 846 | /// _Stand-by State_ | 882 | /// _Stand-by State_ |
| 847 | fn select_card(&self, card: Option<&Card>) -> Result<(), Error> { | 883 | fn select_card(&self, rca: Option<u16>) -> Result<(), Error> { |
| 848 | // Determine Relative Card Address (RCA) of given card | 884 | // Determine Relative Card Address (RCA) of given card |
| 849 | let rca = card.map(|c| c.rca << 16).unwrap_or(0); | 885 | let rca = rca.unwrap_or(0); |
| 850 | 886 | ||
| 851 | let r = Self::cmd(Cmd::sel_desel_card(rca), false); | 887 | let r = Self::cmd(common_cmd::select_card(rca), false); |
| 852 | match (r, rca) { | 888 | match (r, rca) { |
| 853 | (Err(Error::Timeout), 0) => Ok(()), | 889 | (Err(Error::Timeout), 0) => Ok(()), |
| 854 | _ => r, | 890 | _ => r, |
| @@ -889,70 +925,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 889 | }); | 925 | }); |
| 890 | } | 926 | } |
| 891 | 927 | ||
| 892 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | ||
| 893 | // Read the 64-bit SCR register | ||
| 894 | Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 | ||
| 895 | Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; | ||
| 896 | |||
| 897 | let cmd_block = match self.cmd_block.as_deref_mut() { | ||
| 898 | Some(x) => x, | ||
| 899 | None => &mut CmdBlock::new(), | ||
| 900 | }; | ||
| 901 | let scr = &mut cmd_block.0[..2]; | ||
| 902 | |||
| 903 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 904 | let regs = T::regs(); | ||
| 905 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 906 | |||
| 907 | let transfer = Self::prepare_datapath_read( | ||
| 908 | &self.config, | ||
| 909 | #[cfg(sdmmc_v1)] | ||
| 910 | &mut self.dma, | ||
| 911 | scr, | ||
| 912 | 8, | ||
| 913 | 3, | ||
| 914 | ); | ||
| 915 | InterruptHandler::<T>::data_interrupts(true); | ||
| 916 | Self::cmd(Cmd::cmd51(), true)?; | ||
| 917 | |||
| 918 | let res = poll_fn(|cx| { | ||
| 919 | T::state().register(cx.waker()); | ||
| 920 | let status = regs.star().read(); | ||
| 921 | |||
| 922 | if status.dcrcfail() { | ||
| 923 | return Poll::Ready(Err(Error::Crc)); | ||
| 924 | } | ||
| 925 | if status.dtimeout() { | ||
| 926 | return Poll::Ready(Err(Error::Timeout)); | ||
| 927 | } | ||
| 928 | #[cfg(sdmmc_v1)] | ||
| 929 | if status.stbiterr() { | ||
| 930 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 931 | } | ||
| 932 | if status.dataend() { | ||
| 933 | return Poll::Ready(Ok(())); | ||
| 934 | } | ||
| 935 | Poll::Pending | ||
| 936 | }) | ||
| 937 | .await; | ||
| 938 | Self::clear_interrupt_flags(); | ||
| 939 | |||
| 940 | if res.is_ok() { | ||
| 941 | on_drop.defuse(); | ||
| 942 | Self::stop_datapath(); | ||
| 943 | drop(transfer); | ||
| 944 | |||
| 945 | unsafe { | ||
| 946 | let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); | ||
| 947 | card.scr = SCR(u64::from_be_bytes(*scr_bytes)); | ||
| 948 | } | ||
| 949 | } | ||
| 950 | res | ||
| 951 | } | ||
| 952 | |||
| 953 | /// Send command to card | 928 | /// Send command to card |
| 954 | #[allow(unused_variables)] | 929 | #[allow(unused_variables)] |
| 955 | fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { | 930 | fn cmd<R: Resp>(cmd: Cmd<R>, data: bool) -> Result<(), Error> { |
| 956 | let regs = T::regs(); | 931 | let regs = T::regs(); |
| 957 | 932 | ||
| 958 | Self::clear_interrupt_flags(); | 933 | Self::clear_interrupt_flags(); |
| @@ -965,7 +940,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 965 | // Command index and start CP State Machine | 940 | // Command index and start CP State Machine |
| 966 | regs.cmdr().write(|w| { | 941 | regs.cmdr().write(|w| { |
| 967 | w.set_waitint(false); | 942 | w.set_waitint(false); |
| 968 | w.set_waitresp(cmd.resp as u8); | 943 | w.set_waitresp(get_waitresp_val(cmd.response_len())); |
| 969 | w.set_cmdindex(cmd.cmd); | 944 | w.set_cmdindex(cmd.cmd); |
| 970 | w.set_cpsmen(true); | 945 | w.set_cpsmen(true); |
| 971 | 946 | ||
| @@ -980,7 +955,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 980 | }); | 955 | }); |
| 981 | 956 | ||
| 982 | let mut status; | 957 | let mut status; |
| 983 | if cmd.resp == Response::None { | 958 | if cmd.response_len() == ResponseLen::Zero { |
| 984 | // Wait for CMDSENT or a timeout | 959 | // Wait for CMDSENT or a timeout |
| 985 | while { | 960 | while { |
| 986 | status = regs.star().read(); | 961 | status = regs.star().read(); |
| @@ -1016,7 +991,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1016 | // Command index and start CP State Machine | 991 | // Command index and start CP State Machine |
| 1017 | regs.cmdr().write(|w| { | 992 | regs.cmdr().write(|w| { |
| 1018 | w.set_waitint(false); | 993 | w.set_waitint(false); |
| 1019 | w.set_waitresp(Response::Short as u8); | 994 | w.set_waitresp(get_waitresp_val(ResponseLen::R48)); |
| 1020 | w.set_cmdindex(12); | 995 | w.set_cmdindex(12); |
| 1021 | w.set_cpsmen(true); | 996 | w.set_cpsmen(true); |
| 1022 | 997 | ||
| @@ -1035,14 +1010,169 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1035 | Self::stop_datapath(); | 1010 | Self::stop_datapath(); |
| 1036 | } | 1011 | } |
| 1037 | 1012 | ||
| 1038 | /// Initializes card (if present) and sets the bus at the specified frequency. | 1013 | /// Wait for a previously started datapath transfer to complete from an interrupt. |
| 1039 | pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { | 1014 | #[inline] |
| 1015 | async fn complete_datapath_transfer() -> Result<(), Error> { | ||
| 1016 | let regs = T::regs(); | ||
| 1017 | |||
| 1018 | let res = poll_fn(|cx| { | ||
| 1019 | T::state().register(cx.waker()); | ||
| 1020 | let status = regs.star().read(); | ||
| 1021 | |||
| 1022 | if status.dcrcfail() { | ||
| 1023 | return Poll::Ready(Err(Error::Crc)); | ||
| 1024 | } | ||
| 1025 | if status.dtimeout() { | ||
| 1026 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1027 | } | ||
| 1028 | #[cfg(sdmmc_v1)] | ||
| 1029 | if status.stbiterr() { | ||
| 1030 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 1031 | } | ||
| 1032 | if status.dataend() { | ||
| 1033 | return Poll::Ready(Ok(())); | ||
| 1034 | } | ||
| 1035 | Poll::Pending | ||
| 1036 | }) | ||
| 1037 | .await; | ||
| 1038 | |||
| 1039 | Self::clear_interrupt_flags(); | ||
| 1040 | |||
| 1041 | res | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | /// Read a data block. | ||
| 1045 | #[inline] | ||
| 1046 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 1047 | let card_capacity = self.card()?.get_capacity(); | ||
| 1048 | |||
| 1049 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1050 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 1051 | |||
| 1052 | // Always read 1 block of 512 bytes | ||
| 1053 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1054 | let address = match card_capacity { | ||
| 1055 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1056 | _ => block_idx, | ||
| 1057 | }; | ||
| 1058 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1059 | |||
| 1060 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1061 | |||
| 1062 | let transfer = Self::prepare_datapath_read( | ||
| 1063 | &self.config, | ||
| 1064 | #[cfg(sdmmc_v1)] | ||
| 1065 | &mut self.dma, | ||
| 1066 | buffer, | ||
| 1067 | 512, | ||
| 1068 | 9, | ||
| 1069 | ); | ||
| 1070 | InterruptHandler::<T>::data_interrupts(true); | ||
| 1071 | Self::cmd(common_cmd::read_single_block(address), true)?; | ||
| 1072 | |||
| 1073 | let res = Self::complete_datapath_transfer().await; | ||
| 1074 | |||
| 1075 | if res.is_ok() { | ||
| 1076 | on_drop.defuse(); | ||
| 1077 | Self::stop_datapath(); | ||
| 1078 | drop(transfer); | ||
| 1079 | } | ||
| 1080 | res | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | /// Write a data block. | ||
| 1084 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | ||
| 1085 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | ||
| 1086 | |||
| 1087 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1088 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | ||
| 1089 | |||
| 1090 | // Always read 1 block of 512 bytes | ||
| 1091 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1092 | let address = match card.get_capacity() { | ||
| 1093 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1094 | _ => block_idx, | ||
| 1095 | }; | ||
| 1096 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1097 | |||
| 1098 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1099 | |||
| 1100 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 1101 | #[cfg(sdmmc_v1)] | ||
| 1102 | Self::cmd(common_cmd::write_single_block(address), true)?; | ||
| 1103 | |||
| 1104 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | ||
| 1105 | InterruptHandler::<T>::data_interrupts(true); | ||
| 1106 | |||
| 1107 | #[cfg(sdmmc_v2)] | ||
| 1108 | Self::cmd(common_cmd::write_single_block(address), true)?; | ||
| 1109 | |||
| 1110 | let res = Self::complete_datapath_transfer().await; | ||
| 1111 | |||
| 1112 | match res { | ||
| 1113 | Ok(_) => { | ||
| 1114 | on_drop.defuse(); | ||
| 1115 | Self::stop_datapath(); | ||
| 1116 | drop(transfer); | ||
| 1117 | |||
| 1118 | // TODO: Make this configurable | ||
| 1119 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 1120 | |||
| 1121 | let card = self.card.as_ref().unwrap(); | ||
| 1122 | while timeout > 0 { | ||
| 1123 | let ready_for_data = match card { | ||
| 1124 | SdmmcPeripheral::Emmc(_) => self.read_status::<EMMC>(card)?.ready_for_data(), | ||
| 1125 | SdmmcPeripheral::SdCard(_) => self.read_status::<SD>(card)?.ready_for_data(), | ||
| 1126 | }; | ||
| 1127 | |||
| 1128 | if ready_for_data { | ||
| 1129 | return Ok(()); | ||
| 1130 | } | ||
| 1131 | timeout -= 1; | ||
| 1132 | } | ||
| 1133 | Err(Error::SoftwareTimeout) | ||
| 1134 | } | ||
| 1135 | Err(e) => Err(e), | ||
| 1136 | } | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | /// Get a reference to the initialized card | ||
| 1140 | /// | ||
| 1141 | /// # Errors | ||
| 1142 | /// | ||
| 1143 | /// Returns Error::NoCard if [`init_sd_card`](#method.init_sd_card) or | ||
| 1144 | /// [`init_emmc`](#method.init_emmc) has not previously succeeded | ||
| 1145 | #[inline] | ||
| 1146 | pub fn card(&self) -> Result<&SdmmcPeripheral, Error> { | ||
| 1147 | self.card.as_ref().ok_or(Error::NoCard) | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | /// Get the current SDMMC bus clock | ||
| 1151 | pub fn clock(&self) -> Hertz { | ||
| 1152 | self.clock | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | /// Set a specific cmd buffer rather than using the default stack allocated one. | ||
| 1156 | /// This is required if stack RAM cannot be used with DMA and usually manifests | ||
| 1157 | /// itself as an indefinite wait on a dma transfer because the dma peripheral | ||
| 1158 | /// cannot access the memory. | ||
| 1159 | pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { | ||
| 1160 | self.cmd_block = Some(cmd_block) | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> { | ||
| 1040 | let regs = T::regs(); | 1164 | let regs = T::regs(); |
| 1041 | let ker_ck = T::frequency(); | 1165 | let ker_ck = T::frequency(); |
| 1042 | 1166 | ||
| 1043 | let bus_width = match self.d3.is_some() { | 1167 | let bus_width = match (self.d3.is_some(), self.d7.is_some()) { |
| 1044 | true => BusWidth::Four, | 1168 | (true, true) => { |
| 1045 | false => BusWidth::One, | 1169 | if matches!(card, SdmmcPeripheral::SdCard(_)) { |
| 1170 | return Err(Error::BusWidth); | ||
| 1171 | } | ||
| 1172 | BusWidth::Eight | ||
| 1173 | } | ||
| 1174 | (true, false) => BusWidth::Four, | ||
| 1175 | _ => BusWidth::One, | ||
| 1046 | }; | 1176 | }; |
| 1047 | 1177 | ||
| 1048 | // While the SD/SDIO card or eMMC is in identification mode, | 1178 | // While the SD/SDIO card or eMMC is in identification mode, |
| @@ -1061,283 +1191,424 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1061 | }); | 1191 | }); |
| 1062 | 1192 | ||
| 1063 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | 1193 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); |
| 1064 | Self::cmd(Cmd::idle(), false)?; | 1194 | Self::cmd(common_cmd::idle(), false)?; |
| 1065 | 1195 | ||
| 1066 | // Check if cards supports CMD8 (with pattern) | 1196 | match card { |
| 1067 | Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; | 1197 | SdmmcPeripheral::SdCard(ref mut card) => { |
| 1068 | let r1 = regs.respr(0).read().cardstatus(); | 1198 | // Check if cards supports CMD8 (with pattern) |
| 1199 | Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; | ||
| 1200 | let cic = CIC::from(regs.respr(0).read().cardstatus()); | ||
| 1069 | 1201 | ||
| 1070 | let mut card = if r1 == 0x1AA { | 1202 | if cic.pattern() != 0xAA { |
| 1071 | // Card echoed back the pattern. Must be at least v2 | 1203 | return Err(Error::UnsupportedCardVersion); |
| 1072 | Card::default() | 1204 | } |
| 1073 | } else { | ||
| 1074 | return Err(Error::UnsupportedCardVersion); | ||
| 1075 | }; | ||
| 1076 | 1205 | ||
| 1077 | let ocr = loop { | 1206 | if cic.voltage_accepted() & 1 == 0 { |
| 1078 | // Signal that next command is a app command | 1207 | return Err(Error::UnsupportedVoltage); |
| 1079 | Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 | 1208 | } |
| 1080 | 1209 | ||
| 1081 | let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 | 1210 | let ocr = loop { |
| 1082 | | CmdAppOper::HIGH_CAPACITY as u32 | 1211 | // Signal that next command is a app command |
| 1083 | | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; | 1212 | Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55 |
| 1213 | |||
| 1214 | // 3.2-3.3V | ||
| 1215 | let voltage_window = 1 << 5; | ||
| 1216 | // Initialize card | ||
| 1217 | match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { | ||
| 1218 | // ACMD41 | ||
| 1219 | Ok(_) => (), | ||
| 1220 | Err(Error::Crc) => (), | ||
| 1221 | Err(err) => return Err(err), | ||
| 1222 | } | ||
| 1223 | let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into(); | ||
| 1224 | if !ocr.is_busy() { | ||
| 1225 | // Power up done | ||
| 1226 | break ocr; | ||
| 1227 | } | ||
| 1228 | }; | ||
| 1084 | 1229 | ||
| 1085 | // Initialize card | 1230 | if ocr.high_capacity() { |
| 1086 | match Self::cmd(Cmd::app_op_cmd(arg), false) { | 1231 | // Card is SDHC or SDXC or SDUC |
| 1087 | // ACMD41 | 1232 | card.card_type = CardCapacity::HighCapacity; |
| 1088 | Ok(_) => (), | 1233 | } else { |
| 1089 | Err(Error::Crc) => (), | 1234 | card.card_type = CardCapacity::StandardCapacity; |
| 1090 | Err(err) => return Err(err), | 1235 | } |
| 1236 | card.ocr = ocr; | ||
| 1091 | } | 1237 | } |
| 1092 | let ocr: OCR = regs.respr(0).read().cardstatus().into(); | 1238 | SdmmcPeripheral::Emmc(ref mut emmc) => { |
| 1093 | if !ocr.is_busy() { | 1239 | let ocr = loop { |
| 1094 | // Power up done | 1240 | let high_voltage = 0b0 << 7; |
| 1095 | break ocr; | 1241 | let access_mode = 0b10 << 29; |
| 1242 | let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; | ||
| 1243 | // Initialize card | ||
| 1244 | match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) { | ||
| 1245 | Ok(_) => (), | ||
| 1246 | Err(Error::Crc) => (), | ||
| 1247 | Err(err) => return Err(err), | ||
| 1248 | } | ||
| 1249 | let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into(); | ||
| 1250 | if !ocr.is_busy() { | ||
| 1251 | // Power up done | ||
| 1252 | break ocr; | ||
| 1253 | } | ||
| 1254 | }; | ||
| 1255 | |||
| 1256 | emmc.capacity = if ocr.access_mode() == 0b10 { | ||
| 1257 | // Card is SDHC or SDXC or SDUC | ||
| 1258 | CardCapacity::HighCapacity | ||
| 1259 | } else { | ||
| 1260 | CardCapacity::StandardCapacity | ||
| 1261 | }; | ||
| 1262 | emmc.ocr = ocr; | ||
| 1096 | } | 1263 | } |
| 1097 | }; | ||
| 1098 | |||
| 1099 | if ocr.high_capacity() { | ||
| 1100 | // Card is SDHC or SDXC or SDUC | ||
| 1101 | card.card_type = CardCapacity::SDHC; | ||
| 1102 | } else { | ||
| 1103 | card.card_type = CardCapacity::SDSC; | ||
| 1104 | } | 1264 | } |
| 1105 | card.ocr = ocr; | ||
| 1106 | 1265 | ||
| 1107 | Self::cmd(Cmd::all_send_cid(), false)?; // CMD2 | 1266 | Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 |
| 1108 | let cid0 = regs.respr(0).read().cardstatus() as u128; | 1267 | let cid0 = regs.respr(0).read().cardstatus() as u128; |
| 1109 | let cid1 = regs.respr(1).read().cardstatus() as u128; | 1268 | let cid1 = regs.respr(1).read().cardstatus() as u128; |
| 1110 | let cid2 = regs.respr(2).read().cardstatus() as u128; | 1269 | let cid2 = regs.respr(2).read().cardstatus() as u128; |
| 1111 | let cid3 = regs.respr(3).read().cardstatus() as u128; | 1270 | let cid3 = regs.respr(3).read().cardstatus() as u128; |
| 1112 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | 1271 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); |
| 1113 | card.cid = cid.into(); | ||
| 1114 | 1272 | ||
| 1115 | Self::cmd(Cmd::send_rel_addr(), false)?; | 1273 | match card { |
| 1116 | card.rca = regs.respr(0).read().cardstatus() >> 16; | 1274 | SdmmcPeripheral::SdCard(ref mut card) => { |
| 1275 | card.cid = cid.into(); | ||
| 1117 | 1276 | ||
| 1118 | Self::cmd(Cmd::send_csd(card.rca << 16), false)?; | 1277 | Self::cmd(sd_cmd::send_relative_address(), false)?; |
| 1278 | let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus()); | ||
| 1279 | card.rca = rca.address(); | ||
| 1280 | } | ||
| 1281 | SdmmcPeripheral::Emmc(ref mut emmc) => { | ||
| 1282 | emmc.cid = cid.into(); | ||
| 1283 | |||
| 1284 | emmc.rca = 1u16.into(); | ||
| 1285 | Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; | ||
| 1286 | } | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | Self::cmd(common_cmd::send_csd(card.get_address()), false)?; | ||
| 1119 | let csd0 = regs.respr(0).read().cardstatus() as u128; | 1290 | let csd0 = regs.respr(0).read().cardstatus() as u128; |
| 1120 | let csd1 = regs.respr(1).read().cardstatus() as u128; | 1291 | let csd1 = regs.respr(1).read().cardstatus() as u128; |
| 1121 | let csd2 = regs.respr(2).read().cardstatus() as u128; | 1292 | let csd2 = regs.respr(2).read().cardstatus() as u128; |
| 1122 | let csd3 = regs.respr(3).read().cardstatus() as u128; | 1293 | let csd3 = regs.respr(3).read().cardstatus() as u128; |
| 1123 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | 1294 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); |
| 1124 | card.csd = csd.into(); | ||
| 1125 | 1295 | ||
| 1126 | self.select_card(Some(&card))?; | 1296 | self.select_card(Some(card.get_address()))?; |
| 1297 | |||
| 1298 | let bus_width = match card { | ||
| 1299 | SdmmcPeripheral::SdCard(ref mut card) => { | ||
| 1300 | card.csd = csd.into(); | ||
| 1127 | 1301 | ||
| 1128 | self.get_scr(&mut card).await?; | 1302 | self.get_scr(card).await?; |
| 1303 | |||
| 1304 | if !card.scr.bus_width_four() { | ||
| 1305 | BusWidth::One | ||
| 1306 | } else { | ||
| 1307 | BusWidth::Four | ||
| 1308 | } | ||
| 1309 | } | ||
| 1310 | SdmmcPeripheral::Emmc(ref mut emmc) => { | ||
| 1311 | emmc.csd = csd.into(); | ||
| 1312 | |||
| 1313 | bus_width | ||
| 1314 | } | ||
| 1315 | }; | ||
| 1129 | 1316 | ||
| 1130 | // Set bus width | 1317 | // Set bus width |
| 1131 | let (width, acmd_arg) = match bus_width { | 1318 | let widbus = match bus_width { |
| 1132 | BusWidth::Eight => unimplemented!(), | 1319 | BusWidth::Eight => 2, |
| 1133 | BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), | 1320 | BusWidth::Four => 1, |
| 1134 | _ => (BusWidth::One, 0), | 1321 | BusWidth::One => 0, |
| 1322 | _ => unreachable!(), | ||
| 1135 | }; | 1323 | }; |
| 1136 | Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; | 1324 | |
| 1137 | Self::cmd(Cmd::cmd6(acmd_arg), false)?; | 1325 | match card { |
| 1326 | SdmmcPeripheral::SdCard(ref mut card) => { | ||
| 1327 | let acmd_arg = match bus_width { | ||
| 1328 | BusWidth::Four if card.scr.bus_width_four() => 2, | ||
| 1329 | _ => 0, | ||
| 1330 | }; | ||
| 1331 | Self::cmd(common_cmd::app_cmd(card.rca), false)?; | ||
| 1332 | Self::cmd(sd_cmd::cmd6(acmd_arg), false)?; | ||
| 1333 | } | ||
| 1334 | SdmmcPeripheral::Emmc(_) => { | ||
| 1335 | // Write bus width to ExtCSD byte 183 | ||
| 1336 | Self::cmd( | ||
| 1337 | emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), | ||
| 1338 | false, | ||
| 1339 | )?; | ||
| 1340 | |||
| 1341 | // Wait for ready after R1b response | ||
| 1342 | loop { | ||
| 1343 | let status = self.read_status::<EMMC>(&card)?; | ||
| 1344 | |||
| 1345 | if status.ready_for_data() { | ||
| 1346 | break; | ||
| 1347 | } | ||
| 1348 | } | ||
| 1349 | } | ||
| 1350 | } | ||
| 1138 | 1351 | ||
| 1139 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | 1352 | // CPSMACT and DPSMACT must be 0 to set WIDBUS |
| 1140 | Self::wait_idle(); | 1353 | Self::wait_idle(); |
| 1141 | 1354 | ||
| 1142 | regs.clkcr().modify(|w| { | 1355 | regs.clkcr().modify(|w| w.set_widbus(widbus)); |
| 1143 | w.set_widbus(match width { | ||
| 1144 | BusWidth::One => 0, | ||
| 1145 | BusWidth::Four => 1, | ||
| 1146 | BusWidth::Eight => 2, | ||
| 1147 | _ => panic!("Invalid Bus Width"), | ||
| 1148 | }) | ||
| 1149 | }); | ||
| 1150 | 1356 | ||
| 1151 | // Set Clock | 1357 | // Set Clock |
| 1152 | if freq.0 <= 25_000_000 { | 1358 | if freq.0 <= 25_000_000 { |
| 1153 | // Final clock frequency | 1359 | // Final clock frequency |
| 1154 | self.clkcr_set_clkdiv(freq.0, width)?; | 1360 | self.clkcr_set_clkdiv(freq.0, bus_width)?; |
| 1155 | } else { | 1361 | } else { |
| 1156 | // Switch to max clock for SDR12 | 1362 | // Switch to max clock for SDR12 |
| 1157 | self.clkcr_set_clkdiv(25_000_000, width)?; | 1363 | self.clkcr_set_clkdiv(25_000_000, bus_width)?; |
| 1158 | } | 1364 | } |
| 1159 | 1365 | ||
| 1160 | self.card = Some(card); | 1366 | self.card = Some(card); |
| 1161 | 1367 | ||
| 1162 | // Read status | 1368 | match card { |
| 1163 | self.read_sd_status().await?; | 1369 | SdmmcPeripheral::SdCard(_) => { |
| 1370 | // Read status | ||
| 1371 | self.read_sd_status().await?; | ||
| 1164 | 1372 | ||
| 1165 | if freq.0 > 25_000_000 { | 1373 | if freq.0 > 25_000_000 { |
| 1166 | // Switch to SDR25 | 1374 | // Switch to SDR25 |
| 1167 | self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; | 1375 | self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; |
| 1168 | 1376 | ||
| 1169 | if self.signalling == Signalling::SDR25 { | 1377 | if self.signalling == Signalling::SDR25 { |
| 1170 | // Set final clock frequency | 1378 | // Set final clock frequency |
| 1171 | self.clkcr_set_clkdiv(freq.0, width)?; | 1379 | self.clkcr_set_clkdiv(freq.0, bus_width)?; |
| 1172 | 1380 | ||
| 1173 | if self.read_status(&card)?.state() != CurrentState::Transfer { | 1381 | if self.read_status::<SD>(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { |
| 1174 | return Err(Error::SignalingSwitchFailed); | 1382 | return Err(Error::SignalingSwitchFailed); |
| 1383 | } | ||
| 1384 | } | ||
| 1175 | } | 1385 | } |
| 1386 | |||
| 1387 | // Read status after signalling change | ||
| 1388 | self.read_sd_status().await?; | ||
| 1389 | } | ||
| 1390 | SdmmcPeripheral::Emmc(_) => { | ||
| 1391 | self.read_ext_csd().await?; | ||
| 1176 | } | 1392 | } |
| 1177 | } | 1393 | } |
| 1178 | 1394 | ||
| 1179 | // Read status after signalling change | ||
| 1180 | self.read_sd_status().await?; | ||
| 1181 | |||
| 1182 | Ok(()) | 1395 | Ok(()) |
| 1183 | } | 1396 | } |
| 1184 | 1397 | ||
| 1185 | /// Read a data block. | 1398 | /// Initializes card (if present) and sets the bus at the specified frequency. |
| 1186 | #[inline] | 1399 | /// |
| 1187 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | 1400 | /// SD only. |
| 1188 | let card_capacity = self.card()?.card_type; | 1401 | pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> { |
| 1402 | self.init_internal(freq, SdmmcPeripheral::SdCard(Card::default())).await | ||
| 1403 | } | ||
| 1189 | 1404 | ||
| 1190 | // NOTE(unsafe) DataBlock uses align 4 | 1405 | /// Switch mode using CMD6. |
| 1191 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | 1406 | /// |
| 1407 | /// Attempt to set a new signalling mode. The selected | ||
| 1408 | /// signalling mode is returned. Expects the current clock | ||
| 1409 | /// frequency to be > 12.5MHz. | ||
| 1410 | /// | ||
| 1411 | /// SD only. | ||
| 1412 | async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> { | ||
| 1413 | let _ = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); | ||
| 1414 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | ||
| 1415 | // necessary" | ||
| 1192 | 1416 | ||
| 1193 | // Always read 1 block of 512 bytes | 1417 | let set_function = 0x8000_0000 |
| 1194 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | 1418 | | match signalling { |
| 1195 | let address = match card_capacity { | 1419 | // See PLSS v7_10 Table 4-11 |
| 1196 | CardCapacity::SDSC => block_idx * 512, | 1420 | Signalling::DDR50 => 0xFF_FF04, |
| 1197 | _ => block_idx, | 1421 | Signalling::SDR104 => 0xFF_1F03, |
| 1422 | Signalling::SDR50 => 0xFF_1F02, | ||
| 1423 | Signalling::SDR25 => 0xFF_FF01, | ||
| 1424 | Signalling::SDR12 => 0xFF_FF00, | ||
| 1425 | }; | ||
| 1426 | |||
| 1427 | let status = match self.cmd_block.as_deref_mut() { | ||
| 1428 | Some(x) => x, | ||
| 1429 | None => &mut CmdBlock::new(), | ||
| 1198 | }; | 1430 | }; |
| 1199 | Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 | ||
| 1200 | 1431 | ||
| 1201 | let regs = T::regs(); | 1432 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 1202 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1433 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1203 | 1434 | ||
| 1204 | let transfer = Self::prepare_datapath_read( | 1435 | let transfer = Self::prepare_datapath_read( |
| 1205 | &self.config, | 1436 | &self.config, |
| 1206 | #[cfg(sdmmc_v1)] | 1437 | #[cfg(sdmmc_v1)] |
| 1207 | &mut self.dma, | 1438 | &mut self.dma, |
| 1208 | buffer, | 1439 | status.as_mut(), |
| 1209 | 512, | 1440 | 64, |
| 1210 | 9, | 1441 | 6, |
| 1211 | ); | 1442 | ); |
| 1212 | InterruptHandler::<T>::data_interrupts(true); | 1443 | InterruptHandler::<T>::data_interrupts(true); |
| 1213 | Self::cmd(Cmd::read_single_block(address), true)?; | 1444 | Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 |
| 1214 | 1445 | ||
| 1215 | let res = poll_fn(|cx| { | 1446 | let res = Self::complete_datapath_transfer().await; |
| 1216 | T::state().register(cx.waker()); | ||
| 1217 | let status = regs.star().read(); | ||
| 1218 | 1447 | ||
| 1219 | if status.dcrcfail() { | 1448 | // Host is allowed to use the new functions at least 8 |
| 1220 | return Poll::Ready(Err(Error::Crc)); | 1449 | // clocks after the end of the switch command |
| 1221 | } | 1450 | // transaction. We know the current clock period is < 80ns, |
| 1222 | if status.dtimeout() { | 1451 | // so a total delay of 640ns is required here |
| 1223 | return Poll::Ready(Err(Error::Timeout)); | 1452 | for _ in 0..300 { |
| 1453 | cortex_m::asm::nop(); | ||
| 1454 | } | ||
| 1455 | |||
| 1456 | match res { | ||
| 1457 | Ok(_) => { | ||
| 1458 | on_drop.defuse(); | ||
| 1459 | Self::stop_datapath(); | ||
| 1460 | drop(transfer); | ||
| 1461 | |||
| 1462 | // Function Selection of Function Group 1 | ||
| 1463 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; | ||
| 1464 | |||
| 1465 | match selection { | ||
| 1466 | 0 => Ok(Signalling::SDR12), | ||
| 1467 | 1 => Ok(Signalling::SDR25), | ||
| 1468 | 2 => Ok(Signalling::SDR50), | ||
| 1469 | 3 => Ok(Signalling::SDR104), | ||
| 1470 | 4 => Ok(Signalling::DDR50), | ||
| 1471 | _ => Err(Error::UnsupportedCardType), | ||
| 1472 | } | ||
| 1224 | } | 1473 | } |
| 1474 | Err(e) => Err(e), | ||
| 1475 | } | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | /// Reads the SCR register. | ||
| 1479 | /// | ||
| 1480 | /// SD only. | ||
| 1481 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | ||
| 1482 | // Read the 64-bit SCR register | ||
| 1483 | Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 | ||
| 1484 | Self::cmd(common_cmd::app_cmd(card.rca), false)?; | ||
| 1485 | |||
| 1486 | let cmd_block = match self.cmd_block.as_deref_mut() { | ||
| 1487 | Some(x) => x, | ||
| 1488 | None => &mut CmdBlock::new(), | ||
| 1489 | }; | ||
| 1490 | let scr = &mut cmd_block.0[..2]; | ||
| 1491 | |||
| 1492 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 1493 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1494 | |||
| 1495 | let transfer = Self::prepare_datapath_read( | ||
| 1496 | &self.config, | ||
| 1225 | #[cfg(sdmmc_v1)] | 1497 | #[cfg(sdmmc_v1)] |
| 1226 | if status.stbiterr() { | 1498 | &mut self.dma, |
| 1227 | return Poll::Ready(Err(Error::StBitErr)); | 1499 | scr, |
| 1228 | } | 1500 | 8, |
| 1229 | if status.dataend() { | 1501 | 3, |
| 1230 | return Poll::Ready(Ok(())); | 1502 | ); |
| 1231 | } | 1503 | InterruptHandler::<T>::data_interrupts(true); |
| 1232 | Poll::Pending | 1504 | Self::cmd(sd_cmd::send_scr(), true)?; |
| 1233 | }) | 1505 | |
| 1234 | .await; | 1506 | let res = Self::complete_datapath_transfer().await; |
| 1235 | Self::clear_interrupt_flags(); | ||
| 1236 | 1507 | ||
| 1237 | if res.is_ok() { | 1508 | if res.is_ok() { |
| 1238 | on_drop.defuse(); | 1509 | on_drop.defuse(); |
| 1239 | Self::stop_datapath(); | 1510 | Self::stop_datapath(); |
| 1240 | drop(transfer); | 1511 | drop(transfer); |
| 1512 | |||
| 1513 | unsafe { | ||
| 1514 | let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); | ||
| 1515 | card.scr = SCR(u64::from_be_bytes(*scr_bytes)); | ||
| 1516 | } | ||
| 1241 | } | 1517 | } |
| 1242 | res | 1518 | res |
| 1243 | } | 1519 | } |
| 1244 | 1520 | ||
| 1245 | /// Write a data block. | 1521 | /// Reads the SD Status (ACMD13) |
| 1246 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | 1522 | /// |
| 1247 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | 1523 | /// SD only. |
| 1248 | 1524 | async fn read_sd_status(&mut self) -> Result<(), Error> { | |
| 1249 | // NOTE(unsafe) DataBlock uses align 4 | 1525 | let card = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); |
| 1250 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | 1526 | let rca = card.rca; |
| 1251 | 1527 | ||
| 1252 | // Always read 1 block of 512 bytes | 1528 | let cmd_block = match self.cmd_block.as_deref_mut() { |
| 1253 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | 1529 | Some(x) => x, |
| 1254 | let address = match card.card_type { | 1530 | None => &mut CmdBlock::new(), |
| 1255 | CardCapacity::SDSC => block_idx * 512, | ||
| 1256 | _ => block_idx, | ||
| 1257 | }; | 1531 | }; |
| 1258 | Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 | ||
| 1259 | |||
| 1260 | let regs = T::regs(); | ||
| 1261 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1262 | |||
| 1263 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 1264 | #[cfg(sdmmc_v1)] | ||
| 1265 | Self::cmd(Cmd::write_single_block(address), true)?; | ||
| 1266 | 1532 | ||
| 1267 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | 1533 | Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 |
| 1268 | InterruptHandler::<T>::data_interrupts(true); | 1534 | Self::cmd(common_cmd::app_cmd(rca), false)?; // APP |
| 1269 | 1535 | ||
| 1270 | #[cfg(sdmmc_v2)] | 1536 | let status = cmd_block; |
| 1271 | Self::cmd(Cmd::write_single_block(address), true)?; | ||
| 1272 | 1537 | ||
| 1273 | let res = poll_fn(|cx| { | 1538 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 1274 | T::state().register(cx.waker()); | 1539 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1275 | let status = regs.star().read(); | ||
| 1276 | 1540 | ||
| 1277 | if status.dcrcfail() { | 1541 | let transfer = Self::prepare_datapath_read( |
| 1278 | return Poll::Ready(Err(Error::Crc)); | 1542 | &self.config, |
| 1279 | } | ||
| 1280 | if status.dtimeout() { | ||
| 1281 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1282 | } | ||
| 1283 | #[cfg(sdmmc_v1)] | 1543 | #[cfg(sdmmc_v1)] |
| 1284 | if status.stbiterr() { | 1544 | &mut self.dma, |
| 1285 | return Poll::Ready(Err(Error::StBitErr)); | 1545 | status.as_mut(), |
| 1286 | } | 1546 | 64, |
| 1287 | if status.dataend() { | 1547 | 6, |
| 1288 | return Poll::Ready(Ok(())); | 1548 | ); |
| 1289 | } | 1549 | InterruptHandler::<T>::data_interrupts(true); |
| 1290 | Poll::Pending | 1550 | Self::cmd(sd_cmd::sd_status(), true)?; |
| 1291 | }) | ||
| 1292 | .await; | ||
| 1293 | Self::clear_interrupt_flags(); | ||
| 1294 | 1551 | ||
| 1295 | match res { | 1552 | let res = Self::complete_datapath_transfer().await; |
| 1296 | Ok(_) => { | ||
| 1297 | on_drop.defuse(); | ||
| 1298 | Self::stop_datapath(); | ||
| 1299 | drop(transfer); | ||
| 1300 | 1553 | ||
| 1301 | // TODO: Make this configurable | 1554 | if res.is_ok() { |
| 1302 | let mut timeout: u32 = 0x00FF_FFFF; | 1555 | on_drop.defuse(); |
| 1556 | Self::stop_datapath(); | ||
| 1557 | drop(transfer); | ||
| 1303 | 1558 | ||
| 1304 | // Try to read card status (ACMD13) | 1559 | for byte in status.iter_mut() { |
| 1305 | while timeout > 0 { | 1560 | *byte = u32::from_be(*byte); |
| 1306 | match self.read_sd_status().await { | ||
| 1307 | Ok(_) => return Ok(()), | ||
| 1308 | Err(Error::Timeout) => (), // Try again | ||
| 1309 | Err(e) => return Err(e), | ||
| 1310 | } | ||
| 1311 | timeout -= 1; | ||
| 1312 | } | ||
| 1313 | Err(Error::SoftwareTimeout) | ||
| 1314 | } | 1561 | } |
| 1315 | Err(e) => Err(e), | 1562 | card.status = status.0.into(); |
| 1316 | } | 1563 | } |
| 1564 | res | ||
| 1317 | } | 1565 | } |
| 1318 | 1566 | ||
| 1319 | /// Get a reference to the initialized card | 1567 | /// Initializes eMMC and sets the bus at the specified frequency. |
| 1320 | /// | 1568 | /// |
| 1321 | /// # Errors | 1569 | /// eMMC only. |
| 1322 | /// | 1570 | pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> { |
| 1323 | /// Returns Error::NoCard if [`init_card`](#method.init_card) | 1571 | self.init_internal(freq, SdmmcPeripheral::Emmc(Emmc::default())).await |
| 1324 | /// has not previously succeeded | ||
| 1325 | #[inline] | ||
| 1326 | pub fn card(&self) -> Result<&Card, Error> { | ||
| 1327 | self.card.as_ref().ok_or(Error::NoCard) | ||
| 1328 | } | 1572 | } |
| 1329 | 1573 | ||
| 1330 | /// Get the current SDMMC bus clock | 1574 | /// Gets the EXT_CSD register. |
| 1331 | pub fn clock(&self) -> Hertz { | 1575 | /// |
| 1332 | self.clock | 1576 | /// eMMC only. |
| 1333 | } | 1577 | async fn read_ext_csd(&mut self) -> Result<(), Error> { |
| 1578 | let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc(); | ||
| 1334 | 1579 | ||
| 1335 | /// Set a specific cmd buffer rather than using the default stack allocated one. | 1580 | // Note: cmd_block can't be used because ExtCSD is too long to fit. |
| 1336 | /// This is required if stack RAM cannot be used with DMA and usually manifests | 1581 | let mut data_block = DataBlock([0u8; 512]); |
| 1337 | /// itself as an indefinite wait on a dma transfer because the dma peripheral | 1582 | |
| 1338 | /// cannot access the memory. | 1583 | // NOTE(unsafe) DataBlock uses align 4 |
| 1339 | pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { | 1584 | let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) }; |
| 1340 | self.cmd_block = Some(cmd_block) | 1585 | |
| 1586 | Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 | ||
| 1587 | |||
| 1588 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 1589 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1590 | |||
| 1591 | let transfer = Self::prepare_datapath_read( | ||
| 1592 | &self.config, | ||
| 1593 | #[cfg(sdmmc_v1)] | ||
| 1594 | &mut self.dma, | ||
| 1595 | buffer, | ||
| 1596 | 512, | ||
| 1597 | 9, | ||
| 1598 | ); | ||
| 1599 | InterruptHandler::<T>::data_interrupts(true); | ||
| 1600 | Self::cmd(emmc_cmd::send_ext_csd(), true)?; | ||
| 1601 | |||
| 1602 | let res = Self::complete_datapath_transfer().await; | ||
| 1603 | |||
| 1604 | if res.is_ok() { | ||
| 1605 | on_drop.defuse(); | ||
| 1606 | Self::stop_datapath(); | ||
| 1607 | drop(transfer); | ||
| 1608 | |||
| 1609 | card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); | ||
| 1610 | } | ||
| 1611 | res | ||
| 1341 | } | 1612 | } |
| 1342 | } | 1613 | } |
| 1343 | 1614 | ||
| @@ -1359,97 +1630,22 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> { | |||
| 1359 | if let Some(x) = &mut self.d3 { | 1630 | if let Some(x) = &mut self.d3 { |
| 1360 | x.set_as_disconnected(); | 1631 | x.set_as_disconnected(); |
| 1361 | } | 1632 | } |
| 1633 | if let Some(x) = &mut self.d4 { | ||
| 1634 | x.set_as_disconnected(); | ||
| 1635 | } | ||
| 1636 | if let Some(x) = &mut self.d5 { | ||
| 1637 | x.set_as_disconnected(); | ||
| 1638 | } | ||
| 1639 | if let Some(x) = &mut self.d6 { | ||
| 1640 | x.set_as_disconnected(); | ||
| 1641 | } | ||
| 1642 | if let Some(x) = &mut self.d7 { | ||
| 1643 | x.set_as_disconnected(); | ||
| 1644 | } | ||
| 1362 | }); | 1645 | }); |
| 1363 | } | 1646 | } |
| 1364 | } | 1647 | } |
| 1365 | 1648 | ||
| 1366 | /// SD card Commands | ||
| 1367 | impl Cmd { | ||
| 1368 | const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd { | ||
| 1369 | Cmd { cmd, arg, resp } | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | /// CMD0: Idle | ||
| 1373 | const fn idle() -> Cmd { | ||
| 1374 | Cmd::new(0, 0, Response::None) | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | /// CMD2: Send CID | ||
| 1378 | const fn all_send_cid() -> Cmd { | ||
| 1379 | Cmd::new(2, 0, Response::Long) | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | /// CMD3: Send Relative Address | ||
| 1383 | const fn send_rel_addr() -> Cmd { | ||
| 1384 | Cmd::new(3, 0, Response::Short) | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | /// CMD6: Switch Function Command | ||
| 1388 | /// ACMD6: Bus Width | ||
| 1389 | const fn cmd6(arg: u32) -> Cmd { | ||
| 1390 | Cmd::new(6, arg, Response::Short) | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | /// CMD7: Select one card and put it into the _Tranfer State_ | ||
| 1394 | const fn sel_desel_card(rca: u32) -> Cmd { | ||
| 1395 | Cmd::new(7, rca, Response::Short) | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | /// CMD8: | ||
| 1399 | const fn hs_send_ext_csd(arg: u32) -> Cmd { | ||
| 1400 | Cmd::new(8, arg, Response::Short) | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | /// CMD9: | ||
| 1404 | const fn send_csd(rca: u32) -> Cmd { | ||
| 1405 | Cmd::new(9, rca, Response::Long) | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | /// CMD12: | ||
| 1409 | //const fn stop_transmission() -> Cmd { | ||
| 1410 | // Cmd::new(12, 0, Response::Short) | ||
| 1411 | //} | ||
| 1412 | |||
| 1413 | /// CMD13: Ask card to send status register | ||
| 1414 | /// ACMD13: SD Status | ||
| 1415 | const fn card_status(rca: u32) -> Cmd { | ||
| 1416 | Cmd::new(13, rca, Response::Short) | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | /// CMD16: | ||
| 1420 | const fn set_block_length(blocklen: u32) -> Cmd { | ||
| 1421 | Cmd::new(16, blocklen, Response::Short) | ||
| 1422 | } | ||
| 1423 | |||
| 1424 | /// CMD17: Block Read | ||
| 1425 | const fn read_single_block(addr: u32) -> Cmd { | ||
| 1426 | Cmd::new(17, addr, Response::Short) | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | /// CMD18: Multiple Block Read | ||
| 1430 | //const fn read_multiple_blocks(addr: u32) -> Cmd { | ||
| 1431 | // Cmd::new(18, addr, Response::Short) | ||
| 1432 | //} | ||
| 1433 | |||
| 1434 | /// CMD24: Block Write | ||
| 1435 | const fn write_single_block(addr: u32) -> Cmd { | ||
| 1436 | Cmd::new(24, addr, Response::Short) | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | const fn app_op_cmd(arg: u32) -> Cmd { | ||
| 1440 | Cmd::new(41, arg, Response::Short) | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | const fn cmd51() -> Cmd { | ||
| 1444 | Cmd::new(51, 0, Response::Short) | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | /// App Command. Indicates that next command will be a app command | ||
| 1448 | const fn app_cmd(rca: u32) -> Cmd { | ||
| 1449 | Cmd::new(55, rca, Response::Short) | ||
| 1450 | } | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | ////////////////////////////////////////////////////// | 1649 | ////////////////////////////////////////////////////// |
| 1454 | 1650 | ||
| 1455 | trait SealedInstance { | 1651 | trait SealedInstance { |
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 66e4e527c..e97b63925 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs | |||
| @@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) { | |||
| 59 | 59 | ||
| 60 | let mut err = None; | 60 | let mut err = None; |
| 61 | loop { | 61 | loop { |
| 62 | match sdmmc.init_card(mhz(24)).await { | 62 | match sdmmc.init_sd_card(mhz(24)).await { |
| 63 | Ok(_) => break, | 63 | Ok(_) => break, |
| 64 | Err(e) => { | 64 | Err(e) => { |
| 65 | if err != Some(e) { | 65 | if err != Some(e) { |
diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 6d36ef518..787bef25e 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs | |||
| @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { | |||
| 54 | // Should print 400kHz for initialization | 54 | // Should print 400kHz for initialization |
| 55 | info!("Configured clock: {}", sdmmc.clock().0); | 55 | info!("Configured clock: {}", sdmmc.clock().0); |
| 56 | 56 | ||
| 57 | unwrap!(sdmmc.init_card(mhz(25)).await); | 57 | unwrap!(sdmmc.init_sd_card(mhz(25)).await); |
| 58 | 58 | ||
| 59 | let card = unwrap!(sdmmc.card()); | 59 | let card = unwrap!(sdmmc.card()); |
| 60 | 60 | ||
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index abe2d4ba7..96840d8ff 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs | |||
| @@ -53,7 +53,7 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 53 | // Should print 400kHz for initialization | 53 | // Should print 400kHz for initialization |
| 54 | info!("Configured clock: {}", sdmmc.clock().0); | 54 | info!("Configured clock: {}", sdmmc.clock().0); |
| 55 | 55 | ||
| 56 | unwrap!(sdmmc.init_card(mhz(25)).await); | 56 | unwrap!(sdmmc.init_sd_card(mhz(25)).await); |
| 57 | 57 | ||
| 58 | let card = unwrap!(sdmmc.card()); | 58 | let card = unwrap!(sdmmc.card()); |
| 59 | 59 | ||
diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index 07f17b569..c1ed45588 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs | |||
| @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { | |||
| 54 | 54 | ||
| 55 | let mut err = None; | 55 | let mut err = None; |
| 56 | loop { | 56 | loop { |
| 57 | match s.init_card(mhz(24)).await { | 57 | match s.init_sd_card(mhz(24)).await { |
| 58 | Ok(_) => break, | 58 | Ok(_) => break, |
| 59 | Err(e) => { | 59 | Err(e) => { |
| 60 | if err != Some(e) { | 60 | if err != Some(e) { |
| @@ -100,7 +100,7 @@ async fn main(_spawner: Spawner) { | |||
| 100 | 100 | ||
| 101 | let mut err = None; | 101 | let mut err = None; |
| 102 | loop { | 102 | loop { |
| 103 | match s.init_card(mhz(24)).await { | 103 | match s.init_sd_card(mhz(24)).await { |
| 104 | Ok(_) => break, | 104 | Ok(_) => break, |
| 105 | Err(e) => { | 105 | Err(e) => { |
| 106 | if err != Some(e) { | 106 | if err != Some(e) { |
