GD32H7在FatFS里添加 emmc 驱动(DMA+查询模式)
EMMC_WORK_MODE 设定3种工作模式:
1: EMMC_DMA_MODE
2: EMMC_POLLING_MODE with mcu
3: EMMC_POLLING_MODE with user
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
// 问题参考链接: https://blog.csdn.net/Fairchild_1947/article/details/122268377
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "bsp.h"
#include "SEGGER_RTT.h"
/* Definitions of physical drive number for each drive */
#define DEV_MMC (0) /* Example: Map MMC/SD card to physical drive 0 SD卡,卷标为0 */
#define DEV_RAM (1) /* Example: Map Ramdisk to physical drive 1 外部spi flash,卷标为1 */
#define DEV_USB (2) /* Example: Map USB MSD to physical drive 2 U盘,卷标为2 */
//对于 W25Q32
//前 2M 字节给 fatfs 用, 2M 字节后,用于存放字库,字库占用2M
#define FLASH_SECTOR_SIZE (512u)
#define FLASH_SECTOR_COUNT ((FLASH_SECTOR_SIZE*4)*2u) // W25Q32,前2M字节给FATFS占用,其扇区是 4K 字节大小
#define FLASH_BLOCK_SIZE (8u) // 每个BLOCK有8个扇区
#if !(__ARMCC_VERSION >= 6010050) /* 不是AC6编译器,即使用AC5编译器时 */
__align(32) uint8_t scratch[SD_BLOCK_SIZE];
#else /* 使用AC6编译器时 */
__ALIGNED(32) uint8_t scratch[SD_BLOCK_SIZE];
#endif
/**
* @brief 超时检测
* @param None
* @retval None
*/
int SD_CheckStatusWithTimeout(uint32_t timeout)
{
uint32_t timer;
uint32_t cardstate = 0;
/* block until SDIO peripheral is ready again or a timeout occur */
timer = xTaskGetTickCount();
while( xTaskGetTickCount() - timer < timeout)
{
if(emmc_cardstatus_get(&cardstate) == EMMC_OK)
{
return RES_OK;
}
}
return -1;
}
/**
* @brief 状态检测
* @param None
* @retval None
*/
DSTATUS SD_CheckStatus(BYTE lun)
{
volatile DSTATUS Stat = STA_NOINIT;
Stat = STA_NOINIT;
uint32_t cardstate = 0;
if(emmc_cardstatus_get(&cardstate) == EMMC_OK)
{
Stat = RES_OK;
}
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
// int result;
switch (pdrv) {
case DEV_MMC : //SD卡
// result = MMC_disk_status();
// translate the reslut code here
stat = RES_OK;
return stat;
case DEV_RAM : //外部flash
// result = RAM_disk_status();
// translate the reslut code here
stat = RES_OK;
return stat;
case DEV_USB : //U盘
// result = USB_disk_status();
// translate the reslut code here
stat = RES_OK;
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
// int result;
// uint8_t cardstate = 0;
// sd_error_enum status = SD_OK;
switch (pdrv) {
case DEV_MMC : //SD卡
stat = SD_CheckStatus(1);
if(stat != RES_OK)
{
SEGGER_RTT_printf(0,">>fatfs sd disk init err:%d\r\n",stat);
}else
{
SEGGER_RTT_printf(0,">>fatfs sd disk init:%d\r\n",stat);
stat = RES_OK;
}
return stat;
case DEV_RAM : //外部flash
//W25QXX初始化,这里注意返回参数,正确是必须为0
stat = W25QXX_Init();
if(stat)
{
SEGGER_RTT_printf(0,">>fatfs spi flash disk init err:%d\r\n",stat);
}else
{
SEGGER_RTT_printf(0,">>fatfs spi flash disk init:%d\r\n",stat);
stat = RES_OK; // W25QXX初始化完成后,这里注意返回参数,正确是必须为0
}
return stat;
case DEV_USB : //U盘
stat = STA_NOINIT;
stat = USBH_UDISK_Status(); // U盘连接成功,则返回1.否则返回0
if (stat) {
stat &= ~STA_NOINIT;
}
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res = RES_ERROR;
#if (EMMC_WORK_MODE == 1)
emmc_error_enum sd_err;
UINT i = 0;
#else
uint8_t sd_err;
#endif
switch (pdrv) {
case DEV_MMC : //SD卡
// ensure the SDCard is ready for a new operation
if (SD_CheckStatusWithTimeout(100) < 0)
{
SEGGER_RTT_printf(0,">>fatfs sd disk read timeout\r\n");
return res;
}
#if (EMMC_WORK_MODE == 1)
if( !((uint32_t)buff & 0x1f) ) // 检查首地址32字节对齐
{
if(count > 1)
{
sd_err = emmc_multiblocks_read((uint32_t*)buff,
(uint32_t)(sector * SD_BLOCK_SIZE),
SD_BLOCK_SIZE,
count);
}else
{
sd_err = emmc_block_read((uint32_t*)buff,
(uint32_t)(sector * SD_BLOCK_SIZE),
SD_BLOCK_SIZE);
}
if( sd_err == EMMC_OK )
{
/*
the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
adjust the address and the D-Cache size to invalidate accordingly.
*/
uint32_t alignedAddr = (uint32_t)buff & ~0x1F;
SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*SD_BLOCK_SIZE + ((uint32_t)buff - alignedAddr));
res = RES_OK;
}else
{
SEGGER_RTT_0_printf(">>fatfs sd disk read error:%d\r\n",sd_err);
return RES_ERROR;
}
}else
{
for(i = 0; i < count; i ++)
{
sd_err = emmc_block_read((uint32_t*)scratch,
(uint32_t)((sector ++) * SD_BLOCK_SIZE),
SD_BLOCK_SIZE);
if( sd_err != EMMC_OK )
{
SEGGER_RTT_0_printf(">>fatfs sd disk read error:%d\r\n",sd_err);
return RES_ERROR;
}else
{
SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, SD_BLOCK_SIZE);
memcpy(buff, scratch, SD_BLOCK_SIZE);
buff += SD_BLOCK_SIZE;
}
}
if ((i == count) && (sd_err == EMMC_OK))
{
res = RES_OK;
}else
{
return RES_ERROR;
}
}
#elif (EMMC_WORK_MODE == 2)
if(count > 1)
{
sd_err = emmc_multiblocks_read((uint32_t*)buff,
(uint32_t)(sector << 9),
SD_BLOCK_SIZE,
count);
}else
{
sd_err = emmc_block_read((uint32_t*)buff,
(uint32_t)(sector << 9),
SD_BLOCK_SIZE);
}
if( sd_err == EMMC_OK )
{
res = RES_OK;
}else
{
SEGGER_RTT_0_printf(">>fatfs sd disk read error:%d\r\n",sd_err);
return RES_ERROR;
}
#elif (EMMC_WORK_MODE == 3)
sd_err = emmc_read_disk(buff,sector,count);
if(sd_err != EMMC_OK)//读出错
{
SEGGER_RTT_0_printf(">>fatfs sd disk read error:%d\r\n",res);
return RES_ERROR;
}else
{
res = RES_OK;
}
#endif
return res;
case DEV_RAM : //外部flash
for(;count > 0; count--)
{
W25QXX_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector ++;
buff += FLASH_SECTOR_SIZE;
}
res = RES_OK;
return res;
case DEV_USB : //U盘
res = (DRESULT)USBH_UDISK_Read(buff,sector,count);
return res;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res = RES_ERROR;
#if (EMMC_WORK_MODE == 1)
emmc_error_enum sd_err;
UINT i;
#else
uint8_t sd_err;
#endif
switch (pdrv) {
case DEV_MMC : //SD卡
// ensure the SDCard is ready for a new operation
if (SD_CheckStatusWithTimeout(100) < 0)
{
SEGGER_RTT_0_printf(">>fatfs sd disk write timeout\r\n");
return res;
}
#if (EMMC_WORK_MODE == 1)
if( !((uint32_t)buff & 0x03) ) // 检查首地址4字节对齐
{
/*
the SCB_CleanDCache_by_Addr() requires a 32-Byte aligned address
adjust the address and the D-Cache size to clean accordingly.
*/
uint32_t alignedAddr = (uint32_t)buff & ~0x1F;
SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*SD_BLOCK_SIZE + ((uint32_t)buff - alignedAddr));
if(count > 1)
{
sd_err = emmc_multiblocks_write( (uint32_t*)buff,
(uint32_t)(sector * SD_BLOCK_SIZE),
SD_BLOCK_SIZE,
count);
}else
{
sd_err = emmc_block_write( (uint32_t*)buff,
(uint32_t)(sector * SD_BLOCK_SIZE),
SD_BLOCK_SIZE);
}
if( sd_err == EMMC_OK)
{
res = RES_OK;
}else
{
SEGGER_RTT_0_printf(">>fatfs sd disk write error:%d\r\n",sd_err);
return RES_ERROR;
}
}else
{
for(i = 0; i < count; i ++)
{
memcpy(scratch, buff, SD_BLOCK_SIZE);
SCB_CleanDCache_by_Addr((uint32_t*)scratch, SD_BLOCK_SIZE);
sd_err = emmc_block_write((uint32_t*)scratch,
(uint32_t)((sector ++) * SD_BLOCK_SIZE),
SD_BLOCK_SIZE);
if( sd_err != EMMC_OK )
{
SEGGER_RTT_0_printf(">>fatfs sd disk write error:%d\r\n",sd_err);
return RES_ERROR;
}else
{
buff += SD_BLOCK_SIZE;
}
}
if ((i == count) && (sd_err == EMMC_OK))
{
res = RES_OK;
}else
{
return RES_ERROR;
}
}
#elif (EMMC_WORK_MODE == 2)
if(count > 1)
{
sd_err = emmc_multiblocks_write( (uint32_t*)buff,
(uint32_t)(sector << 9),
SD_BLOCK_SIZE,
count);
}else
{
sd_err = emmc_block_write( (uint32_t*)buff,
(uint32_t)(sector << 9),
SD_BLOCK_SIZE);
}
if( sd_err == EMMC_OK)
{
res = RES_OK;
}else
{
SEGGER_RTT_0_printf(">>fatfs sd disk write error:%d\r\n",sd_err);
return RES_ERROR;
}
#elif (EMMC_WORK_MODE == 3)
sd_err = emmc_write_disk((uint8_t*)buff,sector,count);
if(sd_err != EMMC_OK) // 写出错
{
SEGGER_RTT_0_printf(">>fatfs sd disk write error:%d\r\n",res);
return RES_ERROR;
}else
{
// SEGGER_RTT_0_printf(">>fatfs sd disk write...ok\r\n");
res = RES_OK;
}
#endif
return res;
case DEV_RAM : //外部flash
for(;count>0;count--)
{
W25QXX_Write((uint8_t*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff += FLASH_SECTOR_SIZE;
}
res = RES_OK;
return res;
case DEV_USB : //U盘
res = (DRESULT)USBH_UDISK_Write((uint8_t *)buff,sector,count);
return res;
}
return RES_PARERR;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res = RES_OK;
msc_lun info;
switch (pdrv) {
case DEV_MMC : //SD卡
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(DWORD*)buff = sd_cardinfo.LogBlockSize;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = sd_cardinfo.LogBlockSize / SD_BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = sd_cardinfo.LogBlockNbr;
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
return res;
case DEV_RAM : //外部flash
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = FLASH_SECTOR_SIZE;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = FLASH_BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = FLASH_SECTOR_COUNT;
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
return res;
case DEV_USB : //U盘
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
if (USBH_OK == usbh_msc_lun_info_get(&usb_host_msc, 0, &info))
{
*(WORD*)buff = (DWORD)info.capacity.block_size;
res = RES_OK;
}
break;
case GET_BLOCK_SIZE:
*(DWORD *)buff = 512U;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
if (USBH_OK == usbh_msc_lun_info_get(&usb_host_msc, 0, &info))
{
*(DWORD*)buff = (DWORD)info.capacity.block_nbr;
res = RES_OK;
}
break;
default:
res = RES_PARERR;
break;
}
return res;
}
return RES_PARERR;
}
/**
* @brief 获得时间 User defined function to give a current time to fatfs module
* @param 31-25: Year(0-127 org.1980),
* @param 24-21: Month(1-12),
* @param 20-16: Day(1-31)
* @param 15-11: Hour(0-23)
* @param 10-5: Minute(0-59)
* @param 4-0: Second(0-29 *2)
* @retval none
*/
DWORD get_fattime (void)
{
uint32_t time;
rtc_parameter_struct rtc_initpara;
rtc_current_time_get(&rtc_initpara);
time = ((uint32_t)(rtc_initpara.year)) << 25; // 年份,从20xx年计算
time |= ((uint32_t)rtc_initpara.month ) << 21; // 月份
time |= ((uint32_t)rtc_initpara.date ) << 16; // 日期
time |= ((uint32_t)rtc_initpara.hour ) << 11; // 时
time |= ((uint32_t)rtc_initpara.minute ) << 5; // 分
time |= ((uint32_t)rtc_initpara.second / 2 ); // 秒
return time;
}
本文来自博客园,作者:求隐,转载请注明原文链接:https://www.cnblogs.com/duguqiuying/articles/17747190.html