Use DMA for SDIO transfers

This commit is contained in:
iabdalkader 2016-03-05 15:44:39 +02:00
parent 4acaafafa0
commit 9230f0d53e

View File

@ -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);
}