Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DMA support for SDcard #1389

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions stmhal/boards/PYBV3/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#if MICROPY_HW_HAS_SDCARD
#define MICROPY_HW_HAS_SDCARD_DMA (1)
#endif
#define MICROPY_HW_HAS_MMA7660 (1)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
Expand Down
8 changes: 8 additions & 0 deletions stmhal/diskio.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ DRESULT disk_read (

#if MICROPY_HW_HAS_SDCARD
case PD_SDCARD:
#if MICROPY_HW_HAS_SDCARD_DMA
if (sdcard_read_blocks_dma(buff, sector, count) != 0) {
#else
if (sdcard_read_blocks(buff, sector, count) != 0) {
#endif
return RES_ERROR;
}
return RES_OK;
Expand Down Expand Up @@ -183,7 +187,11 @@ DRESULT disk_write (

#if MICROPY_HW_HAS_SDCARD
case PD_SDCARD:
#if MICROPY_HW_HAS_SDCARD_DMA
if (sdcard_write_blocks_dma(buff, sector, count) != 0) {
#else
if (sdcard_write_blocks(buff, sector, count) != 0) {
#endif
return RES_ERROR;
}
return RES_OK;
Expand Down
3 changes: 0 additions & 3 deletions stmhal/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,6 @@ void dma_init(DMA_HandleTypeDef *dma, DMA_Stream_TypeDef *dma_stream, const DMA_
int dma_id = get_dma_id(dma_stream);
//printf("dma_init(%p, %p(%d), 0x%x, 0x%x, %p)\n", dma, dma_stream, dma_id, (uint)dma_channel, (uint)direction, data);

// TODO possibly don't need to clear the entire structure
memset(dma, 0, sizeof(*dma));

// set global pointer for IRQ handler
dma_handle[dma_id] = dma;

Expand Down
157 changes: 97 additions & 60 deletions stmhal/sdcard.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
* THE SOFTWARE.
*/

// TODO make it work with DMA

#include <stm32f4xx_hal.h>

#include "py/nlr.h"
Expand All @@ -34,6 +32,7 @@
#include "pin.h"
#include "genhdr/pins.h"
#include "bufhelper.h"
#include "dma.h"

#if MICROPY_HW_HAS_SDCARD

Expand Down Expand Up @@ -69,11 +68,45 @@ void sdcard_init(void) {
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
// enable SDIO clock
__SDIO_CLK_ENABLE();
#if MICROPY_HW_HAS_SDCARD_DMA
static DMA_HandleTypeDef rx_dma, tx_dma;

// NVIC configuration for SDIO interrupts
HAL_NVIC_SetPriority(SDIO_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SDIO_IRQn);

// Configure DMA Rx parameters
rx_dma.Init.PeriphInc = DMA_PINC_DISABLE;
rx_dma.Init.MemInc = DMA_MINC_ENABLE;
rx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
rx_dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
rx_dma.Init.Mode = DMA_PFCTRL;
rx_dma.Init.Priority = DMA_PRIORITY_VERY_HIGH;
rx_dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
rx_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
rx_dma.Init.MemBurst = DMA_MBURST_INC4;
rx_dma.Init.PeriphBurst = DMA_PBURST_INC4;

dma_init(&rx_dma, DMA2_Stream3, &rx_dma.Init, DMA_CHANNEL_4, DMA_PERIPH_TO_MEMORY, &sd_handle);
sd_handle.hdmarx = &rx_dma;

// Configure DMA Tx parameters
tx_dma.Init.PeriphInc = DMA_PINC_DISABLE;
tx_dma.Init.MemInc = DMA_MINC_ENABLE;
tx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
tx_dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
tx_dma.Init.Mode = DMA_PFCTRL;
tx_dma.Init.Priority = DMA_PRIORITY_VERY_HIGH;
tx_dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
tx_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
tx_dma.Init.MemBurst = DMA_MBURST_INC4;
tx_dma.Init.PeriphBurst = DMA_PBURST_INC4;

dma_init(&tx_dma, DMA2_Stream6, &tx_dma.Init, DMA_CHANNEL_4, DMA_MEMORY_TO_PERIPH, &sd_handle);
sd_handle.hdmatx = &tx_dma;
#endif

// GPIO have already been initialised by sdcard_init

// interrupts are not used at the moment
// they are needed only for DMA transfer (I think...)
}

void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
Expand Down Expand Up @@ -140,99 +173,98 @@ uint64_t sdcard_get_capacity_in_bytes(void) {
return cardinfo.CardCapacity;
}

mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
#if MICROPY_HW_HAS_SDCARD_DMA
void sdcard_irq_handler(void) {
HAL_SD_IRQHandler(&sd_handle);
}

bool sdcard_read_blocks_dma(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
// check that dest pointer is aligned on a 4-byte boundary
if (((uint32_t)dest & 3) != 0) {
return SD_ERROR;
return true;
}

// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return SD_ERROR;
return true;
}

// We must disable IRQs because the SDIO peripheral has a small FIFO
// buffer and we can't let it fill up in the middle of a read.
// This will not be needed when SD uses DMA for transfer.
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
HAL_SD_ErrorTypedef err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks);
MICROPY_END_ATOMIC_SECTION(atomic_state);
// do the read
if (HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks) != SD_OK) {
return true;
}

return err;
// wait for DMA transfer to finish, with a large timeout
if (HAL_SD_CheckReadOperation(&sd_handle, 100000000) != SD_OK) {
return true;
}

return false;
}

mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
bool sdcard_write_blocks_dma(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
// check that src pointer is aligned on a 4-byte boundary
if (((uint32_t)src & 3) != 0) {
return SD_ERROR;
return true;
}

// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return SD_ERROR;
return true;
}

// We must disable IRQs because the SDIO peripheral has a small FIFO
// buffer and we can't let it drain to empty in the middle of a write.
// This will not be needed when SD uses DMA for transfer.
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
HAL_SD_ErrorTypedef err = HAL_SD_WriteBlocks_BlockNumber(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
MICROPY_END_ATOMIC_SECTION(atomic_state);
if (HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks) != SD_OK) {
return true;
}

return err;
}
// wait for DMA transfer to finish, with a large timeout
if (HAL_SD_CheckWriteOperation(&sd_handle, 100000000) != SD_OK) {
return true;
}

#if 0
DMA not implemented
bool sdcard_read_blocks_dma(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
return false;
}
#else
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
// check that dest pointer is aligned on a 4-byte boundary
if (((uint32_t)dest & 3) != 0) {
return false;
return SD_ERROR;
}

// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return false;
}

