diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-07-04 00:25:00 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2025-07-04 00:25:00 +0200 |
| commit | c8a4a4995844be1b61d1a1479a6009eeb69b1117 (patch) | |
| tree | ef85911ac543599b227884c2cb242468487ee11d | |
| parent | 3127e1c50b2ea2efddba199ae780cb5ebb571c00 (diff) | |
stm32/sdmmc: misc improvements
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 124 |
1 files changed, 53 insertions, 71 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index c82407334..6e5d735d7 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -32,25 +32,48 @@ pub struct InterruptHandler<T: Instance> { | |||
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | impl<T: Instance> InterruptHandler<T> { | 34 | impl<T: Instance> InterruptHandler<T> { |
| 35 | fn data_interrupts(enable: bool) { | 35 | fn enable_interrupts() { |
| 36 | let regs = T::regs(); | 36 | let regs = T::regs(); |
| 37 | regs.maskr().write(|w| { | 37 | regs.maskr().write(|w| { |
| 38 | w.set_dcrcfailie(enable); | 38 | w.set_dcrcfailie(true); |
| 39 | w.set_dtimeoutie(enable); | 39 | w.set_dtimeoutie(true); |
| 40 | w.set_dataendie(enable); | 40 | w.set_dataendie(true); |
| 41 | w.set_dbckendie(true); | ||
| 41 | 42 | ||
| 42 | #[cfg(sdmmc_v1)] | 43 | #[cfg(sdmmc_v1)] |
| 43 | w.set_stbiterre(enable); | 44 | w.set_stbiterre(true); |
| 44 | #[cfg(sdmmc_v2)] | 45 | #[cfg(sdmmc_v2)] |
| 45 | w.set_dabortie(enable); | 46 | w.set_dabortie(true); |
| 46 | }); | 47 | }); |
| 47 | } | 48 | } |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | 51 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 51 | unsafe fn on_interrupt() { | 52 | unsafe fn on_interrupt() { |
| 52 | Self::data_interrupts(false); | ||
| 53 | T::state().wake(); | 53 | T::state().wake(); |
| 54 | let status = T::regs().star().read(); | ||
| 55 | T::regs().maskr().modify(|w| { | ||
| 56 | if status.dcrcfail() { | ||
| 57 | w.set_dcrcfailie(false) | ||
| 58 | } | ||
| 59 | if status.dtimeout() { | ||
| 60 | w.set_dtimeoutie(false) | ||
| 61 | } | ||
| 62 | if status.dataend() { | ||
| 63 | w.set_dataendie(false) | ||
| 64 | } | ||
| 65 | if status.dbckend() { | ||
| 66 | w.set_dbckendie(false) | ||
| 67 | } | ||
| 68 | #[cfg(sdmmc_v1)] | ||
| 69 | if status.stbiterr() { | ||
| 70 | w.set_stbiterre(false) | ||
| 71 | } | ||
| 72 | #[cfg(sdmmc_v2)] | ||
| 73 | if status.dabort() { | ||
| 74 | w.set_dabortie(false) | ||
| 75 | } | ||
| 76 | }); | ||
| 54 | } | 77 | } |
| 55 | } | 78 | } |
| 56 | 79 | ||
| @@ -1002,14 +1025,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1002 | // Wait for the abort | 1025 | // Wait for the abort |
| 1003 | while Self::data_active() {} | 1026 | while Self::data_active() {} |
| 1004 | } | 1027 | } |
| 1005 | InterruptHandler::<T>::data_interrupts(false); | 1028 | regs.maskr().write(|_| ()); // disable irqs |
| 1006 | Self::clear_interrupt_flags(); | 1029 | Self::clear_interrupt_flags(); |
| 1007 | Self::stop_datapath(); | 1030 | Self::stop_datapath(); |
| 1008 | } | 1031 | } |
| 1009 | 1032 | ||
| 1010 | /// Wait for a previously started datapath transfer to complete from an interrupt. | 1033 | /// Wait for a previously started datapath transfer to complete from an interrupt. |
| 1011 | #[inline] | 1034 | #[inline] |
| 1012 | async fn complete_datapath_transfer() -> Result<(), Error> { | 1035 | async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { |
| 1013 | let regs = T::regs(); | 1036 | let regs = T::regs(); |
| 1014 | 1037 | ||
| 1015 | let res = poll_fn(|cx| { | 1038 | let res = poll_fn(|cx| { |
| @@ -1029,7 +1052,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1029 | if status.stbiterr() { | 1052 | if status.stbiterr() { |
| 1030 | return Poll::Ready(Err(Error::StBitErr)); | 1053 | return Poll::Ready(Err(Error::StBitErr)); |
| 1031 | } | 1054 | } |
| 1032 | if status.dataend() { | 1055 | let done = match block { |
| 1056 | true => status.dbckend(), | ||
| 1057 | false => status.dataend(), | ||
| 1058 | }; | ||
| 1059 | if done { | ||
| 1033 | return Poll::Ready(Ok(())); | 1060 | return Poll::Ready(Ok(())); |
| 1034 | } | 1061 | } |
| 1035 | Poll::Pending | 1062 | Poll::Pending |
| @@ -1067,10 +1094,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1067 | 512, | 1094 | 512, |
| 1068 | 9, | 1095 | 9, |
| 1069 | ); | 1096 | ); |
| 1070 | InterruptHandler::<T>::data_interrupts(true); | 1097 | InterruptHandler::<T>::enable_interrupts(); |
| 1071 | Self::cmd(common_cmd::read_single_block(address), true)?; | 1098 | Self::cmd(common_cmd::read_single_block(address), true)?; |
| 1072 | 1099 | ||
| 1073 | let res = Self::complete_datapath_transfer().await; | 1100 | let res = Self::complete_datapath_transfer(true).await; |
| 1074 | 1101 | ||
| 1075 | if res.is_ok() { | 1102 | if res.is_ok() { |
| 1076 | on_drop.defuse(); | 1103 | on_drop.defuse(); |
| @@ -1100,7 +1127,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1100 | }; | 1127 | }; |
| 1101 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 | 1128 | Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 |
| 1102 | 1129 | ||
| 1103 | let regs = T::regs(); | ||
| 1104 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1130 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1105 | 1131 | ||
| 1106 | let transfer = Self::prepare_datapath_read( | 1132 | let transfer = Self::prepare_datapath_read( |
| @@ -1111,30 +1137,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1111 | 512 * blocks.len() as u32, | 1137 | 512 * blocks.len() as u32, |
| 1112 | 9, | 1138 | 9, |
| 1113 | ); | 1139 | ); |
| 1114 | InterruptHandler::<T>::data_interrupts(true); | 1140 | InterruptHandler::<T>::enable_interrupts(); |
| 1115 | 1141 | ||
| 1116 | Self::cmd(common_cmd::read_multiple_blocks(address), true)?; | 1142 | Self::cmd(common_cmd::read_multiple_blocks(address), true)?; |
| 1117 | 1143 | ||
| 1118 | let res = poll_fn(|cx| { | 1144 | let res = Self::complete_datapath_transfer(false).await; |
| 1119 | T::state().register(cx.waker()); | ||
| 1120 | let status = regs.star().read(); | ||
| 1121 | |||
| 1122 | if status.dcrcfail() { | ||
| 1123 | return Poll::Ready(Err(Error::Crc)); | ||
| 1124 | } | ||
| 1125 | if status.dtimeout() { | ||
| 1126 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1127 | } | ||
| 1128 | #[cfg(sdmmc_v1)] | ||
| 1129 | if status.stbiterr() { | ||
| 1130 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 1131 | } | ||
| 1132 | if status.dataend() { | ||
| 1133 | return Poll::Ready(Ok(())); | ||
| 1134 | } | ||
| 1135 | Poll::Pending | ||
| 1136 | }) | ||
| 1137 | .await; | ||
| 1138 | 1145 | ||
| 1139 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 | 1146 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 |
| 1140 | Self::clear_interrupt_flags(); | 1147 | Self::clear_interrupt_flags(); |
| @@ -1169,12 +1176,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1169 | Self::cmd(common_cmd::write_single_block(address), true)?; | 1176 | Self::cmd(common_cmd::write_single_block(address), true)?; |
| 1170 | 1177 | ||
| 1171 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | 1178 | let transfer = self.prepare_datapath_write(buffer, 512, 9); |
| 1172 | InterruptHandler::<T>::data_interrupts(true); | 1179 | InterruptHandler::<T>::enable_interrupts(); |
| 1173 | 1180 | ||
| 1174 | #[cfg(sdmmc_v2)] | 1181 | #[cfg(sdmmc_v2)] |
| 1175 | Self::cmd(common_cmd::write_single_block(address), true)?; | 1182 | Self::cmd(common_cmd::write_single_block(address), true)?; |
| 1176 | 1183 | ||
| 1177 | let res = Self::complete_datapath_transfer().await; | 1184 | let res = Self::complete_datapath_transfer(true).await; |
| 1178 | 1185 | ||
| 1179 | match res { | 1186 | match res { |
| 1180 | Ok(_) => { | 1187 | Ok(_) => { |
| @@ -1225,7 +1232,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1225 | 1232 | ||
| 1226 | let block_count = blocks.len(); | 1233 | let block_count = blocks.len(); |
| 1227 | 1234 | ||
| 1228 | let regs = T::regs(); | ||
| 1229 | let on_drop = OnDrop::new(|| Self::on_drop()); | 1235 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1230 | 1236 | ||
| 1231 | #[cfg(sdmmc_v1)] | 1237 | #[cfg(sdmmc_v1)] |
| @@ -1233,36 +1239,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1233 | 1239 | ||
| 1234 | // Setup write command | 1240 | // Setup write command |
| 1235 | let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); | 1241 | let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); |
| 1236 | InterruptHandler::<T>::data_interrupts(true); | 1242 | InterruptHandler::<T>::enable_interrupts(); |
| 1237 | 1243 | ||
| 1238 | #[cfg(sdmmc_v2)] | 1244 | #[cfg(sdmmc_v2)] |
| 1239 | Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | 1245 | Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 |
| 1240 | 1246 | ||
| 1241 | let res = poll_fn(|cx| { | 1247 | let res = Self::complete_datapath_transfer(false).await; |
| 1242 | T::state().register(cx.waker()); | ||
| 1243 | |||
| 1244 | let status = regs.star().read(); | ||
| 1245 | |||
| 1246 | if status.dcrcfail() { | ||
| 1247 | return Poll::Ready(Err(Error::Crc)); | ||
| 1248 | } | ||
| 1249 | if status.dtimeout() { | ||
| 1250 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1251 | } | ||
| 1252 | if status.txunderr() { | ||
| 1253 | return Poll::Ready(Err(Error::Underrun)); | ||
| 1254 | } | ||
| 1255 | #[cfg(sdmmc_v1)] | ||
| 1256 | if status.stbiterr() { | ||
| 1257 | return Poll::Ready(Err(Error::StBitErr)); | ||
| 1258 | } | ||
| 1259 | if status.dataend() { | ||
| 1260 | return Poll::Ready(Ok(())); | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | Poll::Pending | ||
| 1264 | }) | ||
| 1265 | .await; | ||
| 1266 | 1248 | ||
| 1267 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 | 1249 | Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 |
| 1268 | Self::clear_interrupt_flags(); | 1250 | Self::clear_interrupt_flags(); |
| @@ -1597,10 +1579,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1597 | 64, | 1579 | 64, |
| 1598 | 6, | 1580 | 6, |
| 1599 | ); | 1581 | ); |
| 1600 | InterruptHandler::<T>::data_interrupts(true); | 1582 | InterruptHandler::<T>::enable_interrupts(); |
| 1601 | Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 | 1583 | Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 |
| 1602 | 1584 | ||
| 1603 | let res = Self::complete_datapath_transfer().await; | 1585 | let res = Self::complete_datapath_transfer(true).await; |
| 1604 | 1586 | ||
| 1605 | // Host is allowed to use the new functions at least 8 | 1587 | // Host is allowed to use the new functions at least 8 |
| 1606 | // clocks after the end of the switch command | 1588 | // clocks after the end of the switch command |
| @@ -1657,10 +1639,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1657 | 8, | 1639 | 8, |
| 1658 | 3, | 1640 | 3, |
| 1659 | ); | 1641 | ); |
| 1660 | InterruptHandler::<T>::data_interrupts(true); | 1642 | InterruptHandler::<T>::enable_interrupts(); |
| 1661 | Self::cmd(sd_cmd::send_scr(), true)?; | 1643 | Self::cmd(sd_cmd::send_scr(), true)?; |
| 1662 | 1644 | ||
| 1663 | let res = Self::complete_datapath_transfer().await; | 1645 | let res = Self::complete_datapath_transfer(true).await; |
| 1664 | 1646 | ||
| 1665 | if res.is_ok() { | 1647 | if res.is_ok() { |
| 1666 | on_drop.defuse(); | 1648 | on_drop.defuse(); |
| @@ -1703,10 +1685,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1703 | 64, | 1685 | 64, |
| 1704 | 6, | 1686 | 6, |
| 1705 | ); | 1687 | ); |
| 1706 | InterruptHandler::<T>::data_interrupts(true); | 1688 | InterruptHandler::<T>::enable_interrupts(); |
| 1707 | Self::cmd(sd_cmd::sd_status(), true)?; | 1689 | Self::cmd(sd_cmd::sd_status(), true)?; |
| 1708 | 1690 | ||
| 1709 | let res = Self::complete_datapath_transfer().await; | 1691 | let res = Self::complete_datapath_transfer(true).await; |
| 1710 | 1692 | ||
| 1711 | if res.is_ok() { | 1693 | if res.is_ok() { |
| 1712 | on_drop.defuse(); | 1694 | on_drop.defuse(); |
| @@ -1753,10 +1735,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1753 | 512, | 1735 | 512, |
| 1754 | 9, | 1736 | 9, |
| 1755 | ); | 1737 | ); |
| 1756 | InterruptHandler::<T>::data_interrupts(true); | 1738 | InterruptHandler::<T>::enable_interrupts(); |
| 1757 | Self::cmd(emmc_cmd::send_ext_csd(), true)?; | 1739 | Self::cmd(emmc_cmd::send_ext_csd(), true)?; |
| 1758 | 1740 | ||
| 1759 | let res = Self::complete_datapath_transfer().await; | 1741 | let res = Self::complete_datapath_transfer(true).await; |
| 1760 | 1742 | ||
| 1761 | if res.is_ok() { | 1743 | if res.is_ok() { |
| 1762 | on_drop.defuse(); | 1744 | on_drop.defuse(); |
