加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 0. MTD基礎(chǔ)
    • 1. 查看qspi flash大小
    • 2. 需要固化鏡像分區(qū)地址設(shè)置
    • 3. 設(shè)備樹
    • 4. 查看分區(qū)信息
    • 5. 拷貝讀取 MTD 分區(qū)
    • 6. 還原文件
    • 7. 開機(jī)自動還原文件
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

ZYNQ QSPI flash分區(qū)設(shè)置&啟動配置

07/09 10:10
4215
閱讀需 27 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

需求:

一款基于zynq架構(gòu)的產(chǎn)品,只有qspi flash,并沒有其他的存儲設(shè)備,

現(xiàn)在的要求固化某個應(yīng)用程序app,設(shè)置開機(jī)啟動.

但是根據(jù)廠家提供的sdk,編譯出的鏡像重啟后,文件系統(tǒng)的內(nèi)容都會還原,

之前的方案是每次都要把程序放到buildroot下,

然后重新編譯,將rootfs、內(nèi)核鏡像、設(shè)備樹打包到image.ub.bin中,

然后用jtag重新燒錄到flash中。

這很不合理,所以要我們需要對flash進(jìn)行分區(qū),

然后將需要固化的程序通過flashcp燒寫到flash中,然后在用dd命令導(dǎo)出該文件。

0. MTD基礎(chǔ)

該操作依賴linux的MTD子系統(tǒng)。

MTD(Memory Technology Device)是內(nèi)存技術(shù)設(shè)備,它為原始閃存設(shè)備(例如NAND,OneNAND,NOR 等)提供了一個抽象層。

這些不同類型的Flash都可以使用相同的API。

通常內(nèi)核都默認(rèn)支持MTD驅(qū)動。MTD字符設(shè)備-通常稱為**/dev/mtd0,/dev/mtd1**等。

這些字符設(shè)備提供對原始閃存的I/O訪問。

它們支持許多ioctl調(diào)用,用于擦除擦除塊,將其標(biāo)記為不良或檢查擦除塊是否不良,獲取有關(guān)MTD設(shè)備的信息等。

sysfs接口,它提供有關(guān)系統(tǒng)中每個MTD設(shè)備的完整信息。 此接口易于擴(kuò)展,并且鼓勵開發(fā)人員盡可能使用sysfs接口,而不是較舊的ioctl或/proc/mtd接口。

mtd子系統(tǒng)的sysfs接口已在內(nèi)核中進(jìn)行了說明,當(dāng)前可在Documentation/ABI/ testing/sysfs-class-mtd中找到。

/proc/mtd proc文件系統(tǒng)文件提供常規(guī)的MTD信息。 這是舊版界面,而sysfs界面提供了更多信息。

MTD子系統(tǒng)支持帶有軟件硬件ECC的 raw NAND閃存,OneNAND閃存,CFI(通用閃存接口)NOR閃存以及其他類型的閃存。

1. 查看qspi flash大小

進(jìn)入uboot

fmsh>?sf?probe?0
SF:?Detected?n25q256?with?page?size?256?Bytes,?erase?size?4?KiB,?total?32?MiB

該命令式查看設(shè)備信息。

可以看到qspi flash容量為32MB,即0x1E84800

2. 需要固化鏡像分區(qū)地址設(shè)置

一口君使用的平臺需要固化2個文件:cfg(存儲配置信息)、app(可執(zhí)行程序)

加上必須燒錄的boot.bin、image.ub.bin,一共有4個文件,

所以我們需要配置4個分區(qū)。

1) boot.bin、image.ub.bin地址

其中boot.bin包含了fpga的ip核和啟動必要的文件信息,地址固定為0

image.ub.bin的地址通常廠家也會給出默認(rèn)地址,

進(jìn)入uboot打印環(huán)境信息:

fmsh>?printenv

fit_size=0x153f000
flash_off=0x500000
load_addr=0x2000000
qspiboot=echo?Copying?FIT?from?SPI?flash?to?RAM...?
&&?sf?probe?&&?sf?read?${load_addr}?${flash_off}?${fit_size}?&&?bootm?${load_addr}
echo?Copying?FIT?from?SPI?flash?to?RAM...?:
?打印提示信息
sf?probe:
?查看設(shè)備硬件信息
sf?read?${load_addr}?${flash_off}?${fit_size},
?從flash地址flash_off開始讀取fit_size個字節(jié)到ram地址load_addr
bootm?${load_addr}:
?啟動內(nèi)核

