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

 

posted @ 2023-10-07 18:47  求隐  阅读(469)  评论(0编辑  收藏  举报