gnu ucos 加入nandflash 操作并支持nand启动
来源:互联网 发布:ubuntu换语言 编辑:程序博客网 时间:2024/05/21 13:59
nandflash 因为造价低在对大容量的数据存储中发挥着重要的作用。nandflash没有地址或数据总线,如果是8位 nandflash(我见过的最多的情况),那么它只有8个IO口还有一些控制口,控制口在不同状态切换这8个IO口分别用于传输命令、地址和数据。nandflash主要以page(页)为单位进行读写,以block(块)为单位进行擦除。Nand Flash芯片每一位只能从1写为0,而不能从0写为1,所以在对其进行写入操作之前一定要将相应块擦除(擦除就是将相应块的位全部变为1)
s3c2440处理器集成了 nandflash 控制器,还有一个特殊的功能:在系统刚上电之后不依赖于任何代码 把nandflash前4K的内容搬运到“Steppingstone”的内部SRAM缓存。
然后把该Steppingstone映射为Bank0,最后从这4K代码开始执行。这个功能很有用,可以把系统最必要的初始化代码和搬运的代码放到这4K当中--4K已经够多了,记得以前
看《自己动手写操作系》那个bios只是把512字节的东西搬运到内存中。搬运代码就负责把剩余的代码从nandflash中搬运到ram中,然后跳转到ram中去执行主要的程序!
这里使用的是mini2440上的K9F1G08,跟赵春江老师的K9F2G08U0A 几乎无多大差别。 这里的1G代表1Gbit 也就是128Mbyte。关于nandflash命名规则可见如下链接:blog.sina.com.cn/s/blog_604c12520100tqil.html
K9F2G08U0A的一页为(2K+64)字节(加号前面的2K表示的是main区容量,加号后面的64表示的是spare区容量),它的一块为64页,而整个设备包括了2048个块。这样算下来一共有2112M位容量,如果只算main区容量则有256M字节(即256M×8位)。
要实现用8个IO口来要访问这么大的容量,K9F2G08U0A规定了用5个周期来实现。第一个周期访问的地址为A0~A7;第二个周期访问的地址为A8~A11,它作用在IO0~IO3上,而此时IO4~IO7必须为低电平;第三个周期访问的地址为A12~A19;第四个周期访问的地址为A20~A27;第五个周期访问的地址为A28,它作用在IO0上,而此时IO1~IO7必须为低电平。前两个周期传输的是列地址,后三个周期传输的是行地址。通过分析可知,列地址是用于寻址页内空间,行地址用于寻址页,如果要直接访问块,则需要从地址A18开始。
下面重点介绍下如何实现从nandflash中启动。
首先判断是从仿真器启动还是从nandflash启动:
/* * we do sys-critical inits only at reboot, * not when booting from ram! */adrr0, _start/* r0 <- current position of code */cmp r0, #0x0/* don't reloc during debug */blnecpu_init_critblmemsetup/* we run from nandflash*/@ copy ucos to RAMmov r0, #0x0ldrr1, =TEST_RAMmovr2, #0x100000@ get read to call C functions (for copy2ram)ldrsp, DW_STACK_START@ setup stack pointerblcopy2ramcpu_init_crit:movr1, #GPIO_CTL_BASEaddr1, r1, #oGPIO_F这里的adr是相对寻址,也就是从相对于当前 pc 的位置得到标号_start的位置,可见如下链接:
blog.csdn.net/sukhoi27smk/article/details/8876201
上面前3条指令反汇编形式是:
300000c0:e24f00c8 subr0, pc, #200; 0xc8300000c4:e3500000 cmpr0, #0300000c8:1b000005 blne300000e4 <cpu_init_crit>如果是从jtag仿真器 启动那么 _start 被放在0x30000000 位置处r0与0不等,跳转到cpu_init_crit执行。
如果是被烧写到nandflash中并被2440加载到前4K 那么得到的r0寄存器值也就是0。 接下来就执行memsetup 和 copy2ram 。
注意前面在仿真器加载的时候首先load并运行了一个初始化ram的bin文件,这里从 nandflash 启动需要先把ram初始化 然后才能拷贝flash中数据进来。
然后就是copy2ram :
int copy2ram(unsigned long start_addr, unsigned char *buf, int size)
从左到右 第一个参数是 start_addr :
对应着 mov r0, #0x0 也就是从 nandflash 偏移为0出开始读,当然也包括开始的那4K
第二个参数 buf 对应着 ldr r1, =TEST_RAM 前面宏定义 #define TEST_RAM 0x30000000 把nandflash数据拷贝到这个位置。
第三个参数 size 对应着 mov r2, #0x100000 也就是拷贝1M 大小的数据,这个对于我们的小项目来说已经够了。
整个 nandflash 拷贝操作代码是从 u-boot 里面拷贝出来的,直接上代码没必要讲解 。值得注意一点就是函数 nand_read_ll 有一个如下的循环:
for(i=start_addr; i < (start_addr + size);) {/* ·¢³öREAD0ÃüÁî */write_cmd(0);/* Write Address */write_addr_lp(i);write_cmd(0x30);wait_idle();for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {*buf = read_data();buf++;}}如果程序用最高优化等级编译,那么编译器会把上面循环优化的,像 write_cmd read_data 之类的都会拿到循环外面来,这是肯定不对的。
所以对于这种函数要禁止编译器优化需要在函数前面加个声明:
void __attribute__((optimize("O0"))) nand_read_ll(unsigned char *buf,unsigned long start_addr, int size)
还有其它一些函数也需要 禁止优化。
关于优化的可见下面文章:
http://forum.andestech.com/viewtopic.php?f=16&t=225
最后就是 跳转到主程序开始执行了,注意这里要是绝对跳转指令才行(因为这条跳转指令有可能在前4K中,也有可能在0x30000000 以后的某个地址处)!
ldrpc,__main__main:.word main@blmain@ call mainb .
反汇编形式如下:
30000104:e51ff004 ldrpc, [pc, #-4]; 30000108 <__main>30000108 <__main>:30000108:300005c4 andccr0, r0, r4, asr #113000010c:eafffffe b3000010c <__main+0x4>
看到了正好跳转到 0x300005c4 ,也就是main函数起始地址。
前面的函数 copy2ram 把前4K的内容也拷贝到了 0x30000000 位置处,这里的跳转跳转到了 0x300005c4 。
这里还有一些约束条件那就是拷贝 nandflash 的c 文件要被连接器链接进前 4K 里面,这个可以在 ucos.lds 里面指定。 在跳转到main函数之前的代码可能在
两个地址执行(0x00,0x30000000)所以需要是位置无关的,关于位置无关代码可见如下链接:
blog.csdn.net/ustc_dylan/article/details/6965330
示例代码中在Task0 里面有个函数关于nandflash验证的代码如下:
void nand_test(){UINT8buff[2048];inti;for(i = 0;i < 2048;i ++)buff[i]= i & 0xff;nand_init_ll();printf("erase result is %x\r\n",nand_eraseblock(8));printf("write result is %x\r\n",nand_writepage(515,buff,2048));for(i = 0;i < 2048;i ++)buff[i]= 0x0;printf("read result is %x\r\n",nand_read_3(515 * 2048,buff,2048));for(i = 0;i < 4;i ++){printf("%2x ",buff[i]);}nand_ramdom_write(514,2048 - 33,0xf4);printf("result is :%x \r\n",nand_ramdom_read(514,2048 - 33));nand_readID(buff);printf("nand ID is :");for(i = 0;i < 5;i ++)printf("%x ",buff[i]);printf("\r\n");}
上面功能依次是
擦除一块nandflash
向擦除的flash 某个页写一页数据,读出来刚才写的数据;
nand随机写然后再随机读刚才写的数值
读出nandflash的ID
另外还有一个大小端的问题,arm架构支持大小端模式切换,但默认的是小端模式; nandflash 是8位的, 字访问,半字访问,字节访问 读出来字节序列不一样的!! 为了加快速度,一般都选择字访问! 当 nand_readpage 调用函数接口是 nand_read_page
当按照字节读的时候:
for(j=0; (j < NAND_SECTOR_SIZE_LP) && (j < size); j++ ) {
*buf = read_data8();
buf++;
}
打印结果如下:
erase result is 66
write result is 66
read result is 66
0 1 2 3
当按照字读取的时候:
for(j=0; (j < NAND_SECTOR_SIZE_LP) && (j < size); j+=4 ) {
*(UINT32 *)buf = read_data();
buf+=4;
}
erase result is 66
write result is 66
read result is 66
0 1 2 3
可见是小端模式访问!
nandflash操作很多控制细节 都是是参考 zhaocj 的讲解来的,这里就不多废话了。参考链接:
blog.csdn.net/zhaocj/article/details/5803699
blog.csdn.net/zhaocj/article/details/5795254
可以去我的github clone 完整的代码。
- gnu ucos 加入nandflash 操作并支持nand启动
- 给gnu ucos 加入printf 支持
- gnu ucos 加入lcd 显示
- gnu-ucos 加入 bmp 位图显示
- 移植u-boot1.1.4支持操作nandFlash的nand erase命令
- 移植最新uboot之:支持NANDFLASH启动
- 移植u-boot-2012.04----支持Nandflash启动
- u-boot:从NOR FLASH启动并支持NAND FLASH读写的移植
- uboot移植支持nand flash启动
- S5PV210:支持NAND启动u-boot
- 移植u-boot-2012.04----支持nand启动
- 支持nandflash启动,具有USB功能的UBOOT移植
- 移植u-boot12.04到jz2440 -->支持nandflash启动
- 深度分析NandFlash—start.s中添加从Nand Flash启动的代码分析
- uboot的nandflash启动saveenv时Writing to Nand... FAILED问题解决办法
- Eclipse加入PHP插件并支持PHP
- NANDFLASH操作
- nandflash操作
- Win8.1 因权限导致软件安装失败解决办法
- 交替颜色的表格
- HttpURLConnection还是HttpClient?这是个问题!
- 贫穷是一种病,你要治好它
- 尔特热特特特特特瑞特特天宇天宇
- gnu ucos 加入nandflash 操作并支持nand启动
- stty介绍
- data cleaning(数据清洗) 课程笔记
- node pm2 启动 Error: getaddrinfo ENOTFOUND 解决方法
- VS2010未能正确加载"XXX"包
- 即可李经理极乐教两节课两节课两节课
- maven 配置
- TF-IDF java实现
- 天宇天宇天宇特特特忒u偶i偶i偶