可以看到flash地址是flash_off:0x500000

2) 分區(qū)劃分

那現(xiàn)在我們就可以給這4個文件設(shè)置分區(qū)信息了

鏡像 文件實際大小(hex) 起始地址 offset 塊數(shù)
boot.bin 3D0900 0x00000 0x500000 61-80
image.ub.bin D59F80 0x500000 0x1100000 214-272
cfg.bin 200 0x1600000 0x10000 1
app.bin 7800 0x1610000 0x30000 3

 

注意:

offset大小必須是 ?0x10000整數(shù)倍,這個是擦除的最小單位-塊。

每個分區(qū)大小結(jié)合要固化的程序,合理分配,既要考慮后面程序升級需要預(yù)留足夠空間,也不要太大,造成浪費(fèi)

分區(qū)劃分不能超過flash最大值32M

3. 設(shè)備樹

flash分區(qū)設(shè)備樹說明如下:

Documentationdevicetreebindingsmtdpartition.txt

Fixed?Partitions
================

Partitions?can?be?represented?by?sub-nodes?of?a?flash?device.?This?can?be?used
on?platforms?which?have?strong?conventions?about?which?portions?of?a?flash?are
used?for?what?purposes,?but?which?don't?use?an?on-flash?partition?table?such
as?RedBoot.

The?partition?table?should?be?a?subnode?of?the?flash?node?and?should?be?named
'partitions'.?This?node?should?have?the?following?property:
-?compatible?:?(required)?must?be?"fixed-partitions"
Partitions?are?then?defined?in?subnodes?of?the?partitions?node.

For?backwards?compatibility?partitions?as?direct?subnodes?of?the?flash?device?are
supported.?This?use?is?discouraged.
NOTE:?also?for?backwards?compatibility,?direct?subnodes?that?have?a?compatible
string?are?not?considered?partitions,?as?they?may?be?used?for?other?bindings.

#address-cells?&?#size-cells?must?both?be?present?in?the?partitions?subnode?of?the
flash?device.?There?are?two?valid?values?for?both:
<1>:?for?partitions?that?require?a?single?32-bit?cell?to?represent?their
?????size/address?(aka?the?value?is?below?4?GiB)
<2>:?for?partitions?that?require?two?32-bit?cells?to?represent?their
?????size/address?(aka?the?value?is?4?GiB?or?greater).

Required?properties:
-?reg?:?The?partition's?offset?and?size?within?the?flash

Optional?properties:
-?label?:?The?label?/?name?for?this?partition.??If?omitted,?the?label?is?taken
??from?the?node?name?(excluding?the?unit?address).
-?read-only?:?This?parameter,?if?present,?is?a?hint?to?Linux?that?this
??partition?should?only?be?mounted?read-only.?This?is?usually?used?for?flash
??partitions?containing?early-boot?firmware?images?or?data?which?should?not?be
??clobbered.
-?lock?:?Do?not?unlock?the?partition?at?initialization?time?(not?supported?on
??all?devices)

我們只需要關(guān)注分區(qū)的子節(jié)點說明即可:

reg

描述某個flash分區(qū)的offset和size

label(可選)

分區(qū)名字

read-only(可選)

該分區(qū)只讀

根據(jù)前面所有分析內(nèi)容,最終我們修改設(shè)備信息如下:

&qspi0?{
????status?=?"okay";
????flash0:?s25fl256s@0?{
????????compatible?=?"spi-flash","spansion,s25fl256s1",?"jedec,spi-nor";
????????reg?=?<0>;??????/*?chip?select?*/
????????spi-max-frequency?=?<50000000>;
????????m25p,fast-read;
????????page-size?=?<256>;
????????block-size?=?<16>;??/*?2^16,?64KB?*/
????????cdns,read-delay?=?<2>;
????????cdns,tshsl-ns?=?<0>;
????????cdns,tsd2d-ns?=?<0>;
????????cdns,tchsh-ns?=?<0>;
????????cdns,tslch-ns?=?<0>;

????????#address-cells?=?<1>;
????????#size-cells?=?<1>;
????????partition@boot?{
????????????label?=?"boot";
????????????reg?=?<0x0000000?0x500000>;???
????????};
????????partition@uimage.ub?{
????????????label?=?"uimage.ub";
????????????reg?=?<0x500000?0x1100000>;???
????????};?
????????partition@prm?{
????????????label?=?"cfg";
????????????reg?=?<0x1600000?0x10000>;???
????????};?
????????partition@kk_ap?{
????????????label?=?"app";
????????????reg?=?<0x1610000?0x30000>;???
????????};??????????
????};
};

