USB2.0挂载FatFs文件系统
生活随笔
收集整理的這篇文章主要介紹了
USB2.0挂载FatFs文件系统
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、前期準備
1、協議棧
USB協議棧
FatFs文件系統協議棧
2、物理芯片
W25Q64的8M大小的flash芯片
二、描述
文件系統fatfs、USB協議棧、物理層flash存儲芯片關系。
1、單獨使用flash芯片,開發flash芯片的響應的驅動即可進行按照 絕對地址 的讀寫方式進行數據的存儲和讀取。一般的單片機只做存儲的可以這么做。 void W25q64_Spi_Init(void) 初始化flash芯片的驅動 void SPI_FLASH_BufferRead(uint32_t ReadAddr,uint8_t* pBuffer, uint16_t NumByteToRead) 形參1:flash的絕對地址 形參2:讀取到數據要存儲的位置 形參3:要讀取數據的大小 void SPI_FLASH_BufferWrite(uint32_t WriteAddr,uint8_t* pBuffer, uint16_t NumByteToWrite) 形參1:flash的絕對地址 形參2:讀寫到flash中的源數據存儲位置 形參3:要寫入數據的大小 2、flash驅動+文件系統 這個一般要對文件進行管理的時候使用,這時候文件只是存儲在flash的物理層中,只進行了文件系統的邏輯抽象,所有的操作只能在代碼中執行,外部接口不可見。 想要可見要進行接口虛擬例如SD卡。部分是集成在SD中的,不過這種情況不是很多。 DSTATUS disk_initialize (BYTE pdrv) 這個函數中調用上面的W25q64_Spi_Init()函數進行初始化并進行喚醒芯片。 DRESULT disk_read (BYTE pdrv,BYTE *buff,DWORD sector,UINT count) 調用上面的SPI_FLASH_BufferRead()函數進行數據的讀取,但是除此之外要進行你的flash的起始地址偏移和扇區大小的邏輯運算在里面。 /*形參 1、pdrv:設備物理編號 2、buff:讀取出來數據緩存區 3、sector:要讀取得扇區首地址 一個扇區大小是***字節 這個非常重要 每個型號的flash芯片可能不一樣,例如這個就是4096byte大小扇區 m256pe16這款芯片的扇區大小就是512byte,所以在進行邏輯地址運算的時候 這個要進行不同的邏輯地址計算。 4、count:扇區個數(1/2/3。。。128。。。) 操作的最小單位是扇區 不是極小頁 所以這個與M25PE的flash驅動有別 */ eg: #define Msd_Addr 0x50 0000 //這個定義是說明這個U盤的虛擬是從flash的地址0x50 0000 開始的直到結束 DRESULT disk_read (BYTE pdrv,BYTE *buff,DWORD sector,UINT count) { uint32_t address = 0; DRESULT status = RES_PARERR; switch(pdrv) { case ATA: //SD卡 break; case MMC: break; case MSD: //這個是內部flash的虛擬 address = sector*4096; if(count==1) { ReadFlash(address+Msd_Addr,buff,count*4096); //address+Msd_Addr 這個是進行地址偏移 } else { while(count-->0) { ReadFlash(address+Msd_Addr,buff,4096); //address+Msd_Addr 這個是進行地址偏移 address = address + 4096; buff = buff + 4096; } } break; default: status = RES_PARERR; } return status; } DRESULT disk_write (BYTE pdrv,const BYTE *buff,DWORD sector,UINT count) 這個函數調用的是SPI_FLASH_BufferWrite() 寫的時候一定要注意的一點是在寫的響應的地址上面要進行一次擦除操作,不然在windows平臺下 虛擬出U盤之后會出現無法格式化的現象。 /*形參 1、pdrv:設備物理編號(0,) 2、buff:預寫數據的緩沖區 3、sector:扇區首地址 4、count:扇區個數(1.2.。。128) */ DRESULT disk_write (BYTE pdrv,const BYTE *buff,DWORD sector,UINT count) { uint32_t address = 0; DRESULT status = RES_PARERR; if (!count) { return RES_PARERR; /* Check parameter */ } switch(pdrv) { case ATA: break; case MMC: break; case MSD: address = sector*4096; if(count==1) { SPI_FLASH_SectorErase(address+Msd_Addr); //把要寫入的數據的地址 要進行先擦除 重要 WriteFlash(address+Msd_Addr,(uint8_t*)buff,4096); } else { while(count-->0) { SPI_FLASH_SectorErase(address+Msd_Addr); //把要寫入的數據的地址 要進行先擦除 重要 WriteFlash(address+Msd_Addr,(uint8_t*)buff,4096); //address+Msd_Addr地址偏移 address = address + 4096; buff = buff + 4096; } } break; default: status = RES_PARERR; break; } return status; } DRESULT disk_ioctl (BYTE pdrv,BYTE cmd,void *buff) 這個函數很重要奧 里面這些東西在你的U盤被windows識別之前會進行里面的參數進行提取 例如: DRESULT disk_ioctl (BYTE pdrv,BYTE cmd,void *buff) //Miscellaneous Functions { DRESULT status = RES_PARERR; switch(pdrv) { case ATA: break; case MMC: break; case MSD: switch(cmd) { case CTRL_SYNC: break; case GET_BLOCK_SIZE: //同時擦除的扇區個數 *(DWORD*)buff = 1; //這個是 一個塊區 包含多少個 扇區的個數 一般擦除時候用 針對支持塊擦除的介質 break; case GET_SECTOR_COUNT: //GET_SECTOR_COUNT * GET_SECTOR_SIZE + 基地址 = U盤空間結束地址 *(DWORD*)buff = (ALL_FLASH_ADDR-Msd_Addr)/4096; //這個是U盤有多少扇區數量 這個是給到window讀取的 break; case GET_SECTOR_SIZE: //扇區大小 *(WORD*)buff = 4096; break; } status = RES_OK; break; default: status = RES_PARERR; break; } return status; // Process of the command the USB drive } GET_BLOCK_SIZE:這個命令獲取的時候,你返回的內容會影響到擦除和寫入的速度。 =1:說明 一次只能擦除一個扇區 這個開大 會寫入的速率升高,但是這個會占用ram空間,所以我們最好是根據自己的實景情況進行設置。 這個是進行塊擦除的 大小,意思是一個塊區 包含多少個 扇區 GET_SECTOR_COUNT: 這個獲取的就是 你的U盤的大小,大小的值一定要與你實際的flash起始和結束地址對應,不然那的話 會掛載失敗。 公式可以這樣寫或者其他辦法也可以: *(DWORD*)buff = (ALL_FLASH_ADDR-Msd_Addr)/4096; ALL_FLASH_ADDR:這個是flash的結束地址 可以是flash的最大的末尾地址 也可以是比 起始地址大的任意位置。 Msd_Addr:這個是U盤的虛擬地址的起始地址。 4096這個是一個sector的大小,不同的芯片可能會不一樣,這個為了可移植一性高的話,可以做個宏定義。 GET_SECTOR_SIZE: 這個就是進行獲取一個扇區的大小
DWORD get_fattime(void) 這個函數是記錄對文件操作的時間,有改動的話會進行時間戳的記錄。這個最好進行移植一下,不過不進行移植的話,對數據存儲功能貌似沒有多大的影響。
3、flash驅動+fatfs文件系統+USB協議棧 這種方式也是用的最為廣泛的了,在一些小型嵌入式系統中,只要你的flash芯片大小足夠大,都可以虛擬出來U盤,在windows平臺上進行傻瓜操作。 USB中的功能包含很多: HID,CDC,MSC,HUB。。。我們這里只介紹在MSC中進行U盤掛載這一部分。 新定義一下U盤的代碼文件,假設是MSD.c
我們對u盤進行初始化: Msd_Init() 這里面調用: if ( disk_initialize( 2 ) != 0 ) // 進行初始化flash芯片 調用disk_initialize() 2參數 是邏輯驅動號 這個驅動號 是在diskio.c中定義的 return false; /* Get numSectors from media. */ if ( disk_ioctl( 2, GET_SECTOR_COUNT, &numSectors ) != RES_OK ) return false; //這個是進行 U盤屬性的獲取 調用disk_ioctl()函數 #define ATA 0 //u盤邏輯驅動號是 0 #define MMC 1 //u盤邏輯驅動號是 1 #define MSD 2 //u盤邏輯驅動號是 2
對U盤進行讀操作 void Msd_Read( MSDD_CmdStatus_TypeDef *pCmd, uint8_t *data, uint32_t sectors ) 調用disk_read( 2, data, pCmd->lba, sectors )函數 /**************************************************************************//** * @brief * Read from indirectly accessed media. * * @param[in] pCmd * Points to a MSDD_CmdStatus_TypeDef structure which holds info about the * current transfer. * * @param[in] data * Pointer to data buffer. * * @param[in] sectors * Number of 512 byte sectors to read from media. *****************************************************************************/ void Msd_Read( MSDD_CmdStatus_TypeDef *pCmd, uint8_t *data, uint32_t sectors ) { #if ( MSD_MEDIA == MSD_SRAM_MEDIA ) || ( MSD_MEDIA == MSD_PSRAM_MEDIA ) (void)pCmd; (void)data; (void)sectors; #endif
#if ( MSD_MEDIA == MSD_SDCARD_MEDIA ) disk_read( 2, data, pCmd->lba, sectors ); #endif
#if ( MSD_MEDIA == MSD_FLASH_MEDIA ) || ( MSD_MEDIA == MSD_NORFLASH_MEDIA ) /* Write pending data to flash before starting the read operation. */ Msd_Flush(); //memcpy( data, pCmd->pData, sectors * 512 ); //pCmd->pData += sectors * 512; memcpy( data, pCmd->pData, sectors * 4096 ); pCmd->pData += sectors * 4096; #endif } 對U盤進行寫操作 void Msd_Write( MSDD_CmdStatus_TypeDef *pCmd, uint8_t *data, uint32_t sectors ) 調用 disk_write( 2, data, pCmd->lba, sectors )函數 所有的操作都是以扇區sector進行操作的。 /**************************************************************************//** * @brief * Write to indirectly accessed media. * * @param[in] pCmd * Points to a MSDD_CmdStatus_TypeDef structure which holds info about the * current transfer. * * @param[in] data * Pointer to data buffer. * * @param[in] sectors * Number of 512 byte sectors to write to media. *****************************************************************************/ void Msd_Write( MSDD_CmdStatus_TypeDef *pCmd, uint8_t *data, uint32_t sectors ) { #if ( MSD_MEDIA == MSD_SRAM_MEDIA ) || ( MSD_MEDIA == MSD_PSRAM_MEDIA ) (void)pCmd; (void)data; (void)sectors; #endif
#if ( MSD_MEDIA == MSD_SDCARD_MEDIA ) disk_write( 2, data, pCmd->lba, sectors ); #endif
#if ( MSD_MEDIA == MSD_FLASH_MEDIA ) || ( MSD_MEDIA == MSD_NORFLASH_MEDIA ) unsigned int i; uint32_t offset;
i = 0; while ( i < sectors ) { if ( !flashStatus.pendingWrite ) { /* Copy an entire flash page to the page buffer */ flashStatus.pendingWrite = true; flashStatus.pPageBase = (uint8_t*)((uint32_t)pCmd->pData & ~( flashPageSize - 1 )); offset = pCmd->pData - flashStatus.pPageBase; memcpy( flashPageBuf, flashStatus.pPageBase, flashPageSize );
/* Write the received data in the page buffer */ //memcpy( flashPageBuf + offset, data, 512 ); //data += 512; //pCmd->pData += 512; memcpy( flashPageBuf + offset, data, 4096 ); data += 4096; pCmd->pData += 4096;
USBTIMER_Start( FLUSH_TIMER_ID, FLUSH_TIMER_TIMEOUT, FlushTimerTimeout ); } else { /* Check if current sector is located in the page buffer. */ offset = pCmd->pData - flashStatus.pPageBase; if ( offset >= flashPageSize ) { /* * Current sector not located in page buffer, flush pending data * before continuing. */ Msd_Flush(); i--; } else { /* Write the received data in the page buffer */ //memcpy( flashPageBuf + offset, data, 512 ); //data += 512; //pCmd->pData += 512; memcpy( flashPageBuf + offset, data, 4096 ); data += 4096; pCmd->pData += 4096;
USBTIMER_Start( FLUSH_TIMER_ID, FLUSH_TIMER_TIMEOUT, FlushTimerTimeout ); } } i++; } #endif }
以上的所有函數又會被msdd.c中的MSDD_Handler()函數進行調用 調用是根據USB協議棧傳下來的值去確定的。 bool MSDD_Handler(void) { static uint32_t len; /* Note: len is static ! */ switch (msdState) { case MSDD_ACCESS_INDIRECT: if (pCmdStatus->xferLen) { len = EFM32_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst); msdState = MSDD_IDLE; if (pCmdStatus->direction) { Msd_Read(pCmdStatus, mediaBuffer, len / 4096); //Msd_Read(pCmdStatus, mediaBuffer, len / 512); } UsbXferBotData(mediaBuffer, len, XferBotDataIndirectCallback); } else { /* We are done ! */ msdState = savedState; if (msdState == MSDD_SEND_CSW) { SendCsw(); EnableNextCbw(); msdState = MSDD_WAITFOR_CBW; } else if (msdState == MSDD_STALL_IN) { USBD_StallEp(MSD_BULK_IN); msdState = MSDD_WAIT_FOR_INUNSTALLED; } } break; case MSDD_WRITE_INDIRECT: Msd_Write(pCmdStatus, mediaBuffer, len / 4096); pCmdStatus->lba += len / 4096; msdState = MSDD_ACCESS_INDIRECT; break;
case MSDD_DO_CMD_TASK: if (pCbw->CBWCB[ 0 ] == SCSI_STARTSTOP_UNIT) { Msd_Flush(); } /* else if ( .... ) Add more when needed. */ SendCsw(); EnableNextCbw(); msdState = MSDD_WAITFOR_CBW; break; default: break; } return (msdState == MSDD_WAITFOR_CBW) || (msdState == MSDD_IDLE); }
只要USB中MSDD和MSD和MSC中的讀寫函數移植正確 ,就可以正常的數據讀寫和掛載。
1、單獨使用flash芯片,開發flash芯片的響應的驅動即可進行按照 絕對地址 的讀寫方式進行數據的存儲和讀取。一般的單片機只做存儲的可以這么做。 void W25q64_Spi_Init(void) 初始化flash芯片的驅動 void SPI_FLASH_BufferRead(uint32_t ReadAddr,uint8_t* pBuffer, uint16_t NumByteToRead) 形參1:flash的絕對地址 形參2:讀取到數據要存儲的位置 形參3:要讀取數據的大小 void SPI_FLASH_BufferWrite(uint32_t WriteAddr,uint8_t* pBuffer, uint16_t NumByteToWrite) 形參1:flash的絕對地址 形參2:讀寫到flash中的源數據存儲位置 形參3:要寫入數據的大小 2、flash驅動+文件系統 這個一般要對文件進行管理的時候使用,這時候文件只是存儲在flash的物理層中,只進行了文件系統的邏輯抽象,所有的操作只能在代碼中執行,外部接口不可見。 想要可見要進行接口虛擬例如SD卡。部分是集成在SD中的,不過這種情況不是很多。 DSTATUS disk_initialize (BYTE pdrv) 這個函數中調用上面的W25q64_Spi_Init()函數進行初始化并進行喚醒芯片。 DRESULT disk_read (BYTE pdrv,BYTE *buff,DWORD sector,UINT count) 調用上面的SPI_FLASH_BufferRead()函數進行數據的讀取,但是除此之外要進行你的flash的起始地址偏移和扇區大小的邏輯運算在里面。 /*形參 1、pdrv:設備物理編號 2、buff:讀取出來數據緩存區 3、sector:要讀取得扇區首地址 一個扇區大小是***字節 這個非常重要 每個型號的flash芯片可能不一樣,例如這個就是4096byte大小扇區 m256pe16這款芯片的扇區大小就是512byte,所以在進行邏輯地址運算的時候 這個要進行不同的邏輯地址計算。 4、count:扇區個數(1/2/3。。。128。。。) 操作的最小單位是扇區 不是極小頁 所以這個與M25PE的flash驅動有別 */ eg: #define Msd_Addr 0x50 0000 //這個定義是說明這個U盤的虛擬是從flash的地址0x50 0000 開始的直到結束 DRESULT disk_read (BYTE pdrv,BYTE *buff,DWORD sector,UINT count) { uint32_t address = 0; DRESULT status = RES_PARERR; switch(pdrv) { case ATA: //SD卡 break; case MMC: break; case MSD: //這個是內部flash的虛擬 address = sector*4096; if(count==1) { ReadFlash(address+Msd_Addr,buff,count*4096); //address+Msd_Addr 這個是進行地址偏移 } else { while(count-->0) { ReadFlash(address+Msd_Addr,buff,4096); //address+Msd_Addr 這個是進行地址偏移 address = address + 4096; buff = buff + 4096; } } break; default: status = RES_PARERR; } return status; } DRESULT disk_write (BYTE pdrv,const BYTE *buff,DWORD sector,UINT count) 這個函數調用的是SPI_FLASH_BufferWrite() 寫的時候一定要注意的一點是在寫的響應的地址上面要進行一次擦除操作,不然在windows平臺下 虛擬出U盤之后會出現無法格式化的現象。 /*形參 1、pdrv:設備物理編號(0,) 2、buff:預寫數據的緩沖區 3、sector:扇區首地址 4、count:扇區個數(1.2.。。128) */ DRESULT disk_write (BYTE pdrv,const BYTE *buff,DWORD sector,UINT count) { uint32_t address = 0; DRESULT status = RES_PARERR; if (!count) { return RES_PARERR; /* Check parameter */ } switch(pdrv) { case ATA: break; case MMC: break; case MSD: address = sector*4096; if(count==1) { SPI_FLASH_SectorErase(address+Msd_Addr); //把要寫入的數據的地址 要進行先擦除 重要 WriteFlash(address+Msd_Addr,(uint8_t*)buff,4096); } else { while(count-->0) { SPI_FLASH_SectorErase(address+Msd_Addr); //把要寫入的數據的地址 要進行先擦除 重要 WriteFlash(address+Msd_Addr,(uint8_t*)buff,4096); //address+Msd_Addr地址偏移 address = address + 4096; buff = buff + 4096; } } break; default: status = RES_PARERR; break; } return status; } DRESULT disk_ioctl (BYTE pdrv,BYTE cmd,void *buff) 這個函數很重要奧 里面這些東西在你的U盤被windows識別之前會進行里面的參數進行提取 例如: DRESULT disk_ioctl (BYTE pdrv,BYTE cmd,void *buff) //Miscellaneous Functions { DRESULT status = RES_PARERR; switch(pdrv) { case ATA: break; case MMC: break; case MSD: switch(cmd) { case CTRL_SYNC: break; case GET_BLOCK_SIZE: //同時擦除的扇區個數 *(DWORD*)buff = 1; //這個是 一個塊區 包含多少個 扇區的個數 一般擦除時候用 針對支持塊擦除的介質 break; case GET_SECTOR_COUNT: //GET_SECTOR_COUNT * GET_SECTOR_SIZE + 基地址 = U盤空間結束地址 *(DWORD*)buff = (ALL_FLASH_ADDR-Msd_Addr)/4096; //這個是U盤有多少扇區數量 這個是給到window讀取的 break; case GET_SECTOR_SIZE: //扇區大小 *(WORD*)buff = 4096; break; } status = RES_OK; break; default: status = RES_PARERR; break; } return status; // Process of the command the USB drive } GET_BLOCK_SIZE:這個命令獲取的時候,你返回的內容會影響到擦除和寫入的速度。 =1:說明 一次只能擦除一個扇區 這個開大 會寫入的速率升高,但是這個會占用ram空間,所以我們最好是根據自己的實景情況進行設置。 這個是進行塊擦除的 大小,意思是一個塊區 包含多少個 扇區 GET_SECTOR_COUNT: 這個獲取的就是 你的U盤的大小,大小的值一定要與你實際的flash起始和結束地址對應,不然那的話 會掛載失敗。 公式可以這樣寫或者其他辦法也可以: *(DWORD*)buff = (ALL_FLASH_ADDR-Msd_Addr)/4096; ALL_FLASH_ADDR:這個是flash的結束地址 可以是flash的最大的末尾地址 也可以是比 起始地址大的任意位置。 Msd_Addr:這個是U盤的虛擬地址的起始地址。 4096這個是一個sector的大小,不同的芯片可能會不一樣,這個為了可移植一性高的話,可以做個宏定義。 GET_SECTOR_SIZE: 這個就是進行獲取一個扇區的大小
DWORD get_fattime(void) 這個函數是記錄對文件操作的時間,有改動的話會進行時間戳的記錄。這個最好進行移植一下,不過不進行移植的話,對數據存儲功能貌似沒有多大的影響。
3、flash驅動+fatfs文件系統+USB協議棧 這種方式也是用的最為廣泛的了,在一些小型嵌入式系統中,只要你的flash芯片大小足夠大,都可以虛擬出來U盤,在windows平臺上進行傻瓜操作。 USB中的功能包含很多: HID,CDC,MSC,HUB。。。我們這里只介紹在MSC中進行U盤掛載這一部分。 新定義一下U盤的代碼文件,假設是MSD.c
我們對u盤進行初始化: Msd_Init() 這里面調用: if ( disk_initialize( 2 ) != 0 ) // 進行初始化flash芯片 調用disk_initialize() 2參數 是邏輯驅動號 這個驅動號 是在diskio.c中定義的 return false; /* Get numSectors from media. */ if ( disk_ioctl( 2, GET_SECTOR_COUNT, &numSectors ) != RES_OK ) return false; //這個是進行 U盤屬性的獲取 調用disk_ioctl()函數 #define ATA 0 //u盤邏輯驅動號是 0 #define MMC 1 //u盤邏輯驅動號是 1 #define MSD 2 //u盤邏輯驅動號是 2
對U盤進行讀操作 void Msd_Read( MSDD_CmdStatus_TypeDef *pCmd, uint8_t *data, uint32_t sectors ) 調用disk_read( 2, data, pCmd->lba, sectors )函數 /**************************************************************************//** * @brief * Read from indirectly accessed media. * * @param[in] pCmd * Points to a MSDD_CmdStatus_TypeDef structure which holds info about the * current transfer. * * @param[in] data * Pointer to data buffer. * * @param[in] sectors * Number of 512 byte sectors to read from media. *****************************************************************************/ void Msd_Read( MSDD_CmdStatus_TypeDef *pCmd, uint8_t *data, uint32_t sectors ) { #if ( MSD_MEDIA == MSD_SRAM_MEDIA ) || ( MSD_MEDIA == MSD_PSRAM_MEDIA ) (void)pCmd; (void)data; (void)sectors; #endif
#if ( MSD_MEDIA == MSD_SDCARD_MEDIA ) disk_read( 2, data, pCmd->lba, sectors ); #endif
#if ( MSD_MEDIA == MSD_FLASH_MEDIA ) || ( MSD_MEDIA == MSD_NORFLASH_MEDIA ) /* Write pending data to flash before starting the read operation. */ Msd_Flush(); //memcpy( data, pCmd->pData, sectors * 512 ); //pCmd->pData += sectors * 512; memcpy( data, pCmd->pData, sectors * 4096 ); pCmd->pData += sectors * 4096; #endif } 對U盤進行寫操作 void Msd_Write( MSDD_CmdStatus_TypeDef *pCmd, uint8_t *data, uint32_t sectors ) 調用 disk_write( 2, data, pCmd->lba, sectors )函數 所有的操作都是以扇區sector進行操作的。 /**************************************************************************//** * @brief * Write to indirectly accessed media. * * @param[in] pCmd * Points to a MSDD_CmdStatus_TypeDef structure which holds info about the * current transfer. * * @param[in] data * Pointer to data buffer. * * @param[in] sectors * Number of 512 byte sectors to write to media. *****************************************************************************/ void Msd_Write( MSDD_CmdStatus_TypeDef *pCmd, uint8_t *data, uint32_t sectors ) { #if ( MSD_MEDIA == MSD_SRAM_MEDIA ) || ( MSD_MEDIA == MSD_PSRAM_MEDIA ) (void)pCmd; (void)data; (void)sectors; #endif
#if ( MSD_MEDIA == MSD_SDCARD_MEDIA ) disk_write( 2, data, pCmd->lba, sectors ); #endif
#if ( MSD_MEDIA == MSD_FLASH_MEDIA ) || ( MSD_MEDIA == MSD_NORFLASH_MEDIA ) unsigned int i; uint32_t offset;
i = 0; while ( i < sectors ) { if ( !flashStatus.pendingWrite ) { /* Copy an entire flash page to the page buffer */ flashStatus.pendingWrite = true; flashStatus.pPageBase = (uint8_t*)((uint32_t)pCmd->pData & ~( flashPageSize - 1 )); offset = pCmd->pData - flashStatus.pPageBase; memcpy( flashPageBuf, flashStatus.pPageBase, flashPageSize );
/* Write the received data in the page buffer */ //memcpy( flashPageBuf + offset, data, 512 ); //data += 512; //pCmd->pData += 512; memcpy( flashPageBuf + offset, data, 4096 ); data += 4096; pCmd->pData += 4096;
USBTIMER_Start( FLUSH_TIMER_ID, FLUSH_TIMER_TIMEOUT, FlushTimerTimeout ); } else { /* Check if current sector is located in the page buffer. */ offset = pCmd->pData - flashStatus.pPageBase; if ( offset >= flashPageSize ) { /* * Current sector not located in page buffer, flush pending data * before continuing. */ Msd_Flush(); i--; } else { /* Write the received data in the page buffer */ //memcpy( flashPageBuf + offset, data, 512 ); //data += 512; //pCmd->pData += 512; memcpy( flashPageBuf + offset, data, 4096 ); data += 4096; pCmd->pData += 4096;
USBTIMER_Start( FLUSH_TIMER_ID, FLUSH_TIMER_TIMEOUT, FlushTimerTimeout ); } } i++; } #endif }
以上的所有函數又會被msdd.c中的MSDD_Handler()函數進行調用 調用是根據USB協議棧傳下來的值去確定的。 bool MSDD_Handler(void) { static uint32_t len; /* Note: len is static ! */ switch (msdState) { case MSDD_ACCESS_INDIRECT: if (pCmdStatus->xferLen) { len = EFM32_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst); msdState = MSDD_IDLE; if (pCmdStatus->direction) { Msd_Read(pCmdStatus, mediaBuffer, len / 4096); //Msd_Read(pCmdStatus, mediaBuffer, len / 512); } UsbXferBotData(mediaBuffer, len, XferBotDataIndirectCallback); } else { /* We are done ! */ msdState = savedState; if (msdState == MSDD_SEND_CSW) { SendCsw(); EnableNextCbw(); msdState = MSDD_WAITFOR_CBW; } else if (msdState == MSDD_STALL_IN) { USBD_StallEp(MSD_BULK_IN); msdState = MSDD_WAIT_FOR_INUNSTALLED; } } break; case MSDD_WRITE_INDIRECT: Msd_Write(pCmdStatus, mediaBuffer, len / 4096); pCmdStatus->lba += len / 4096; msdState = MSDD_ACCESS_INDIRECT; break;
case MSDD_DO_CMD_TASK: if (pCbw->CBWCB[ 0 ] == SCSI_STARTSTOP_UNIT) { Msd_Flush(); } /* else if ( .... ) Add more when needed. */ SendCsw(); EnableNextCbw(); msdState = MSDD_WAITFOR_CBW; break; default: break; } return (msdState == MSDD_WAITFOR_CBW) || (msdState == MSDD_IDLE); }
只要USB中MSDD和MSD和MSC中的讀寫函數移植正確 ,就可以正常的數據讀寫和掛載。
總結
以上是生活随笔為你收集整理的USB2.0挂载FatFs文件系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用地球同步卫星在一个1Mbps的信道上
- 下一篇: HDU 5514 题解