FATS文件系統(tǒng)移植經(jīng)驗_第1頁
FATS文件系統(tǒng)移植經(jīng)驗_第2頁
FATS文件系統(tǒng)移植經(jīng)驗_第3頁
FATS文件系統(tǒng)移植經(jīng)驗_第4頁
FATS文件系統(tǒng)移植經(jīng)驗_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

1、STM32 FatFS 移植經(jīng)驗分享STM32中 FatFS移植前言與廢話 做項目時網(wǎng)找資料,不會的東西上網(wǎng)查閱一下多半可以解決,一些尚未解決的問題也會有所啟發(fā)。最近由于項目的需要,仔細閱讀了SD卡相關內(nèi)容,順藤摸瓜學習FatFS。網(wǎng)上關于SD卡和FatFS的內(nèi)容非常的多,重復的部分我就不介紹了,我把移植和使用部分的經(jīng)驗和大家分享一下。剛開始的時候,我找來一些現(xiàn)成的代碼研究一下,不用說看的是一頭霧水??碏atFS示例代碼,也不知如何移植。最后還是下定決心,慢慢的閱讀FatFS的相關文檔和范例代碼,對于移植部分一點一點的研究,相信一定會有所收獲。 一、硬件準備 開始移植之前,你必須要有一塊SD卡

2、。從形狀上來說,有普通的SD卡,有很小的microSD卡,microSD卡就是手機中長見的TF卡。購買microSD卡的時候,往往會附帶一個SD卡套,那么小個頭的microSD卡就變成了普通的SD卡,接口都是一樣的。 但是還是您注意了,建議大家購買2G以下的SD卡(如果可以的話,買個128M的SD卡就可以達到實驗的效果,價格也非常便宜)。剛開始移植的時候,我使用了4G的SD卡,但是發(fā)現(xiàn)程序無法完成SD卡的初始化。查閱網(wǎng)上相關的資料,發(fā)現(xiàn)SD卡技術已2G作為分界線,大于或者等于4G的卡屬于高速SD卡,和小于或者等于4G的SD卡略有區(qū)別。二、軟件準備 在進行移植之前,先編寫一些最簡單的STM32程

3、序。在調(diào)試之前,我都會完成USART的初始化和發(fā)送函數(shù),通過串口把STM32的運行狀態(tài)打印出來,這樣配合Jlink硬件調(diào)試,可以很快的找到錯誤。由于SD卡可以使用SPI進行讀寫操作,所以還需要完成SPI的初始化工作。 先來說一下USART的操作,我個人比較喜歡使用系統(tǒng)的printf函數(shù),所以還需要引入stdio頭文件。在IAR中必須設定option的某個選項。如下圖所示。 2012-4-3 16:51 上傳下載附件 (85.65 KB) 除了完成USART的初始化工作以外,還需要重寫fputc函數(shù),具體的代碼如下。1. int fputc(int ch, FILE * f)2. 3. USAR

4、T_SendData(USART1, (uint8_t)ch);4. while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) = RESET ); 5. return ch;6. 復制代碼然后說一下SPI的初始化工作。閱讀網(wǎng)上的代碼,發(fā)現(xiàn)STM32 V2的庫函數(shù)和V3函數(shù)中,關于SPI端口初始化的部分還是有些出入的。 V2庫中,把SCK,MOSI,MISO全部設置為復用輸出。而V3庫中,SCK,MOSI設置為復用輸出,而MISO設置為浮動輸入。在SD的SPI接口中,SCK,MOSI和MOSI,甚至包括CS都使用了上拉電阻。您需要注意一下幾點1. 沒有

5、上拉電阻時 MISO應該如何設置由于我的開發(fā)板中沒有使用上拉電阻,若設定MISO為浮動輸入的話,或許會有某些問題,由于SD卡的輸出端口驅(qū)動能力很弱,很有可能就接收不到返回數(shù)據(jù),事實也正是如此。所以MISO最后被我甚至成了上拉輸入模式,具體的代碼如下。(所以還是要相信過來人的電路圖,老實的加一個上拉電阻。)2. SPI的模式應該如何選擇 SPI的速度不能太快,在初始化時時鐘設為400k以下為宜。3. SPI的速度應該如何選擇 SD卡使用SPI的模式0和模式3,這兩個模式是等價的。1. void SPI1_Config(void)2. 3. /使能APB2上相關時鐘4. /使能SPI時鐘,使能GP

