1. 程式人生 > >移植fatfs上電覆位前兩次不能正確開啟檔案解決方法

移植fatfs上電覆位前兩次不能正確開啟檔案解決方法

最近移植了fatfs到stm32,昨晚寫進了第一個txt檔案,然後就睡覺了,以為移植差不多了,今晚試了一下,發現不好用了,
res = f_open(&file, "text.txt", FA_OPEN_ALWAYS  | FA_READ | FA_WRITE);  但是復位兩次就可以用了,跟蹤發現的確是正好兩次;
查網上有人說把MISO改為上拉,我試了下沒有效果,決定自己跟蹤找錯誤;
跟蹤發現f_open res返回1,對應FR_DISK_ERR 底層驅動錯誤
繼續跟蹤發現是f_open呼叫的chk_mounted的這一句fmt = check_fs(fs, bsect);檢查檔案系統錯誤;

繼續跟蹤發現 check_fs裡的第一句if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK)return 3;直接錯誤返回3;
繼續跟蹤disk_read發現是讀扇區函式res = MSD_ReadSingleBlock(sector, buff); 返回res=1
繼續跟蹤MSD_ReadSingleBlock發現是
.......................................
............................
r1 = _send_command(CMD17, sector, 0);//獨一塊命令 if(r1 != 0x00)//r1!=0x00,則接收命令錯誤 { return 1;//返回寫塊錯誤 } // Start read and return the result r1 = _read_buffer(buffer, MSD_BLOCKSIZE, RELEASE);//讀MSD_BLOCKSIZE(512)個位元組資料到buffer,讀完後release

.................................
............................................
就是讀資料時候錯誤返回1;
而當我想跟蹤_read_buffer的時候發現只要跟蹤進去,就不會返回錯誤1,正確的返回0,很是頭大,然後仔細想一想,在r1 = _read_buffer這裡設定斷點跟蹤就沒錯誤,應該是和這裡的時序有關,因為除錯和實際執行直接時間的差別;
然後看了下_send_command(CMD17, sector, 0)時序圖


斷點設定的是畫紅圈的那裡,說明延長這個時間,問題就會解決;
_read_buffer裡是通過以下一段延時的

.......................................
............................
for(retry=0; retry<2000; retry++) { r1 = _spi_read_write(DUMMY_BYTE); if(r1 == 0xFE)//成功 {  retry = 0;//成功標誌 break; } } // Timeout return超時 if(retry == 2000) { _card_disable();//關片選  return 1;//返回超時錯誤 }
.......................................
............................
程式為retry自加到2000就返回r1超時錯誤,設定斷點在 return 1;//返回超時錯誤 這一句,也的確會執行到這裡;
於是把程式改為for(retry=0; retry<4000; retry++),錯誤解決了,後來跟蹤發現這裡復位次retry都會自加到0x855(2133),正好超出2000!

整個錯誤按理說應該很好查,但是由於是復位前兩次,而且錯誤和時序有關,設定斷點的位置會影響錯誤存在與否,所以每一次除錯都要斷電,上電,開啟除錯,設定斷點,所以跟蹤到這個錯誤非常麻煩,也用了我一晚上的時間,寫下這個,希望其他人有類似的錯誤可以參考下。

還有不明白的地方是:

1.為什麼只在復位前兩次出現這個問題?
2.chk_mounted裡兩次呼叫check_fs,也就是兩次呼叫disk_read,同樣就是兩次呼叫_read_buffer,跟蹤發現總是第二次才出現這個錯誤,第一次和第二次唯一的區別是第一次讀的是物理0扇區,第二次讀的是物理8192扇區(我的8G SDHC,邏輯0扇區在物理扇區的8192扇區),是不是因為扇區地址大,定址時間長了?那同樣讀更大的扇區會不會耗時更長?