362 lines
10 KiB
C
362 lines
10 KiB
C
|
||
|
||
#include "drv_sdio_sd.h"
|
||
#include "string.h"
|
||
#include <rtthread.h>
|
||
|
||
#define SD_TIMEOUT (1000000U)
|
||
#define SECTOR_SIZE 512
|
||
//#define SD_DMA_MODE 1
|
||
|
||
#define DEBUG
|
||
|
||
#ifdef RT_USING_DFS
|
||
#include <dfs_fs.h>
|
||
|
||
static SD_HandleTypeDef hsd;
|
||
static HAL_SD_CardInfoTypedef sdcard_info;
|
||
static rt_uint32_t _sdcard_buffer[SECTOR_SIZE / sizeof(rt_uint32_t)];
|
||
static struct rt_device sdcard_device;
|
||
static struct rt_semaphore sd_lock;
|
||
|
||
#ifdef SD_DMA_MODE
|
||
static DMA_HandleTypeDef SDTxDMAHandler,SDRxDMAHandler;
|
||
#endif
|
||
|
||
#ifdef DEBUG
|
||
#define DEBUG_PRINTF(...) rt_kprintf(__VA_ARGS__)
|
||
#else
|
||
#define DEBUG_PRINTF(...)
|
||
#endif
|
||
|
||
rt_err_t sdio_sd_init(void)
|
||
{
|
||
hsd.Instance = SDIO;
|
||
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
|
||
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
|
||
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
|
||
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
|
||
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
|
||
hsd.Init.ClockDiv = SDIO_INIT_CLK_DIV;
|
||
|
||
if (HAL_SD_Init(&hsd, &sdcard_info) != HAL_OK)
|
||
return RT_ERROR;
|
||
|
||
if(HAL_SD_WideBusOperation_Config(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
|
||
return RT_ERROR;
|
||
|
||
return RT_EOK;
|
||
}
|
||
|
||
void HAL_SD_MspInit(SD_HandleTypeDef *hsd)
|
||
{
|
||
DMA_HandleTypeDef TxDMAHandler,RxDMAHandler;
|
||
GPIO_InitTypeDef GPIO_Initure;
|
||
|
||
__HAL_RCC_SDIO_CLK_ENABLE();
|
||
#if (SD_DMA_MODE == 1)
|
||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||
#endif
|
||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||
|
||
//PC8,9,10,11,12
|
||
GPIO_Initure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
|
||
GPIO_Initure.Mode = GPIO_MODE_AF_PP;
|
||
GPIO_Initure.Pull = GPIO_PULLUP;
|
||
GPIO_Initure.Speed = GPIO_SPEED_HIGH;
|
||
GPIO_Initure.Alternate = GPIO_AF12_SDIO;
|
||
HAL_GPIO_Init(GPIOC, &GPIO_Initure);
|
||
|
||
//PD2
|
||
GPIO_Initure.Pin = GPIO_PIN_2;
|
||
HAL_GPIO_Init(GPIOD,&GPIO_Initure);
|
||
|
||
#if (SD_DMA_MODE==1) //ʹÓÃDMAģʽ
|
||
HAL_NVIC_SetPriority(SDMMC1_IRQn,2,0); //ÅäÖÃSDMMC1Öжϣ¬ÇÀÕ¼ÓÅÏȼ¶2£¬×ÓÓÅÏȼ¶0
|
||
HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //ʹÄÜSDMMC1ÖжÏ
|
||
|
||
//ÅäÖ÷¢ËÍDMA
|
||
SDRxDMAHandler.Instance = DMA2_Stream3;
|
||
SDRxDMAHandler.Init.Channel = DMA_CHANNEL_4;
|
||
SDRxDMAHandler.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||
SDRxDMAHandler.Init.PeriphInc = DMA_PINC_DISABLE;
|
||
SDRxDMAHandler.Init.MemInc = DMA_MINC_ENABLE;
|
||
SDRxDMAHandler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||
SDRxDMAHandler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||
SDRxDMAHandler.Init.Mode = DMA_PFCTRL;
|
||
SDRxDMAHandler.Init.Priority = DMA_PRIORITY_VERY_HIGH;
|
||
SDRxDMAHandler.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
|
||
SDRxDMAHandler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||
SDRxDMAHandler.Init.MemBurst = DMA_MBURST_INC4;
|
||
SDRxDMAHandler.Init.PeriphBurst = DMA_PBURST_INC4;
|
||
|
||
__HAL_LINKDMA(hsd, hdmarx, SDRxDMAHandler); //½«½ÓÊÕDMAºÍSD¿¨µÄ·¢ËÍDMAÁ¬½ÓÆðÀ´
|
||
HAL_DMA_DeInit(&SDRxDMAHandler);
|
||
HAL_DMA_Init(&SDRxDMAHandler); //³õʼ»¯½ÓÊÕDMA
|
||
|
||
//ÅäÖýÓÊÕDMA
|
||
SDTxDMAHandler.Instance = DMA2_Stream6;
|
||
SDTxDMAHandler.Init.Channel = DMA_CHANNEL_4;
|
||
SDTxDMAHandler.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||
SDTxDMAHandler.Init.PeriphInc = DMA_PINC_DISABLE;
|
||
SDTxDMAHandler.Init.MemInc = DMA_MINC_ENABLE;
|
||
SDTxDMAHandler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||
SDTxDMAHandler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||
SDTxDMAHandler.Init.Mode = DMA_PFCTRL;
|
||
SDTxDMAHandler.Init.Priority = DMA_PRIORITY_VERY_HIGH;
|
||
SDTxDMAHandler.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
|
||
SDTxDMAHandler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||
SDTxDMAHandler.Init.MemBurst = DMA_MBURST_INC4;
|
||
SDTxDMAHandler.Init.PeriphBurst = DMA_PBURST_INC4;
|
||
|
||
__HAL_LINKDMA(hsd, hdmatx, SDTxDMAHandler);//½«·¢ËÍDMAºÍSD¿¨µÄ·¢ËÍDMAÁ¬½ÓÆðÀ´
|
||
HAL_DMA_DeInit(&SDTxDMAHandler);
|
||
HAL_DMA_Init(&SDTxDMAHandler); //³õʼ»¯·¢ËÍDMA
|
||
|
||
|
||
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 3, 0); //½ÓÊÕDMAÖжÏÓÅÏȼ¶
|
||
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
|
||
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 3, 0); //·¢ËÍDMAÖжÏÓÅÏȼ¶
|
||
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
|
||
#endif
|
||
}
|
||
|
||
rt_uint8_t SD_GetCardInfo(HAL_SD_CardInfoTypedef *cardinfo)
|
||
{
|
||
return HAL_SD_Get_CardInfo(&hsd, cardinfo);
|
||
}
|
||
|
||
#if (SD_DMA_MODE==1)
|
||
|
||
HAL_SD_ErrorTypedef SD_ReadBlocks(void* buf,uint64_t sector ,uint32_t cnt)
|
||
{
|
||
HAL_SD_ErrorTypedef err;
|
||
|
||
err = HAL_SD_ReadBlocks_DMA(&hsd, buf, sector, SECTOR_SIZE, cnt);
|
||
if(err != SD_OK)
|
||
{
|
||
DEBUG_PRINTF("err: %d\n", err);
|
||
return err;
|
||
}
|
||
|
||
return HAL_SD_CheckReadOperation(&hsd, (uint32_t)SD_TIMEOUT);
|
||
}
|
||
|
||
HAL_SD_ErrorTypedef SD_WriteBlocks(const void* buf,uint64_t sector,uint32_t cnt)
|
||
{
|
||
HAL_SD_ErrorTypedef err;
|
||
|
||
err = HAL_SD_WriteBlocks_DMA(&hsd, (uint32_t *)buf, sector, SECTOR_SIZE, cnt);
|
||
if(err != SD_OK)
|
||
{
|
||
DEBUG_PRINTF("err: %d\n", err);
|
||
return err;
|
||
}
|
||
|
||
return HAL_SD_CheckWriteOperation(&hsd, (uint32_t)SD_TIMEOUT);
|
||
}
|
||
|
||
void SDMMC1_IRQHandler(void)
|
||
{
|
||
HAL_SD_IRQHandler(&hsd);
|
||
}
|
||
|
||
void DMA2_Stream6_IRQHandler(void)
|
||
{
|
||
HAL_DMA_IRQHandler(hsd.hdmatx);
|
||
}
|
||
|
||
void DMA2_Stream3_IRQHandler(void)
|
||
{
|
||
HAL_DMA_IRQHandler(hsd.hdmarx);
|
||
}
|
||
#else
|
||
|
||
HAL_SD_ErrorTypedef SD_ReadBlocks(void* buf, uint64_t sector, uint32_t cnt)
|
||
{
|
||
return HAL_SD_ReadBlocks(&hsd, (uint32_t * )buf, sector, SECTOR_SIZE, cnt);
|
||
}
|
||
|
||
HAL_SD_ErrorTypedef SD_WriteBlocks(const void* buf, uint64_t sector, uint32_t cnt)
|
||
{
|
||
return HAL_SD_WriteBlocks(&hsd, (uint32_t * )buf, sector, SECTOR_SIZE, cnt);
|
||
}
|
||
#endif
|
||
|
||
static rt_err_t rt_sdcard_init(rt_device_t dev)
|
||
{
|
||
if (rt_sem_init(&sd_lock, "sdlock", 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
||
{
|
||
DEBUG_PRINTF("init sd lock semaphore failed\n");
|
||
return RT_ERROR;
|
||
}
|
||
else
|
||
{
|
||
DEBUG_PRINTF("SD Card init OK\n");
|
||
return RT_EOK;
|
||
}
|
||
}
|
||
|
||
static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
|
||
{
|
||
return RT_EOK;
|
||
}
|
||
|
||
static rt_err_t rt_sdcard_close(rt_device_t dev)
|
||
{
|
||
return RT_EOK;
|
||
}
|
||
|
||
static rt_size_t rt_sdcard_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
|
||
{
|
||
HAL_SD_ErrorTypedef status = SD_OK;
|
||
rt_uint32_t retry;
|
||
|
||
rt_sem_take(&sd_lock, RT_WAITING_FOREVER);
|
||
|
||
retry = 3;
|
||
while(retry)
|
||
{
|
||
/* read all sectors */
|
||
if ((rt_uint32_t)buffer % 4 != 0)
|
||
{
|
||
rt_uint32_t index;
|
||
|
||
/* which is not alignment with 4 or chip SRAM */
|
||
for (index = 0; index < size; index++)
|
||
{
|
||
status = SD_ReadBlocks(buffer, (uint64_t)pos * SECTOR_SIZE, 1);
|
||
if (status != HAL_OK)
|
||
break;
|
||
|
||
/* copy to the buffer */
|
||
rt_memcpy(((rt_uint8_t*)buffer + index * SECTOR_SIZE), _sdcard_buffer, SECTOR_SIZE);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
status = SD_ReadBlocks(buffer, (uint64_t)pos*SECTOR_SIZE, size);
|
||
}
|
||
|
||
if (status == HAL_OK)
|
||
break;
|
||
|
||
retry --;
|
||
}
|
||
|
||
rt_sem_release(&sd_lock);
|
||
|
||
if (status == HAL_OK)
|
||
{
|
||
return size;
|
||
}
|
||
else
|
||
{
|
||
DEBUG_PRINTF("rt_sdcard_read, ");
|
||
DEBUG_PRINTF("dev: %08X, pos: %d, ", (uint32_t)dev, pos);
|
||
DEBUG_PRINTF("buffer: 0x%08X, size: %d\n", buffer, size);
|
||
DEBUG_PRINTF("read failed: status/%d, buffer 0x%08x\n", status, buffer);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
static rt_size_t rt_sdcard_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
|
||
{
|
||
HAL_SD_ErrorTypedef status = SD_OK;
|
||
rt_uint32_t retry;
|
||
static rt_uint32_t count = 0;
|
||
|
||
RT_ASSERT(((uint32_t)buffer & 0x3) == 0x0); //align to 4 bytes;
|
||
|
||
rt_sem_take(&sd_lock, RT_WAITING_FOREVER);
|
||
|
||
retry = 3;
|
||
while(retry)
|
||
{
|
||
/* read all sectors */
|
||
if ((rt_uint32_t)buffer % 4 != 0)
|
||
{
|
||
rt_uint32_t index;
|
||
|
||
/* which is not alignment with 4 or chip SRAM */
|
||
for (index = 0; index < size; index++)
|
||
{
|
||
/* copy to the buffer */
|
||
rt_memcpy(((rt_uint8_t*)buffer + index * SECTOR_SIZE), _sdcard_buffer, SECTOR_SIZE);
|
||
status = SD_WriteBlocks(buffer, (uint64_t)pos * SECTOR_SIZE, 1);
|
||
if (status != HAL_OK)
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
status = SD_WriteBlocks(buffer, (uint64_t)pos*SECTOR_SIZE, size);
|
||
}
|
||
|
||
if (status == HAL_OK)
|
||
break;
|
||
|
||
retry --;
|
||
}
|
||
|
||
rt_sem_release(&sd_lock);
|
||
|
||
if (status == HAL_OK)
|
||
{
|
||
return size;
|
||
}
|
||
else
|
||
{
|
||
DEBUG_PRINTF("rt_sdcard_write: %d, ", count);
|
||
DEBUG_PRINTF("dev: %08X, pos: %d, ", (uint32_t)dev, pos);
|
||
DEBUG_PRINTF("buffer: 0x%08X, size: %d\n", (uint32_t)buffer, size);
|
||
DEBUG_PRINTF("write failed: status/%d, buffer 0x%08x\n", status, buffer);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
static rt_err_t rt_sdcard_control(rt_device_t dev, rt_uint8_t cmd, void *args)
|
||
{
|
||
RT_ASSERT(dev != RT_NULL);
|
||
|
||
if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
|
||
{
|
||
struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *)args;
|
||
|
||
if (geometry == RT_NULL)
|
||
return -RT_ERROR;
|
||
|
||
geometry->bytes_per_sector = sdcard_info.CardBlockSize;
|
||
geometry->block_size = sdcard_info.CardBlockSize;
|
||
geometry->sector_count = sdcard_info.CardCapacity / sdcard_info.CardBlockSize;
|
||
}
|
||
|
||
return RT_EOK;
|
||
}
|
||
|
||
static int rt_hw_sdcard_init(void)
|
||
{
|
||
if (sdio_sd_init() != RT_EOK)
|
||
{
|
||
DEBUG_PRINTF("sdcard init failed\n");
|
||
return RT_ERROR;
|
||
}
|
||
|
||
/* register sdcard device */
|
||
sdcard_device.type = RT_Device_Class_Block;
|
||
sdcard_device.init = rt_sdcard_init;
|
||
sdcard_device.open = rt_sdcard_open;
|
||
sdcard_device.close = rt_sdcard_close;
|
||
sdcard_device.read = rt_sdcard_read;
|
||
sdcard_device.write = rt_sdcard_write;
|
||
sdcard_device.control = rt_sdcard_control;
|
||
|
||
rt_device_register(&sdcard_device, "sd0",
|
||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
|
||
|
||
return RT_EOK;
|
||
}
|
||
INIT_BOARD_EXPORT(rt_hw_sdcard_init);
|
||
#endif
|