重新編譯rootfs打包后重新啟動即可。

4. 查看分區(qū)信息

#?cat?/proc/mtd?
dev:????size???erasesize??name
mtd0:?00500000?00010000?"boot"
mtd1:?01100000?00010000?"uimage.ub"
mtd2:?00010000?00010000?"cfg"
mtd3:?00030000?00010000?"app"
#?ls?/dev/mtd*?-l
crw-------????1?root?????root???????90,???0?Jan??1?00:00?/dev/mtd0
crw-------????1?root?????root???????90,???1?Jan??1?00:00?/dev/mtd0ro
crw-------????1?root?????root???????90,???2?Jan??1?00:00?/dev/mtd1
crw-------????1?root?????root???????90,???3?Jan??1?00:00?/dev/mtd1ro
crw-------????1?root?????root???????90,???4?Jan??1?00:00?/dev/mtd2
crw-------????1?root?????root???????90,???5?Jan??1?00:00?/dev/mtd2ro
crw-------????1?root?????root???????90,???6?Jan??1?00:00?/dev/mtd3
crw-------????1?root?????root???????90,???7?Jan??1?00:00?/dev/mtd3ro
brw-------????1?root?????root???????31,???0?Jan??1?00:00?/dev/mtdblock0
brw-------????1?root?????root???????31,???1?Jan??1?00:00?/dev/mtdblock1
brw-------????1?root?????root???????31,???2?Jan??1?00:00?/dev/mtdblock2
brw-------????1?root?????root???????31,???3?Jan??1?00:00?/dev/mtdblock3

/dev/mtd0,/dev/mtd0ro,/dev/mtdblock0代表的是同一個MTD分區(qū),但是**/dev/mtd0,/dev/mtd0ro都是字符設(shè)備,其中/dev/mtd0ro是只讀字符設(shè)備,/dev/mtdblock0是塊設(shè)備。
常見的
mtd-utils,nand_write等工具只能操作/dev/mtdX**字符設(shè)備,因為只有字符設(shè)備才支持ioctl操作。

5. 拷貝讀取 MTD 分區(qū)

查看 MTD 分區(qū)

cat?/proc/mtd

擦除 MTD 分區(qū)

flash_eraseall?/dev/mtdX

擦除/dev/mtd0分區(qū)的第1塊數(shù)據(jù)。

flash_erase?/dev/mtd0?0x0?1

寫 MTD 分區(qū) NOR Flash

flashcp?/tmp/mtd.bin?/dev/mtdX

寫 MTD 分區(qū) NAND Flash

nandwrite?/tmp/image.bin?/dev/mtdX

讀 MTD 分區(qū)

dd?if=/dev/mtdX?of=/tmp/mtd.bin

a) 燒寫cfg.bin文件到mtd2

首先需要下載文件導(dǎo)開發(fā)板,可以用sd卡、網(wǎng)口(tftp)、串口(rz命令),根據(jù)自己的開發(fā)板資源。

執(zhí)行下面命令燒錄:

flash_erase?/dev/mtd2?0x0?1
flashcp?cfg.bin?/dev/mtd2

導(dǎo)出分區(qū)文件

dd?if=/dev/mtd2?of=/mnt/cfg.bin

b) 燒寫app.bin到mtd3

flash_erase?/dev/mtd3?0x0?3
flashcp?app?/dev/mtd3

導(dǎo)出分區(qū)文件

dd?if=/dev/mtd3?of=/mnt/app.bin

6. 還原文件

注意導(dǎo)出的文件除了我們燒錄的文件之外,

尾部還有多余FF,所以還需要去掉這些多余的部分,

所以我們必須要還原文件。

如下圖所示:

【文件必須以二進(jìn)制形式打開才能看到,彭老師用的Hex Editor Neo】

下載地址:

https://hhdsoftware.com/free-hex-editor

