2424 * THE SOFTWARE.
2525 */
2626
27- // TODO make it work with DMA
28-
2927#include STM32_HAL_H
3028
3129#include "py/nlr.h"
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
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.
6870static 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
7074void 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
107142void 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+
171211mp_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