diff options
| author | chemicstry <[email protected]> | 2022-03-16 20:20:39 +0200 |
|---|---|---|
| committer | chemicstry <[email protected]> | 2022-03-16 20:20:39 +0200 |
| commit | 8a8e5c4b736adf1d83f6849d7f86c26dabf73675 (patch) | |
| tree | a8439e348929415c0e767c4669713906aab24cc4 | |
| parent | 48fc48ea7d0d73c7071e0f353c52eda10ad5a1b4 (diff) | |
Fix SDMMC v2 and add H7 example
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 94 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/sdmmc.rs | 23 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/sdmmc.rs | 42 | ||||
| m--------- | stm32-data | 0 |
4 files changed, 119 insertions, 40 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 18e53ce10..60060c79e 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -12,7 +12,7 @@ use embassy_hal_common::unborrow; | |||
| 12 | use futures::future::poll_fn; | 12 | use futures::future::poll_fn; |
| 13 | use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; | 13 | use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; |
| 14 | 14 | ||
| 15 | use crate::dma::{NoDma, TransferOptions}; | 15 | use crate::dma::NoDma; |
| 16 | use crate::gpio::sealed::AFType; | 16 | use crate::gpio::sealed::AFType; |
| 17 | use crate::gpio::{Pull, Speed}; | 17 | use crate::gpio::{Pull, Speed}; |
| 18 | use crate::interrupt::Interrupt; | 18 | use crate::interrupt::Interrupt; |
| @@ -191,26 +191,23 @@ pub struct Sdmmc<'d, T: Instance, P: Pins<T>, Dma = NoDma> { | |||
| 191 | card: Option<Card>, | 191 | card: Option<Card>, |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | #[cfg(sdmmc_v1)] | ||
| 194 | impl<'d, T: Instance, P: Pins<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> { | 195 | impl<'d, T: Instance, P: Pins<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> { |
| 195 | /// # Safety | 196 | pub fn new( |
| 196 | /// | ||
| 197 | /// Futures that borrow this type can't be leaked | ||
| 198 | #[inline(always)] | ||
| 199 | pub unsafe fn new( | ||
| 200 | _peripheral: impl Unborrow<Target = T> + 'd, | 197 | _peripheral: impl Unborrow<Target = T> + 'd, |
| 201 | pins: impl Unborrow<Target = P> + 'd, | 198 | pins: impl Unborrow<Target = P> + 'd, |
| 202 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | 199 | irq: impl Unborrow<Target = T::Interrupt> + 'd, |
| 203 | config: Config, | 200 | config: Config, |
| 204 | dma: Dma, | 201 | dma: impl Unborrow<Target = Dma> + 'd, |
| 205 | ) -> Self { | 202 | ) -> Self { |
| 206 | unborrow!(irq, pins); | 203 | unborrow!(irq, pins, dma); |
| 207 | pins.configure(); | 204 | pins.configure(); |
| 208 | 205 | ||
| 209 | T::enable(); | 206 | T::enable(); |
| 210 | T::reset(); | 207 | T::reset(); |
| 211 | 208 | ||
| 212 | let inner = T::inner(); | 209 | let inner = T::inner(); |
| 213 | let clock = inner.new_inner(T::frequency()); | 210 | let clock = unsafe { inner.new_inner(T::frequency()) }; |
| 214 | 211 | ||
| 215 | irq.set_handler(Self::on_interrupt); | 212 | irq.set_handler(Self::on_interrupt); |
| 216 | irq.unpend(); | 213 | irq.unpend(); |
| @@ -227,7 +224,45 @@ impl<'d, T: Instance, P: Pins<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> { | |||
| 227 | card: None, | 224 | card: None, |
| 228 | } | 225 | } |
| 229 | } | 226 | } |
| 227 | } | ||
| 228 | |||
| 229 | #[cfg(sdmmc_v2)] | ||
| 230 | impl<'d, T: Instance, P: Pins<T>> Sdmmc<'d, T, P, NoDma> { | ||
| 231 | pub fn new( | ||
| 232 | _peripheral: impl Unborrow<Target = T> + 'd, | ||
| 233 | pins: impl Unborrow<Target = P> + 'd, | ||
| 234 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 235 | config: Config, | ||
| 236 | ) -> Self { | ||
| 237 | unborrow!(irq, pins); | ||
| 238 | pins.configure(); | ||
| 239 | |||
| 240 | T::enable(); | ||
| 241 | T::reset(); | ||
| 242 | |||
| 243 | info!("Freq: {}", T::frequency().0); | ||
| 244 | |||
| 245 | let inner = T::inner(); | ||
| 246 | let clock = unsafe { inner.new_inner(T::frequency()) }; | ||
| 247 | |||
| 248 | irq.set_handler(Self::on_interrupt); | ||
| 249 | irq.unpend(); | ||
| 250 | irq.enable(); | ||
| 251 | |||
| 252 | Self { | ||
| 253 | sdmmc: PhantomData, | ||
| 254 | pins, | ||
| 255 | irq, | ||
| 256 | config, | ||
| 257 | dma: NoDma, | ||
| 258 | clock, | ||
| 259 | signalling: Default::default(), | ||
| 260 | card: None, | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 230 | 264 | ||
| 265 | impl<'d, T: Instance, P: Pins<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> { | ||
| 231 | #[inline(always)] | 266 | #[inline(always)] |
| 232 | pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> { | 267 | pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> { |
| 233 | let inner = T::inner(); | 268 | let inner = T::inner(); |
| @@ -687,7 +722,7 @@ impl SdmmcInner { | |||
| 687 | length_bytes: u32, | 722 | length_bytes: u32, |
| 688 | block_size: u8, | 723 | block_size: u8, |
| 689 | data_transfer_timeout: u32, | 724 | data_transfer_timeout: u32, |
| 690 | dma: &mut Dma, | 725 | #[allow(unused_variables)] dma: &mut Dma, |
| 691 | ) { | 726 | ) { |
| 692 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 727 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 693 | let regs = self.0; | 728 | let regs = self.0; |
| @@ -705,13 +740,13 @@ impl SdmmcInner { | |||
| 705 | cfg_if::cfg_if! { | 740 | cfg_if::cfg_if! { |
| 706 | if #[cfg(sdmmc_v1)] { | 741 | if #[cfg(sdmmc_v1)] { |
| 707 | let request = dma.request(); | 742 | let request = dma.request(); |
| 708 | dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, TransferOptions { | 743 | dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, crate::dma::TransferOptions { |
| 709 | pburst: crate::dma::Burst::Incr4, | 744 | pburst: crate::dma::Burst::Incr4, |
| 710 | flow_ctrl: crate::dma::FlowControl::Peripheral, | 745 | flow_ctrl: crate::dma::FlowControl::Peripheral, |
| 711 | ..Default::default() | 746 | ..Default::default() |
| 712 | }); | 747 | }); |
| 713 | } else if #[cfg(sdmmc_v2)] { | 748 | } else if #[cfg(sdmmc_v2)] { |
| 714 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer_addr)); | 749 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *mut u32 as u32)); |
| 715 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); | 750 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); |
| 716 | } | 751 | } |
| 717 | } | 752 | } |
| @@ -736,7 +771,7 @@ impl SdmmcInner { | |||
| 736 | length_bytes: u32, | 771 | length_bytes: u32, |
| 737 | block_size: u8, | 772 | block_size: u8, |
| 738 | data_transfer_timeout: u32, | 773 | data_transfer_timeout: u32, |
| 739 | dma: &mut Dma, | 774 | #[allow(unused_variables)] dma: &mut Dma, |
| 740 | ) { | 775 | ) { |
| 741 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 776 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 742 | let regs = self.0; | 777 | let regs = self.0; |
| @@ -754,13 +789,13 @@ impl SdmmcInner { | |||
| 754 | cfg_if::cfg_if! { | 789 | cfg_if::cfg_if! { |
| 755 | if #[cfg(sdmmc_v1)] { | 790 | if #[cfg(sdmmc_v1)] { |
| 756 | let request = dma.request(); | 791 | let request = dma.request(); |
| 757 | dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, TransferOptions { | 792 | dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, crate::dma::TransferOptions { |
| 758 | pburst: crate::dma::Burst::Incr4, | 793 | pburst: crate::dma::Burst::Incr4, |
| 759 | flow_ctrl: crate::dma::FlowControl::Peripheral, | 794 | flow_ctrl: crate::dma::FlowControl::Peripheral, |
| 760 | ..Default::default() | 795 | ..Default::default() |
| 761 | }); | 796 | }); |
| 762 | } else if #[cfg(sdmmc_v2)] { | 797 | } else if #[cfg(sdmmc_v2)] { |
| 763 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer_addr)); | 798 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *const u32 as u32)); |
| 764 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); | 799 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); |
| 765 | } | 800 | } |
| 766 | } | 801 | } |
| @@ -1104,7 +1139,7 @@ impl SdmmcInner { | |||
| 1104 | while self.cmd_active() {} | 1139 | while self.cmd_active() {} |
| 1105 | 1140 | ||
| 1106 | // Command arg | 1141 | // Command arg |
| 1107 | regs.argr().write(|w| w.set_cmdargr(cmd.arg)); | 1142 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); |
| 1108 | 1143 | ||
| 1109 | // Command index and start CP State Machine | 1144 | // Command index and start CP State Machine |
| 1110 | regs.cmdr().write(|w| { | 1145 | regs.cmdr().write(|w| { |
| @@ -1113,14 +1148,13 @@ impl SdmmcInner { | |||
| 1113 | w.set_cmdindex(cmd.cmd); | 1148 | w.set_cmdindex(cmd.cmd); |
| 1114 | w.set_cpsmen(true); | 1149 | w.set_cpsmen(true); |
| 1115 | 1150 | ||
| 1116 | cfg_if::cfg_if! { | 1151 | #[cfg(sdmmc_v2)] |
| 1117 | if #[cfg(sdmmc_v2)] { | 1152 | { |
| 1118 | // Special mode in CP State Machine | 1153 | // Special mode in CP State Machine |
| 1119 | // CMD12: Stop Transmission | 1154 | // CMD12: Stop Transmission |
| 1120 | let cpsm_stop_transmission = cmd.cmd == 12; | 1155 | let cpsm_stop_transmission = cmd.cmd == 12; |
| 1121 | w.set_cmdstop(cpsm_stop_transmission); | 1156 | w.set_cmdstop(cpsm_stop_transmission); |
| 1122 | w.set_cmdtrans(data); | 1157 | w.set_cmdtrans(data); |
| 1123 | } | ||
| 1124 | } | 1158 | } |
| 1125 | }); | 1159 | }); |
| 1126 | 1160 | ||
| @@ -1160,7 +1194,7 @@ impl SdmmcInner { | |||
| 1160 | while self.cmd_active() {} | 1194 | while self.cmd_active() {} |
| 1161 | 1195 | ||
| 1162 | // Command arg | 1196 | // Command arg |
| 1163 | regs.argr().write(|w| w.set_cmdargr(0)); | 1197 | regs.argr().write(|w| w.set_cmdarg(0)); |
| 1164 | 1198 | ||
| 1165 | // Command index and start CP State Machine | 1199 | // Command index and start CP State Machine |
| 1166 | regs.cmdr().write(|w| { | 1200 | regs.cmdr().write(|w| { |
| @@ -1300,7 +1334,15 @@ pin_trait!(D5Pin, Instance); | |||
| 1300 | pin_trait!(D6Pin, Instance); | 1334 | pin_trait!(D6Pin, Instance); |
| 1301 | pin_trait!(D7Pin, Instance); | 1335 | pin_trait!(D7Pin, Instance); |
| 1302 | 1336 | ||
| 1303 | dma_trait!(SdioDma, Instance); | 1337 | cfg_if::cfg_if! { |
| 1338 | if #[cfg(sdmmc_v1)] { | ||
| 1339 | dma_trait!(SdioDma, Instance); | ||
| 1340 | } else if #[cfg(sdmmc_v2)] { | ||
| 1341 | // SDMMCv2 uses internal DMA | ||
| 1342 | pub trait SdioDma<T: Instance> {} | ||
| 1343 | impl<T: Instance> SdioDma<T> for NoDma {} | ||
| 1344 | } | ||
| 1345 | } | ||
| 1304 | 1346 | ||
| 1305 | pub trait Pins<T: Instance>: sealed::Pins<T> + 'static { | 1347 | pub trait Pins<T: Instance>: sealed::Pins<T> + 'static { |
| 1306 | const BUSWIDTH: BusWidth; | 1348 | const BUSWIDTH: BusWidth; |
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 46ac44500..301d7dda0 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs | |||
| @@ -13,28 +13,23 @@ use example_common::*; | |||
| 13 | 13 | ||
| 14 | fn config() -> Config { | 14 | fn config() -> Config { |
| 15 | let mut config = Config::default(); | 15 | let mut config = Config::default(); |
| 16 | config.rcc.hse = Some(8.mhz().into()); | 16 | config.rcc.sys_ck = Some(48.mhz().into()); |
| 17 | config.rcc.hclk = Some(48.mhz().into()); | ||
| 18 | config.rcc.pclk2 = Some(48.mhz().into()); | ||
| 19 | config.rcc.pll48 = true; | ||
| 20 | config | 17 | config |
| 21 | } | 18 | } |
| 22 | 19 | ||
| 23 | #[embassy::main(config = "config()")] | 20 | #[embassy::main(config = "config()")] |
| 24 | async fn main(_spawner: Spawner, p: Peripherals) -> ! { | 21 | async fn main(_spawner: Spawner, p: Peripherals) -> ! { |
| 25 | info!("Hello World, dude!"); | 22 | info!("Hello World!"); |
| 26 | 23 | ||
| 27 | let irq = interrupt::take!(SDIO); | 24 | let irq = interrupt::take!(SDIO); |
| 28 | 25 | ||
| 29 | let mut sdmmc = unsafe { | 26 | let mut sdmmc = Sdmmc::new( |
| 30 | Sdmmc::new( | 27 | p.SDIO, |
| 31 | p.SDIO, | 28 | (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11), |
| 32 | (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11), | 29 | irq, |
| 33 | irq, | 30 | Default::default(), |
| 34 | Default::default(), | 31 | p.DMA2_CH3, |
| 35 | p.DMA2_CH3, | 32 | ); |
| 36 | ) | ||
| 37 | }; | ||
| 38 | 33 | ||
| 39 | info!("Configured clock: {}", sdmmc.clock.0); | 34 | info!("Configured clock: {}", sdmmc.clock.0); |
| 40 | 35 | ||
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs new file mode 100644 index 000000000..255c5568f --- /dev/null +++ b/examples/stm32h7/src/bin/sdmmc.rs | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | #[path = "../example_common.rs"] | ||
| 6 | mod example_common; | ||
| 7 | |||
| 8 | use embassy::executor::Spawner; | ||
| 9 | use embassy_stm32::sdmmc::Sdmmc; | ||
| 10 | use embassy_stm32::time::U32Ext; | ||
| 11 | use embassy_stm32::{interrupt, Config, Peripherals}; | ||
| 12 | use example_common::*; | ||
| 13 | |||
| 14 | fn config() -> Config { | ||
| 15 | let mut config = Config::default(); | ||
| 16 | config.rcc.sys_ck = Some(200.mhz().into()); | ||
| 17 | config | ||
| 18 | } | ||
| 19 | |||
| 20 | #[embassy::main(config = "config()")] | ||
| 21 | async fn main(_spawner: Spawner, p: Peripherals) -> ! { | ||
| 22 | info!("Hello World!"); | ||
| 23 | |||
| 24 | let irq = interrupt::take!(SDMMC1); | ||
| 25 | |||
| 26 | let mut sdmmc = Sdmmc::new( | ||
| 27 | p.SDMMC1, | ||
| 28 | (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11), | ||
| 29 | irq, | ||
| 30 | Default::default(), | ||
| 31 | ); | ||
| 32 | |||
| 33 | info!("Configured clock: {}", sdmmc.clock.0); | ||
| 34 | |||
| 35 | unwrap!(sdmmc.init_card(25.mhz()).await); | ||
| 36 | |||
| 37 | let card = unwrap!(sdmmc.card()); | ||
| 38 | |||
| 39 | info!("Card: {:#?}", Debug2Format(card)); | ||
| 40 | |||
| 41 | loop {} | ||
| 42 | } | ||
diff --git a/stm32-data b/stm32-data | |||
| Subproject 2b8eb83c7aa01200f8215248793da2489209116 | Subproject 938770167164faa46970af4f6096ec7c8b19591 | ||
