GD32F407调试SD卡FATFS文件系统

1.准备文件

GD官网下载区下载开发板Demo包《GD32F4xx_Demo_Suites_V2.2.0》和《GD32F4xx_Firmware_Library_VX.X.X》。
解压《GD32F4xx_Demo_Suites_V2.2.0》找到文件里的文件fat_fs和SDIO_SDCardTest工程。这些是我们所需的文件系统和SDIO的初始化程序。
在这里插入图片描述
在这里插入图片描述

2.移植

复制SDIO的接口文件到工程文件下
在这里插入图片描述
工程下建立Fatfs文件夹并添加fat_fs的文件到工程
在这里插入图片描述
头文件目录添加
在这里插入图片描述

3.配置是否支持OS

本文是使用的FreeRTOS
在这里插入图片描述
然后修改ffsystem.c文件,打开对应的操作系统即可。

	/*------------------------------------------------------------------------*/
	/* Sample Code of OS Dependent Functions for FatFs                        */
	/* (C)ChaN, 2018                                                          */
	/*------------------------------------------------------------------------*/
	
	
	#include "ff.h"
	
	
	#if FF_USE_LFN == 3	/* Dynamic memory allocation */
	
	/*------------------------------------------------------------------------*/
	/* Allocate a memory block                                                */
	/*------------------------------------------------------------------------*/
	
	void* ff_memalloc (	/* Returns pointer to the allocated memory block (null if not enough core) */
		UINT msize		/* Number of bytes to allocate */
	)
	{
		return malloc(msize);	/* Allocate a new memory block with POSIX API */
	}
	
	
	/*------------------------------------------------------------------------*/
	/* Free a memory block                                                    */
	/*------------------------------------------------------------------------*/
	
	void ff_memfree (
		void* mblock	/* Pointer to the memory block to free (nothing to do if null) */
	)
	{
		free(mblock);	/* Free the memory block with POSIX API */
	}
	
	#endif
	
	
	
	#if FF_FS_REENTRANT	/* Mutal exclusion */
	
	/*------------------------------------------------------------------------*/
	/* Create a Synchronization Object                                        */
	/*------------------------------------------------------------------------*/
	/* This function is called in f_mount() function to create a new
	/  synchronization object for the volume, such as semaphore and mutex.
	/  When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
	*/
	
	//const osMutexDef_t Mutex[FF_VOLUMES];	/* Table of CMSIS-RTOS mutex */
	
	
	int ff_cre_syncobj (	/* 1:Function succeeded, 0:Could not create the sync object */
		BYTE vol,			/* Corresponding volume (logical drive number) */
		FF_SYNC_t* sobj		/* Pointer to return the created sync object */
	)
	{
	//	/* Win32 */
	//	*sobj = CreateMutex(NULL, FALSE, NULL);
	//	return (int)(*sobj != INVALID_HANDLE_VALUE);
	
		/* uITRON */
	//	T_CSEM csem = {TA_TPRI,1,1};
	//	*sobj = acre_sem(&csem);
	//	return (int)(*sobj > 0);
	
		/* uC/OS-II */
	//	OS_ERR err;
	//	*sobj = OSMutexCreate(0, &err);
	//	return (int)(err == OS_NO_ERR);
	
		/* FreeRTOS */
		*sobj = xSemaphoreCreateMutex();
		return (int)(*sobj != NULL);
	
		/* CMSIS-RTOS */
	//	*sobj = osMutexCreate(&Mutex[vol]);
	//	return (int)(*sobj != NULL);
	}
	
	
	/*------------------------------------------------------------------------*/
	/* Delete a Synchronization Object                                        */
	/*------------------------------------------------------------------------*/
	/* This function is called in f_mount() function to delete a synchronization
	/  object that created with ff_cre_syncobj() function. When a 0 is returned,
	/  the f_mount() function fails with FR_INT_ERR.
	*/
	
	int ff_del_syncobj (	/* 1:Function succeeded, 0:Could not delete due to an error */
		FF_SYNC_t sobj		/* Sync object tied to the logical drive to be deleted */
	)
	{
	//	/* Win32 */
	//	return (int)CloseHandle(sobj);
	
		/* uITRON */
	//	return (int)(del_sem(sobj) == E_OK);
	
		/* uC/OS-II */
	//	OS_ERR err;
	//	OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
	//	return (int)(err == OS_NO_ERR);
	
		/* FreeRTOS */
	    vSemaphoreDelete(sobj);
		return 1;
	
		/* CMSIS-RTOS */
	//	return (int)(osMutexDelete(sobj) == osOK);
	}
	
	
	/*------------------------------------------------------------------------*/
	/* Request Grant to Access the Volume                                     */
	/*------------------------------------------------------------------------*/
	/* This function is called on entering file functions to lock the volume.
	/  When a 0 is returned, the file function fails with FR_TIMEOUT.
	*/
	
	int ff_req_grant (	/* 1:Got a grant to access the volume, 0:Could not get a grant */
		FF_SYNC_t sobj	/* Sync object to wait */
	)
	{
	//	/* Win32 */
	//	return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
	
		/* uITRON */
	//	return (int)(wai_sem(sobj) == E_OK);
	
		/* uC/OS-II */
	//	OS_ERR err;
	//	OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
	//	return (int)(err == OS_NO_ERR);
	
		/* FreeRTOS */
		return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
	
		/* CMSIS-RTOS */
	//	return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
	}
	
	
	/*------------------------------------------------------------------------*/
	/* Release Grant to Access the Volume                                     */
	/*------------------------------------------------------------------------*/
	/* This function is called on leaving file functions to unlock the volume.
	*/
	
	void ff_rel_grant (
		FF_SYNC_t sobj	/* Sync object to be signaled */
	)
	{
	//	/* Win32 */
	//	ReleaseMutex(sobj);
	
		/* uITRON */
	//	sig_sem(sobj);
	
		/* uC/OS-II */
	//	OSMutexPost(sobj);
	
		/* FreeRTOS */
		xSemaphoreGive(sobj);
	
		/* CMSIS-RTOS */
	//	osMutexRelease(sobj);
	}
	
	#endif

