Nand Flash

介紹

2016-07-06_111757.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Flash Device    = N Block
Blocl = N Page
Page = N Byte + OOB

Nand Flash
+-------------------------------------+
| B1 | B2 | ... | B16 |
| | | | |
+-------------------------------------+

+----+
| B1 | => N Page + OOB
| |
+----+

Page
大小有 512, 2048, 4096, 8192 (bytes),常見的為 2048 (bytes)
page 容量 512 bytes 的稱 small page,大於等2k bytes 都稱為large page

Spare or OOB (out of boundary)
每一個 page 在實體的結構中除了 2k bytes的使用空間,還會有 64 bytes 額外的容量
供hw/sw儲存一些額外的資訊,通常會用來儲存ecc的data,來效正nand flash使用久後會有bit不能使用的問題

Block
nand flash chip 寫入的最小單位, 每 64 page 即為一個block
因為 page size 會有不同,block size 也就不同
一顆chip裡有多少block,是依nand flash的大小而定,但通常是 2 的冪次方。

Read/Write operation
nand flash 讀寫方式異於一般的磁性儲性裝置。因為結構上的問題
如果要針對特定的 page 寫入,只能把資料寫由1 -> 0,
如果要0->1 那只能針對整個 block (64 pages)做動作,此動作稱為 erase,而寫入page的動作稱為 program,
一般 nand chip 的資料都會標明erase/program的時間
以 Micro MT29F2G08AABWP 為例,erase/program的時間分別為(2ms/300us)


# write -> Block
# read -> Page

比較檔案相關指令

1
2
# 顯示 16 進制內容,只顯示 10 行
hexdump -C A.bin | head -n 10

建立 UBI images

流程: 1.使用 mkfs.ubifs 製作 ubifs 格式 2.將第一步的檔案做成可燒錄的 image

1.進入 Linux 使用 mtdinfo 看資訊

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mtdinfo /dev/mtd-open -u
mtd6
Name: mtd-name
Type: nand
Eraseblock size: 1048576 bytes, 1024.0 KiB
Amount of eraseblocks: 4018 (4213178368 bytes, 3.9 GiB)
Minimum input/output unit size: 8192 bytes
Sub-page size: 8192 bytes
OOB size: 256 bytes
Character device major/minor: 90:12
Bad blocks are allowed: true
Device is writable: true
Default UBI VID header offset: 8192
Default UBI data offset: 16384
Default UBI LEB size: 1032192 bytes, 1008.0 KiB
Maximum UBI volumes count: 128

2.由 mtdinfo 得知 mkfs.ubifs 資訊

1
2
3
4
5
6
mkfs.ubifs -v 
-r ubifs
-m 8192 # Minimum input/output unit size: 8192 bytes
-e 1032192 # Default UBI LEB size: 1032192 bytes, 1008.0 KiB
-c 4018 # Amount of eraseblocks: 4018 (4213178368 bytes, 3.9 GiB)
-o ubifs.img # output file name

  1. UBI generieren
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ubinize  
-vv # Display detail info
-o output/ubi.img # output file name
-m 8192 # Minimum input/output unit size: 8192 bytes
-p 1024KiB # Eraseblock size: 1048576 bytes, ""1024.0 KiB""
config.ini # config 檔案

# config.ini
# 用來建立 volumes ,描述此 volumes 資訊
[ubifs_volume]
mode=ubi
image=ubifs.img
vol_id=1
vol_size=4071MiB # This volume size
vol_type=dynamic
vol_name=fs
vol_alignment=1
vol_flags=autoresize

ubinize 會讀 2 個檔案進去,config.ini , ubifs.img

Linux

1
2
3
4
5
6
tftp -gr ubi-4g.img 192.168.1.2
ubidetach -d 0 /dev/ubi_ctrl
ubiformat /dev/mtd6 -f ubifs.img
ubiattach /dev/ubi_ctrl -m 6
mkdir userfs
mount -t ubifs /dev/ubi0_0 ./userfs/

Uboot

1
2
3
4
tftpboot ubi.img
nand write 0x68000000 0x4e00000 $filesize
ubi part nand0,6 0
ubifsmount open

Error

1
2
3
4
5
Q:UBI error: vtbl_check: too large reserved_pebs 4064, good PEBs 4010
A:vol_size 太大,要調小

Q:ubi_read_volume_table
A:把 config.ini 裡面的 vol_alignment=1 & vol_flags=autoresize 移除

Read / Write

Read

1
2
3
4
5
6
7
先用 mtdinfo /dev/mtd7 找出要讀的 part (看 mtd name)
或是 cat /proc/mtd
dev: size erasesize name
mtd0: 000a0000 00010000 "boot"
mtd1: 00060000 00010000 "env"
...
再用 nanddump -p -f nandinfo.txt /dev/mtd7 將內容讀到 nandinfo.txt 檔案

Write

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>

#define MTD_NAME "mtd7"
#define TMP_NAME "tmp.txt"
int main()
{
FILE *fp;
int rv = 0;
char sys_cmd[80];
char data[80] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB};

// Erase nand flash
sprintf(sys_cmd, "flash_erase /dev/%s 0 0", MTD_NAME);
rv = system(sys_cmd);
if (rv) {
printf("ERROR : Flash erase !\n");
}

// Open file and write data
fp = fopen(TMP_NAME, "wb");
fwrite(data, sizeof(data[0]), sizeof(data)/sizeof(data[0]), fp);
fclose(fp);

// Write to nand
sprintf(sys_cmd, "nandwrite -p -s 0 /dev/%s %s", MTD_NAME,TMP_NAME);
system(sys_cmd);
return 0;
}

參考網站

Reference 1

Reference 2

Reference 3

Reference 4

Reference 5

Reference 6