// do the read
if (HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE) != SD_OK) {
return false;
return SD_ERROR;
}

// wait for DMA transfer to finish, with a large timeout
if (HAL_SD_CheckReadOperation(&sd_handle, 100000000) != SD_OK) {
return false;
}
// We must disable IRQs because the SDIO peripheral has a small FIFO
// buffer and we can't let it fill up in the middle of a read.
// This will not be needed when SD uses DMA for transfer.
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
HAL_SD_ErrorTypedef err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks);
MICROPY_END_ATOMIC_SECTION(atomic_state);

return true;
return err;
}

bool sdcard_write_blocks_dma(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
// check that src pointer is aligned on a 4-byte boundary
if (((uint32_t)src & 3) != 0) {
return false;
return SD_ERROR;
}

// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return false;
}

SD_Error status;

status = HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
if (status != SD_OK) {
return false;
return SD_ERROR;
}

// wait for DMA transfer to finish, with a large timeout
status = HAL_SD_CheckWriteOperation(&sd_handle, 100000000);
if (status != SD_OK) {
return false;
}
// We must disable IRQs because the SDIO peripheral has a small FIFO
// buffer and we can't let it drain to empty in the middle of a write.
// This will not be needed when SD uses DMA for transfer.
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
HAL_SD_ErrorTypedef err = HAL_SD_WriteBlocks_BlockNumber(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
MICROPY_END_ATOMIC_SECTION(atomic_state);

return true;
return err;
}
#endif

Expand Down Expand Up @@ -278,8 +310,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_info_obj, sd_info);

STATIC mp_obj_t sd_read(mp_obj_t self, mp_obj_t block_num) {
uint8_t *dest = m_new(uint8_t, SDCARD_BLOCK_SIZE);
#if MICROPY_HW_HAS_SDCARD_DMA
bool ret = sdcard_read_blocks_dma(dest, mp_obj_get_int(block_num), 1);
#else
mp_uint_t ret = sdcard_read_blocks(dest, mp_obj_get_int(block_num), 1);

#endif
if (ret != 0) {
m_del(uint8_t, dest, SDCARD_BLOCK_SIZE);
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_read_blocks failed [%u]", ret));
Expand All @@ -295,9 +330,11 @@ STATIC mp_obj_t sd_write(mp_obj_t self, mp_obj_t block_num, mp_obj_t data) {
if (bufinfo.len % SDCARD_BLOCK_SIZE != 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "writes must be a multiple of %d bytes", SDCARD_BLOCK_SIZE));
}

#if MICROPY_HW_HAS_SDCARD_DMA
bool ret = sdcard_write_blocks_dma(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE);
#else
mp_uint_t ret = sdcard_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE);

#endif
if (ret != 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_write_blocks failed [%u]", ret));
}
Expand Down
6 changes: 6 additions & 0 deletions stmhal/sdcard.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,10 @@ uint64_t sdcard_get_capacity_in_bytes(void);
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);

#if MICROPY_HW_HAS_SDCARD_DMA
void sdcard_irq_handler(void);
bool sdcard_read_blocks_dma(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
bool sdcard_write_blocks_dma(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
#endif

extern const struct _mp_obj_base_t pyb_sdcard_obj;
7 changes: 7 additions & 0 deletions stmhal/stm32f4xx_it.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include "uart.h"
#include "storage.h"
#include "can.h"
#include "sdcard.h"

extern void __fatal_error(const char*);
extern PCD_HandleTypeDef pcd_handle;
Expand Down Expand Up @@ -438,3 +439,9 @@ void CAN2_RX1_IRQHandler(void) {
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1);
}
#endif // MICROPY_HW_ENABLE_CAN

#if MICROPY_HW_HAS_SDCARD_DMA
void SDIO_IRQHandler(void) {
sdcard_irq_handler();
}
#endif // MICROPY_HW_HAS_SDCARD_DMA
8 changes: 8 additions & 0 deletions stmhal/usbd_msc_storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,11 @@ int8_t SDCARD_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) {
* @retval Status
*/
int8_t SDCARD_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
#if MICROPY_HW_HAS_SDCARD_DMA
if (sdcard_read_blocks_dma(buf, blk_addr, blk_len) != 0) {
#else
if (sdcard_read_blocks(buf, blk_addr, blk_len) != 0) {
#endif
return -1;
}
return 0;
Expand All @@ -316,7 +320,11 @@ int8_t SDCARD_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_
* @retval Status
*/
int8_t SDCARD_STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
#if MICROPY_HW_HAS_SDCARD_DMA
if (sdcard_write_blocks_dma(buf, blk_addr, blk_len) != 0) {
#else
if (sdcard_write_blocks(buf, blk_addr, blk_len) != 0) {
#endif
return -1;
}
return 0;
Expand Down