rust: sdcard read/write sectors using DMA

This commit is contained in:
Wladimir J. van der Laan 2019-08-12 17:04:07 +00:00
parent ed91b43e2a
commit 0dcbeda646
2 changed files with 68 additions and 3 deletions

View File

@ -1,5 +1,4 @@
//! SD card slot access (in SPI mode) on Maix Go //! SD card slot access (in SPI mode) on Maix Go
// TODO: actually use the DMA channel that is claimed…
use core::convert::TryInto; use core::convert::TryInto;
use crate::soc::dmac::{dma_channel, DMAC}; use crate::soc::dmac::{dma_channel, DMAC};
@ -189,6 +188,22 @@ impl<'a, X: SPI> SDCard<'a, X> {
self.spi.send_data(self.spi_cs, data); self.spi.send_data(self.spi_cs, data);
} }
fn write_data_dma(&self, data: &[u32]) {
self.spi.configure(
work_mode::MODE0,
frame_format::STANDARD,
8, /* data bits */
0, /* endian */
0, /*instruction length*/
0, /*address length*/
0, /*wait cycles*/
aitm::STANDARD,
tmod::TRANS,
);
self.spi
.send_data_dma(self.dmac, self.channel, self.spi_cs, data);
}
fn read_data(&self, data: &mut [u8]) { fn read_data(&self, data: &mut [u8]) {
self.spi.configure( self.spi.configure(
work_mode::MODE0, work_mode::MODE0,
@ -204,6 +219,22 @@ impl<'a, X: SPI> SDCard<'a, X> {
self.spi.recv_data(self.spi_cs, data); self.spi.recv_data(self.spi_cs, data);
} }
fn read_data_dma(&self, data: &mut [u32]) {
self.spi.configure(
work_mode::MODE0,
frame_format::STANDARD,
8, /* data bits */
0, /* endian */
0, /*instruction length*/
0, /*address length*/
0, /*wait cycles*/
aitm::STANDARD,
tmod::RECV,
);
self.spi
.recv_data_dma(self.dmac, self.channel, self.spi_cs, data);
}
/* /*
* Send 5 bytes command to the SD card. * Send 5 bytes command to the SD card.
* @param cmd: The user expected command to send to SD card. * @param cmd: The user expected command to send to SD card.
@ -554,13 +585,18 @@ impl<'a, X: SPI> SDCard<'a, X> {
return Err(()); return Err(());
} }
let mut error = false; let mut error = false;
let mut dma_chunk = [0u32; SEC_LEN];
for chunk in data_buf.chunks_mut(SEC_LEN) { for chunk in data_buf.chunks_mut(SEC_LEN) {
if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ { if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ {
error = true; error = true;
break; break;
} }
/* Read the SD block data : read NumByteToRead data */ /* Read the SD block data : read NumByteToRead data */
self.read_data(chunk); self.read_data_dma(&mut dma_chunk);
/* Place the data received as u32 units from DMA into the u8 target buffer */
for (a, b) in chunk.iter_mut().zip(dma_chunk.iter()) {
*a = (b & 0xff) as u8;
}
/* Get CRC bytes (not really needed by us, but required by SD) */ /* Get CRC bytes (not really needed by us, but required by SD) */
let mut frame = [0u8; 2]; let mut frame = [0u8; 2];
self.read_data(&mut frame); self.read_data(&mut frame);
@ -610,11 +646,15 @@ impl<'a, X: SPI> SDCard<'a, X> {
self.end_cmd(); self.end_cmd();
return Err(()); return Err(());
} }
let mut dma_chunk = [0u32; SEC_LEN];
for chunk in data_buf.chunks(SEC_LEN) { for chunk in data_buf.chunks(SEC_LEN) {
/* Send the data token to signify the start of the data */ /* Send the data token to signify the start of the data */
self.write_data(&frame); self.write_data(&frame);
/* Write the block data to SD : write count data by block */ /* Write the block data to SD : write count data by block */
self.write_data(chunk); for (a, &b) in dma_chunk.iter_mut().zip(chunk.iter()) {
*a = b.into();
}
self.write_data_dma(&mut dma_chunk);
/* Put dummy CRC bytes */ /* Put dummy CRC bytes */
self.write_data(&[0xff, 0xff]); self.write_data(&[0xff, 0xff]);
/* Read data response */ /* Read data response */

View File

@ -75,6 +75,7 @@ pub trait SPI {
); );
fn set_clk_rate(&self, spi_clk: u32) -> u32; fn set_clk_rate(&self, spi_clk: u32) -> u32;
fn recv_data<X: TruncU32>(&self, chip_select: u32, rx: &mut [X]); fn recv_data<X: TruncU32>(&self, chip_select: u32, rx: &mut [X]);
fn recv_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, rx: &mut [u32]);
fn send_data<X: Into<u32> + Copy>(&self, chip_select: u32, tx: &[X]); fn send_data<X: Into<u32> + Copy>(&self, chip_select: u32, tx: &[X]);
fn send_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, tx: &[u32]); fn send_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, tx: &[u32]);
fn fill_data(&self, chip_select: u32, value: u32, tx_len: usize); fn fill_data(&self, chip_select: u32, value: u32, tx_len: usize);
@ -193,6 +194,30 @@ impl<IF: SPI01> SPI for SPIImpl<IF> {
} }
} }
/// Receive 32-bit data using DMA.
// make sure to set tmod to tmod::RECV
fn recv_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, rx: &mut [u32]) {
if rx.len() == 0 {
return;
}
unsafe {
self.spi.ctrlr1.write(|w| w.bits((rx.len() - 1).try_into().unwrap()));
self.spi.ssienr.write(|w| w.bits(0x01));
self.spi.dmacr.write(|w| w.bits(0x3)); /*enable dma receive */
sysctl::dma_select(channel_num, IF::DMA_RX);
dmac.set_single_mode(channel_num, self.spi.dr.as_ptr() as u64, rx.as_ptr() as u64,
address_increment::NOCHANGE, address_increment::INCREMENT,
burst_length::LENGTH_1, transfer_width::WIDTH_32, rx.len() as u32);
self.spi.dr[0].write(|w| w.bits(0xffffffff));
self.spi.ser.write(|w| w.bits(1 << chip_select));
dmac.wait_done(channel_num);
self.spi.ser.write(|w| w.bits(0x00));
self.spi.ssienr.write(|w| w.bits(0x00));
}
}
/// Send arbitrary data /// Send arbitrary data
fn send_data<X: Into<u32> + Copy>(&self, chip_select: u32, tx: &[X]) { fn send_data<X: Into<u32> + Copy>(&self, chip_select: u32, tx: &[X]) {
unsafe { unsafe {