uboot研读笔记 | 04 - 移植uboot 2012.04到JZ2440(支持Nor Flash读写)

在上一篇文章中初步的移植了 uboot 到JZ2440开发板,参考文章:

在支持Nor Flash操作之前,首先要对Nor Flash的读写方法有一定的了解,参考文章:

uboot启动之后正常打印出了CPU信息(比如时钟信息),但是接下来uboot程序提示flash出错,并且死机,如图,在本文中讲述如何定位问题,解决问题,使uboot支持nor flash读写:

1. 定位Flash读写出错问题

定位出错问题所在的方法很简单,定位到红色的日志信息 “Flash:” 在程序中的位置即可,这个内容搜索在VS Code全局搜索中很慢,所以沿着uboot启动过程寻找,很快,在arch/arm/lib/board.c文件中找到,在函数board_init_r中,也就是uboot启动的第2阶段。

在代码中可以看到:

此处首先打印出日志信息“Flash:”,然后调用 flash_ini t获取 flash_size,接着对获取到的flash_size进行判断,如果flash_size等于0,则再打印“failed”日志,并且调用hang函数,挂起CPU,即死机:

那么,初步定位,问题就在于 flash_init 函数有问题,进入该函数查看其源码。

flash_init 函数的源码定义在drivers/mtd/cfi_flash.c文件中,在该函数中,重点代码如图:

可以看到uboot很尽力了,首先调用flash_detect_legacy函数获取Flash的CFI信息,如果获取失败,则调用flash_get_size 函数获取CFI信息,获取之后,将CFI信息中的Flash 大小赋值给size变量,然后返回。

所以,目前问题变为:这两种获取Flash中CFI信息的方法中出现了错误,没有获取到CFI信息

  • 第一种方法:flash_detect_legacy

通过跳转到其定义,可以看到源码是通过宏定义CONFIG_FLASH_CFI_LEGACY配置的,在smdk2440.h文件中搜索一下,可以看到被定义,所以flash_detect_legacy相关方法启用:

在函数的源码中,有一句调试信息通过debug语句输出,可以通过该条语句来查看读取出的三个ID值:

默认情况下,debug函数是被关闭的, 在该文件最开始开启debug的宏定义:

再次编译uboot:

make distclean
make smdk2440_config
make

然后下载u-boot.bin到Nor Flash去,启动,查看串口输出结果:

是不是很棒!

在输出的调试信息中可以看到,Flash的CFI被读出来了,但Flash仍然失败,有待进一步分析,接着根据源代码分析问题原因。

2. 读出ID正确但Flash还是失败的原因

在调试信息中可以看到,读取出的ID信息为c2 2249 0,查看Nor Flash芯片手册可以看到,0xc2为Manifacture ID,0x2249为Device ID,读出的信息是正确的,但是为什么系统仍然提示Flash出现错误呢?

问题就在于,JEDEC这种古老的标准,它在读取出 ID 信息之后,跑去和Flash库(一个数组)中的信息进行对比匹配,如果匹配到了,就取出预先已经定义好的信息,比如Flash大小之类的信息,如图中红框所示:

jedec_flash_match函数定义在drivers/mtd/jedec_flash.c文件中,源码如图:

翻译一下这个函数的注释就明白了:

将jedec id 和table相比进行匹配,如果匹配到值,则填充整个flash_info结构体!

所以,读取到的ID值正确,但是系统仍然报错Flash的情况只有一个:预先设置的table中不存在目前的FlashID所匹配的信息。

3. 添加板载Nor Flash的jedec信息

jedec_table同样定义在该文件中(drivers/mtd/jedec_flash.c)。

首先是类似于 CONFIG_SYS_FLASH_LEGACY_256Kx8 这样的宏定义,对Flash进行大概的分类,JZ2440开发板板载Nor Flash型号是MX29LV160DBTI-70G,大小是16M-bit,换算是字节大小就是2MB

在jedec_table的最后发给仿照其它信息,添加本款Flash的jedec信息:

  • ① mfr_id

该信息为Manifacture ID,在文件include/flash.h中定义,这里使用MX的:

  • ② dev_id(器件ID)

器件ID在文件drivers/mtd/jedec_flash.c中宏定义,如图,添加本款Flash的:

  • ③ name

这个按喜好写就行。

  • ④ uaddr(unlock addr,解锁地址)

使用16位的解锁地址宏定义 MTD_UADDR_0x0555_0x02AA 即可。

  • ⑤ DevSize(器件容量大小)

容量大小也在drivers/mtd/jedec_flash.c文件中设置,这里选择SIZE_2MiB:

  • ⑥ CmdSet(使用的指令集)

使用默认的CFI_CMDSET_AMD_LEGACY即可。

  • ⑦NumEraseRegions(擦除区域种类个数)

本款Flash芯片的擦除扇区结构总共有4种,如图:

  • ⑧regions

使用ERASEINFO()宏定义填写上面擦除区域种类的详细信息,该宏定义的格式如下:

ERASEINFO(size,blocks)	//表示sIze大小(单位是字节)的扇区有blocks个

综合以上分析,最后填充的本款Flash信息为:

/* JZ2440开发板板载NoR FLASH */
#ifdef CONFIG_SYS_FLASH_LEGACY_1024Kx16
	{
		.mfr_id		= (u8)MX_MANUFACT,
		.dev_id		= MX29LV160DBTI,
		.name		= "MX MX29LV160DBTI",
		.uaddr		= {
			[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
		},
		.DevSize		= SIZE_2MiB,
		.CmdSet			= CFI_CMDSET_AMD_LEGACY,
		.NumEraseRegions	= 4,
		.regions		= {
			ERASEINFO(16*1024, 1),
			ERASEINFO(8*1024, 2),
			ERASEINFO(32*1024, 1),
			ERASEINFO(64*1024, 31),
		}
	},
#endif

添加信息完成后,在单板配置文件include/configs/smdk2440.h中开启这款Flash的宏定义:

编译,下载,在串口终端查看输出:

可以看到flash检测不会卡死,uboot正常启动到命令行界面,但是仍然有一个报错信息,根据报错信息在文件中搜索,找到该行日志的打印位置,可以看到,当扇区数量大于宏定义CONFIG_SYS_MAX_FLASH_SECT时,系统就会打印出这行日志信息:

找到该宏定义在单板配置文件中,该款Flash实际扇区是35个,修改该宏定义:

编译,下载,再次查看串口输出:

可以看到,Flash检测没有任何问题,uboot正常启动到命令行界面,并且命令可以正常使用,调试完毕,不用输出调试信息,所以将drivers/mtd/cfi_flash.c文件中开头添加的宏定义关掉:

再次编译输出,可以看到Flash的检测调试信息不会打印。

4. 修改uboot命令行打印头信息

在之前的打印信息中,uboot命令行可以正常使用,但是打印头信息还是"smdk2410",这里可以在单板配置文件include/configs/smdk2440.h中修改宏定义,如图,改为我们需要显示的信息:

修改之后再次编译,下载,查看串口输出,结果符合预期:

补充,可以使用uboot命令flinfo查看当前flash存储器信息,与上面的知识进行对比理解:

扇区起始地址与数据手册相对应(RO是uboot软件中指定的,RO标示出的是当前程序存储区):

接收更多精彩文章及资源推送,欢迎订阅我的微信公众号:『mculover666』

发布了227 篇原创文章 · 获赞 590 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/Mculover666/article/details/104501251
今日推荐