4.修改添加文件

  1. 添加初始化和中断程序

    #include "fatfs.h"
    #include "sdcard.h"
    
    sd_card_info_struct sd_cardinfo; /* information of SD card */
    	
    /*!
        \brief      this function handles SDIO interrupt request
        \param[in]  none
        \param[out] none
        \retval     none
    */
    void SDIO_IRQHandler(void)
    {
        sd_interrupts_process();
    }
    	
    /*!
        \brief      initialize the card, get the card information, set the bus mode and transfer mode
        \param[in]  none
        \param[out] none
        \retval     sd_error_enum
    */
    sd_error_enum sd_config(void)
    {
        sd_error_enum status = SD_OK;
        uint32_t cardstate = 0;
    
        nvic_irq_enable(SDIO_IRQn, 5, 0);
    	
        /* initialize the card */
        status = sd_init();
        if(SD_OK == status){
            status = sd_card_information_get(&sd_cardinfo);
        }
        if(SD_OK == status){
            status = sd_card_select_deselect(sd_cardinfo.card_rca);
        }
        status = sd_cardstatus_get(&cardstate);
        if(cardstate & 0x02000000){
            trace("\r\n The card is locked!");
    #if 0
            /* unlock the card if necessary */
            status = sd_lock_unlock(SD_UNLOCK);
            if(SD_OK != status){
                trace("\r\n Unlock failed!");
                while (1){
                }
            }else{
                trace("\r\n The card is unlocked! Please reset MCU!");
            }
    #endif
            while (1){
            }
        }
        if ((SD_OK == status) && (!(cardstate & 0x02000000)))
        {
            /* set bus mode */
            status = sd_bus_mode_config(SDIO_BUSMODE_4BIT);
    //        status = sd_bus_mode_config( SDIO_BUSMODE_1BIT );
        }
        if (SD_OK == status)
        {
            /* set data transfer mode */
    //        status = sd_transfer_mode_config( SD_DMA_MODE );
            status = sd_transfer_mode_config( SD_POLLING_MODE );
        }
        return status;
    }
    
  2. 添加文件系统初始化程序

     #include "fatfs.h"
     
     uint8_t retSD;    /* Return value for SD */
     char SDPath[4];   /* SD logical drive path */
    
     void MX_FATFS_Init(void)
     {
       /*## FatFS: Link the SD driver ###########################*/
       retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
    
     }
    
  3. 文件系统的SDIO接口,注意GD32和STM32的区别,STM32通过CubeMX生成的程序是以sector为单位写的,写的buf为byte。GD32是以地址写的,buf为WORD。

     static volatile DSTATUS Stat = STA_NOINIT;
     //static QueueHandle_t SDQueueID = NULL;
     /* Private function prototypes -----------------------------------------------*/
     static DSTATUS SD_CheckStatus(BYTE lun);
     DSTATUS SD_initialize (BYTE);
     DSTATUS SD_status (BYTE);
     DRESULT SD_read (BYTE, BYTE*, DWORD, UINT);
     #if _USE_WRITE == 1
     DRESULT SD_write (BYTE, const BYTE*, DWORD, UINT);
     #endif /* _USE_WRITE == 1 */
     #if _USE_IOCTL == 1
     DRESULT SD_ioctl (BYTE, BYTE, void*);
     #endif  /* _USE_IOCTL == 1 */
    
     const Diskio_drvTypeDef  SD_Driver =
     {
       SD_initialize,
       SD_status,
       SD_read,
     #if  _USE_WRITE == 1
       SD_write,
     #endif /* _USE_WRITE == 1 */
     
     #if  _USE_IOCTL == 1
       SD_ioctl,
     #endif /* _USE_IOCTL == 1 */
     };
     
     static 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(sd_cardstatus_get(&cardstate) == SD_OK)
     	{
     		return RES_OK;
     	}	
       }
     
       return -1;
     }
    
     static DSTATUS SD_CheckStatus(BYTE lun)
     {
         Stat = STA_NOINIT;
         uint32_t cardstate = 0;
     	
     	if(sd_cardstatus_get(&cardstate) == SD_OK)
     	{
     		Stat = RES_OK;
     	}	
     
       return RES_OK;
     }
    
     extern sd_error_enum sd_config(void);
    
     /**
       * @brief  Initializes a Drive
       * @param  lun : not used
       * @retval DSTATUS: Operation status
       */
     DSTATUS SD_initialize(BYTE lun)
     {
       Stat = STA_NOINIT;
       uint8_t sd_state = MSD_OK;
     	
       /* initialize the card */
       sd_state = sd_config();
     
       Stat = (sd_state == SD_OK) ? MSD_OK : MSD_ERROR;	
     	
       return Stat;
     }
    
     /**
       * @brief  Gets Disk Status
       * @param  lun : not used
       * @retval DSTATUS: Operation status
       */
     DSTATUS SD_status(BYTE lun)
     {
       return SD_CheckStatus(lun);
     }
    
     /* USER CODE BEGIN beforeReadSection */
     /* can be used to modify previous code / undefine following code / add new code */
     /* USER CODE END beforeReadSection */
     /**
       * @brief  Reads Sector(s)
       * @param  lun : not used
       * @param  *buff: Data buffer to store read data
       * @param  sector: Sector address (LBA)
       * @param  count: Number of sectors to read (1..128)
       * @retval DRESULT: Operation result
       */
     
     DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
     {
       DRESULT res = RES_ERROR;
       uint8_t sd_state = MSD_OK;
    
       /*
       * ensure the SDCard is ready for a new operation
       */
       if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
       {
         return res;
       }
     
     	/* Fast path cause destination buffer is correctly aligned */
     	sd_transfer_mode_config( SD_POLLING_MODE );	
     
     	/* Read block(s) in DMA transfer mode */
     	sd_state = sd_block_read((uint32_t*)buff, (sector*512), (count*512));	
     
     	if(sd_state != SD_OK)
     	{
     		res = RES_ERROR;
     	}	
     	else
     	{
     		res = RES_OK;
     	}	
     
       return res;
     }
    
     /* USER CODE BEGIN beforeWriteSection */
     /* can be used to modify previous code / undefine following code / add new code */
     /* USER CODE END beforeWriteSection */
     /**
       * @brief  Writes Sector(s)
       * @param  lun : not used
       * @param  *buff: Data to be written
       * @param  sector: Sector address (LBA)
       * @param  count: Number of sectors to write (1..128)
       * @retval DRESULT: Operation result
       */
     #if _USE_WRITE == 1
     
     DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
     {
       DRESULT res = RES_ERROR;
       uint8_t sd_state = MSD_OK;	
     
       /*
       * ensure the SDCard is ready for a new operation
       */	
       if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
       {
         return res;
       }
     
       sd_transfer_mode_config( SD_POLLING_MODE );		
       /* Write block(s) in DMA transfer mode */
       sd_state = sd_block_write((uint32_t*)buff, (sector*512), (count*512));
       if(sd_state != SD_OK)	
       {
         res = RES_ERROR;
       }	
       else
       {
     	res = RES_OK;
       }
    
       return res;
     }
      #endif /* _USE_WRITE == 1 */
    
     /**
       * @brief  I/O control operation
       * @param  lun : not used
       * @param  cmd: Control code
       * @param  *buff: Buffer to send/receive control data
       * @retval DRESULT: Operation result
       */
     #if _USE_IOCTL == 1
     DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
     {
       DRESULT res = RES_ERROR;
       sd_card_info_struct CardInfo;
     
       if (Stat & STA_NOINIT) return RES_NOTRDY;
     
       switch (cmd)
       {
       /* Make sure that no pending write process */
       case CTRL_SYNC :
         res = RES_OK;
         break;
     
       /* Get number of sectors on the disk (DWORD) */
       case GET_SECTOR_COUNT :
          sd_card_information_get(&CardInfo);
         *(DWORD*)buff = CardInfo.card_blocksize;
         res = RES_OK;
         break;
     
       /* Get R/W sector size (WORD) */
       case GET_SECTOR_SIZE :
          sd_card_information_get(&CardInfo);
         *(WORD*)buff = CardInfo.card_blocksize;
         res = RES_OK;
         break;
     
       /* Get erase block size in unit of sector (DWORD) */
       case GET_BLOCK_SIZE :
          sd_card_information_get(&CardInfo);
         *(DWORD*)buff = CardInfo.card_blocksize / SD_DEFAULT_BLOCK_SIZE;
         res = RES_OK;
         break;
     
       default:
         res = RES_PARERR;
       }
     
       return res;
     }
     #endif /* _USE_IOCTL == 1 */
    

