diff options
| author | Anton Lazarev <[email protected]> | 2025-03-25 06:29:16 -0700 |
|---|---|---|
| committer | Anton Lazarev <[email protected]> | 2025-03-31 12:47:41 -0700 |
| commit | 5325f1d911753e76a6b56d7747b816d24a7eb172 (patch) | |
| tree | 3a29c25230e88c1f301a83d781e70dc03074160e | |
| parent | 14bb4ee9e414137f318f64e82d808d4012e30680 (diff) | |
scaffold eMMC support
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 710 |
1 files changed, 395 insertions, 315 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index a28fd51e8..6dbb524b7 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -10,11 +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::{ | 13 | use sdio_host::common_cmd::{self, Resp, ResponseLen}; |
| 14 | common_cmd::{self, Resp, ResponseLen}, | 14 | use sdio_host::emmc::{ExtCSD, EMMC}; |
| 15 | sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}, | 15 | use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; |
| 16 | sd_cmd, Cmd, | 16 | use sdio_host::{sd_cmd, Cmd}; |
| 17 | }; | ||
| 18 | 17 | ||
| 19 | #[cfg(sdmmc_v1)] | 18 | #[cfg(sdmmc_v1)] |
| 20 | use crate::dma::ChannelAndRequest; | 19 | use crate::dma::ChannelAndRequest; |
| @@ -174,12 +173,21 @@ pub struct Card { | |||
| 174 | pub status: SDStatus, | 173 | pub status: SDStatus, |
| 175 | } | 174 | } |
| 176 | 175 | ||
| 177 | impl Card { | 176 | #[derive(Clone, Copy, Debug, Default)] |
| 178 | /// Size in bytes | 177 | /// eMMC storage |
| 179 | pub fn size(&self) -> u64 { | 178 | pub struct Emmc { |
| 180 | // SDHC / SDXC / SDUC | 179 | /// The capacity of this card |
| 181 | u64::from(self.csd.block_count()) * 512 | 180 | pub capacity: CardCapacity, |
| 182 | } | 181 | /// Operation Conditions Register |
| 182 | pub ocr: OCR<EMMC>, | ||
| 183 | /// Relative Card Address | ||
| 184 | pub rca: u16, | ||
| 185 | /// Card ID | ||
| 186 | pub cid: CID<EMMC>, | ||
| 187 | /// Card Specific Data | ||
| 188 | pub csd: CSD<EMMC>, | ||
| 189 | /// Extended Card Specific Data | ||
| 190 | pub ext_csd: ExtCSD, | ||
| 183 | } | 191 | } |
| 184 | 192 | ||
| 185 | #[repr(u8)] | 193 | #[repr(u8)] |
| @@ -290,6 +298,61 @@ impl Default for Config { | |||
| 290 | } | 298 | } |
| 291 | } | 299 | } |
| 292 | 300 | ||
| 301 | /// Peripheral that can be operated over SDMMC | ||
| 302 | #[derive(Clone, Copy, Debug)] | ||
| 303 | pub enum SdmmcPeripheral { | ||
| 304 | /// SD Card | ||
| 305 | SdCard(Card), | ||
| 306 | /// eMMC memory | ||
| 307 | Emmc(Emmc), | ||
| 308 | } | ||
| 309 | |||
| 310 | impl SdmmcPeripheral { | ||
| 311 | /// Get this peripheral's address on the SDMMC bus | ||
| 312 | fn get_address(&self) -> u16 { | ||
| 313 | match self { | ||
| 314 | Self::SdCard(c) => c.rca, | ||
| 315 | Self::Emmc(e) => e.rca, | ||
| 316 | } | ||
| 317 | } | ||
| 318 | /// Is this a standard or high capacity peripheral? | ||
| 319 | fn get_capacity(&self) -> CardCapacity { | ||
| 320 | match self { | ||
| 321 | Self::SdCard(c) => c.card_type, | ||
| 322 | Self::Emmc(e) => e.capacity, | ||
| 323 | } | ||
| 324 | } | ||
| 325 | /// Size in bytes | ||
| 326 | fn size(&self) -> u64 { | ||
| 327 | match self { | ||
| 328 | // SDHC / SDXC / SDUC | ||
| 329 | Self::SdCard(c) => u64::from(c.csd.block_count()) * 512, | ||
| 330 | // capacity > 2GB | ||
| 331 | Self::Emmc(e) => u64::from(e.ext_csd.sector_count()) * 512, | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | /// Get a mutable reference to the SD Card. | ||
| 336 | /// | ||
| 337 | /// Panics if there is another peripheral instead. | ||
| 338 | fn get_sd_card(&mut self) -> &mut Card { | ||
| 339 | match *self { | ||
| 340 | Self::SdCard(ref mut c) => c, | ||
| 341 | _ => unreachable!("SD only"), | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | /// Get a mutable reference to the eMMC. | ||
| 346 | /// | ||
| 347 | /// Panics if there is another peripheral instead. | ||
| 348 | fn get_emmc(&mut self) -> &mut Emmc { | ||
| 349 | match *self { | ||
| 350 | Self::Emmc(ref mut e) => e, | ||
| 351 | _ => unreachable!("eMMC only"), | ||
| 352 | } | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 293 | /// Sdmmc device | 356 | /// Sdmmc device |
| 294 | pub struct Sdmmc<'d, T: Instance> { | 357 | pub struct Sdmmc<'d, T: Instance> { |
| 295 | _peri: Peri<'d, T>, | 358 | _peri: Peri<'d, T>, |
| @@ -309,7 +372,7 @@ pub struct Sdmmc<'d, T: Instance> { | |||
| 309 | /// Current signalling scheme to card | 372 | /// Current signalling scheme to card |
| 310 | signalling: Signalling, | 373 | signalling: Signalling, |
| 311 | /// Card | 374 | /// Card |
| 312 | card: Option<Card>, | 375 | card: Option<SdmmcPeripheral>, |
| 313 | 376 | ||
| 314 | /// An optional buffer to be used for commands | 377 | /// An optional buffer to be used for commands |
| 315 | /// This should be used if there are special memory location requirements for dma | 378 | /// This should be used if there are special memory location requirements for dma |
| @@ -662,101 +725,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 662 | Ok(()) | 725 | Ok(()) |
| 663 | } | 726 | } |
| 664 | 727 | ||
| 665 | /// Switch mode using CMD6. | ||
| 666 | /// | ||
| 667 | /// Attempt to set a new signalling mode. The selected | ||
| 668 | /// signalling mode is returned. Expects the current clock | ||
| 669 | /// frequency to be > 12.5MHz. | ||
| 670 | async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> { | ||
| 671 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | ||
| 672 | // necessary" | ||
| 673 | |||
| 674 | let set_function = 0x8000_0000 | ||
| 675 | | match signalling { | ||
| 676 | // See PLSS v7_10 Table 4-11 | ||
| 677 | Signalling::DDR50 => 0xFF_FF04, | ||
| 678 | Signalling::SDR104 => 0xFF_1F03, | ||
| 679 | Signalling::SDR50 => 0xFF_1F02, | ||
| 680 | Signalling::SDR25 => 0xFF_FF01, | ||
| 681 | Signalling::SDR12 => 0xFF_FF00, | ||
| 682 | }; | ||
| 683 | |||
| 684 | let status = match self.cmd_block.as_deref_mut() { | ||
| 685 | Some(x) => x, | ||
| 686 | None => &mut CmdBlock::new(), | ||
| 687 | }; | ||
| 688 | |||
| 689 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 690 | let regs = T::regs(); | ||
| 691 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 692 | |||
| 693 | let transfer = Self::prepare_datapath_read( | ||
| 694 | &self.config, | ||
| 695 | #[cfg(sdmmc_v1)] | ||
| 696 | &mut self.dma, | ||
| 697 | status.as_mut(), | ||
| 698 | 64, | ||
| 699 | 6, | ||
| 700 | ); | ||
| 701 | InterruptHandler::<T>::data_interrupts(true); | ||
| 702 | Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 | ||
| 703 | |||
| 704 | let res = poll_fn(|cx| { | ||
| 705 | T::state().register(cx.waker()); | ||
| 706 | let status = regs.star().read(); | ||
| 707 | |||
| 708 | if status.dcrcfail() { | ||
| 709 | return Poll::Ready(Err(Error::Crc)); | ||
| 710 | } | ||
| 711 | if status.dtimeout() { | ||
| 712 | return Poll::Ready(Err(Error::Timeout)); | ||
| 713 | } | ||
| 714 | #[cfg(sdmmc_v1)] | ||
| 715 | if status.stbiterr() { | ||
| 716 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 717 | } | ||
| 718 | if status.dataend() { | ||
| 719 | return Poll::Ready(Ok(())); | ||
| 720 | } | ||
| 721 | Poll::Pending | ||
| 722 | }) | ||
| 723 | .await; | ||
| 724 | Self::clear_interrupt_flags(); | ||
| 725 | |||
| 726 | // Host is allowed to use the new functions at least 8 | ||
| 727 | // clocks after the end of the switch command | ||
| 728 | // transaction. We know the current clock period is < 80ns, | ||
| 729 | // so a total delay of 640ns is required here | ||
| 730 | for _ in 0..300 { | ||
| 731 | cortex_m::asm::nop(); | ||
| 732 | } | ||
| 733 | |||
| 734 | match res { | ||
| 735 | Ok(_) => { | ||
| 736 | on_drop.defuse(); | ||
| 737 | Self::stop_datapath(); | ||
| 738 | drop(transfer); | ||
| 739 | |||
| 740 | // Function Selection of Function Group 1 | ||
| 741 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; | ||
| 742 | |||
| 743 | match selection { | ||
| 744 | 0 => Ok(Signalling::SDR12), | ||
| 745 | 1 => Ok(Signalling::SDR25), | ||
| 746 | 2 => Ok(Signalling::SDR50), | ||
| 747 | 3 => Ok(Signalling::SDR104), | ||
| 748 | 4 => Ok(Signalling::DDR50), | ||
| 749 | _ => Err(Error::UnsupportedCardType), | ||
| 750 | } | ||
| 751 | } | ||
| 752 | Err(e) => Err(e), | ||
| 753 | } | ||
| 754 | } | ||
| 755 | |||
| 756 | /// Query the card status (CMD13, returns R1) | 728 | /// Query the card status (CMD13, returns R1) |
| 757 | fn read_status(&self, card: &Card) -> Result<CardStatus<SD>, Error> { | 729 | fn read_status<Ext>(&self, card: &SdmmcPeripheral) -> Result<CardStatus<Ext>, Error> |
| 730 | where | ||
| 731 | CardStatus<Ext>: From<u32>, | ||
| 732 | { | ||
| 758 | let regs = T::regs(); | 733 | let regs = T::regs(); |
| 759 | let rca = card.rca; | 734 | let rca = card.get_address(); |
| 760 | 735 | ||
| 761 | Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 | 736 | Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 |
| 762 | 737 | ||
| @@ -764,78 +739,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 764 | Ok(r1.into()) | 739 | Ok(r1.into()) |
| 765 | } | 740 | } |
| 766 | 741 | ||
| 767 | /// Reads the SD Status (ACMD13) | ||
| 768 | async fn read_sd_status(&mut self) -> Result<(), Error> { | ||
| 769 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | ||
| 770 | let rca = card.rca; | ||
| 771 | |||
| 772 | let cmd_block = match self.cmd_block.as_deref_mut() { | ||
| 773 | Some(x) => x, | ||
| 774 | None => &mut CmdBlock::new(), | ||
| 775 | }; | ||
| 776 | |||
| 777 | Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 | ||
| 778 | Self::cmd(common_cmd::app_cmd(rca), false)?; // APP | ||
| 779 | |||
| 780 | let status = cmd_block; | ||
| 781 | |||
| 782 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 783 | let regs = T::regs(); | ||
| 784 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 785 | |||
| 786 | let transfer = Self::prepare_datapath_read( | ||
| 787 | &self.config, | ||
| 788 | #[cfg(sdmmc_v1)] | ||
| 789 | &mut self.dma, | ||
| 790 | status.as_mut(), | ||
| 791 | 64, | ||
| 792 | 6, | ||
| 793 | ); | ||
| 794 | InterruptHandler::<T>::data_interrupts(true); | ||
| 795 | Self::cmd(sd_cmd::sd_status(), true)?; | ||
| 796 | |||
| 797 | let res = poll_fn(|cx| { | ||
| 798 | T::state().register(cx.waker()); | ||
| 799 | let status = regs.star().read(); | ||
| 800 | |||
| 801 | if status.dcrcfail() { | ||
| 802 | return Poll::Ready(Err(Error::Crc)); | ||
| 803 | } | ||
| 804 | if status.dtimeout() { | ||
| 805 | return Poll::Ready(Err(Error::Timeout)); | ||
| 806 | } | ||
| 807 | #[cfg(sdmmc_v1)] | ||
| 808 | if status.stbiterr() { | ||
| 809 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 810 | } | ||
| 811 | if status.dataend() { | ||
| 812 | return Poll::Ready(Ok(())); | ||
| 813 | } | ||
| 814 | Poll::Pending | ||
| 815 | }) | ||
| 816 | .await; | ||
| 817 | Self::clear_interrupt_flags(); | ||
| 818 | |||
| 819 | if res.is_ok() { | ||
| 820 | on_drop.defuse(); | ||
| 821 | Self::stop_datapath(); | ||
| 822 | drop(transfer); | ||
| 823 | |||
| 824 | for byte in status.iter_mut() { | ||
| 825 | *byte = u32::from_be(*byte); | ||
| 826 | } | ||
| 827 | self.card.as_mut().unwrap().status = status.0.into(); | ||
| 828 | } | ||
| 829 | res | ||
| 830 | } | ||
| 831 | |||
| 832 | /// Select one card and place it into the _Tranfer State_ | 742 | /// Select one card and place it into the _Tranfer State_ |
| 833 | /// | 743 | /// |
| 834 | /// If `None` is specifed for `card`, all cards are put back into | 744 | /// If `None` is specifed for `card`, all cards are put back into |
| 835 | /// _Stand-by State_ | 745 | /// _Stand-by State_ |
| 836 | fn select_card(&self, card: Option<&Card>) -> Result<(), Error> { | 746 | fn select_card(&self, rca: Option<u16>) -> Result<(), Error> { |
| 837 | // Determine Relative Card Address (RCA) of given card | 747 | // Determine Relative Card Address (RCA) of given card |
| 838 | let rca = card.map(|c| c.rca).unwrap_or(0); | 748 | let rca = rca.unwrap_or(0); |
| 839 | 749 | ||
| 840 | let r = Self::cmd(common_cmd::select_card(rca), false); | 750 | let r = Self::cmd(common_cmd::select_card(rca), false); |
| 841 | match (r, rca) { | 751 | match (r, rca) { |
| @@ -878,67 +788,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 878 | }); | 788 | }); |
| 879 | } | 789 | } |
| 880 | 790 | ||
| 881 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | ||
| 882 | // Read the 64-bit SCR register | ||
| 883 | Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 | ||
| 884 | Self::cmd(common_cmd::app_cmd(card.rca), false)?; | ||
| 885 | |||
| 886 | let cmd_block = match self.cmd_block.as_deref_mut() { | ||
| 887 | Some(x) => x, | ||
| 888 | None => &mut CmdBlock::new(), | ||
| 889 | }; | ||
| 890 | let scr = &mut cmd_block.0[..2]; | ||
| 891 | |||
| 892 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 893 | let regs = T::regs(); | ||
| 894 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 895 | |||
| 896 | let transfer = Self::prepare_datapath_read( | ||
| 897 | &self.config, | ||
| 898 | #[cfg(sdmmc_v1)] | ||
| 899 | &mut self.dma, | ||
| 900 | scr, | ||
| 901 | 8, | ||
| 902 | 3, | ||
| 903 | ); | ||
| 904 | InterruptHandler::<T>::data_interrupts(true); | ||
| 905 | Self::cmd(sd_cmd::send_scr(), true)?; | ||
| 906 | |||
| 907 | let res = poll_fn(|cx| { | ||
| 908 | T::state().register(cx.waker()); | ||
| 909 | let status = regs.star().read(); | ||
| 910 | |||
| 911 | if status.dcrcfail() { | ||
| 912 | return Poll::Ready(Err(Error::Crc)); | ||
| 913 | } | ||
| 914 | if status.dtimeout() { | ||
| 915 | return Poll::Ready(Err(Error::Timeout)); | ||
| 916 | } | ||
| 917 | #[cfg(sdmmc_v1)] | ||
| 918 | if status.stbiterr() { | ||
| 919 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 920 | } | ||
| 921 | if status.dataend() { | ||
| 922 | return Poll::Ready(Ok(())); | ||
| 923 | } | ||
| 924 | Poll::Pending | ||
| 925 | }) | ||
| 926 | .await; | ||
| 927 | Self::clear_interrupt_flags(); | ||
| 928 | |||
| 929 | if res.is_ok() { | ||
| 930 | on_drop.defuse(); | ||
| 931 | Self::stop_datapath(); | ||
| 932 | drop(transfer); | ||
| 933 | |||
| 934 | unsafe { | ||
| 935 | let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); | ||
| 936 | card.scr = SCR(u64::from_be_bytes(*scr_bytes)); | ||
| 937 | } | ||
| 938 | } | ||
| 939 | res | ||
| 940 | } | ||
| 941 | |||
| 942 | /// Send command to card | 791 | /// Send command to card |
| 943 | #[allow(unused_variables)] | 792 | #[allow(unused_variables)] |
| 944 | fn cmd<R: Resp>(cmd: Cmd<R>, data: bool) -> Result<(), Error> { | 793 | fn cmd<R: Resp>(cmd: Cmd<R>, data: bool) -> Result<(), Error> { |
| @@ -1024,6 +873,170 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1024 | Self::stop_datapath(); | 873 | Self::stop_datapath(); |
| 1025 | } | 874 | } |
| 1026 | 875 | ||
| 876 | /// Read a data block. | ||
| 877 | #[inline] | ||
| 878 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 879 | let card_capacity = self.card()?.get_capacity(); | ||
| 880 | |||
| 881 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 882 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 883 | |||
| 884 | // Always read 1 block of 512 bytes | ||
| 885 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 886 | let address = match card_capacity { | ||
| 887 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 888 | _ => block_idx, | ||
| 889 | }; | ||
| 890 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 891 | |||
| 892 | let regs = T::regs(); | ||
| 893 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 894 | |||
| 895 | let transfer = Self::prepare_datapath_read( | ||
| 896 | &self.config, | ||
| 897 | #[cfg(sdmmc_v1)] | ||
| 898 | &mut self.dma, | ||
| 899 | buffer, | ||
| 900 | 512, | ||
| 901 | 9, | ||
| 902 | ); | ||
| 903 | InterruptHandler::<T>::data_interrupts(true); | ||
| 904 | Self::cmd(common_cmd::read_single_block(address), true)?; | ||
| 905 | |||
| 906 | let res = poll_fn(|cx| { | ||
| 907 | T::state().register(cx.waker()); | ||
| 908 | let status = regs.star().read(); | ||
| 909 | |||
| 910 | if status.dcrcfail() { | ||
| 911 | return Poll::Ready(Err(Error::Crc)); | ||
| 912 | } | ||
| 913 | if status.dtimeout() { | ||
| 914 | return Poll::Ready(Err(Error::Timeout)); | ||
| 915 | } | ||
| 916 | #[cfg(sdmmc_v1)] | ||
| 917 | if status.stbiterr() { | ||
| 918 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 919 | } | ||
| 920 | if status.dataend() { | ||
| 921 | return Poll::Ready(Ok(())); | ||
| 922 | } | ||
| 923 | Poll::Pending | ||
| 924 | }) | ||
| 925 | .await; | ||
| 926 | Self::clear_interrupt_flags(); | ||
| 927 | |||
| 928 | if res.is_ok() { | ||
| 929 | on_drop.defuse(); | ||
| 930 | Self::stop_datapath(); | ||
| 931 | drop(transfer); | ||
| 932 | } | ||
| 933 | res | ||
| 934 | } | ||
| 935 | |||
| 936 | /// Write a data block. | ||
| 937 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | ||
| 938 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | ||
| 939 | |||
| 940 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 941 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | ||
| 942 | |||
| 943 | // Always read 1 block of 512 bytes | ||
| 944 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 945 | let address = match card.get_capacity() { | ||
| 946 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 947 | _ => block_idx, | ||
| 948 | }; | ||
| 949 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 950 | |||
| 951 | let regs = T::regs(); | ||
| 952 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 953 | |||
| 954 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 955 | #[cfg(sdmmc_v1)] | ||
| 956 | Self::cmd(common_cmd::write_single_block(address), true)?; | ||
| 957 | |||
| 958 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | ||
| 959 | InterruptHandler::<T>::data_interrupts(true); | ||
| 960 | |||
| 961 | #[cfg(sdmmc_v2)] | ||
| 962 | Self::cmd(common_cmd::write_single_block(address), true)?; | ||
| 963 | |||
| 964 | let res = poll_fn(|cx| { | ||
| 965 | T::state().register(cx.waker()); | ||
| 966 | let status = regs.star().read(); | ||
| 967 | |||
| 968 | if status.dcrcfail() { | ||
| 969 | return Poll::Ready(Err(Error::Crc)); | ||
| 970 | } | ||
| 971 | if status.dtimeout() { | ||
| 972 | return Poll::Ready(Err(Error::Timeout)); | ||
| 973 | } | ||
| 974 | #[cfg(sdmmc_v1)] | ||
| 975 | if status.stbiterr() { | ||
| 976 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 977 | } | ||
| 978 | if status.dataend() { | ||
| 979 | return Poll::Ready(Ok(())); | ||
| 980 | } | ||
| 981 | Poll::Pending | ||
| 982 | }) | ||
| 983 | .await; | ||
| 984 | Self::clear_interrupt_flags(); | ||
| 985 | |||
| 986 | match res { | ||
| 987 | Ok(_) => { | ||
| 988 | on_drop.defuse(); | ||
| 989 | Self::stop_datapath(); | ||
| 990 | drop(transfer); | ||
| 991 | |||
| 992 | // TODO: Make this configurable | ||
| 993 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 994 | |||
| 995 | let card = self.card.as_ref().unwrap(); | ||
| 996 | while timeout > 0 { | ||
| 997 | let ready_for_data = match card { | ||
| 998 | SdmmcPeripheral::Emmc(_) => self.read_status::<EMMC>(card)?.ready_for_data(), | ||
| 999 | SdmmcPeripheral::SdCard(_) => self.read_status::<SD>(card)?.ready_for_data(), | ||
| 1000 | }; | ||
| 1001 | |||
| 1002 | if ready_for_data { | ||
| 1003 | return Ok(()); | ||
| 1004 | } | ||
| 1005 | timeout -= 1; | ||
| 1006 | } | ||
| 1007 | Err(Error::SoftwareTimeout) | ||
| 1008 | } | ||
| 1009 | Err(e) => Err(e), | ||
| 1010 | } | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | /// Get a reference to the initialized card | ||
| 1014 | /// | ||
| 1015 | /// # Errors | ||
| 1016 | /// | ||
| 1017 | /// Returns Error::NoCard if [`init_card`](#method.init_card) | ||
| 1018 | /// has not previously succeeded | ||
| 1019 | #[inline] | ||
| 1020 | pub fn card(&self) -> Result<&SdmmcPeripheral, Error> { | ||
| 1021 | self.card.as_ref().ok_or(Error::NoCard) | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | /// Get the current SDMMC bus clock | ||
| 1025 | pub fn clock(&self) -> Hertz { | ||
| 1026 | self.clock | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | /// Set a specific cmd buffer rather than using the default stack allocated one. | ||
| 1030 | /// This is required if stack RAM cannot be used with DMA and usually manifests | ||
| 1031 | /// itself as an indefinite wait on a dma transfer because the dma peripheral | ||
| 1032 | /// cannot access the memory. | ||
| 1033 | pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { | ||
| 1034 | self.cmd_block = Some(cmd_block) | ||
| 1035 | } | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | /// SD only | ||
| 1039 | impl<'d, T: Instance> Sdmmc<'d, T> { | ||
| 1027 | /// Initializes card (if present) and sets the bus at the specified frequency. | 1040 | /// Initializes card (if present) and sets the bus at the specified frequency. |
| 1028 | pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { | 1041 | pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { |
| 1029 | let regs = T::regs(); | 1042 | let regs = T::regs(); |
| @@ -1114,7 +1127,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1114 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | 1127 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); |
| 1115 | card.csd = csd.into(); | 1128 | card.csd = csd.into(); |
| 1116 | 1129 | ||
| 1117 | self.select_card(Some(&card))?; | 1130 | self.select_card(Some(card.rca))?; |
| 1118 | 1131 | ||
| 1119 | self.get_scr(&mut card).await?; | 1132 | self.get_scr(&mut card).await?; |
| 1120 | 1133 | ||
| @@ -1148,7 +1161,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1148 | self.clkcr_set_clkdiv(25_000_000, width)?; | 1161 | self.clkcr_set_clkdiv(25_000_000, width)?; |
| 1149 | } | 1162 | } |
| 1150 | 1163 | ||
| 1151 | self.card = Some(card); | 1164 | self.card = Some(SdmmcPeripheral::SdCard(card)); |
| 1152 | 1165 | ||
| 1153 | // Read status | 1166 | // Read status |
| 1154 | self.read_sd_status().await?; | 1167 | self.read_sd_status().await?; |
| @@ -1161,7 +1174,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1161 | // Set final clock frequency | 1174 | // Set final clock frequency |
| 1162 | self.clkcr_set_clkdiv(freq.0, width)?; | 1175 | self.clkcr_set_clkdiv(freq.0, width)?; |
| 1163 | 1176 | ||
| 1164 | if self.read_status(&card)?.state() != CurrentState::Transfer { | 1177 | if self.read_status::<SD>(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { |
| 1165 | return Err(Error::SignalingSwitchFailed); | 1178 | return Err(Error::SignalingSwitchFailed); |
| 1166 | } | 1179 | } |
| 1167 | } | 1180 | } |
| @@ -1173,22 +1186,34 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1173 | Ok(()) | 1186 | Ok(()) |
| 1174 | } | 1187 | } |
| 1175 | 1188 | ||
| 1176 | /// Read a data block. | 1189 | /// Switch mode using CMD6. |
| 1177 | #[inline] | 1190 | /// |
| 1178 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | 1191 | /// Attempt to set a new signalling mode. The selected |
| 1179 | let card_capacity = self.card()?.card_type; | 1192 | /// signalling mode is returned. Expects the current clock |
| 1193 | /// frequency to be > 12.5MHz. | ||
| 1194 | /// | ||
| 1195 | /// SD only. | ||
| 1196 | async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> { | ||
| 1197 | let _ = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); | ||
| 1198 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | ||
| 1199 | // necessary" | ||
| 1180 | 1200 | ||
| 1181 | // NOTE(unsafe) DataBlock uses align 4 | 1201 | let set_function = 0x8000_0000 |
| 1182 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | 1202 | | match signalling { |
| 1203 | // See PLSS v7_10 Table 4-11 | ||
| 1204 | Signalling::DDR50 => 0xFF_FF04, | ||
| 1205 | Signalling::SDR104 => 0xFF_1F03, | ||
| 1206 | Signalling::SDR50 => 0xFF_1F02, | ||
| 1207 | Signalling::SDR25 => 0xFF_FF01, | ||
| 1208 | Signalling::SDR12 => 0xFF_FF00, | ||
| 1209 | }; | ||
| 1183 | 1210 | ||
| 1184 | // Always read 1 block of 512 bytes | 1211 | let status = match self.cmd_block.as_deref_mut() { |
| 1185 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | 1212 | Some(x) => x, |
| 1186 | let address = match card_capacity { | 1213 | None => &mut CmdBlock::new(), |
| 1187 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1188 | _ => block_idx, | ||
| 1189 | }; | 1214 | }; |
| 1190 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1191 | 1215 | ||
| 1216 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 1192 | let regs = T::regs(); | 1217 | let regs = T::regs(); |
| 1193 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1218 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1194 | 1219 | ||
| @@ -1196,12 +1221,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1196 | &self.config, | 1221 | &self.config, |
| 1197 | #[cfg(sdmmc_v1)] | 1222 | #[cfg(sdmmc_v1)] |
| 1198 | &mut self.dma, | 1223 | &mut self.dma, |
| 1199 | buffer, | 1224 | status.as_mut(), |
| 1200 | 512, | 1225 | 64, |
| 1201 | 9, | 1226 | 6, |
| 1202 | ); | 1227 | ); |
| 1203 | InterruptHandler::<T>::data_interrupts(true); | 1228 | InterruptHandler::<T>::data_interrupts(true); |
| 1204 | Self::cmd(common_cmd::read_single_block(address), true)?; | 1229 | Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 |
| 1205 | 1230 | ||
| 1206 | let res = poll_fn(|cx| { | 1231 | let res = poll_fn(|cx| { |
| 1207 | T::state().register(cx.waker()); | 1232 | T::state().register(cx.waker()); |
| @@ -1225,41 +1250,64 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1225 | .await; | 1250 | .await; |
| 1226 | Self::clear_interrupt_flags(); | 1251 | Self::clear_interrupt_flags(); |
| 1227 | 1252 | ||
| 1228 | if res.is_ok() { | 1253 | // Host is allowed to use the new functions at least 8 |
| 1229 | on_drop.defuse(); | 1254 | // clocks after the end of the switch command |
| 1230 | Self::stop_datapath(); | 1255 | // transaction. We know the current clock period is < 80ns, |
| 1231 | drop(transfer); | 1256 | // so a total delay of 640ns is required here |
| 1257 | for _ in 0..300 { | ||
| 1258 | cortex_m::asm::nop(); | ||
| 1232 | } | 1259 | } |
| 1233 | res | ||
| 1234 | } | ||
| 1235 | 1260 | ||
| 1236 | /// Write a data block. | 1261 | match res { |
| 1237 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | 1262 | Ok(_) => { |
| 1238 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | 1263 | on_drop.defuse(); |
| 1264 | Self::stop_datapath(); | ||
| 1265 | drop(transfer); | ||
| 1239 | 1266 | ||
| 1240 | // NOTE(unsafe) DataBlock uses align 4 | 1267 | // Function Selection of Function Group 1 |
| 1241 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | 1268 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; |
| 1242 | 1269 | ||
| 1243 | // Always read 1 block of 512 bytes | 1270 | match selection { |
| 1244 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | 1271 | 0 => Ok(Signalling::SDR12), |
| 1245 | let address = match card.card_type { | 1272 | 1 => Ok(Signalling::SDR25), |
| 1246 | CardCapacity::StandardCapacity => block_idx * 512, | 1273 | 2 => Ok(Signalling::SDR50), |
| 1247 | _ => block_idx, | 1274 | 3 => Ok(Signalling::SDR104), |
| 1275 | 4 => Ok(Signalling::DDR50), | ||
| 1276 | _ => Err(Error::UnsupportedCardType), | ||
| 1277 | } | ||
| 1278 | } | ||
| 1279 | Err(e) => Err(e), | ||
| 1280 | } | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | /// Reads the SCR register. | ||
| 1284 | /// | ||
| 1285 | /// SD only. | ||
| 1286 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | ||
| 1287 | // Read the 64-bit SCR register | ||
| 1288 | Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 | ||
| 1289 | Self::cmd(common_cmd::app_cmd(card.rca), false)?; | ||
| 1290 | |||
| 1291 | let cmd_block = match self.cmd_block.as_deref_mut() { | ||
| 1292 | Some(x) => x, | ||
| 1293 | None => &mut CmdBlock::new(), | ||
| 1248 | }; | 1294 | }; |
| 1249 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | 1295 | let scr = &mut cmd_block.0[..2]; |
| 1250 | 1296 | ||
| 1297 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 1251 | let regs = T::regs(); | 1298 | let regs = T::regs(); |
| 1252 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1299 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1253 | 1300 | ||
| 1254 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | 1301 | let transfer = Self::prepare_datapath_read( |
| 1255 | #[cfg(sdmmc_v1)] | 1302 | &self.config, |
| 1256 | Self::cmd(common_cmd::write_single_block(address), true)?; | 1303 | #[cfg(sdmmc_v1)] |
| 1257 | 1304 | &mut self.dma, | |
| 1258 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | 1305 | scr, |
| 1306 | 8, | ||
| 1307 | 3, | ||
| 1308 | ); | ||
| 1259 | InterruptHandler::<T>::data_interrupts(true); | 1309 | InterruptHandler::<T>::data_interrupts(true); |
| 1260 | 1310 | Self::cmd(sd_cmd::send_scr(), true)?; | |
| 1261 | #[cfg(sdmmc_v2)] | ||
| 1262 | Self::cmd(common_cmd::write_single_block(address), true)?; | ||
| 1263 | 1311 | ||
| 1264 | let res = poll_fn(|cx| { | 1312 | let res = poll_fn(|cx| { |
| 1265 | T::state().register(cx.waker()); | 1313 | T::state().register(cx.waker()); |
| @@ -1283,52 +1331,84 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1283 | .await; | 1331 | .await; |
| 1284 | Self::clear_interrupt_flags(); | 1332 | Self::clear_interrupt_flags(); |
| 1285 | 1333 | ||
| 1286 | match res { | 1334 | if res.is_ok() { |
| 1287 | Ok(_) => { | 1335 | on_drop.defuse(); |
| 1288 | on_drop.defuse(); | 1336 | Self::stop_datapath(); |
| 1289 | Self::stop_datapath(); | 1337 | drop(transfer); |
| 1290 | drop(transfer); | ||
| 1291 | |||
| 1292 | // TODO: Make this configurable | ||
| 1293 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 1294 | |||
| 1295 | let card = self.card.as_ref().unwrap(); | ||
| 1296 | while timeout > 0 { | ||
| 1297 | let status = self.read_status(card)?; | ||
| 1298 | 1338 | ||
| 1299 | if status.ready_for_data() { | 1339 | unsafe { |
| 1300 | return Ok(()); | 1340 | let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); |
| 1301 | } | 1341 | card.scr = SCR(u64::from_be_bytes(*scr_bytes)); |
| 1302 | timeout -= 1; | ||
| 1303 | } | ||
| 1304 | Err(Error::SoftwareTimeout) | ||
| 1305 | } | 1342 | } |
| 1306 | Err(e) => Err(e), | ||
| 1307 | } | 1343 | } |
| 1344 | res | ||
| 1308 | } | 1345 | } |
| 1309 | 1346 | ||
| 1310 | /// Get a reference to the initialized card | 1347 | /// Reads the SD Status (ACMD13) |
| 1311 | /// | ||
| 1312 | /// # Errors | ||
| 1313 | /// | 1348 | /// |
| 1314 | /// Returns Error::NoCard if [`init_card`](#method.init_card) | 1349 | /// SD only. |
| 1315 | /// has not previously succeeded | 1350 | async fn read_sd_status(&mut self) -> Result<(), Error> { |
| 1316 | #[inline] | 1351 | let card = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); |
| 1317 | pub fn card(&self) -> Result<&Card, Error> { | 1352 | let rca = card.rca; |
| 1318 | self.card.as_ref().ok_or(Error::NoCard) | ||
| 1319 | } | ||
| 1320 | 1353 | ||
| 1321 | /// Get the current SDMMC bus clock | 1354 | let cmd_block = match self.cmd_block.as_deref_mut() { |
| 1322 | pub fn clock(&self) -> Hertz { | 1355 | Some(x) => x, |
| 1323 | self.clock | 1356 | None => &mut CmdBlock::new(), |
| 1324 | } | 1357 | }; |
| 1325 | 1358 | ||
| 1326 | /// Set a specific cmd buffer rather than using the default stack allocated one. | 1359 | Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 |
| 1327 | /// This is required if stack RAM cannot be used with DMA and usually manifests | 1360 | Self::cmd(common_cmd::app_cmd(rca), false)?; // APP |
| 1328 | /// itself as an indefinite wait on a dma transfer because the dma peripheral | 1361 | |
| 1329 | /// cannot access the memory. | 1362 | let status = cmd_block; |
| 1330 | pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { | 1363 | |
| 1331 | self.cmd_block = Some(cmd_block) | 1364 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 1365 | let regs = T::regs(); | ||
| 1366 | let on_drop = OnDrop::new(|| Self::on_drop()); | ||
| 1367 | |||
| 1368 | let transfer = Self::prepare_datapath_read( | ||
| 1369 | &self.config, | ||
| 1370 | #[cfg(sdmmc_v1)] | ||
| 1371 | &mut self.dma, | ||
| 1372 | status.as_mut(), | ||
| 1373 | 64, | ||
| 1374 | 6, | ||
| 1375 | ); | ||
| 1376 | InterruptHandler::<T>::data_interrupts(true); | ||
| 1377 | Self::cmd(sd_cmd::sd_status(), true)?; | ||
| 1378 | |||
| 1379 | let res = poll_fn(|cx| { | ||
| 1380 | T::state().register(cx.waker()); | ||
| 1381 | let status = regs.star().read(); | ||
| 1382 | |||
| 1383 | if status.dcrcfail() { | ||
| 1384 | return Poll::Ready(Err(Error::Crc)); | ||
| 1385 | } | ||
| 1386 | if status.dtimeout() { | ||
| 1387 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1388 | } | ||
| 1389 | #[cfg(sdmmc_v1)] | ||
| 1390 | if status.stbiterr() { | ||
| 1391 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 1392 | } | ||
| 1393 | if status.dataend() { | ||
| 1394 | return Poll::Ready(Ok(())); | ||
| 1395 | } | ||
| 1396 | Poll::Pending | ||
| 1397 | }) | ||
| 1398 | .await; | ||
| 1399 | Self::clear_interrupt_flags(); | ||
| 1400 | |||
| 1401 | if res.is_ok() { | ||
| 1402 | on_drop.defuse(); | ||
| 1403 | Self::stop_datapath(); | ||
| 1404 | drop(transfer); | ||
| 1405 | |||
| 1406 | for byte in status.iter_mut() { | ||
| 1407 | *byte = u32::from_be(*byte); | ||
| 1408 | } | ||
| 1409 | card.status = status.0.into(); | ||
| 1410 | } | ||
| 1411 | res | ||
| 1332 | } | 1412 | } |
| 1333 | } | 1413 | } |
| 1334 | 1414 | ||
