登录
注册
一键加入QQ群
友善之臂官方网站
首 页
联系我们
淘宝店铺
维基教程
资料下载
搜索帖子!
NanoPC-T2
Core4418
NanoPC-T3 Plus
Core6818
NanoPi-M4B
NanoPC-T4
NanoPC-T6
NanoPi-NEO
NanoPi-NEO Core
NanoPi-NEO Air
NanoPi-M1 Plus
NanoPi-Duo2
NanoPi-NEO3
核心板:
Smart210
Tiny210
Smart4418
Smart6818
SOM-RK3399V2
CM3588(新品)
路由器:
R1
R1S
R2S
R2S Plus
R2C Plus
R4S
R5S
R5C
R6C
R6S
热门版块:
友善之臂最新动态
站点服务
Linux技术交流区
站务管理与公告
裸机程序和微型OS
友善之臂官方客服中心
默认风格
用户中心首页
编辑个人资料
查看个人资料
好友列表
用户权限查看
积分管理
积分转换
特殊组购买
收藏夹
我的主题
基本统计信息
到访IP统计
管理团队
管理统计
在线统计
会员排行
版块排行
帖子排行
个人首页
我的收藏
好友近况
友善之家
U-boot技术交流区
tiny210--U-Boot实现NAND的擦除(型号:K9GAG08U0F)
友友粉丝快线
开发板销售中心
嵌入式最新资讯
友善之臂最新动态
友善之臂官方客服中心
开发板实战手册及教程
应用方案和定制开发
NanoPi 交流与讨论
NanoPi 玩家交流区
ROM发布区
硬软DIY及开发
嵌入式交流与讨论
Android技术交流区
Linux技术交流区
U-boot技术交流区
WinCE技术交流区
Ubuntu技术交流区
裸机程序和微型OS
OpenWRT讨论区
开发板硬件讨论区
相关资料下载及使用技巧
站点服务
二手交易区
我的论坛我的贴
站务管理与公告
上一主题
下一主题
新 帖
主题 : tiny210--U-Boot实现NAND的擦除(型号:K9GAG08U0F)
复制链接
|
浏览器收藏
|
打印
2012shiyi
级别: 新手上路
作者资料
发送短消息
加为好友
UID:
70046
精华:
1
发帖:
39
金钱:
250 两
威望:
50 点
贡献值:
1 点
综合积分:
98 分
注册时间:
2012-05-15
最后登录:
2013-10-04
楼主
发表于: 2013-03-11 16:14
全看
|
小
中
大
tiny210--U-Boot实现NAND的擦除(型号:K9GAG08U0F)
管理提醒:
本帖被 xoom 执行加亮操作(2013-03-12)
(我是菜鸟,贡献点微薄之力)
1、NAND的初始化:
#if defined(CONFIG_CMD_NAND)
puts("NAND: ");
nand_init(); /* go init the NAND */
#endif
调用函数:
nand_init_chip(&nand_info
, &nand_chip
, base_address
); 参数base_address
=0xB0E000000。
函数功能:
设置nand_chip结构体:
nand->IO_ADDR_R = 0xB0E000000;
还有调用board_nand_init函数,这个函数和芯片操作息息相关,也是设置nand_chip结构体,设置初始化好了NAND。
现在看看核心代码:
先获取NAND的ID号的1st Cycle 和2nd Cycle,
然后通过nand_flash_ids[]数组来匹配,找出我们芯片对应的成员:
for (i = 0; nand_flash_ids
.name != NULL; i++) {
if (tmp == nand_flash_ids
.id) {
type = &nand_flash_ids
;
break;
}
}
找出我们芯片对应的成员:
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
nand_flash_ids[]结构体原型:
struct nand_flash_dev {
char *name;
int id;
unsigned long pagesize;
unsigned long chipsize;
unsigned long erasesize;
unsigned long options;
};
再获取NAND的ID号的3st Cycle 和4nd Cycle,这次的数据主要是体现该芯片的内部信息,如页大小,有多少块等,然后用这些值来设置nand->ecc结构体:
这里说明一下芯片内部一个信息:
Cell Type:SLC / MLC
bit2&bit3表示的是芯片的类型,是SLC还是某种MLC:
Bit2,bit3=0x00 : SLC,简单说就是内部单个存储单元,存储一位的数据,所能表示的数值只有0,1,也就需要两种不同的电压来表示,所以叫做2 Level的Cell。
Bit2,bit3=0x01/0x10/0x11 : 4 /8/16 Level Cell,都叫做MLC,其含义是内部单个存储单元设计成可以表示多个,即4/8/16个不同的电压,对应地,可以表示2,3,4位的数据。 这类的MLC的nand flash,由于单个存储单元,要存储更多的数据,所以内部结构更复杂,读取和写入数据的逻辑更复杂,相对数据出错的几率也比SLC要大。
所以,一般MLC的使用,都需要检错和纠错能力更强的硬件或软件算法,以保证数据的正确性。
软件实现此类的多位数据的检错和纠错的效率相对较低,一般是硬件本身就已经提供此功能。
对应的其为硬件ECC,也就是Linux内核MTD中的HW_ECC。
遇到的问题:读取设备ID为0,说明我们的NNAD读操作有误,经过检测得到解决办法:
在读操作之前没有先复位NAND,导致操作NAND出错,在NAND操作前添加代码:
/*Reset*/
s3c_nand_hwcontrol(0,NAND_CMD_RESET, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
s3c_nand_device_ready(0);
s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*******/
(后来发现,这部分可以不加,因为后面代码还会在读一次,那次就有复位)
这样打印的设备ID就是NAND: ID=d5
由于六次ID数据包含了该芯片的很多信息,所以打印出来:
1st Cycle(Maker Code)=ecH,
2st Cycle(Device Code)=d5H,
3st Cycle(cellinfo)=94H,
4st Cycle(Page Size, Block Size,Redundant Area Size)=76H,
5st Cycle(Plane Number, ECC Level, Organization.)=54H,
6st Cycle(Device Technology, EDO, Interface.)=43H,
我们的芯片是MLC会调用下面代码:
nand_type = S3C_NAND_TYPE_MLC;
nand->options |= NAND_NO_SUBPAGE_WRITE; /* NOP = 1 if MLC */
nand->ecc.read_page = s3c_nand_read_page_4bit;
nand->ecc.write_page = s3c_nand_write_page_4bit;
nand->ecc.size = 512;
nand->ecc.bytes = 8; /* really 7 bytes */
nand->ecc.layout = &s3c_nand_oob_mlc_64;
到了函数nand_scan(struct mtd_info *mtd, int maxchips)
Mtd:nand_info;
Maxchips:1
函数核心代码:
nand_set_defaults(chip, busw); //设置NAND的操作函数集
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, &nand_dev_id, table);
// 读取NAND的型号,并且最终根据{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},来设置nand_chip结构体。
Uboot已经定义好了NAND命令:
U_BOOT_CMD(
nand, CONFIG_SYS_MAXARGS, 1, do_nand,
"NAND sub-system",
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read - addr off|partition size\n"
"nand write - addr off|partition size\n"
" read/write 'size' bytes starting at offset 'off'\n"
" to/from memory address 'addr', skipping bad blocks.\n"
......
)
所以nand的操作都是从do_nand函数开始的:
启动结果:
NAND: NAND device: Manufacturer ID: 0xec, Chip ID: 0xd5 (Samsung NAND 2GiB 3,3V 8-bit)
NAND bus width 8 instead 16 bit
随便测试一下:
210 # nand write.e
no devices available
解决:
屏蔽nand_base函数里:
#if 0
if (IS_ERR(type)) {
#ifndef CONFIG_SYS_NAND_QUIET_TEST
printk(KERN_WARNING "No NAND device found!!!\n");
#endif
chip->select_chip(mtd, -1);
return PTR_ERR(type);
}
#endif
到此NAND的初始化就结束了。现在不如NAND的三大重头戏:
1、nand的擦除函数的实现:
核心代码:
if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
nand_erase_options_t opts;//核心结构体
struct nand_chip *chip = meminfo->priv; //取出初始化设置好的nand_chip;
int ret = meminfo->block_isbad(meminfo, erase.addr); //检测坏块
result = meminfo->erase(meminfo, &erase); //擦除函数
现在看看 meminfo->erase(meminfo, &erase),就是函数nand_erase(struct mtd_info *mtd, struct erase_info *instr)。
参数:mtd结构体,这个负责调用nand_chip的擦除函数,擦除大小信息放在instr结构体。
根据下面的问题:
问题:
210 # nand erase 0 100000
nand_curr_device=0
NAND erase: device 0 offset 0x0, size 0x100000
Skipping bad block at 0x00000000
BUG: failure at nand_base.c:187/nand_select_chip()!
经过打印知道问题所在:
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
printk(KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
*dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
return ERR_PTR(-EINVAL);
}
由于我们执行这个函数,进入if语句了,这样就会返回,导致后面的chip->page_shift = ffs(mtd->writesize) - 1;没有执行,这样chip->page_shift = 0,这问题就大了,在检测坏块的时候nand_block_bad函数:
chipnr = (int)(ofs >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
而select_chip:
static void nand_select_chip(struct mtd_info *mtd, int chipnr)
{
struct nand_chip *chip = mtd->priv;
switch (chipnr) {
case -1:
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
break;
case 0:
break;
default:
BUG();
}
}
这明显就出错。
在if (busw != (chip->options & NAND_BUSWIDTH_16)) 就返回了,导致后面的chip->page_shift没有操作,结果为0。这样,
chipnr = (int)(ofs >> chip->chip_shift)得到的chipnr就有问题,nand_select_chip函数的switch函数就会跑到default:BUG();
所以屏蔽这部分:
#if 0
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
printk(KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
*dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
// return ERR_PTR(-EINVAL);
}
#endif
函数nand_flash_detect_non_onfi是个很重要的函数,我们的芯片重要信息设置(修改的重点):
if
(!type->pagesize) {
int extid;
chip->cellinfo = chip->read_byte(mtd);
extid = chip->read_byte(mtd);
//mtd->writesize = 1024 << (extid & 0x3);
我们的NAND一页是8k,所以修改:
mtd->writesize = 2048<< (extid & 0x3);
extid >>= 2;
//mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
我们的NAND每一页obb为512B,改为:
mtd->oobsize =512;
extid >>= 2;
//mtd->erasesize = (64 * 1024) << (extid & 0x03);
问题:
我们的NAND是以128K为一倍的,所以:
mtd->erasesize = (128 * 1024) << (extid & 0x03);
extid >>= 2;
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
}
启动结果(少了一句):
NAND: NAND device: Manufacturer ID: 0xec, Chip ID: 0xd5 (Samsung NAND 2GiB 3,3V 8-bit)
操作结果:
#nand erase 0 10000000
NAND erase: device 0 offset 0x0, size 0x10000000
Skipping bad block at 0x00800000
Skipping bad block at 0x00880000
Erasing at 0xff80000 -- 100% complete.
OK
擦除函数到这里就解决。
[ 此帖被2012shiyi在2013-03-12 10:41重新编辑 ]
顶端
回复
引用
分享
lihp1603
级别: 侠客
作者资料
发送短消息
加为好友
UID:
87780
精华:
0
发帖:
93
金钱:
470 两
威望:
94 点
贡献值:
0 点
综合积分:
186 分
注册时间:
2013-02-26
最后登录:
2016-07-27
1楼
发表于: 2013-04-01 16:26
全看
|
小
中
大
妹的,搞了半天,我把NAND flash的芯片型号给搞错了,我之前下的哪个资料太啃了,用的是它以前的版本!
顶端
回复
引用
分享
lihp1603
级别: 侠客
作者资料
发送短消息
加为好友
UID:
87780
精华:
0
发帖:
93
金钱:
470 两
威望:
94 点
贡献值:
0 点
综合积分:
186 分
注册时间:
2013-02-26
最后登录:
2016-07-27
2楼
发表于: 2013-04-01 20:10
全看
|
小
中
大
mtd->oobsize =512;
uboot启动以后出现:no oob scheme defined for oobsize
顶端
回复
引用
分享
lihp1603
级别: 侠客
作者资料
发送短消息
加为好友
UID:
87780
精华:
0
发帖:
93
金钱:
470 两
威望:
94 点
贡献值:
0 点
综合积分:
186 分
注册时间:
2013-02-26
最后登录:
2016-07-27
3楼
发表于: 2013-04-02 08:50
全看
|
小
中
大
回 楼主(2012shiyi) 的帖子
图片:
楼主,上面那个有一个我不太明白的是,S5PV210的数据手册上面写它支持的page size在mlc的时候,才4k,可我们用的nand为8k,这个过程是怎么处理的?我的nand现在老是提示上面那条信息,说oobsize有问题,我搜索了一下,在Uboot里面他没的512的支持,楼主对这两步是怎么处理的?
顶端
回复
引用
分享
上一主题
下一主题
友善之家
U-boot技术交流区
http://www.aiothome.net
访问内容超出本站范围,不能确定是否安全
继续访问
取消访问