5.测试

测试前,确保SD卡的格式为FAT32和512字节。

void Fat32_SD_test(void)
{
    FATFS fs;                 // Work area (file system object) for logical drive
    FIL fil;                  // file objects
    uint8_t rtext[100];                     /* File read buffers */
    char filename[] = "GD32_SD_FATFS.txt";
    uint8_t wtext[] = "This is GD32 working with FatFs"; /* File write buffer */
    uint32_t byteswritten;                /* File write counts */
    uint32_t bytesread;                   /* File read counts */

    trace("\r\n ****** FatFs Example ******\r\n\r\n");

    /*##-1- Register the file system object to the FatFs module ##############*/
    retSD = f_mount(&fs, "", 0);
    if(retSD)
    {
        trace(" mount error : %d \r\n",retSD);
    }
    else
    {
        trace(" mount sucess!!! \r\n");
    }

    /*##-2- Create and Open new text file objects with write access ######*/
    retSD = f_open(&fil, filename, FA_CREATE_ALWAYS | FA_WRITE);
    card_info_get();
    if(retSD)
        trace(" open file error : %d\r\n",retSD);
    else
        trace(" open file sucess!!! \r\n");

    /*##-3- Write data to the text files ###############################*/
    retSD = f_write(&fil, wtext, sizeof(wtext), (void *)&byteswritten);
    if(retSD)
        trace(" write file error : %d\r\n",retSD);
    else
    {
        trace(" write file sucess!!! \r\n");
        trace(" write Data : %s\r\n",wtext);
    }

    /*##-4- Close the open text files ################################*/
    retSD = f_close(&fil);
    if(retSD)
        trace(" close error : %d\r\n",retSD);
    else
        trace(" close sucess!!! \r\n");

    /*##-5- Open the text files object with read access ##############*/
    retSD = f_open(&fil, filename, FA_READ);
    if(retSD)
        trace(" open file error : %d\r\n",retSD);
    else
        trace(" open file sucess!!! \r\n");

    /*##-6- Read data from the text files ##########################*/
    retSD = f_read(&fil, rtext, sizeof(rtext), (UINT*)&bytesread);
    if(retSD)
        trace(" read error!!! %d\r\n",retSD);
    else
    {
        trace(" read sucess!!! \r\n");
        trace(" read Data : %s\r\n",rtext);
    }

    /*##-7- Close the open text files ############################*/
    retSD = f_close(&fil);
    if(retSD)
        trace(" close error!!! %d\r\n",retSD);
    else
        trace(" close sucess!!! \r\n");

    /*##-8- Compare read data with the expected data ############*/
    if(bytesread == byteswritten)
    {
        trace(" FatFs is working well!!!\r\n");
    }
}