6、IOA時鐘5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 |6. RCC_APB2Periph_GPIOA ,ENABLE );7. /定義一個GPIO結(jié)構(gòu)體8. GPIO_InitTypeDefGPIO_InitStructure; 9.10. /SPI SCK MOSI11. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7; 12. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 13. GPIO_InitStructure.GPIO_Mo

7、de = GPIO_Mode_AF_PP;/復用推挽輸出14. GPIO_Init(GPIOA, &GPIO_InitStructure); 15.16. /SPI MISO17. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; 18. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 19. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;/上拉輸入20. GPIO_Init(GPIOA, &GPIO_InitStructure); 21. 22. /自定義SPI結(jié)

8、構(gòu)體23. SPI_InitTypeDef SPI_InitStructure;24. /雙線雙向全雙工25. SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 26. /主機模式27. SPI_InitStructure.SPI_Mode = SPI_Mode_Master; 28. /8位幀結(jié)構(gòu)29. SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; 30. /時鐘空閑時為低31. SPI_InitStructure.SPI_CPOL = SPI_CPOL_

9、Low; 32. /第一個上升沿捕獲數(shù)據(jù)。模式,033. SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; 34. /MSS 端口軟件控制,實際沒有使用35. SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; 36. /SPI時鐘72Mhz / 256 = 281.25K 400K37. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; 38. /數(shù)據(jù)傳輸高位在前39. SPI_InitStructure.SPI_FirstBit =

10、 SPI_FirstBit_MSB; 40. SPI_InitStructure.SPI_CRCPolynomial = 7;/41. /初始化SPI142. SPI_Init(SPI1, &SPI_InitStructure);43. /使能SPI1 44. SPI_Cmd(SPI1, ENABLE); 45. 復制代碼除了初始化操作以外,還需要一個SPI發(fā)送函數(shù)和一個SPI接收函數(shù)。由于SPI是同步通信方式,所以SPI接收函數(shù),實際上只需要發(fā)送0xFF就可以,具體的代碼如下。1. uint8_t SPI1_SendByte(uint8_t byte)2. 3. /等待發(fā)送緩沖寄存器為空4.

11、 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) = RESET);5. /發(fā)送數(shù)據(jù)6. SPI_I2S_SendData(SPI1, byte); 7. /等待接收緩沖寄存器為非空8. while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) = RESET);9. /返回從SPI通信中接收到的數(shù)據(jù)10. return SPI_I2S_ReceiveData(SPI1);11. 12. uint8_t SPI1_ReceiveByte()13. 14. /等待發(fā)送緩沖寄存器為空15.

12、while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) = RESET);16. /發(fā)送數(shù)據(jù),通過發(fā)送xff,獲得返回數(shù)據(jù)17. SPI_I2S_SendData(SPI1, 0xff); 18. /等待接收緩沖寄存器為非空19. while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) = RESET);20. /返回從SPI通信中接收到的數(shù)據(jù)21. return SPI_I2S_ReceiveData(SPI1);22. 復制代碼三、移植前的“心靈”準備 “移植”實際上就是研究他人的代碼,你

13、必須敏銳的看清代碼的核心內(nèi)容,了解你必須要做什么,哪一些可以以后再實現(xiàn)。在移植的初步階段,我建議您使用最簡單的方法完成某些內(nèi)容,而不是去重視代碼效率。例如,在移植過程中需要使用到延時函數(shù),可以使用軟件延時,可以配合Systick延時,甚至可以使用uCOS的延時函數(shù)。但是我建議您在面對選擇的時候選擇最簡單的函數(shù)軟件延時,雖然它不準確效率也不高,但是您可以把更多的精力投入到其他重要的內(nèi)容中去,你會覺得移植是那么簡單,而延時函數(shù)的效率提高是錦上添花的事情。 例如您在移植之前會查看FatFS中關于STM32的移植范例。在該范例中,有關于SD卡插入,SD卡上電控制,SD卡寫保護檢測的函數(shù)。除了這些函數(shù)之

14、外,代碼中通過宏定義的方法,可以選擇使用DMA來傳送SPI數(shù)據(jù),初始化SD卡時使用低速SPI,讀寫塊的時候使用高速SPI,雖然這些改動讓您覺得代碼強大而高效,但是對您的移植一定用處都沒有。您需要從最簡單的generic開始,如果從這個文件開始,您會覺得移植是那么的簡單,僅需要十幾分鐘。我相信您看完文章就會了,其實非常的簡單。四、移植開始從generic開始 您所需要操作的只是mmcbb文件,里面主要包括SD卡的初始化、讀塊和寫塊函數(shù)。其實修改僅需要三步。 第一步,修改宏定義,添加合適的頭文件,添加延時函數(shù) 第二步,修改多字節(jié)發(fā)送函數(shù) 第三步,修改多字節(jié)接收函數(shù) 下面我通過原代碼和移植代碼的比較

