Skip to content

Commit 1f68155

Browse files
authored
Merge pull request #43 from NanaHigh/nanahigh/sdio
feat(sdio): add write block operations to sdh
2 parents 68b4827 + 7919f0e commit 1f68155

File tree

7 files changed

+278
-68
lines changed

7 files changed

+278
-68
lines changed

bouffalo-hal/src/sdio.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod nodma_sdh;
66
mod ops;
77
mod pad;
88
mod register;
9+
pub mod sdcard;
910
pub use config::*;
1011
pub use dma_sdh::*;
1112
pub use pad::*;

bouffalo-hal/src/sdio/dma_sdh.rs

Lines changed: 93 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::glb;
99
use core::ops::Deref;
1010
use core::sync::atomic::{Ordering, fence};
1111
use embedded_io::Write;
12-
use embedded_sdmmc::{Block, BlockDevice, BlockIdx};
12+
use embedded_sdmmc::Block;
1313

1414
/// Managed Secure Digital Host Controller peripheral.
1515
pub struct Sdh<SDH, PADS, CH> {
@@ -75,8 +75,11 @@ impl<'a, SDH: Deref<Target = RegisterBlock>, PADS, CH: Deref<Target = UntypedCha
7575
// SDH_TX_INT_CLK_SEL.
7676
sdh.tx_configuration.modify(|val| val.set_tx_int_clk_sel(1));
7777
// SDH enable interrupt.
78-
sdh.normal_interrupt_status_enable
79-
.modify(|val| val.enable_buffer_read_ready());
78+
sdh.normal_interrupt_status_enable.modify(|val| {
79+
val.enable_buffer_read_ready()
80+
.enable_buffer_write_ready()
81+
.enable_transfer_complete()
82+
});
8083
// SDH_Set_Timeout.
8184
sdh.timeout_control.modify(|val| val.set_timeout_val(0x0e));
8285
// SDH_Powon.
@@ -99,7 +102,7 @@ impl<'a, SDH: Deref<Target = RegisterBlock>, PADS, CH: Deref<Target = UntypedCha
99102

100103
/// Read block from sdcard using system dma controller.
101104
#[inline]
102-
fn read_block_sys_dma(&self, block: &mut Block, block_idx: u32) {
105+
pub(crate) fn read_block_sys_dma(&self, block: &mut Block, block_idx: u32) {
103106
unsafe {
104107
// SDH_SD_TRANSFER_MODE.
105108
self.sdh.transfer_mode.modify(|val| {
@@ -160,38 +163,101 @@ impl<'a, SDH: Deref<Target = RegisterBlock>, PADS, CH: Deref<Target = UntypedCha
160163
}
161164
}
162165

163-
/// Release the SDH instance and return the pads and configs.
166+
/// Write block from sdcard using system dma controller.
164167
#[inline]
165-
pub fn free(self) -> (SDH, PADS, CH) {
166-
(self.sdh, self.pads, self.dma_channel)
167-
}
168-
}
168+
pub(crate) fn write_block_sys_dma(&self, block: &Block, block_idx: u32) {
169+
unsafe {
170+
// SDH_SD_TRANSFER_MODE.
171+
self.sdh.transfer_mode.modify(|val| {
172+
val.set_data_transfer_mode(DataTransferMode::MOSI) // SDH_TO_HOST_DIR.
173+
.set_auto_cmd_mode(AutoCMDMode::None) // SDH_AUTO_CMD_EN.
174+
});
169175

170-
impl<'a, SDH: Deref<Target = RegisterBlock>, PADS, CH: Deref<Target = UntypedChannel<'a>>>
171-
BlockDevice for Sdh<SDH, PADS, CH>
172-
{
173-
type Error = core::convert::Infallible;
176+
// Block_size.
177+
self.sdh
178+
.block_size
179+
.modify(|val| val.set_transfer_block(512));
174180

175-
#[inline]
176-
fn read(
177-
&self,
178-
blocks: &mut [Block],
179-
start_block_idx: BlockIdx,
180-
_reason: &str,
181-
) -> Result<(), Self::Error> {
182-
for (i, block) in blocks.iter_mut().enumerate() {
183-
self.read_block_sys_dma(block, start_block_idx.0 + i as u32);
181+
// Block_count.
182+
self.sdh.block_count.modify(|val| val.set_blocks_count(1));
183+
184+
// SDH_ClearIntStatus(SDH_INT_BUFFER_WRITE_READY).
185+
self.sdh
186+
.normal_interrupt_status
187+
.modify(|val| val.clear_buffer_write_ready());
188+
}
189+
send_command(&self.sdh, SdhResp::R1, CmdType::Normal, 24, block_idx, true);
190+
191+
while !self
192+
.sdh
193+
.normal_interrupt_status
194+
.read()
195+
.is_buffer_write_ready()
196+
{
197+
// SDH_INT_BUFFER_WRITE_READY.
198+
// Wait for buffer write ready.
199+
core::hint::spin_loop()
200+
}
201+
202+
for j in 0..Block::LEN / 4 {
203+
let tx_lli_pool = &mut [LliPool::new(); 1];
204+
let val = [
205+
block[j * 4 + 0],
206+
block[j * 4 + 1],
207+
block[j * 4 + 2],
208+
block[j * 4 + 3],
209+
];
210+
let tx_transfer = &mut [LliTransfer {
211+
src_addr: val.as_ptr() as u32,
212+
dst_addr: 0x20060020,
213+
nbytes: 4,
214+
}];
215+
216+
self.dma_channel.lli_reload(tx_lli_pool, 1, tx_transfer, 1);
217+
self.dma_channel.start();
218+
219+
while self.dma_channel.is_busy() {
220+
core::hint::spin_loop();
221+
}
222+
223+
self.dma_channel.stop();
224+
225+
// FIXME modify to a proper fence
226+
fence(Ordering::SeqCst);
227+
228+
unsafe {
229+
self.sdh
230+
.normal_interrupt_status
231+
.modify(|val| val.clear_buffer_write_ready());
232+
}
233+
}
234+
235+
// Wait for transfer completed.
236+
while !self
237+
.sdh
238+
.normal_interrupt_status
239+
.read()
240+
.is_transfer_completed()
241+
{
242+
core::hint::spin_loop();
243+
}
244+
245+
unsafe {
246+
self.sdh
247+
.normal_interrupt_status
248+
.modify(|val| val.clear_transfer_completed());
184249
}
185-
Ok(())
186250
}
187251

252+
/// Read block from sdcard using system dma controller.
188253
#[inline]
189-
fn write(&self, _blocks: &[Block], _start_block_idx: BlockIdx) -> Result<(), Self::Error> {
190-
todo!();
254+
pub(crate) fn num_blocks(&self) -> embedded_sdmmc::BlockCount {
255+
embedded_sdmmc::BlockCount(self.block_count)
191256
}
192257

258+
/// Release the SDH instance and return the pads and configs.
193259
#[inline]
194-
fn num_blocks(&self) -> Result<embedded_sdmmc::BlockCount, Self::Error> {
195-
Ok(embedded_sdmmc::BlockCount(self.block_count))
260+
pub fn free(self) -> (SDH, PADS, CH) {
261+
(self.sdh, self.pads, self.dma_channel)
196262
}
197263
}

bouffalo-hal/src/sdio/nodma_sdh.rs

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use super::config::Config;
2-
use super::ops::{card_init, read_block};
2+
use super::ops::{card_init, read_block, write_block};
33
use super::pad::Pads;
44
use super::register::{BusVoltage, ClkGenMode, DmaMode, RegisterBlock};
55
use crate::glb;
66
use core::ops::Deref;
77
use embedded_io::Write;
8-
use embedded_sdmmc::{Block, BlockDevice, BlockIdx};
8+
use embedded_sdmmc::Block;
99

1010
/// Managed Secure Digital Host Controller peripheral.
1111
pub struct Sdh<SDH, PADS> {
@@ -67,8 +67,11 @@ impl<SDH: Deref<Target = RegisterBlock>, PADS> Sdh<SDH, PADS> {
6767
// SDH_TX_INT_CLK_SEL.
6868
sdh.tx_configuration.modify(|val| val.set_tx_int_clk_sel(1));
6969
// SDH enable interrupt.
70-
sdh.normal_interrupt_status_enable
71-
.modify(|val| val.enable_buffer_read_ready());
70+
sdh.normal_interrupt_status_enable.modify(|val| {
71+
val.enable_buffer_read_ready()
72+
.enable_buffer_write_ready()
73+
.enable_transfer_complete()
74+
});
7275
// SDH_Set_Timeout.
7376
sdh.timeout_control.modify(|val| val.set_timeout_val(0x0e));
7477
// SDH_Powon.
@@ -88,36 +91,27 @@ impl<SDH: Deref<Target = RegisterBlock>, PADS> Sdh<SDH, PADS> {
8891
self.block_count = card_init(&self.sdh, w, debug)
8992
}
9093

91-
/// Release the SDH instance and return the pads and configs.
94+
/// Read a block from the SDH peripheral.
9295
#[inline]
93-
pub fn free(self) -> (SDH, PADS) {
94-
(self.sdh, self.pads)
96+
pub(crate) fn read_block(&self, block: &mut Block, block_idx: u32) {
97+
read_block(&self.sdh, block, block_idx);
9598
}
96-
}
97-
98-
impl<SDH: Deref<Target = RegisterBlock>, PADS> BlockDevice for Sdh<SDH, PADS> {
99-
type Error = core::convert::Infallible;
10099

100+
/// Write a block to the SDH peripheral.
101101
#[inline]
102-
fn read(
103-
&self,
104-
blocks: &mut [Block],
105-
start_block_idx: BlockIdx,
106-
_reason: &str,
107-
) -> Result<(), Self::Error> {
108-
for (i, block) in blocks.iter_mut().enumerate() {
109-
read_block(&self.sdh, block, start_block_idx.0 + i as u32);
110-
}
111-
Ok(())
102+
pub(crate) fn write_block(&self, block: &Block, block_idx: u32) {
103+
write_block(&self.sdh, block, block_idx);
112104
}
113105

106+
/// Read the block count from the SDH peripheral.
114107
#[inline]
115-
fn write(&self, _blocks: &[Block], _start_block_idx: BlockIdx) -> Result<(), Self::Error> {
116-
todo!();
108+
pub(crate) fn num_blocks(&self) -> embedded_sdmmc::BlockCount {
109+
embedded_sdmmc::BlockCount(self.block_count)
117110
}
118111

112+
/// Release the SDH instance and return the pads and configs.
119113
#[inline]
120-
fn num_blocks(&self) -> Result<embedded_sdmmc::BlockCount, Self::Error> {
121-
Ok(embedded_sdmmc::BlockCount(self.block_count))
114+
pub fn free(self) -> (SDH, PADS) {
115+
(self.sdh, self.pads)
122116
}
123117
}

bouffalo-hal/src/sdio/ops.rs

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,60 @@ pub(crate) fn read_block(sdh: &RegisterBlock, block: &mut Block, block_idx: u32)
7777
}
7878
}
7979

80+
#[inline]
81+
pub(crate) fn write_block(sdh: &RegisterBlock, block: &Block, block_idx: u32) {
82+
unsafe {
83+
// SDH_SD_TRANSFER_MODE.
84+
sdh.transfer_mode.modify(|val| {
85+
val.set_data_transfer_mode(DataTransferMode::MOSI) // SDH_TO_HOST_DIR.
86+
.set_auto_cmd_mode(AutoCMDMode::None) // SDH_AUTO_CMD_EN.
87+
});
88+
89+
// Block_size.
90+
sdh.block_size.modify(|val| val.set_transfer_block(512));
91+
92+
// Block_count.
93+
sdh.block_count.modify(|val| val.set_blocks_count(1));
94+
95+
// SDH_ClearIntStatus(SDH_INT_BUFFER_WRITE_READY).
96+
sdh.normal_interrupt_status
97+
.modify(|val| val.clear_buffer_write_ready());
98+
}
99+
send_command(sdh, SdhResp::R1, CmdType::Normal, 24, block_idx, true);
100+
101+
while !sdh.normal_interrupt_status.read().is_buffer_write_ready() {
102+
// SDH_INT_BUFFER_WRITE_READY.
103+
// Wait for buffer write ready.
104+
core::hint::spin_loop()
105+
}
106+
107+
for j in 0..Block::LEN / 4 {
108+
let data_val = u32::from_le_bytes([
109+
block[j * 4 + 0],
110+
block[j * 4 + 1],
111+
block[j * 4 + 2],
112+
block[j * 4 + 3],
113+
]);
114+
115+
unsafe {
116+
sdh.buffer_data_port
117+
.modify(|val| val.set_buffer_data(data_val));
118+
sdh.normal_interrupt_status
119+
.modify(|val| val.clear_buffer_write_ready());
120+
}
121+
}
122+
123+
// Wait for transfer completed.
124+
while !sdh.normal_interrupt_status.read().is_transfer_completed() {
125+
core::hint::spin_loop();
126+
}
127+
128+
unsafe {
129+
sdh.normal_interrupt_status
130+
.modify(|val| val.clear_transfer_completed());
131+
}
132+
}
133+
80134
/// Send command to sdcard.
81135
#[inline]
82136
pub(crate) fn send_command(
@@ -210,19 +264,19 @@ pub(crate) fn card_init<W: Write>(sdh: &RegisterBlock, w: &mut W, debug: bool) -
210264
send_command(sdh, SdhResp::R1, CmdType::Normal, 6, 0x0, false);
211265
sleep_ms(100);
212266

213-
let kb_size = (block_count as f64) * (block_size as f64) / 1024.0;
214-
let mb_size = kb_size / 1024.0;
215-
let gb_size = mb_size / 1024.0;
267+
if debug {
268+
let kb_size = (block_count as f64) * (block_size as f64) / 1024.0;
269+
let mb_size = kb_size / 1024.0;
270+
let gb_size = mb_size / 1024.0;
216271

217-
let cap = sdh.capabilities.read();
218-
let version = sdh.host_controller_version.read();
272+
let cap = sdh.capabilities.read();
273+
let version = sdh.host_controller_version.read();
219274

220-
writeln!(*w, "SpecifiicVersion: {:?}", version.specific_version()).ok();
221-
writeln!(*w, "SlotType: {:?}", cap.slot_type()).ok();
222-
writeln!(*w, "SDMA support: {}", cap.is_sdma_supported()).ok();
223-
writeln!(*w, "ADMA2 support: {}", cap.is_adma2_supported()).ok();
275+
writeln!(*w, "SpecifiicVersion: {:?}", version.specific_version()).ok();
276+
writeln!(*w, "SlotType: {:?}", cap.slot_type()).ok();
277+
writeln!(*w, "SDMA support: {}", cap.is_sdma_supported()).ok();
278+
writeln!(*w, "ADMA2 support: {}", cap.is_adma2_supported()).ok();
224279

225-
if debug {
226280
if kb_size < 1024.0 {
227281
writeln!(*w, "sdcard init done, size: {:.2} KB", kb_size).ok();
228282
} else if mb_size < 1024.0 {

0 commit comments

Comments
 (0)