版本:v1.2
摘要
本文主要介紹了嵌入式開發過程中,將固件從PC端下載到開發板中的各種方式,主要包括NFS掛載,Nand Flash和Nor Flash,USB,RS232,網卡NIC等方式。
2013-12-15
修訂歷史 | ||
---|---|---|
修訂 1.2 | 2013-12-15 | crl |
|
||
修訂 1.0 | 2011-08-25 | crl |
|
版權 © 2013 Crifan, http://crifan.com
目錄
表格清單
- 3.1. 嵌入式開發中固件燒錄的方式
- 3.2. 將文件下載到Uboot中的方式
- 3.3. 如何把Uboot的內存中數據寫入到存儲設備上
摘要
目前在嵌入式開發中,經常要實現將對應的固件,燒寫到開發板中,然后開發板才能運行我們的程序。
嵌入式開發,很多用的是Linux系統,也有用WinCE和其他系統,但此文只介紹Linux系統下面的情況。
Linux系統中,多數為bootloader+ kernel + rootfs的模式。
其中,所用的bootloader,多為uboot。負責初始化硬件和設置好軟件環境,
然后加載kernel,運行kernel,kernel運行后,再去加載rootfs,之后就是你所看到的運行的Linux了。
其中,在開發過程中,常常會遇到,需要把某個文件,比如U-boot.bin,uImage,rootfs等文件
從PC上,下載到Uboot的SDRAM,即內存中,
然后再用對應命令或工具,將數據寫入到某存儲介質中。
其中,有時候也需要在發布產品之后,在系統運行的情況下,動態升級整個系統的固件的。
此文就是主要探討,此嵌入式Linux中,開發過程中和產品發布后,相關的固件燒寫方式。
摘要
固件,firmware
所謂固件,就是文件,固化在存儲介質上的文件,而文件,其實就是數據。
嵌入式開發中,尤其是Linux開發,常見的方式是,從板子(個人用的是arm的板子)上啟動,會允許Uboot,然后Uboot去加載kernel內核,個人常用的kernel是uImage,然后Linux運行后,去加載根文件系統rootfs,個人常用到的yaffs2文件系統。
前后系統運行所需要的文件,總的來說,就是這三個:
- Uboot,比如u-boot.bin
- Kernel,比如uImage
- Rootfs,比如yaffs2.rootfs.arm
而大家一直說的固件,在系統是Linux系統的情況下,常常就是指的是這些文件。
所謂燒寫,就是寫數據,把文件(固件/數據)寫到存儲介質(Nand Flash, Nor Flash等)上。
而對於燒寫這個詞,說法很多,常見的有:
燒寫=燒錄=flash=編程=program=programming
下面另外提到的,更新固件,其實也指的是將新的固件燒寫進去,即所謂更新固件,更新系統。
存儲介質,此處主要是指,嵌入式中存放firmware的地方,多數是Nor Flash加上Nand Flash的組合。其他的,也有單獨是Nor Flash,單獨是Nand Flash,單獨是SD/MMC卡等方式。
USB Host,即對於開發板來說,USB是Host端,所以,此時可以去插上一個U盤,對應的是USB Mass Storage的用法,所以,可以理解為:
開發板是USB Host = USB Mass Storage =開發板可以外接 U盤
而USB Device,即對於開發板來說,自己是作為USB的Device端。
而USB Device端,相對於USB Host來說,也叫USB Slave端。
此時的UBS Host就是PC端了,然后PC端連出一根USB線,接上開發板,然后開發板就是USB Device=USB Slave端了,就可以當做U盤用了。
即:
開發板是USB Slave = USB Device = 開發板自己是PC上的U盤。
更多關於USB方面的基本概念和邏輯,可以參考:
目錄
摘要
固件開發方式,這里討論的主要有兩種。
一種是開發過程中,產品發布之前,用到的一些方式。
另外一種是,產品發布之后,產品已經運行了系統了,此時,如何在線動態地更新固件,實現系統升級的功能。
先列出不同的分類:
表 3.1. 嵌入式開發中固件燒錄的方式
開發過程中,固件燒寫方式 | 不需要燒寫kernel和rootfs的方式 | 即直接通過tftp,nfs等方式掛在kernel和rootfs的方式 |
將kernel,rootfs,uboot等燒寫到存儲介質上的方式 | 一步到位的方式(直接通過工具燒寫文件到對應存儲介質上) | |
兩步到位的方式(先將數據先寫入到Uboot中,再用uboot中的命令把數據寫到存儲介質上) | ||
產品發布后,動態升級系統的方式 | 即,通過讀寫對應的Linux下的設備節點,實現更新固件 |
下面就詳細討論這兩種過程中所用到的固件升級方式。
此處介紹的是,在開發過程中,如何實現固件更新,開發調試,根據是否一定要將新版的固件,燒寫到存儲介質上,可以分兩種:
- 一種是不需要燒寫kernel和rootfs的方式;
- 另外一種是,需要把新版本的固件,即uboot,kernel,rootfs,燒寫到存儲介質上的。
此種做法,在實際開發中,還是有一些人會用到的。
其背景是,嵌入式開發中,相對普通上層軟件開發,每次新編譯出一個版本的軟件,都要很麻煩地燒錄到對應的存儲介質,比如Nor Flash上,然后給開發板上電,繼續開始調試開發,而不能像開發上層PC端軟件,在IDE中,編譯一下,點擊運行,即可看到最新結果。
所以,嵌入式開發中,開發的效率顯得很低,其中一個方法,可以先對避開此問題,避免每次都要重新燒寫新編譯的程序的問題,那就是,對於新版本的kernel和rootfs,分別通過tftp或NFS掛在kernel,通過NFS掛在rootfs,的方式,重新編譯一個新版本的kernel或者是rootfs時,每次都不用重新燒寫,只需要把對應的文件,放到對應的tftp或者NFS的文件夾下面即可。
此法詳細做法相關的部分內容,下面會涉及,故此處不做太多探討。而且真的詳細討論的話,超出了此文的范疇。
此處,只是對於此法進行概要說明:
- 目標
實現kernel通過tftp掛載,rootfs通過nfs掛載的方式,實現高效率的嵌入式開發
- 前提
- 硬件
- 開發板上有網卡
- 網卡已連接到一個路由或交換機,並且PC端,即提供tftp和nfs的服務器端,也連到此網絡,開發板和PC端,同屬於一個局域網段。
- 軟件
- PC端運行了tftp服務,新編譯的kernel文件,放在tftp的根目錄下
- PC端運行了nfs服務,所用的Linux內涵,也設置並啟用了對應的nfs服務,編譯好的rootfs,放在nfs服務的根目錄下。
- 硬件
- 如何操作
- uboot中,通過tftp mem_addr kernel_file的方式去加載內核
- 內核運行起來后,通過NFS去掛在rootfs
- 正常加載rootfs后,就可以像普通的Linux開發一樣,通過串口,輸入命令操作Linux了
- 優缺點
- 優點
免去了每次新編譯的kernel和rootfs,都要重新燒寫這一麻煩的事情
- 缺點
- 很明顯,如果開發中,涉及到對應的網絡驅動的調試等,內核的NFS服務的調試等,即本身所用到的網絡功能都是要調試的對象,那就不能用此法了
- 另外,網絡加載文件的速度,一般都是不錯的,但是也不排除,有時候會受其他PC端某個網絡資源占用太多的程序的影響
- 而網絡加載文件的穩定性,不同的環境,差異很大。多數情況下,都是很穩定的,但是也有人遇到各種原因,導致不穩定的,所以此時此法即使可用,但用起來也會很郁悶
- 優點
需要將對應的文件,燒寫到存儲介質上,此時,有兩種方法:
- 一種是一步到位的方式,即直接通過某工具將文件寫入到存儲介質上。
- 另外一種是兩步到位的方式,先通過某種方式把文件下載到Uboot中,再通過Uboot中的命令,去把數據寫入到存儲介質上。
目前常見的存儲介質,主要有Nor Flash和Nand Flash,所以下面主要講解如何燒寫Nor Flash還是Nand Flash。
另外,還有一些存儲介質是SD/MMC卡等,其燒寫數據,我用過的燒寫數據方式是,一種是在Uboot中,把下載到內存中的數據,寫入到SD/MMC卡中,或者在板子已經跑起來了Linux的環境下,把數據寫入到SD/MMC卡中。
由於Nor Flash接口比較常見和通用,而且有專門的規范定義了對應的操作命令,所以,目前有很多工具,只要你板子上的Nor Flash是常見的Nor Flash,那么這些工具,多數都可以直接拿過來用,直接將文件燒寫到Nor Flash中。
- 目標
通過某些工具,連接上開發板或直接接上對應的硬件芯片Nor Flash,直接通過工具燒寫文件到目標存儲介質(即對應的硬件芯片)上。即不需要開發板上面運行Uboot或者Linux系統。用工具直接操作即可。
- 前提
- 硬件
- 你所使用的Nor Flash,如果是那種通用的(其實大多數都是通用的),工具所支持的
- 開發板具有對應的硬件接口,比如JTAG接口
- 你自己有對應的硬件工具,比如JLink硬件
- 軟件
- 對應的軟件工具支持對應的Nor Flash芯片,比如J-Flash,支持很多種常見Nor Flash的燒寫
- 硬件
- 如何操作
個人接觸比較多的是,Jlink硬件 + 軟件工具J-Flash ARM。其如何操作,參見:[4]
下表簡單總結了,如何將數據通過硬件接口+相關軟件,下載到Uboot中的方式:
表 3.2. 將文件下載到Uboot中的方式
開發板上的硬件接口 | 軟件協議 | 相關軟件或Uboot中的命令 | 說明 |
---|---|---|---|
USB | USB Host – USB Mass Storage | Fatls usb 0 fatload usb addr file |
USB cable |
USB Slave/Device | DNW |
USB cable |
|
RS232 | Kermit/Ymodem | loadb/loady | RS232 Cable |
NIC | Tftp | tftp file |
network interface card |
NFS | NFS |
network interface card |
|
SD/MMC | SD/MMC | Fatls mmc 0 Fatload mmc 0 addr file |
|
JTAG | JTAG | IDE tool |
Hardware debug tool |
下面,對每一種方式進行詳細的闡述:
關於USB Host和USB Device,上面已經名詞解釋過了,此處不再贅述。
現在很多開發板上,都有USB的Host和USB的Device的接口。
所以,對應着,可以實現,外接U盤到開發板上,或者將開發板作為U盤連到PC上
然后操作U盤,把文件拷貝到U盤里,實現對應的把文件數據傳輸到開發板上這一功能。
- 目標
把插在開發板上的U盤中的文件,拷貝Uboot的內存中
- 前提
- 硬件
- 開發板上有USB Host芯片和接口
以我這里的TQ2440的板子為例,用的CPU是三星的S3C2440,其中包含了一個OHCI的USB Host主控制器。
板子上也有USB Host接口。
- 自己有U盤
- 開發板上有USB Host芯片和接口
- 軟件
- Uboot中已經實現了USB Host Controller的驅動
如果Uboot中沒有你的板子上的USB Host Controller的驅動的話,需要自己移植,甚至從頭實現的話,這個工作量和難度,還是不小的。
以此處的S3C2440的驅動為例,此處已經把新的版本的Uboot中的相關代碼,移植到了TQ2440的1.1.6的uboot中,實現了對應的S3C2440的OHCI的驅動。
相關過程和源碼,參考:[5]
- U盤的文件系統是FAT格式的
如果你的U盤是NTFS等其他格式,那么要重新格式化為FAT16/FAT32格式。
當然,如果是其他的文件系統,比如ext2等,也是可以的,下面對應的命令就是ext2ls和ext2load了。
- Uboot中已經實現了USB Host Controller的驅動
- 硬件
- 如何操作
在Uboot中使用對應命令來操作U盤:
- usb rescan
去初始化usb host。關於usb 子系統更多的相關的命令,可以通過
help usb
看到更多的幫助信息。
- fatls usb 0
將你U盤的FAT文件系統中的文件列出來,以確保USB現在可以正常工作,和知道你當前U盤里面有哪些文件,此時應該可以看到你所要拷貝的文件,如果你是把文件放在根目錄的話。(一般都是把u-boot.bin等文件,放到U盤根目錄的)
- fatload usb 0 mem_addr file_name
去將U盤中的文件file_name載入到內存中mem_addr的位置。
- usb rescan
- 目標
將PC端的文件,通過USB線,傳輸到作為USB Device端的開發板上的Uboot的內存中
- 前提
- 硬件
- 板子上有對應的USB Device功能的controller和對應的USB Device接口
- 軟件
- PC端已經安裝了對應的USB相關驅動
- PC端需要有對應的DNW軟件
- Uboot中實現了對應的命令
以TQ2440為例,其中已經有了usb slave 相關功能和命令
- 硬件
- 如何操作
具體的操作,相對比較麻煩,此處只列出主要步驟:
- 去Uboot端執行對應的usb slave命令
以等待PC主機端傳輸文件
- 去PC端用DNW去傳輸文件
USB Port -> Transmit -> 選擇要傳輸的文件
然后對應的文件就可以傳輸到對應的Uboot中的內存中去了。
更多的細節,如何操作,請參看TQ2440的手冊:[1]
在此,免費為天嵌的TQ2440宣傳一句,其資料和相關文檔,做的是蠻不錯的,東西很全,很詳細,尤其適合初學者。
- 去Uboot端執行對應的usb slave命令
RS232的連接方式,是最常見的。
即,開發板上有串口接口,然后接了根RS232線,連到PC端,然后PC端用一個串口終端程序,連接開發板,比如常見的Windows XP系統自帶的超級終端Hyper Terminal,功能強大的SecureCRT,以及Putty等等,都是不錯的串口工具。
其中關於如何在Win7下面使用超級終端(Hyper Terminal),不了解的可以去參考:[11]
Kermit是一種協議,廣泛使用的協議,用來傳輸文件和數據的協議,很早之前就有了此協議,所以現在很多地方都已實現和支持此協議。
關於Kermit和Ymodem的詳情,去看我轉的帖子:[2]
而關於Kermit,XModem,Ymodem和Zmodem之間的區別和聯系,可以去看:[6]
- 目標
通過Kermit協議,將文件通過RS232接口傳送到Uboot的內存中
- 前提
- 硬件
- 開發板中有RS232接口,並且已連接到PC端
- 軟件
- Uboot中已經實現kermit協議的loadb命令
這個,一般的uboot中都已實現。
此處說一個詭異的事情,之前遇到過,即使help中沒有看到loadb的命令,但是實際也是支持loadb的,估計是uboot開發者,把此命令注釋掉了,但是實際kermit協議用途太廣泛,而uboot本身程序中早已經實現了,所以loadb還是已經在uboot中的了。
- Uboot中已經實現kermit協議的loadb命令
- 硬件
- 如何操作
- 在uboot中,輸入loadb
- 在PC端使用串口程序去傳送文件
以windows XP下的串口工具超級終端為例:
選擇Transfer ⇒ Send File ⇒ Protocol選擇Kermit,FileName選擇你所要傳送的文件->點擊確定即可。然后就是慢慢傳送文件了。
至於文件數據傳輸后,放在uboot的內存中的哪個位置,是由你uboot中的環境變量loadaddr決定,我這里的是loadaddr=0x800000。
當然,你也可以在執行loady的時候,后面加上你要的地址,比如:
loadb 0x1000000
Kermit協議,數據傳輸速度比較慢,我這里傳輸了個8MB的文件,大概要40分鍾左右的。
關於Ymodem協議,是從之前的Xmodem協議演化出來的,之后還有Zmodem。
簡單的說就是,一個數據包大小為1KB的數據傳輸協議。
更多的解釋,參見上面已經提到的[6]
- 目標
通過Ymodem協議,將文件通過RS232接口傳送到Uboot的內存中
- 前提
- 硬件
- 開發板中有RS232接口,並且已連接到PC端
- 軟件
- Uboot中已經實現Ymodem協議的loady命令
- 硬件
- 如何操作
- 在uboot中,輸入loady
- 在PC端使用串口程序去傳送文件
以windows XP下的串口工具超級終端為例:
選擇Transfer ⇒ Send File ⇒ Protocol選擇Ymodem,FileName選擇你所要傳送的文件->點擊確定即可。然后就是慢慢傳送文件了。
- 示例
Bootldr> loady ## Ready for binary (ymodem) download to 0x00800000 at 115200 bps... CCCxyzModem - CRC mode, 2(SOH)/8192(STX)/0(CAN) packets, 5 retries ## Total Size = 0x00800000 = 8388608 Bytes
多數開發板上,也都帶有網卡接口,然后通過網線,連接到一個路由或者交換機上,另外一個PC也連接到此路由或交換機上,然后通過網線,將PC上的文件數據,傳輸到板子上。
- 目標
將文件通過tftp方式,從PC端,下載到Uboot的內存中
- 前提
- 硬件
- 硬件板子上有網卡
- 板子通過網線連到路由或交換機上,PC也連到該路由或交換機上,共處同一個網段
- 軟件
- PC端設置好tftp服務
關於PC端安裝了tftp服務(TFTP service),詳情可以參考:[7]
- 安裝好tftp服務后,把對應的u-boot.bin等文件,放到tftp的根目錄下
- Uboot中,首先肯定是已經實現了網卡驅動,以及添加了對應的tftp命令
此兩個前提,一般開發板都已經具有此條件
- PC端設置好tftp服務
- 硬件
- 如何操作
在Uboot中,執行命令
tftp mem_addr file_name就可以將文件file_name傳送到Uboot的內存地址mem_addr中了。
- 示例
EmbedSky> tftp 0x30010000 u-boot.bin dm9000 i/o: 0x20000300, id: 0x90000a46 MAC: 0a:1b:2c:3d:4e:5f TFTP from server 192.168.1.101; our IP address is 192.168.1.120 Filename 'u-boot.bin'. Load address: 0x30010000 Loading: T ############### done Bytes transferred = 207396 (32a24 hex)
- 目標
將文件從SD/MMC卡中,拷貝到Uboot的內存中
- 前提
- 硬件
- 開發板有SD/MMC的controller,有對應的SD/MMC插槽
- 自己有SD或MMC卡
- 軟件
- Uboot中實現了對應的SD/MMC驅動及對應的命令
關於uboot中,把新版本的mmc驅動,移植到舊的上,可以參考:[8]
- SD/MMC卡是FAT文件系統
當然,如果是其他的文件系統,比如ext2等,也是可以的,下面對應的命令就是ext2ls和ext2load了。
- Uboot中實現了對應的SD/MMC驅動及對應的命令
- 硬件
- 如何操作
- mmcinit或mmc rescan
即初始化mmc,舊版本的uboot的是mmcinit,新版本的uboot是mmc rescan
- fatls mmc 0
將mmc卡中的文件列出來,確保mmc卡工作正常和知道里面有哪些文件
- fatload mmc 0 mem_addr file_name
將mmc卡中的file_name文件拷貝到內存mem_addr處。
- mmcinit或mmc rescan
- 示例
EmbedSky> mmcinit mmc: Probing for SDHC ... mmc: SD 2.0 or later card found trying to detect SD Card... Manufacturer: 0x02, OEM "TM" Product name: "SA04G", revision 0.5 Serial number: 2621440179 Manufacturing date: 7/2010 CRC: 0x73, b0 = 1 READ_BL_LEN=15, C_SIZE_MULT=0, C_SIZE=365 size = 0 SD Card detected RCA: 0x1234 type: SDHC EmbedSky> md 30000000 30000000: 00000000 00000000 00000000 00000000 ................ 30000010: 00000000 00000000 00000000 00000000 ................ 。。。 300000f0: 00000000 00000000 00000000 00000000 ................ EmbedSky> fatls mmc 0 512 nikon001.dsc misc/ dcim/ 194 error.html 2 file(s), 2 dir(s) EmbedSky> help fatload fatload <interface> <dev[:part]> <addr> <filename> [bytes] - load binary file 'filename' from 'dev' on 'interface' to address 'addr' from dos filesystem EmbedSky> fatload mmc 0 30000000 error.html reading error.html 194 bytes read EmbedSky> md 30000000 30000000: 4d54483c 423c3e4c 3e59444f 6e6f7257 <HTML><BODY>Wron 30000010: 50492067 7263733c 3e747069 646e6977 g IP<script>wind 。。。 300000f0: 00000000 00000000 00000000 00000000 ................ EmbedSky>
上述md(memory display)命令,只是為了顯示內存中的內容,用以表示,拷貝文件前后內存中數據的變化。
前面的操作,是把數據從外部傳輸到Uboot的內存中,接下來,就要把對應的數據,寫入到對應的存儲介質中去。
常見的存儲介質以及Uboot中相關的命令,分類如下:
表 3.3. 如何把Uboot的內存中數據寫入到存儲設備上
存儲介質 | Uboot中相關命令 | 說明 |
---|---|---|
Nand Flash |
nand erase |
先擦除才能再寫入數據 |
Nor Flash |
erase |
先擦除才能再寫入數據 |
USB | usb write | |
SD/MMC | mmc write |
下面分別介紹,在Uboot中,對於每種存儲設備,如何用相關的命令,把數據寫入到對應存儲設備中。
- 目標
把Uboot中內存中數據,寫入到Nand Flash中去
- 前提
- 軟件
- Uboot中,已經實現了nand erase和nand write命令了
- 軟件
- 如何操作
- nand erase
需要先用nand的erase命令,去擦出對應的區域
- nand write
然后再用nand write,把內存中的數據,寫入到nand 中。
- nand erase
關於Nor Flash,需要額外說明一些事情。
本身Flash這個名詞,在存儲領域方面,包括了Nand Flash和Nor Flash。
而由於Nor Flash出現最早,應用很廣泛,所以Uboot中,對於單獨說Flash這個詞,是指的是Nor Flash。
所以,會有對應的命令:
flinfo = Flash Info = Nor Flash Info
而又由於Nor Flash的很多操作,很像SDRAM等設備,可以直接讀,(寫操作需要特定的命令),但是可以把Nor Flash的操作,兼容統一到cp拷貝這個命令中去。
所以,很多時候,你會發現,好像沒有單獨的Nor Flash的讀寫的命令,其實是包含在了cp這個命令中了。
另外,對於cp命令本身,其有三種方式:
- cp.b單位為b=byte=字節的方式,去拷貝數據
- cp.w單位為w=word=字的方式,去拷貝數據
- cp.l單位為l=long=長整型的方式,去拷貝數據
不過,對於eeprom,也有單獨的一套eeprom的命令的,比如eeprom write,用於將數據寫入到eeprom中去。
- 目標
把Uboot中內存中數據,寫入到Nor Flash中去
- 前提
- 軟件
- Uboot中,已經實現了Nor flash 相關的命令了,包括erase和cp命令支持了Nor Flash了
- 軟件
- 如何操作
在Uboot中,執行下列命令:
- protect off
只有在你當前需要重新寫入新數據的Nor Flash的Block是已經被寫保護的情況下,才需要此步驟去解除鎖定。
一般情況下,都不需要此步驟的。
- erase
去擦出Nor Flash中的數據
- cp或eeprom write
將內存中的數據,寫入到Nor Flash中。
- protect off
- 目標
將Uboot中的內存中的數據,寫入到USB設備中
- 前提
- 軟件
- Uboot中已經實現了對應的usb write命令
- 軟件
- 如何操作
在Uboot中,執行下列命令:
- usb write
將對應的內存中的數據,寫入到Usb設備中。
- usb write
除了開發過程中,去燒寫固件之外,在發布產品后,很多廠商,希望在系統運行的情況下,實時地,可以去更新對應的固件,比如kernel的uImage或者rootfs等,此時,多數系統,往往是不太容易這樣去升級的,不過還是有可能實現這樣的在線升級系統的。
基本的思路是,在運行的Linux中,通過操作對應的設備節點,比如:
[1] TQ2440開發板使用手冊