S3C6410 之裸机程序烧写
学习ARM时,看到三星ARM11 的官方手册上写道:S3C6410具备一个内部SRAM的缓冲器,叫做“STEPPINGSTONE”,支持NAND FLASH的系统引导。当系统启动时,NAND FLASH存储器的前4KB将自动被载入到“SETPPINGSTONE”中,然后系统自动执行这些载入的引导代码。(默认的话该存储区应该被映射到地址空间0处)。
于是一直就想写个裸机程序,长度不超过4KB,存放在NAND FLASH的最开始,这样每次系统上电从NAND FLASH启动时,都会把这段代码拷贝到被映射到地址0x0 处的“STEPPINGSTONE”处。这个应该是bootloader 的雏形吧,一上电就执行的程序。可是在裸机环境下一直找不到烧写NAND FLASH的方法。买了个JLink,貌似在Windows 下据说不能烧写NAND FLASH,尚未验证。网上大部分方法都是针对Uboot 烧写内存,通过USB或者串口,网络。没有看到写道NAND FLASH的方法。没办法,只能凑活着写道内存中,先看看自己的程序是不是写对了。突然有一天,翻翻韦东山老师的书:《嵌入式Linux应用开发完全手册》上一张,降到Uboot中怎么从内存烧写东西到NAND FLASH中去。突然灵机一动,可以将程序先烧到内存中,在从内存中烧到NAND FLASH中去。最后,NAND FLASH中的Bootloader (Uboot)会被覆盖掉,上电就会自动运行自己的裸机程序,而非Bootloader。
想法有了,就去实现下:为此写了个小程序,来验证下。改程序的思路是:四个按键对应四个LED,按键按下,LED亮;松开LED灭。
三个程序如下:
key.c
1 #define KEYCON (*(volatile unsigned long *)0x7F008830)
2 #define KEYDAT (*(volatile unsigned long *)0x7F008834)
3
4 /* 设置Key0 - Key4 为输入状态*/
5 void KeyConfigure()
6 {
7 KEYCON = 0x0;
8 }
9
10 /*只是最简单的查询按键状态,没有消抖功能,毕竟只是验证用*/
11 int KeyStatus()
12 {
13 return KEYDAT;
14 }
led.c
extern int KeyStatus();
extern void KeyConfigure();
#define LEDCON (*(unsigned long int *)0x7F008820)
#define LEDDAT (*(unsigned long int *)0x7F008824)
int main(void)
{
LEDCON = 0x1111; //GPM低四位全部输出
KeyConfigure();
while (1)
{
LEDDAT = KeyStatus() & 0xf; //
}
}
start.s
1 .global _start
2
3 _start:
4
5 /*设置协处理器*/
6 ldr r0, =0x70000000
7 orr r0, r0, #0x13
8 mcr p15, 0, r0, c15, c2, 4
9
10 /* 关闭看门狗定时器 */
11 ldr r0, =0x7E004000
12 ldr r1, =0x0
13 str r1, [r0]
14
15 ldr sp, = 8*1024
16 bl main
17
18 halt:
19 b halt
Makefile
1 CC = arm-linux-gcc
2 LD = arm-linux-ld
3 OBJDUMP = arm-linux-objdump
4 OBJCOPY = arm-linux-objcopy
5
6 OBJ = start.o key.o led.o
7
8 led.bin : led.elf
9 $(OBJCOPY) -O binary led.elf led.bin
10 $(OBJDUMP) -d led.elf > led.dis
11 cp led.bin ~/nfs_root/
12 ##### cp 命令的意思是我把 NFS 文件系统放在了家目录下的nfs_root 里面
13
14 led.elf : $(OBJ)
15 $(LD) -o led.elf -Ttext 0x0 $(OBJ)
16
17 led.o : led.c
18 $(CC) -fno-stack-protector -c -o $@ $<
19
20 key.o : key.c
21 $(CC) -fno-stack-protector -c -o $@ $<
22
23 start.o : start.s
24 $(CC) -fno-stack-protector -c -o $@ $<
25
26
27 clean :
28 rm $(OBJ) led.elf led.bin led.dis
根据上述四个文件,make 即可生成索要烧写的纯二进制文件 led.bin
啰嗦下,之所以使用NFS文件系统通过Uboot和网络烧写二进制文件到内存,而非通过传统的USB烧写,是应为我xxx在64bit的win7 中装不上DNW的USB驱动,穿不了文件。不要问我为什么不用兼容性更好的XP。我是4G的内存,XP只能3G左右的内存,32bit的Win7估计也就3.5G的内存,老子总不能让浪费4G的内存不用吧?再说了,微软不是要放弃XP吗?懒得折腾换到XP了,所以只好用网络烧写了(PS:懒得吐槽windows了)。
至于怎么在Linux主机上开启NFS系统,详见上述韦东山老师的书。(PS:大家不要被我的开发环境给搞晕了,一会Win7一会儿linux的。我主要是在ubuntu上用ARM-linux* 那一套开发的,用的Ubuntu开发环境是在Win7上 用ssh 远程登录操控的,这样一个Ubuntu 主机可以多用户操作,是在是很方便。只是用了下Win7的串口跟开发板相连,应为Ubuntu主机离我很远。所以只能通过交换机 + Ubuntu 主机 + Win7 主机 + 开发板架构了。之所以不用虚拟机,感觉速度太慢,受不了。)
闲话少说:开发板烧写过Uboot 后,上电停留在Uboot状态,退出到命令行输入方式,设置Uboot的网络参数,来和Ubuntu主机通过NFS文件系统烧写程序。
Uboot设置网络参数
1 printenv :
2 bootdelay=1
3 baudrate=115200
4 ethaddr=00:40:5c:26:0a:5b
5 ipaddr=192.168.2.111
6 serverip=192.168.2.100
7 gatewayip=192.168.2.1
8 netmask=255.255.255.0
9 stdin=serial
10 stdout=serial
11 stderr=serial
12
13 上述打印的网络参数中,只有 ipaddr , serverip, gatewayip, netmask 需要设置。我的Ubuntu 主机IP地址为 10.11.52.249, 子网掩码为 255。255.0.0,网关为10.11.52.1
14 所以可以设置开发板的IP地址为 10.11.52.248, 子网掩码和网关筒主机即可。
15 用 setenv name value 命令即可
16 setenv ipaddr 10.11.52.248
17 setenv serverip 10.11.52.249
18 setenv gateway 10.11.52.1
19 setenv netmask 255.255.0.0
20 然后保存:saveenv 即可
然后即可将上面生成的led.bin 烧写到内存中去。
通过NFS文件系统烧写二进制文件到ARM内存中
nfs 0x50000000 10.11.52.249:/home/cat/nfs_root/led.bin
@用法解析
nfs 内存地址 nfs网络文件地址
烧写完后,即可通过uboot 的nand 命令将0x50000000的内存内容烧写到Nand FLASH中去
1 @ 擦除NANDFLASH
2 nand erase 0x0 0x200000
3 命令 擦除 nand偏移 擦除长度
4
5 @ 写NANDFLASH
6 nand write 0x50000000 0x0 0x20000000
7 命令 写 内存地址 nand 偏移 写长度
8
9 @ 读NANDFLASH 到终端,可以跟反汇编文件对比是否正确
10 nand dump 0x0
11 命令 读 从该offset的一个扇区的内容
然后上电,设置开发板从Nand FLASH启动,即可看到上电不会执行Uboot(被裸机程序覆盖掉了),而是直接执行裸机程序了。
注:
(1)start.s 中设置协处理器的原因是ARM11的采用的架构是arm1136jzf-s把memory和Peripheral接口分开了,你需要在初始化时告诉cpu,
哪些地址范围是属于Peripheral的,否则它就当memory访问,当然就访问不到属于Peripheral 区间的IO口寄存器。
可以通过ARM11的协处理器cp15来告诉CPU外设寄存器的地址,在ARM11芯片架构手册上可以看到怎样实现该操作:
CRn Op1 CRm Op2
c15 0 c2 0 Data Memory Remap R/W 0x01C97CC8 page 3-162
1 Instruction Memory Remap R/W 0x01C97CC8 page 3-162
2 DMA Memory Remap R/W 0x01C97CC8 page 3-162
4 Peripheral Port Memory Remap R/W 0x00000000 page 3-162
如果不设置的话,在Uboot下烧写到内存中运行没问题,因为Uboot已经替你设置好了,但是烧写到NAND FLASH中去的话会出现问题,因为没有Uboot替你设置这些东西。
(2) 烧写NAND FLASH时一定要先擦除再烧写,因为nand由于结构的特殊性,只能先充电,再放电,不能直接对每一位置高置低。
因此规定,进行nand写入操作前,必须对nand进行擦除操作。擦除就是充电,对每一位置高,写入0xFF,而写入动作就是对特定位进行放电的操作了,这样才能得到正确的数据
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 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 | 1 | 2 | 3 | 4 | 5 | 6 |
导航
统计
- 随笔 - 91
- 文章 - 1
- 评论 - 13
- 引用 - 0
公告
+加关注
搜索
常用链接
我的标签
- Verilog(1)
随笔分类
随笔档案
- 2016年1月 (1)
- 2015年12月 (1)
- 2015年7月 (3)
- 2015年5月 (2)
- 2015年4月 (1)
- 2015年3月 (5)
- 2015年1月 (3)
- 2014年12月 (1)
- 2014年10月 (2)
- 2014年9月 (1)
- 2014年4月 (1)
- 2014年3月 (1)
- 2014年2月 (2)
- 2014年1月 (1)
- 2013年11月 (2)
- 2013年10月 (1)
- 2013年8月 (6)
- 2013年7月 (1)
- 2013年6月 (7)
- 2013年5月 (2)
- 2013年2月 (1)
- 2012年12月 (2)
- 2012年11月 (3)
- 2012年10月 (4)
- 2012年9月 (1)
- 2012年8月 (1)
- 2012年7月 (4)
- 2012年6月 (2)
- 2012年5月 (1)
- 2012年4月 (3)
- 2012年2月 (3)
- 2011年12月 (2)
- 2011年10月 (7)
- 2011年9月 (13)
最新评论
- 1. Re:express 框架之session
- store: new MongoStore({ })的参数是不是变成了url? 我用这个格式的会报错:host:'localhost', port: 27017, db: '' ,报错是:Connec......
- --ruipos
- 2. Re:express 框架之session
- @天涯没多远抓包和session存在的生命周期有关系吗...
- --比昂
- 3. Re:express 框架之session
- 有一个疑惑,如果session生命周期设为两周,那么岂不是可以可以通过抓包获取他人的sessionid然后通过伪造sessionid登录,造成安全问题。
- --天涯没多远
- 4. Re:C和C++中指针与地址的区别
- 解释的很好
- --Coder_Teng
- 5. Re:在嵌入式Linux系统(OK6410)中移植Boa 服务器
- cgi怎么输出中文到页面呢
- --高QC
阅读排行榜
- 1. express 框架之session(13288)
- 2. 如何在64位的linux系统上使用汇编和C语言混合编程(4009)
- 3. 转--sof和pof文件格式,以及rbf文件(3593)
- 4. express 框架之 路由与中间件(3366)
- 5. 飞凌开发板:S3C6410 之裸机程序烧写(2920)
评论排行榜
- 1. express 框架之session(7)
- 2. FPGA 中的警告:Warning: Some pins have incomplete I/O assignments (Missing drive strength and slew rate)(2)
- 3. 在嵌入式Linux系统(OK6410)中移植Boa 服务器(1)
- 4. 转载-关于C语言中函数调用和参数传递机制的探讨(1)
- 5. C和C++中指针与地址的区别(1)