6.追加写/读

FRESULT f_open_append_addr (
    FIL* fp,            /* [OUT] File object to create */
    const char* path,    /* [IN]  File name to be opened */
	unsigned long addr,	
	BYTE mode
)
{
    FRESULT fr;
 
    /* Opens an existing file. If not exist, creates a new file. */
    fr = f_open(fp, path, mode);
    if (fr == FR_OK) {
        /* Seek to file addr */
//        fr = f_lseek(fp, f_size(fp));
		 fr = f_lseek(fp, addr);
        if (fr != FR_OK)
            f_close(fp);
    }
    return fr;
}

unsigned char f_sd_r(unsigned long addr,void *pDat,unsigned long len)
{
	uint32_t bytesread; /* File write counts */
	
//	f_mount(&fs, "", 0);	
	retSD = f_open_append_addr(&fil, filename, addr, FA_READ | FA_OPEN_ALWAYS);
	if(!retSD)
	{
		retSD = f_read(&fil, pDat, len, (void *)&bytesread);	
		f_close(&fil);		
	}
//	f_mount(NULL, "", 0);
	
    return retSD;
}

unsigned char f_sd_w(unsigned long addr,void *pDat,unsigned long len)
{
	uint32_t byteswritten; /* File write counts */

//	f_mount(&fs, "", 0);		
	retSD = f_open_append_addr(&fil, filename, addr, FA_WRITE | FA_OPEN_ALWAYS);
	if(!retSD)
	{
		retSD = f_write(&fil, pDat, len, (void *)&byteswritten);	
		f_close(&fil);		
	}	
//	f_mount(NULL, "", 0);
    return retSD;
}
  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
