1、setenv 命令
該命令用於設定環境變數,用法介紹如下
# setenvsetenv - set environment variablesUsage:setenv name value ... - set environment variable 'name' to 'value ...'setenv name - delete environment variable 'name'
如介紹所述,當要設定環境變數時,用法如:
setenv name value,當要刪除環境變數時,用法如:
setenv name。函數的實現多數為字串處理流程,在完成處理後會更新當前 env 的
crc 校正值。這個命令的操作都是在記憶體中進行的,如果不寫入emmc重啟就會丟失,儲存則需要用
saveenv 命令將記憶體中的所有env都寫入emmc中。
2、mmc 命令
該命令用於初始化 SD 儲存卡,用法介紹如下
mmc - MMC sub-systemUsage:mmc init [dev] - init MMC sub systemmmc device [dev] - show or set current device
如介紹所述,當要初始化 SD 儲存卡時,用法如:
mmc init [dev],其中 dev 可以指定裝置編號,預設編號為 1。用法:
mmc device [dev] 顯示當前裝置或者設定當前裝置為 dev 編號的裝置。
3、fatload 命令
該命令用於從 FAT 檔案系統裝置中讀取指定檔案放入指定記憶體中,用法介紹如下:
usage: fatload <interface> <dev[:part]> <addr> <filename> [bytes]
如介紹所述,當要讀取檔案時,需要裝置已經完成初始化並註冊到檔案系統中,讀取時用法如:
fatload mmc 1 0x81000000 boot.img[size],其中 mmc 1 為檔案 boot.img 儲存的裝置,0x81000000 為讀取的內容存放的記憶體位址。
4、fatinfo 命令
該命令用於查看 FAT 格式裝置的基本資料,用法介紹如下:
usage: fatinfo <interface> <dev[:part]>
在使用該命令的時候直接指定需要查看的裝置和編號即可,如:
fatinfo mmc 1,結果如下:
Interface: MMC Device 0: Vendor: Rev: Prod: Type: Hard Disk Capacity: 3789.0 MB = 3.7 GB (7759872 x 512)Partition 1: Filesystem: FAT32 "NO NAME "
5、fatls 命令
該命令用於查看 FAT 格式裝置的目錄和檔案資訊,用法介紹如下:
usage: fatls <interface> <dev[:part]> [directory]
在使用該命令的時候需要指定裝置及其編號,預設目錄為根目錄,如果想查看其它目錄則可以通過 [directory] 參數指定,如:
fatls mmc 1 customized,結果如下:
./ ../ 4106240 arm_tools.tar 1713 readme_cn.txt gen_customer/2 file(s), 3 dir(s)
6、fatname 命令
該命令用於從 FAT 格式裝置的根目錄讀取指定檔案,用法介紹如下:
usage: fatname <interface> <dev[:part]> <filename>
在使用該命令的時候同樣需要指定裝置和編號,如果該檔案存在則會返回讀回資料的長度,如果檔案不存在則返回 -1 並在命令列列印相關訊息,用法如:fatname mmc 1 fire。
附:uboot 調試經驗
1、燒錄問題:以前經常遇到用串口燒錄 xloader、uboot、boot 的時候串口傳輸出錯,就會導致燒錄失敗並且開不了機,而且在雙 uboot 的情況下仍然開不了機。只能用硬體的方式進入強制燒錄模式才行。在查看相關源碼後發現在燒錄的時候不管傳輸的鏡像檔案是否完整,都會去做燒錄的動作,而且只對傳輸過去的內容做crc校正,這也造成了crc校正失去了應有的意義。
解決方案:在燒錄動作之前加入了鏡像完整性檢測,如果載入的鏡像不完整就不會更新emmc中原有的鏡像,這樣就解決此問題了。
2、環境變數丟失的問題:有的時候會發現系統裡面的一些重要參數(如:電池電量表、充電電流等)丟掉了,這些參數是通過 uboot 環境變數的形式儲存在 emmc 中的,如果這些重要參數丟掉了會導致嚴重的問題,但遇到這種情況的機率比較小,就一直認為是 emmc 的隨機問題,還做了環境變數備份的機制。後來通過客戶那邊的反饋資訊才發現一種必現的情況,就是開機的時候一起按住Power 鍵 +音量加鍵 ,按照這種情況,系統應該進入燒錄模式,也就是會從 SD 記憶卡中讀取鏡像開始燒錄了,如果 SD 記憶卡沒有系統鏡像則會燒錄失敗,而測試到的情況表明燒錄失敗後,重啟手機那些環境變數就已經丟掉了。
解決方案:分析代碼才發現原來只要進入燒錄模式的第一個動作就是擦除原有的環境變數,而不管使用者是否有插入 SD 記憶卡或者 SD 記憶卡中是否有鏡像,於是將擦除環境變數的動作移動到了 uboot 燒錄完成之後,這樣就能保證使用者誤操作開機不會導致環境變數異常丟失了。
3、環境變數備份:為了防止 emmc 或者 nand 異常出錯導致環境變數錯誤,需要對環境變數做一個備份。
解決方案:系統的環境變數(env1)儲存在 emmc 位移為 0x400000 的地址處,長度只有 8192,在設計時為環境變數預留的儲存空間為 2M,所以有很大的空間可以用來做備份(env2),現在選定位移地址為 0x480000 為備份起始地址,長度同樣為 8192。在開機的時候,會分別對兩處環境變數分別做 crc 檢驗,然後與其儲存的 crc 校正值比較,如果相同則表示環境變數沒有錯誤,如果不同則說明當前環境變數出錯,如果出錯了則將正確的那處環境變數讀到記憶體中使用,並將出錯的那處環境變數重寫,如果兩處都出錯,則應該維修了。為了簡化處理流程,在寫新的環境變數的時候,同時會寫到兩處,寫的過程則是先完成 env1 的擦除和重寫再做 env2 的擦除和重寫同時更新 crc 校正值。在 uboot 中把不必要的環境變數都去掉了,這樣一般只有在燒錄系統的時候才會對環境變數有改寫,這樣也減少了出錯的機率。以下是開機時判斷環境變數是否出錯的代碼:
void env_relocate_spec (void){int crc1_ok = 0, crc2_ok = 0, b_save_env = 0;env_t *tmp_env1, *tmp_env2;/* 申請兩塊記憶體用來儲存從 emmc 讀取出來的環境變數 */tmp_env1 = (env_t *) malloc(CONFIG_ENV_SIZE);tmp_env2 = (env_t *) malloc(CONFIG_ENV_SIZE);/* 讀取環境變數 */if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))printf("No Valid First Environment Area Found\n");if (readenv(CONFIG_ENV_BK_OFFSET, (u_char *) tmp_env2))printf("No Valid Secondary Environment Area Found\n");/* 對環境變數做 crc 校正並與儲存值比較 */crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);/* 判斷環境變數是否出錯 */if(!crc1_ok && !crc2_ok) {free(tmp_env1);free(tmp_env2);printf("Env crc1 and crc2 is not OK\n");return use_default();} else if(crc1_ok && !crc2_ok) {gd->env_valid = 1;b_save_env = 1;} else if (!crc1_ok && crc2_ok) {gd->env_valid = 2;} else {/* both ok - check serial */if(tmp_env1->crc == 0 && tmp_env2->crc != 0) {gd->env_valid = 2;} else if(tmp_env2->crc == 0 && tmp_env1->crc != 0){gd->env_valid = 1;b_save_env = 1;} else if(tmp_env2->crc == 0 && tmp_env1->crc == 0) {printf("No Vaild Env, return to default Env.\n");return use_default();} else { /* crc are equal - almost impossible */gd->env_valid = 1;}printf("The Same Environment.\n");}/* 包含部分異常處理 */free(env_ptr);if(gd->env_valid == 1) {env_ptr = tmp_env1;if(b_save_env) run_command("saveenv", 0);printf ("Env1 is OK\n\n");free(tmp_env2);} else {env_ptr = tmp_env2;printf ("Save env2 to env1 \n\n");run_command("saveenv", 0);free(tmp_env1);}gd->env_addr = env_ptr->data;if(getenv("second_env") == NULL)return;setenv("second_env", 0);/* 將代碼中的環境變數儲存到 emmc 中,僅在燒錄系統時作用 */add_sencond_env();}