還原文件有很多方法,一口君自己寫了個小程序,

原理:

逐字節(jié)讀取文件,然后判斷是否是0xFF,連續(xù)讀取到16個0xff(防止文件中也由多個0XFF出現(xiàn)),

則認(rèn)為讀到了有效文件尾部,記錄有效文件長度,然后根據(jù)該長度,復(fù)制成最終文件,該文件就是我們所需要的最終文件。

源碼:

#include?<stdio.h>
#include?<stdlib.h>
#include?<fcntl.h>
#include?<unistd.h>
#include?<sys/stat.h>
#include?<sys/types.h>

int?main(int?argc,?char**?argv)
{
?int?fd_p;
?int?fdw_p;
?unsigned?char?c;
?int?count?=?0;
?int?pos?=?0;
?int?i;

?if(argc?!=?3)
?{
??printf("argument?errorn");
??for(int?i?=?0;?i?<?argc?;?i++)
??{
???printf("argv[%d]?=?%sn",?i,?argv[i]);
??}
?}

?fd_p?=?open(argv[1],?O_RDWR);
?if(fd_p?<?0){
??printf("open?file??%s?failedn",?argv[1]);
??return?-1;
?}

?fdw_p?=?open(argv[2],?O_RDWR?|?O_CREAT);
?if(fdw_p?<?0){
??printf("open?file?%s?failedn",?argv[2]);
??return?-1;
?}

?while(1){
??read(fd_p,?&c,?1);
??if(c?==?0xff){
???count++;
???if(count?>=?16){
????break;
???}
??}
??else{
???count?=?0;
??}
??pos++;
?}

?lseek(fd_p,?SEEK_SET,?0);
?for(i=0;?i<pos-15;?i++){
??read(fd_p,?&c,?1);
??write(fdw_p,?&c,?1);
?}
?return?0;
}

測試:

可見寫入到分區(qū)的文件和我們從分區(qū)讀取后再還原的文件時一致的。

重啟后,再驗證

從MD5校驗碼可知,可執(zhí)行程序還原正確。

7. 開機(jī)自動還原文件

要想開機(jī)后自動還原該文件,并啟動程序app,步驟如下:

    將exportimg拷貝文件系統(tǒng)**/mnt**下,(目錄有執(zhí)行權(quán)限即可)設(shè)置開機(jī)子啟動腳本
sdk/buildroot-xxxxxx/output/target/etc/init.d/rcS

文件尾部添加:

dd?if=/dev/mtd2?of=/mnt/cfg.bin
dd?if=/dev/mtd3?of=/mnt/app.bin

touch?/mnt/app
touch?/mnt/cfg

chmod?777?/mnt/app
chmod?777?/mnt/cfg

/mnt/exportimg?/mnt/app.bin?/mnt/app
/mnt/exportimg?/mnt/cfg.bin?/mnt/cfg

rm?/mnt/cfg.bin
rm?/mnt/app.bin

/mnt/app?&?

本例在復(fù)旦微fmsh平臺測試通過。
zynq平臺應(yīng)該也沒問題。

 

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
12110192 1 Delphi Automotive LLP Combination Line Connector
暫無數(shù)據(jù) 查看
770854-1 1 TE Connectivity CONTACT, AMPSEAL SN/LP

ECAD模型

下載ECAD模型
$0.17 查看
LQW18AN33NG00D 1 Murata Manufacturing Co Ltd General Purpose Inductor, 0.033uH, 2%, 1 Element, Air-Core, SMD, 0603, CHIP, 0603

ECAD模型

下載ECAD模型
$0.15 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

公眾號『一口Linux』號主彭老師,擁有15年嵌入式開發(fā)經(jīng)驗和培訓(xùn)經(jīng)驗。曾任職ZTE,某研究所,華清遠(yuǎn)見教學(xué)總監(jiān)。擁有多篇網(wǎng)絡(luò)協(xié)議相關(guān)專利和軟件著作。精通計算機(jī)網(wǎng)絡(luò)、Linux系統(tǒng)編程、ARM、Linux驅(qū)動、龍芯、物聯(lián)網(wǎng)。原創(chuàng)內(nèi)容基本從實際項目出發(fā),保持原理+實踐風(fēng)格,適合Linux驅(qū)動新手入門和技術(shù)進(jìn)階。