mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Use DMA for SDIO transfers
This commit is contained in:
parent
4acaafafa0
commit
9230f0d53e
@ -8,6 +8,7 @@
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stm32f4xx_hal.h>
|
||||
#include <core_cmInstr.h>
|
||||
|
||||
#include "mp.h"
|
||||
#include "mdefs.h"
|
||||
@ -17,8 +18,54 @@
|
||||
#include "sdcard.h"
|
||||
#include "omv_boardconfig.h"
|
||||
|
||||
#define SDIO_TIMEOUT (100) /* in ms */
|
||||
static SD_HandleTypeDef SDHandle;
|
||||
#define SDIO_TIMEOUT (0xFFFFFFFF) // Delay counter
|
||||
#define SDIO_TXRX_STREAM DMA2_Stream3
|
||||
#define SDIO_TXRX_CHANNEL DMA_CHANNEL_4
|
||||
|
||||
#define UNALIGNED_BUFFER(p) ((uint32_t)p & 3)
|
||||
#define CCM_BUFFER(p) (!(((uint32_t) p) & (1u<<29)))
|
||||
|
||||
SD_HandleTypeDef SDHandle;
|
||||
static DMA_HandleTypeDef DMAHandle;
|
||||
|
||||
static void dma_init(DMA_Stream_TypeDef *dma_stream, uint32_t dma_channel, uint32_t direction)
|
||||
{
|
||||
DMAHandle.Instance = dma_stream;
|
||||
DMAHandle.Init.Channel = dma_channel;
|
||||
DMAHandle.Init.Direction = direction;
|
||||
DMAHandle.Init.MemInc = DMA_MINC_ENABLE;
|
||||
DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||||
DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||||
DMAHandle.Init.Mode = DMA_PFCTRL;
|
||||
DMAHandle.Init.Priority = DMA_PRIORITY_LOW;
|
||||
DMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
|
||||
DMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
DMAHandle.Init.MemBurst = DMA_MBURST_INC4;
|
||||
DMAHandle.Init.PeriphBurst = DMA_PBURST_INC4;
|
||||
|
||||
// Associate the DMA handle with the SDIO handle
|
||||
// Note: The DMA handle is linked to both SDIO TX/RX handles
|
||||
// since we're using a single DMA channel/IRQHandler for TX/RX.
|
||||
__HAL_LINKDMA(&SDHandle, hdmatx, DMAHandle);
|
||||
__HAL_LINKDMA(&SDHandle, hdmarx, DMAHandle);
|
||||
|
||||
HAL_DMA_DeInit(&DMAHandle);
|
||||
if (HAL_DMA_Init(&DMAHandle) != HAL_OK) {
|
||||
// Initialization Error
|
||||
__BKPT(0);
|
||||
}
|
||||
|
||||
// Configure and enable SD IRQ Channel
|
||||
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 4, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
|
||||
}
|
||||
|
||||
static void dma_deinit()
|
||||
{
|
||||
// Just disable the DMA IRQ
|
||||
HAL_NVIC_DisableIRQ(DMA2_Stream3_IRQn);
|
||||
}
|
||||
|
||||
bool sdcard_is_present(void)
|
||||
{
|
||||
@ -27,38 +74,49 @@ bool sdcard_is_present(void)
|
||||
|
||||
void sdcard_init(void)
|
||||
{
|
||||
volatile int retry=10;
|
||||
|
||||
/* SDIO initial configuration */
|
||||
SDHandle.Instance = SDIO;
|
||||
SDHandle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
|
||||
SDHandle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
|
||||
SDHandle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; //TODO
|
||||
SDHandle.Init.BusWide = SDIO_BUS_WIDE_1B;
|
||||
SDHandle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
|
||||
SDHandle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; //INIT_CLK_DIV will be used first
|
||||
|
||||
/* DeInit in case of reboot */
|
||||
HAL_SD_DeInit(&SDHandle);
|
||||
|
||||
/* Init the SD interface */
|
||||
HAL_SD_CardInfoTypedef cardinfo;
|
||||
while(HAL_SD_Init(&SDHandle, &cardinfo) != SD_OK && --retry) {
|
||||
systick_sleep(100);
|
||||
}
|
||||
|
||||
if (retry == 0) {
|
||||
BREAK();
|
||||
}
|
||||
|
||||
/* Configure the SD Card in wide bus mode. */
|
||||
if (HAL_SD_WideBusOperation_Config(&SDHandle, SDIO_BUS_WIDE_4B) != SD_OK) {
|
||||
BREAK();
|
||||
}
|
||||
}
|
||||
|
||||
bool sdcard_power_on(void)
|
||||
{
|
||||
volatile int retry=10;
|
||||
HAL_SD_CardInfoTypedef cardinfo;
|
||||
|
||||
if (!sdcard_is_present()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SDIO configuration
|
||||
SDHandle.Instance = SDIO;
|
||||
SDHandle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
|
||||
SDHandle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
|
||||
SDHandle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
|
||||
SDHandle.Init.BusWide = SDIO_BUS_WIDE_1B;
|
||||
SDHandle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
|
||||
SDHandle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; //INIT_CLK_DIV will be used first
|
||||
|
||||
// Deinit SD
|
||||
HAL_SD_DeInit(&SDHandle);
|
||||
// Init SD interface
|
||||
while(HAL_SD_Init(&SDHandle, &cardinfo) != SD_OK && retry--) {
|
||||
if (retry == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
systick_sleep(100);
|
||||
}
|
||||
|
||||
/* Configure the SD Card in wide bus mode. */
|
||||
if (HAL_SD_WideBusOperation_Config(&SDHandle, SDIO_BUS_WIDE_4B) != SD_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configure and enable DMA IRQ Channel
|
||||
// SDIO IRQ should have a higher priority than DMA IRQ because it needs to
|
||||
// preempt the DMA irq handler to set a flag indicating the end of transfer.
|
||||
HAL_NVIC_SetPriority(SDIO_IRQn, 3, 0);
|
||||
HAL_NVIC_EnableIRQ(SDIO_IRQn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -70,20 +128,73 @@ void sdcard_power_off(void)
|
||||
mp_uint_t sdcard_read_blocks(uint8_t *buff, uint32_t sector, uint32_t count)
|
||||
{
|
||||
HAL_SD_ErrorTypedef err;
|
||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
err = HAL_SD_ReadBlocks(&SDHandle, (uint32_t*)buff,
|
||||
sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count);
|
||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
||||
|
||||
// If buffer is unaligned or located in CCM don't use DMA.
|
||||
if (CCM_BUFFER(buff) || UNALIGNED_BUFFER(buff)) {
|
||||
if (UNALIGNED_BUFFER(buff)) {
|
||||
printf("unaligned read buf:%p count%lu \n", buff, count);
|
||||
}
|
||||
// This transfer has to be done in an atomic section.
|
||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
err = HAL_SD_ReadBlocks(&SDHandle, (uint32_t*)buff,
|
||||
sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count);
|
||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
||||
} else {
|
||||
// Disable USB IRQ to prevent FatFS/MSC contention
|
||||
HAL_NVIC_DisableIRQ(OTG_FS_IRQn); __DSB(); __ISB();
|
||||
|
||||
dma_init(SDIO_TXRX_STREAM, SDIO_TXRX_CHANNEL, DMA_PERIPH_TO_MEMORY);
|
||||
|
||||
err = HAL_SD_ReadBlocks_DMA(&SDHandle, (uint32_t*)buff,
|
||||
sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count);
|
||||
|
||||
if (err == SD_OK) {
|
||||
err = HAL_SD_CheckReadOperation(&SDHandle, SDIO_TIMEOUT);
|
||||
}
|
||||
|
||||
if (err != SD_OK) {
|
||||
printf("read buf:%p addr:%lu count%lu error:%d\n", buff, sector, count, err);
|
||||
}
|
||||
dma_deinit();
|
||||
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
|
||||
}
|
||||
return (err != SD_OK);
|
||||
}
|
||||
|
||||
mp_uint_t sdcard_write_blocks(const uint8_t *buff, uint32_t sector, uint32_t count)
|
||||
{
|
||||
HAL_SD_ErrorTypedef err;
|
||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
err = HAL_SD_WriteBlocks(&SDHandle, (uint32_t*)buff,
|
||||
sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count);
|
||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
||||
|
||||
// If buffer is unaligned or located in CCM don't use DMA.
|
||||
if (CCM_BUFFER(buff) || UNALIGNED_BUFFER(buff)) {
|
||||
if (UNALIGNED_BUFFER(buff)) {
|
||||
printf("unaligned write buf:%p count%lu \n", buff, count);
|
||||
}
|
||||
|
||||
// This transfer has to be done in an atomic section.
|
||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
err = HAL_SD_WriteBlocks(&SDHandle, (uint32_t*)buff,
|
||||
sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count);
|
||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
||||
} else {
|
||||
// Disable USB IRQ to prevent FatFS/MSC contention
|
||||
HAL_NVIC_DisableIRQ(OTG_FS_IRQn); __DSB(); __ISB();
|
||||
|
||||
dma_init(SDIO_TXRX_STREAM, SDIO_TXRX_CHANNEL, DMA_MEMORY_TO_PERIPH);
|
||||
|
||||
err = HAL_SD_WriteBlocks_DMA(&SDHandle, (uint32_t*)buff,
|
||||
sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count);
|
||||
|
||||
if (err == SD_OK) {
|
||||
err = HAL_SD_CheckWriteOperation(&SDHandle, SDIO_TIMEOUT);
|
||||
}
|
||||
|
||||
if (err != SD_OK) {
|
||||
printf("write buf:%p addr:%lu count%lu error:%d\n", buff, sector, count, err);
|
||||
}
|
||||
dma_deinit();
|
||||
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
|
||||
}
|
||||
return (err != SD_OK);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user