Skip to content

Commit 6edffd0

Browse files
dhylandsdpgeorge
authored andcommitted
stmhal: Add dma support for sdcard.
This started out using IgorLektorovEpam work in PR adafruit#1389 and reworked it.
1 parent b677f03 commit 6edffd0

1 file changed

Lines changed: 76 additions & 69 deletions

File tree

stmhal/sdcard.c

Lines changed: 76 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
// TODO make it work with DMA
28-
2927
#include STM32_HAL_H
3028

3129
#include "py/nlr.h"
@@ -34,6 +32,8 @@
3432
#include "pin.h"
3533
#include "genhdr/pins.h"
3634
#include "bufhelper.h"
35+
#include "dma.h"
36+
#include "irq.h"
3737

3838
#if MICROPY_HW_HAS_SDCARD
3939

@@ -64,8 +64,12 @@
6464

6565
#endif
6666

67-
67+
// TODO: I think that as an optimization, we can allocate these dynamically
68+
// if an sd card is detected. This will save approx 260 bytes of RAM
69+
// when no sdcard was being used.
6870
static SD_HandleTypeDef sd_handle;
71+
static DMA_HandleTypeDef sd_rx_dma, sd_tx_dma;
72+
static DMA_InitTypeDef sd_rx_dma_init, sd_tx_dma_init;
6973

7074
void sdcard_init(void) {
7175
GPIO_InitTypeDef GPIO_Init_Structure;
@@ -98,13 +102,45 @@ void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
98102
// enable SDIO clock
99103
__SDIO_CLK_ENABLE();
100104

101-
// GPIO have already been initialised by sdcard_init
105+
// NVIC configuration for SDIO interrupts
106+
HAL_NVIC_SetPriority(SDIO_IRQn, IRQ_PRI_SDIO, IRQ_SUBPRI_SDIO);
107+
HAL_NVIC_EnableIRQ(SDIO_IRQn);
108+
109+
// TODO: Since SDIO is fundamentally half-duplex, we really only need to
110+
// tie up one DMA channel. However, the HAL DMA API doesn't
111+
// seem to provide a convenient way to change the direction. I believe that
112+
// its as simple as changing the CR register and the Init.Direction field
113+
// and make DMA_SetConfig public.
114+
115+
// Configure DMA Rx parameters
116+
sd_rx_dma_init.PeriphInc = DMA_PINC_DISABLE;
117+
sd_rx_dma_init.MemInc = DMA_MINC_ENABLE;
118+
sd_rx_dma_init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
119+
sd_rx_dma_init.MemDataAlignment = DMA_MDATAALIGN_WORD;
120+
sd_rx_dma_init.Mode = DMA_PFCTRL;
121+
sd_rx_dma_init.Priority = DMA_PRIORITY_VERY_HIGH;
122+
sd_rx_dma_init.FIFOMode = DMA_FIFOMODE_ENABLE;
123+
sd_rx_dma_init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
124+
sd_rx_dma_init.MemBurst = DMA_MBURST_INC4;
125+
sd_rx_dma_init.PeriphBurst = DMA_PBURST_INC4;
126+
127+
// Configure DMA Tx parameters
128+
sd_tx_dma_init.PeriphInc = DMA_PINC_DISABLE;
129+
sd_tx_dma_init.MemInc = DMA_MINC_ENABLE;
130+
sd_tx_dma_init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
131+
sd_tx_dma_init.MemDataAlignment = DMA_MDATAALIGN_WORD;
132+
sd_tx_dma_init.Mode = DMA_PFCTRL;
133+
sd_tx_dma_init.Priority = DMA_PRIORITY_VERY_HIGH;
134+
sd_tx_dma_init.FIFOMode = DMA_FIFOMODE_ENABLE;
135+
sd_tx_dma_init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
136+
sd_tx_dma_init.MemBurst = DMA_MBURST_INC4;
137+
sd_tx_dma_init.PeriphBurst = DMA_PBURST_INC4;
102138

103-
// interrupts are not used at the moment
104-
// they are needed only for DMA transfer (I think...)
139+
// GPIO have already been initialised by sdcard_init
105140
}
106141

107142
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
143+
HAL_NVIC_DisableIRQ(SDIO_IRQn);
108144
__SDIO_CLK_DISABLE();
109145
}
110146

@@ -168,6 +204,10 @@ uint64_t sdcard_get_capacity_in_bytes(void) {
168204
return cardinfo.CardCapacity;
169205
}
170206

207+
void SDIO_IRQHandler(void) {
208+
HAL_SD_IRQHandler(&sd_handle);
209+
}
210+
171211
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
172212
// check that dest pointer is aligned on a 4-byte boundary
173213
if (((uint32_t)dest & 3) != 0) {
@@ -179,90 +219,57 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo
179219
return SD_ERROR;
180220
}
181221

