1.启动过程
从两种方式来简单介绍启动方式,分别是Nor启动和Nand启动
Nor启动
使用Nor启动时,NorFlash的基地址为0,片内RAM地址为0x4000,0000
CPU读出Nor上第一个指令(前4个字节)执行。
Nand启动
使用Nand启动时,片内RAM的基地址为0,NorFlash是不可访问的状态。
2440的硬件把Nand前4K内容搬移到片内RAM中,然后CPU从0地址取出第一条指令执行。
CPU取第一条指令都是从0地址去取,只不过不同的启动方式,对应的0地址是不同的。有了第一条指令并执行,剩下的也就像多米诺骨牌一样。
2.汇编知识
LDR 读内存
LDR R0 ,[R1] 类似C语言中,R0 = *R1,读取R1指向内存区域中的内容,存入R0
STR 写内存
STR R0 ,[R1] 类似C语言中, *R1 = R0,将R0写入R1指向的内存区域
B 无条件跳转指令
MOV
MOV R0,R1 把 R1的值赋给R0
MOV R0,#0x100 把 100赋给R0
LDR伪指令
LDR R0,=0x12345678这句话的意思是,把0x12345678这个值赋给R0
但是我们会有一个问题?为什么我们不用MOV指令来将这个值给R0呢?其实原因很简单,每条指令最终都会翻译成32位(4字节)的机器码,机器码上需要几位来表示操作指令(MOV还是B,或者是其他),还需要几位来表示操纵哪个寄存器,有时候还需要目的寄存器。这么下来,一条留给我们表示0x12345678这个数肯定是不够32位(4字节)的,所以一条指令完成不了这个赋值任务,所以需要用LDR伪指令来赋值。LDR伪指令最终是要被翻译成多条指令来完成这个任务的。
add
add r0,r1,#4 相当于r0=r1+4
sub
sub r0,r1,#4 相当于r0=r1-4
sub r0,r1,r2 相当于r0=r1-r2
bl
bl main 跳转到main,并且把返回地址(即下一条指令地址)保存在lr寄存器中
ldm 读内存,写入多个寄存器
ldmia sp,{fp,sp,pc}
其中ia(increase after) 后缀的意思是"先读后增",什么叫先读后增呢,就是先把sp指向的位置的值读到寄存器中,之后sp再增加。(或者说先操纵数据,后移动指针)
stm 把多个寄存器的值,写入内存
stmdb sp!,{fp,ip,lr,pc}
其中db(decrease before)后缀的意思是"先减后存",什么叫先减后存呢,就是sp先减少,之后把寄存器中的值存到sp指向的位置(或者说先移动指针,后操纵数据)
例子1:点灯程序led_on.S
.text
.global _start
_start:
/*配置GPF4为输出引脚*/
ldr r1,=0x56000050
mov r0,#0x100
str r0,[r1]
/*配置GPF4输出高电平*/
ldr r1,=0x56000054
mov r0,#0
str r0,[r1]
/*死循环*/
halt:
b halt
编译 arm-linux-gcc -c -o led_on.o led_on.S
链接 arm-linux-ld -Ttext 0 led_on.o -o led_on.elf
生成bin arm-linux-objcopy -o binary -S led_on.elf led_on.bin
反汇编 arm-linux-objdump -D led_on.elf > led_on.dis
例子2:在汇编中调用main函数
.text
.global _start
_start:
/*设置内存: sp栈*/
ldr sp,=4096 /*nand启动*/
//ldr sp,=0x40000000+4096 /*nor启动*/
/*调用main*/
bl main
halt:
b halt
例子3:判断是nor/nand启动
在编写程序时,需要先了解nor和nand的区别,通过区别编写程序就能得到实际的启动方式
/* 写0到0地址,再读出来
* 如果得到0,表示0地址上的内容被修改了,他对应ram,这就是nand启动
* 否则就是nor启动
*/
mov r1,#0
ldr r0,[r1] /*读出原来的值备份*/
str r1,[r1] /*0->[0]*/
ldr r2,[r1] /*r2=[0]*/
cmp r1,r2 /*r1 == r2? 如果相等,是NAND启动*/
ldr sp,=0x40000000+4096 /*先假设是nor启动*/
moveq sp,#4096 /*nand启动*/
streq r0,[r1] /*恢复原来的值*/
3.gcc
4.Makefile
为什么要引入Makefile?因为makefile能只编译修改过的.c为.o,免去了重复编译的过程,提高效率。
4.1 Makefile基础
规则
当依赖比目标新的时候(也就是修改过了),执行命令
目标文件:依赖文件
通配符 test:a.o b.o gcc -o test $^ %.o:%.c gcc -c -o $@ $< 【第二行】 $^表示所有的依赖,在上面的例子中也就是a.o b.o 【第三行】 %.o:%.c 对所有.c文件,都生成.o文件 【第四行】 $@ 表示的是目标文件,也就是%.o。$<表示第一个依赖文件,也就是%.c 假想目标 通过执行make <目标>命令,就可以执行makefile中相应目标文件下的命令(要满足依赖比目标新的规则)。如果没有<目标>的话,则会默认执行第一个目标。 有时候我们会遇到这种情况,如下所示 clean: rm *.o test 如果这个时候目录中存在名字叫clean的文件的话,根据"依赖比目标新就执行命令"的规则,目标clean是没有依赖的,也就是依赖没有目标新,这个时候我们执行make clean命令的时候不能达到预期的效果。这时候就需要假想目标,声明假想目标的方式很简单,如下所示。 clean: rm *.o test .PHONY: clean 声明假想目标之后,在执行make clean就能达预期的效果了。 即时变量,延时变量 A:= xxxx A的值即可确定,这是即时变量 B = xxxx B的值使用到时才确定,这是延时变量 下面用一个例子更好说明这一点 A:= $(C) B = $(C) C = abc all: @echo $(A) @echo $(B) 最终打印出来的结果是 A为空,B为abc。 makefile函数 $(foreach var,list,test) 这个函数的作用就是提取list中的每个字符串成员(以空格划分),赋值给var,之后变成test,这样说可能比较抽象,我们看一个例子。 A = a b c B = $(foreach f,$(A),$(f).o) all: @echo B = $(B) 最终打印的结果为B = a.o b.o c.o,例子中的a b c分别赋值给f,再变成$(f).o,也就是a.o b.o和c.o $(filter pattern ...,text) 在text中取出符合pattern的值 $(filter-out pattern ...,text)在text中取出不符合pattern的值 C = a b c d/ D = $(filter %/,$(C)) E = $(filter-out %/,$(C)) all: @echo D = $(D) @echo E = $(E) 最终打印的结果为 D = d/ E = a b c $(wildcard pattern) 在pattren中定义了文件名格式,wildcard函数的作用是取出这个符合这个格式并且存在的文件 例子:首先我们先假设当前目录下存在a.c b.c c.c三个文件 files = $(wildcard *.c) filesname = a.c b.c c.c d.c e.c files2 = $(wildcard $(filesname)) all: @echo files = $(files) @echo files2 = $(files2) 最终打印的结果为 files = a.c b.c c.c 符合*.c格式 files2 = a.c b.c c.c d.c e.c由于当前目录不存在,所以没有打印 $(patsubst pattern,replacement,$(var)) 从var中取每个值,如果符合pattern,就替换为replacement 例子: files = a.c b.c c.c d.c e.c abc dep_files = $(patsubst %.c,%.d,$(files)) all: @echo dep_files = $(dep_files) 最终打印的结果为 dep_files = a.d b.d c.d d.d e.d abc 4.2 Makefile自动依赖 其中目录文件如下 在向makefile中自动添加头文件依赖的之前,我们需要知道下面几条gcc命令 gcc -M main.c 查看main.c依赖的头文件(-M会将标准库的头文件也包含进来,如果不想这样,可以使用-MM),例如下面所示: 我们也可以将结果输出重定向到对应的.d文件中,如下所示: gcc -MM main.c > main.d sed命令 sed是一个非交互式的流编辑器。而流编辑器是指sed每次只从文件(或输入)读入一行,然后对该行进行指定的处理,并将结果输出到屏幕,接着读入下一行。 通过sed命令我们可以将main.d中的内容进行修改,由main.o: main.c szg_math.h 变更为main.o main.d : main.c szg_math.h 将main.d加入到目标文件中。 sed 's,(main).o[ :]*,1.o main.d : ,g' < main.d > main.q 看到结果果然如我们所料。上面的命令大体上分为两个步骤。 1.将main.d中内容交给sed进行处理 2.将sed处理好后的内容输出到main.q(名字瞎取的) 下面我们详细的分析一下sed命令的处理流程和参数意义: sed 's,(main).o[ :]*,1.o main.d : ,g' sed中的s符号告诉sed命令,这次要做一个替换的任务。 s符号的格式为:[address[,address]] s/pattern-to-find/replacement-pattern/[g p w n]。 [address[,address]]:是指要处理的行的范围,在这次的操作中采用的是默认值。 pattern-to-find:是指要匹配的字符串,在这次操作中指的是(main).o[ :]*。 (main)指的就是main,只不过括起来加入到符号表中,之后我们可以通过1来等价于main。 .o就是匹配字符.o。 [ :]*就是正则表达式,其意思为匹配若干个空格和冒号。 所以这一字段匹配的字符其实就是main.o: replacement-pattern:是指要替换成的字符串,在这次操作中指的是1.o main.d :,将1替换过来其实就是main.o main.d : 在有了以上几条命令之后,我们用一个比较综合的例子来进行说明 # wildcard找到当前目录下所有的.c文件 # patsubst将所有%.c转化为%.o SRC_FILES=$(wildcard *.c) OBJ_FILES=$(patsubst %.c,%.o,$(SRC_FILES)) CC = gcc CFLAGS = -lpthread -g test:$(OBJ_FILES) $(CC) -o test $^ $(CFLAGS) %.o:%.c $(CC) -c -o $@ $< $(CFLAGS) sinclude $(SRC_FILES:.c=.d) # 1.@ 告诉makefile不打印命令 # 2.set -e的作用是告诉后面命令返回值非0时立刻退出,用分号是为了让 # set -e作用到后面所有命令(makefile 中的''就是连接下一行,让其视为同一行命令) # 3.$(CC) -MM $(CFLAGS) $< > $@.$$$$ # $$是转义字符$,假设$@是a.d 那最终执行的就是 > a.d.$$ 其中$$在shell中的特殊变量表示执行进程号 %.d:%.c @set -e;rm -f $@; $(CC) -MM $(CFLAGS) $< > $@.$$$$; sed 's,($*).o[ :]*,1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$ clean: rm *.o *.d test .PHONY:clean
上一篇:《2440裸机》时钟体系
下一篇:《2440裸机》UART
推荐阅读最新更新时间:2024-11-11 10:39
推荐帖子
- 对于1KV的高压,它的放电回路电阻应该怎么设置啊?
- 对于1KV的高压,它的放电回路电阻应该怎么设置啊?对于1KV的高压,它的放电回路电阻应该怎么设置啊?根据你的放电电流,电阻能达到相应的功力并有一定余量即可10M,1/8w原帖由jxb01033016于2010-3-2909:25发表10M,1/8w 你,,,够狠,早爆了
- linda_xia 模拟电子
- “玩板”+周航慈书第10章第2个例子
- 此内容由EEWORLD论坛网友chenbingjy原创,如需转载或用于商业用途需征得作者同意并注明出处第10章采样任务设计10.2使用定时器中断控制采样周期当采样周期与节拍周期在同一个数量级时,如果仍然用延时函数来控制采样周期,其采样周期的时间抖动将比较明显(相邻两次采样的时间间隔误差不能忽略),会严重影响采样结果的质量。这时,可以另外使用一个定时器,由定时中断产生稳定的采样周期。下面的例子是用AD芯片TLC549采集电压值,采样周期由定时器3来控制,采
- chenbingjy 测评中心专版
- LPC1768芯片,关于USB连接复位问题
- 以前我用导线把3脚与4脚短接,我的芯片就会复位。用15脚与16脚短接,芯片不会复位。今天测试发现不行,不明白原因。请教怎么才能让芯片,每次想要复位的时候都复位一下。因为我想外部接一个按钮LPC1768芯片,关于USB连接复位问题红包求助啊,可以给个红包,真的没办法了
- yunhai14 ARM技术
- 关于MP3硬件开源的全套资料(GD5600 GD5800 GD5801系列)
- 国电科技全面开源MP3硬件,包括GD5600GD5800GD5801系列最小工作系统里面包括PCB,原理图,BOM表,datasheet,用户只需下载就可以直接导入生产,非常方便,让没有设计能力的公司省去了设计的繁琐。此开源资料生产的模块可以直接用于防盗器,提示器,工业报警器等安防领域。只要有使用到声音的地方都能用到它!关于MP3硬件开源的全套资料(GD5600GD5800GD5801系列)偶也下来看看,菜鸟找入门资料学习下来学习学习!!谢谢提供下载来玩玩学习哈!
- piao100 下载中心专版
- 关于高频信号线和多层电路板走线
- 有没有这方面的书推荐一下,去书店逛了一圈,发现讲这类的书很难找。关于高频信号线和多层电路板走线关于高频,纸上谈兵的也只是点理论,实践相当重要。你可以到外国大的网站(电子公司)去看看,推荐一本还不错的,挺实用的一本书:《pcb和电磁兼容设计》江思敏28元。里面有很多关于高速信号如何LAYout的内容,对实际的工作也很有用的
- trason 嵌入式系统
- 【BIGTREETECH PI开发板】+08.音频测试(zmj)
- 【BIGTREETECHPI开发板】+08.音频测试(zmj)BIGTREETECHPi开发板拥有一个3.5mm音频接口,既可以播放音乐也可以用来录音。理论上讲可以一边听歌一边玩开发板(●'◡'●)1.程序安装BIGTREETECHPi开发板的系统支持常见的各种音频播放器软件,大家可以依据自己喜好自行选择,我这边安装了一堆//------播放器及依赖安装(可选)sudoaptinstallzoom-playerwor
- 卿小小 国产芯片交流
设计资源 培训 开发板 精华推荐
- 10MB/s 多协议芯片组使用 LTC1543 电缆可选多协议 DTE/DCE 端口支持 Net1 和 Net2 标准
- A_35_V10基于IPS2电机换向传感器的设计
- usrp 8200mini sdr 软件无线电,收音机
- STC8F2K08S2
- EVAL-ADG5208FEBZ,ADG5208F 过压保护 8:1 多路复用器评估板
- PCA85263ATL-ARD评估板
- LT5400 四路匹配电阻网络的典型应用
- MBN52832,WSM-BL241-ADA-008 BLE 模块的参考设计
- 开源例子
- VAR-DVK-MX6_PRO,基于 VAR-SOM-MX6 的开发套件,带有 7" LCD 和电容式触摸面板