15、,來說明這個移植問題。4.1修改頭文件和宏定義原代碼如下1. /* Include device specific declareation file here */2. #include 3. /* Initialize MMC control port (CS/CLK/DI:output, DO/WP/INS:input) */4. #define INIT_PORT() init_port(); 5. /* Delay n microseconds */6. #define DLY_US(n) dly_us(n); 7.8. #define CS_H() bset(P0) /* Set

16、MMC CS high */9. #define CS_L() bclr(P0) /* Set MMC CS low */10. #define CK_H() bset(P1) /* Set MMC SCLK high */11. #defineCK_L() bclr(P1) /* Set MMC SCLK low */12. #define DI_H() bset(P2) /* Set MMC DI high */13. #define DI_L() bclr(P2) /* Set MMC DI low */14. #define DO btest(P3) /* Get MMC DO val

17、ue (high:true, low:false) */15.16. /* Socket: Card is inserted (yes:true, no:false, default:true) */17. #define INS (1) 18. /* Socket: Card is write protected (yes:true, no:false, default:false) */.19. #define WP (0) 復制代碼=修改后的代碼如下=1. /* Include device specific declareation file here */2. #include st

18、m32f10x.h3. #include spi1.h4. #include 5. /* Initialize MMC control port (CS/CLK/DI:output, DO/WP/INS:input) */6. #define INIT_PORT() init_port(); 7. /* Set MMC CS high */8. #define CS_H() GPIO_SetBits(GPIOE,GPIO_Pin_7)9. /* Set MMC CS low */10. #define CS_L() GPIO_ResetBits(GPIOE,GPIO_Pin_7)11. /*

19、Delay n microseconds */12. #define DLY_US(n) dly_us(n); 13. /* Socket: Card is inserted (yes:true, no:false, default:true) */14. #define INS (1) 15. /* Socket: Card is write protected (yes:true, no:false, default:false) */16. #define WP (0) 復制代碼使用STM32時需要包含STM3210x頭文件;spi1.h包括了spi相關操作函數(shù)。修改了CS操作的宏定義。

20、 除了一個宏定義外,還需要些一個延時函數(shù)和一個初始化函數(shù)。延時函數(shù)使用軟件延時,很不精確,但是可以說明問題。初始化函數(shù),只是配置CS端口,而SPI初始化工作在調(diào)用fatfs API函數(shù)時已完成初始化。(若是SPI初始化也完成了CS的操作,init_port()可以省略)1. /初始化端口2. void init_port()3. 4. /初始化時鐘GPIOE5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE ,ENABLE );6. /配置GPIOE.77. /定義一個GPIO結(jié)構(gòu)體8. GPIO_InitTypeDefGPIO_InitStructu

21、re; 9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; 10. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 11. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;12. GPIO_Init(GPIOE, &GPIO_InitStructure); 13. 14. /軟件演示函數(shù)15. void dly_us(uint16_t n)16. 17. for( ; n 0 ; n-)18. for(uint8_t i = 100 ; i 0 ; i-);

22、19. 20.復制代碼4.2 多字節(jié)發(fā)送函數(shù)原代碼和修改后的代碼如下。1. static2. void xmit_mmc (3. const BYTE* buff, /* Data to be sent */4. UINT bc /* Number of bytes to send */5. )6. 7. BYTE d;8. do 9. d = *buff+; /* Get a byte to be sent */10. if (d & 0x80) DI_H(); else DI_L(); /* bit7 */11. CK_H(); CK_L();12. if (d & 0x40) DI_H(

23、); else DI_L(); /* bit6 */13. CK_H(); CK_L();14. if (d & 0x20) DI_H(); else DI_L(); /* bit5 */15. CK_H(); CK_L();16. if (d & 0x10) DI_H(); else DI_L(); /* bit4 */17. CK_H(); CK_L();18. if (d & 0x08) DI_H(); else DI_L(); /* bit3 */19. CK_H(); CK_L();20. if (d & 0x04) DI_H(); else DI_L(); /* bit2 */21

