aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchemicstry <[email protected]>2023-02-18 01:35:35 +0200
committerchemicstry <[email protected]>2023-02-18 01:37:06 +0200
commita53f525f510de07e8c35d38ecc575cb8ea929dd9 (patch)
treecda725bead4d8504d15d68e2b275fa529e5531d8
parente3f8020c3bdf726dfa451b5b190f27191507a18f (diff)
stm32/sdmmc: Fix SDIOv1 writes
-rw-r--r--embassy-stm32/src/dma/bdma.rs1
-rw-r--r--embassy-stm32/src/dma/dma.rs23
-rw-r--r--embassy-stm32/src/dma/gpdma.rs10
-rw-r--r--embassy-stm32/src/dma/mod.rs16
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs40
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs39
6 files changed, 124 insertions, 5 deletions
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 6160b9f40..5a7a408bb 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -192,6 +192,7 @@ mod low_level_api {
192 options.flow_ctrl == crate::dma::FlowControl::Dma, 192 options.flow_ctrl == crate::dma::FlowControl::Dma,
193 "Peripheral flow control not supported" 193 "Peripheral flow control not supported"
194 ); 194 );
195 assert!(options.fifo_threshold.is_none(), "FIFO mode not supported");
195 196
196 let ch = dma.ch(channel_number as _); 197 let ch = dma.ch(channel_number as _);
197 198
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index fec60f708..385a833f7 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -4,7 +4,7 @@ use core::task::Waker;
4use embassy_cortex_m::interrupt::Priority; 4use embassy_cortex_m::interrupt::Priority;
5use embassy_sync::waitqueue::AtomicWaker; 5use embassy_sync::waitqueue::AtomicWaker;
6 6
7use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize}; 7use super::{Burst, FifoThreshold, FlowControl, Request, TransferOptions, Word, WordSize};
8use crate::_generated::DMA_CHANNEL_COUNT; 8use crate::_generated::DMA_CHANNEL_COUNT;
9use crate::interrupt::{Interrupt, InterruptExt}; 9use crate::interrupt::{Interrupt, InterruptExt};
10use crate::pac::dma::{regs, vals}; 10use crate::pac::dma::{regs, vals};
@@ -40,6 +40,17 @@ impl From<FlowControl> for vals::Pfctrl {
40 } 40 }
41} 41}
42 42
43impl From<FifoThreshold> for vals::Fth {
44 fn from(value: FifoThreshold) -> Self {
45 match value {
46 FifoThreshold::Quarter => vals::Fth::QUARTER,
47 FifoThreshold::Half => vals::Fth::HALF,
48 FifoThreshold::ThreeQuarters => vals::Fth::THREEQUARTERS,
49 FifoThreshold::Full => vals::Fth::FULL,
50 }
51 }
52}
53
43struct ChannelState { 54struct ChannelState {
44 waker: AtomicWaker, 55 waker: AtomicWaker,
45} 56}
@@ -236,6 +247,16 @@ mod low_level_api {
236 ch.par().write_value(peri_addr as u32); 247 ch.par().write_value(peri_addr as u32);
237 ch.m0ar().write_value(mem_addr as u32); 248 ch.m0ar().write_value(mem_addr as u32);
238 ch.ndtr().write_value(regs::Ndtr(mem_len as _)); 249 ch.ndtr().write_value(regs::Ndtr(mem_len as _));
250 ch.fcr().write(|w| {
251 if let Some(fth) = options.fifo_threshold {
252 // FIFO mode
253 w.set_dmdis(vals::Dmdis::DISABLED);
254 w.set_fth(fth.into());
255 } else {
256 // Direct mode
257 w.set_dmdis(vals::Dmdis::ENABLED);
258 }
259 });
239 ch.cr().write(|w| { 260 ch.cr().write(|w| {
240 w.set_dir(dir); 261 w.set_dir(dir);
241 w.set_msize(data_size); 262 w.set_msize(data_size);
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index d252cef3e..442fee48e 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -176,8 +176,16 @@ mod low_level_api {
176 mem_len: usize, 176 mem_len: usize,
177 incr_mem: bool, 177 incr_mem: bool,
178 data_size: WordSize, 178 data_size: WordSize,
179 _options: TransferOptions, 179 options: TransferOptions,
180 ) { 180 ) {
181 assert!(options.mburst == crate::dma::Burst::Single, "Burst mode not supported");
182 assert!(options.pburst == crate::dma::Burst::Single, "Burst mode not supported");
183 assert!(
184 options.flow_ctrl == crate::dma::FlowControl::Dma,
185 "Peripheral flow control not supported"
186 );
187 assert!(options.fifo_threshold.is_none(), "FIFO mode not supported");
188
181 // "Preceding reads and writes cannot be moved past subsequent writes." 189 // "Preceding reads and writes cannot be moved past subsequent writes."
182 fence(Ordering::SeqCst); 190 fence(Ordering::SeqCst);
183 191
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index b51e0d40b..f5a82fb7a 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -188,6 +188,19 @@ pub enum FlowControl {
188 188
189#[derive(Debug, Copy, Clone, PartialEq, Eq)] 189#[derive(Debug, Copy, Clone, PartialEq, Eq)]
190#[cfg_attr(feature = "defmt", derive(defmt::Format))] 190#[cfg_attr(feature = "defmt", derive(defmt::Format))]
191pub enum FifoThreshold {
192 /// 1/4 full FIFO
193 Quarter,
194 /// 1/2 full FIFO
195 Half,
196 /// 3/4 full FIFO
197 ThreeQuarters,
198 /// Full FIFO
199 Full,
200}
201
202#[derive(Debug, Copy, Clone, PartialEq, Eq)]
203#[cfg_attr(feature = "defmt", derive(defmt::Format))]
191pub struct TransferOptions { 204pub struct TransferOptions {
192 /// Peripheral burst transfer configuration 205 /// Peripheral burst transfer configuration
193 pub pburst: Burst, 206 pub pburst: Burst,
@@ -195,6 +208,8 @@ pub struct TransferOptions {
195 pub mburst: Burst, 208 pub mburst: Burst,
196 /// Flow control configuration 209 /// Flow control configuration
197 pub flow_ctrl: FlowControl, 210 pub flow_ctrl: FlowControl,
211 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
212 pub fifo_threshold: Option<FifoThreshold>,
198} 213}
199 214
200impl Default for TransferOptions { 215impl Default for TransferOptions {
@@ -203,6 +218,7 @@ impl Default for TransferOptions {
203 pburst: Burst::Single, 218 pburst: Burst::Single,
204 mburst: Burst::Single, 219 mburst: Burst::Single,
205 flow_ctrl: FlowControl::Dma, 220 flow_ctrl: FlowControl::Dma,
221 fifo_threshold: None,
206 } 222 }
207 } 223 }
208} 224}
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 3f07e0c07..3c99a0b6c 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -2,6 +2,7 @@
2 2
3use core::default::Default; 3use core::default::Default;
4use core::future::poll_fn; 4use core::future::poll_fn;
5use core::ops::{Deref, DerefMut};
5use core::task::Poll; 6use core::task::Poll;
6 7
7use embassy_hal_common::drop::OnDrop; 8use embassy_hal_common::drop::OnDrop;
@@ -40,7 +41,23 @@ impl Default for Signalling {
40} 41}
41 42
42#[repr(align(4))] 43#[repr(align(4))]
43pub struct DataBlock([u8; 512]); 44#[derive(Debug, Clone)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46pub struct DataBlock(pub [u8; 512]);
47
48impl Deref for DataBlock {
49 type Target = [u8; 512];
50
51 fn deref(&self) -> &Self::Target {
52 &self.0
53 }
54}
55
56impl DerefMut for DataBlock {
57 fn deref_mut(&mut self) -> &mut Self::Target {
58 &mut self.0
59 }
60}
44 61
45/// Errors 62/// Errors
46#[non_exhaustive] 63#[non_exhaustive]
@@ -570,6 +587,12 @@ impl SdmmcInner {
570 regs.clkcr().write(|w| { 587 regs.clkcr().write(|w| {
571 w.set_pwrsav(false); 588 w.set_pwrsav(false);
572 w.set_negedge(false); 589 w.set_negedge(false);
590
591 // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
592 // See chip erratas for more details.
593 #[cfg(sdmmc_v1)]
594 w.set_hwfc_en(false);
595 #[cfg(sdmmc_v2)]
573 w.set_hwfc_en(true); 596 w.set_hwfc_en(true);
574 597
575 #[cfg(sdmmc_v1)] 598 #[cfg(sdmmc_v1)]
@@ -807,10 +830,16 @@ impl SdmmcInner {
807 let regs = self.0; 830 let regs = self.0;
808 let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); 831 let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
809 832
833 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
834 #[cfg(sdmmc_v1)]
835 self.cmd(Cmd::write_single_block(address), true)?;
836
810 unsafe { 837 unsafe {
811 self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9, data_transfer_timeout, dma); 838 self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9, data_transfer_timeout, dma);
812 self.data_interrupts(true); 839 self.data_interrupts(true);
813 } 840 }
841
842 #[cfg(sdmmc_v2)]
814 self.cmd(Cmd::write_single_block(address), true)?; 843 self.cmd(Cmd::write_single_block(address), true)?;
815 844
816 let res = poll_fn(|cx| { 845 let res = poll_fn(|cx| {
@@ -922,7 +951,9 @@ impl SdmmcInner {
922 let request = dma.request(); 951 let request = dma.request();
923 dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, crate::dma::TransferOptions { 952 dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, crate::dma::TransferOptions {
924 pburst: crate::dma::Burst::Incr4, 953 pburst: crate::dma::Burst::Incr4,
954 mburst: crate::dma::Burst::Incr4,
925 flow_ctrl: crate::dma::FlowControl::Peripheral, 955 flow_ctrl: crate::dma::FlowControl::Peripheral,
956 fifo_threshold: Some(crate::dma::FifoThreshold::Full),
926 ..Default::default() 957 ..Default::default()
927 }); 958 });
928 } else if #[cfg(sdmmc_v2)] { 959 } else if #[cfg(sdmmc_v2)] {
@@ -970,7 +1001,9 @@ impl SdmmcInner {
970 let request = dma.request(); 1001 let request = dma.request();
971 dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, crate::dma::TransferOptions { 1002 dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, crate::dma::TransferOptions {
972 pburst: crate::dma::Burst::Incr4, 1003 pburst: crate::dma::Burst::Incr4,
1004 mburst: crate::dma::Burst::Incr4,
973 flow_ctrl: crate::dma::FlowControl::Peripheral, 1005 flow_ctrl: crate::dma::FlowControl::Peripheral,
1006 fifo_threshold: Some(crate::dma::FifoThreshold::Full),
974 ..Default::default() 1007 ..Default::default()
975 }); 1008 });
976 } else if #[cfg(sdmmc_v2)] { 1009 } else if #[cfg(sdmmc_v2)] {
@@ -982,6 +1015,11 @@ impl SdmmcInner {
982 regs.dctrl().modify(|w| { 1015 regs.dctrl().modify(|w| {
983 w.set_dblocksize(block_size); 1016 w.set_dblocksize(block_size);
984 w.set_dtdir(false); 1017 w.set_dtdir(false);
1018 #[cfg(sdmmc_v1)]
1019 {
1020 w.set_dmaen(true);
1021 w.set_dten(true);
1022 }
985 }); 1023 });
986 } 1024 }
987 1025
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
index 0edd8a61a..b57e955f6 100644
--- a/examples/stm32f4/src/bin/sdmmc.rs
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -4,11 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::sdmmc::Sdmmc; 7use embassy_stm32::sdmmc::{DataBlock, Sdmmc};
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::mhz;
9use embassy_stm32::{interrupt, Config}; 9use embassy_stm32::{interrupt, Config};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12/// This is a safeguard to not overwrite any data on the SD card.
13/// If you don't care about SD card contents, set this to `true` to test writes.
14const ALLOW_WRITES: bool = false;
15
12#[embassy_executor::main] 16#[embassy_executor::main]
13async fn main(_spawner: Spawner) -> ! { 17async fn main(_spawner: Spawner) -> ! {
14 let mut config = Config::default(); 18 let mut config = Config::default();
@@ -34,11 +38,42 @@ async fn main(_spawner: Spawner) -> ! {
34 // Should print 400kHz for initialization 38 // Should print 400kHz for initialization
35 info!("Configured clock: {}", sdmmc.clock().0); 39 info!("Configured clock: {}", sdmmc.clock().0);
36 40
37 unwrap!(sdmmc.init_card(mhz(25)).await); 41 unwrap!(sdmmc.init_card(mhz(24)).await);
38 42
39 let card = unwrap!(sdmmc.card()); 43 let card = unwrap!(sdmmc.card());
40 44
41 info!("Card: {:#?}", Debug2Format(card)); 45 info!("Card: {:#?}", Debug2Format(card));
46 info!("Clock: {}", sdmmc.clock());
47
48 // Arbitrary block index
49 let block_idx = 16;
50
51 // SDMMC uses `DataBlock` instead of `&[u8]` to ensure 4 byte alignment required by the hardware.
52 let mut block = DataBlock([0u8; 512]);
53
54 sdmmc.read_block(block_idx, &mut block).await.unwrap();
55 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
56
57 if !ALLOW_WRITES {
58 info!("Writing is disabled.");
59 loop {}
60 }
61
62 info!("Filling block with 0x55");
63 block.fill(0x55);
64 sdmmc.write_block(block_idx, &block).await.unwrap();
65 info!("Write done");
66
67 sdmmc.read_block(block_idx, &mut block).await.unwrap();
68 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
69
70 info!("Filling block with 0xAA");
71 block.fill(0xAA);
72 sdmmc.write_block(block_idx, &block).await.unwrap();
73 info!("Write done");
74
75 sdmmc.read_block(block_idx, &mut block).await.unwrap();
76 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
42 77
43 loop {} 78 loop {}
44} 79}