182-
// We must disable IRQs because the SDIO peripheral has a small FIFO
183-
// buffer and we can't let it fill up in the middle of a read.
184-
// This will not be needed when SD uses DMA for transfer.
185-
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
186-
HAL_SD_ErrorTypedef err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks);
187-
MICROPY_END_ATOMIC_SECTION(atomic_state);
222+
HAL_SD_ErrorTypedef err = SD_OK;
188223

189-
return err;
190-
}
224+
if (query_irq() == IRQ_STATE_ENABLED) {
225+
dma_init(&sd_rx_dma, DMA_STREAM_SDIO_RX, &sd_rx_dma_init, DMA_CHANNEL_SDIO_RX, DMA_PERIPH_TO_MEMORY, &sd_handle);
226+
sd_handle.hdmarx = &sd_rx_dma;
191227

192-
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
193-
// check that src pointer is aligned on a 4-byte boundary
194-
if (((uint32_t)src & 3) != 0) {
195-
return SD_ERROR;
196-
}
228+
err = HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks);
229+
if (err == SD_OK) {
230+
// wait for DMA transfer to finish, with a large timeout
231+
err = HAL_SD_CheckReadOperation(&sd_handle, 100000000);
232+
}
197233

198-
// check that SD card is initialised
199-
if (sd_handle.Instance == NULL) {
200-
return SD_ERROR;
234+
dma_deinit(sd_handle.hdmarx);
235+
sd_handle.hdmarx = NULL;
236+
} else {
237+
err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks);
201238
}
202239

203-
// We must disable IRQs because the SDIO peripheral has a small FIFO
204-
// buffer and we can't let it drain to empty in the middle of a write.
205-
// This will not be needed when SD uses DMA for transfer.
206-
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
207-
HAL_SD_ErrorTypedef err = HAL_SD_WriteBlocks_BlockNumber(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
208-
MICROPY_END_ATOMIC_SECTION(atomic_state);
209-
210240
return err;
211241
}
212242

213-
#if 0
214-
DMA not implemented
215-
bool sdcard_read_blocks_dma(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
216-
// check that dest pointer is aligned on a 4-byte boundary
217-
if (((uint32_t)dest & 3) != 0) {
218-
return false;
219-
}
220-
221-
// check that SD card is initialised
222-
if (sd_handle.Instance == NULL) {
223-
return false;
224-
}
225-
226-
// do the read
227-
if (HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE) != SD_OK) {
228-
return false;
229-
}
230-
231-
// wait for DMA transfer to finish, with a large timeout
232-
if (HAL_SD_CheckReadOperation(&sd_handle, 100000000) != SD_OK) {
233-
return false;
234-
}
235-
236-
return true;
237-
}
238-
239-
bool sdcard_write_blocks_dma(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
243+
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
240244
// check that src pointer is aligned on a 4-byte boundary
241245
if (((uint32_t)src & 3) != 0) {
242-
return false;
246+
return SD_ERROR;
243247
}
244248

245249
// check that SD card is initialised
246250
if (sd_handle.Instance == NULL) {
247-
return false;
251+
return SD_ERROR;
248252
}
249253

250-
SD_Error status;
254+
HAL_SD_ErrorTypedef err = SD_OK;
251255

252-
status = HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
253-
if (status != SD_OK) {
254-
return false;
255-
}
256+
if (query_irq() == IRQ_STATE_ENABLED) {
257+
dma_init(&sd_tx_dma, DMA_STREAM_SDIO_TX, &sd_tx_dma_init, DMA_CHANNEL_SDIO_TX, DMA_MEMORY_TO_PERIPH, &sd_handle);
258+
sd_handle.hdmatx = &sd_tx_dma;
256259

257-
// wait for DMA transfer to finish, with a large timeout
258-
status = HAL_SD_CheckWriteOperation(&sd_handle, 100000000);
259-
if (status != SD_OK) {
260-
return false;
260+
err = HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
261+
if (err == SD_OK) {
262+
// wait for DMA transfer to finish, with a large timeout
263+
err = HAL_SD_CheckWriteOperation(&sd_handle, 100000000);
264+
}
265+
dma_deinit(sd_handle.hdmatx);
266+
sd_handle.hdmatx = NULL;
267+
} else {
268+
err = HAL_SD_WriteBlocks_BlockNumber(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
261269
}
262270

263-
return true;
271+
return err;
264272
}
265-
#endif
266273

267274
/******************************************************************************/
268275
// Micro Python bindings

0 commit comments

Comments
 (0)