要在STM32F407移植FATFS文件系统,首先需要了解FATFS是一个开源的文件系统,它可以在嵌入式设备上实现存储器的文件读写操作。 在移植FATFS之前,需要准备一些基本的材料,如软件开发环境、相关的文档和资料。可以从FATFS的官方网站下载最新版本的库文件和相关的示例代码。 首先,创建一个新的工程,并在工程中添加所需的库文件和头文件。将fatfs.c和diskio.c两个源文件添加到工程,并在工程设置中包含相关的头文件目录。 接下来,在工程中添加适配底层硬件的代码,在这里是针对STM32F407的。需要编写适配FATFS的底层I/O读写操作的代码,包括初始化SD卡、读取扇区数据和写入扇区数据。 然后,根据具体需求配置FATFS的参数。可以在fatfs_conf.h文件中修改相关的参数,如簇大小、扇区大小和最大文件数等。这些参数根据实际应用需求进行调整。 最后,编写应用程序代码。可以利用FATFS提供的API来实现文件的打开、读取和写入等操作。需要注意的是在使用FATFS API之前,需要先调用f_mount函数挂载文件系统。 完成以上步骤后,就可以进行编译和烧录操作,将程序下载到STM32F407上进行测试。可以通过读取和写入文件来验证FATFS的正常工作。 总结来说,STM32F407移植FATFS文件系统需要准备相关的材料,包括库文件和文档。然后添加相关的源文件和头文件到工程中,并编写适配底层硬件的代码。之后根据需求配置FATFS参数,并编写应用程序代码。最后进行编译和烧录操作,进行测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值