24、. CK_H(); CK_L();22. if (d & 0x02) DI_H(); else DI_L(); /* bit1 */23. CK_H(); CK_L();24. if (d & 0x01) DI_H(); else DI_L(); /* bit0 */25. CK_H(); CK_L();26. while (-bc);27. 28.復制代碼=修改后的代碼=1. static void xmit_mmc (const BYTE* buff, UINT bc)2. 3. BYTE d;4. do 5. /* Get a byte to be sent */6. d = *buff

25、+; 7. /通過SPI發(fā)送8. SPI1_SendByte(d);9. while (-bc);10. 11.復制代碼4.3 多字節(jié)接收函數(shù)原代碼和修改后的代碼如下。1. static2. void rcvr_mmc (3. BYTE *buff, /* Pointer to read buffer */4. UINT bc /* Number of bytes to receive */5. )6. 7. BYTE r;8. DI_H(); /* Send 0xFF */9. do 10. r = 0; if (DO) r+; /* bit7 */11. CK_H(); CK_L();12

26、. r = 1; if (DO) r+; /* bit6 */13. CK_H(); CK_L();14. r = 1; if (DO) r+; /* bit5 */15. CK_H(); CK_L();16. r = 1; if (DO) r+; /* bit4 */17. CK_H(); CK_L();18. r = 1; if (DO) r+; /* bit3 */19. CK_H(); CK_L();20. r = 1; if (DO) r+; /* bit2 */21. CK_H(); CK_L();22. r = 1; if (DO) r+; /* bit1 */23. CK_H(

27、); CK_L();24. r = 1; if (DO) r+; /* bit0 */25. CK_H(); CK_L();26. *buff+ = r; /* Store a received byte */27. while (-bc);28. 29.復制代碼=修改后的函數(shù)=1. static void rcvr_mmc ( BYTE *buff, UINT bc )2. 3. BYTE r;4.5. do 6. /重新賦值7. r = 0; 8. /通過SPI獲得數(shù)據(jù)9. r = SPI1_ReceiveByte();10. /* Store a received byte */11.

28、*buff+ = r; 12. while (-bc);13. 復制代碼在這里多說一句,源代碼中DI_H(); /* Send 0xFF */ 作者的本意應該是把IO設為輸入狀態(tài),51系列單片機就是這么操作的,但是寫代碼注釋寫成了發(fā)送0xFF,其實并不需要發(fā)送0xFF。到這里就完成了fatfs的STM32移植工作,雖然只有簡單的三步,但是卻花了我整整三天的時間。我想您看了這樣的描述,不知道能否在10分鐘之內(nèi)完成修改。五 FatFS初步使用 接下來就是使用FatFS了,看了這個函數(shù)我找回了當初初學C語言的感覺,打開一個文件,然后讀一些數(shù)據(jù),然后創(chuàng)建另一個文件,在文件中寫一些數(shù)據(jù),最后關閉文件。1

29、. int main(void)2. 3. /初始化Systick4. RCC_Config();5. /初始化串口6. USART1_Config();7. /初始化SPI18. SPI1_Config();9. printf(start to read filen);10. /* Register volume work area (never fails) */11. f_mount(0, &fatfs); 12. printf(nOpen a test file (test.txt).n);13. rc = f_open(&fil, test.txt, FA_READ);14. if

30、(rc) die(rc); 15. 16. printf(nType the file content.n);17. for (;) 18. rc = f_read(&fil, buff, sizeof(buff), &br); /* Read a chunk of file */19. if (rc | !br) break; /* Error or end of file */20. for (i = 0; i br; i+) /* Type the data */21. putchar(buffi);22. 23. if (rc) die(rc);24.25. printf(nClose

31、 the file.n);26. rc = f_close(&fil);27. if (rc) die(rc);28.29. printf(nCreate a new file (hello.txt).n);30. rc = f_open(&fil, HELLO.TXT, FA_WRITE | FA_CREATE_ALWAYS);31. if (rc) die(rc);32.33. printf(nWrite a text data. (Hello world!)n);34. rc = f_write(&fil, Hello world!rn, 14, &bw);35. if (rc) die(rc);36. printf(%u bytes written.n, bw);37.38. printf(nClose the file.n);39. rc = f_close(&fil);40. if (rc) die(rc);41. 42. while (1)43. 44. 45. 46.復制代碼如果出現(xiàn)失敗的話,程序會進入die函數(shù),該函數(shù)會輸出錯誤代碼,并進入一個無限循環(huán)。通過串口的輸出

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論