- 第001节辅线1_硬件知识_LED原理图
- 第002节辅线1_硬件知识_s3c2440启动流程与GPIO操作
- 第003节编写第一个程序点亮LED
- 第004节汇编与机器码
- 第005006节编程知识_进制-字节序
- 第007节编写C程序控制LED
- 第008节
- 第009节解析C程序的内部机制
第001节:辅线1_硬件知识_LED原理图
-
实现点亮LED的步骤:\
-
1.看原理图,确定控制led的引脚\
- 通过主芯片使用引脚输出:3.3V点亮led;0V熄灭led。
-接法:
- 引脚驱动能力不足:使用三极管,
- 接法介绍:
-接法1:
-接法2:
- 通过主芯片使用引脚输出:3.3V点亮led;0V熄灭led。
-
2.看主芯片手册,确定如何设置/控制引脚
-
3.写程序
-
第002节:辅线1_硬件知识_s3c2440启动流程与GPIO操作
-
知识点:
-
网络net,同名的net表示连接在一起
-
网络中的n,常表示低电平有效
-
怎么让GPF4输出1/0\
- 先配置为输出引脚
- 设置状态
-
设置GPFCON[9:8]=0b01(0b表示二进制,9为0,8为1),GPF4配置为输出
-
设置GPFDAT[4]=1:输出高电平,led熄灭
-
设置GPFDAT[4]=0:输出低电平,led点亮
-
-
S3C2440框架与启动过程:
-
S3C2440框架图:
-
启动过程:大多数ARM芯片从0地址启动
-
Nor启动时候,Nor Flash基地址为0;片内RAM地址为0x4000,0000\
- cpu读出Nor上第一个指令(前4字节),执行,
- cpu继续读出其他指令执行。
-
Nand启动,片内4kRAM基地址为0; Nor Flash不可以访问\
- 2440硬件把Nand前4k内容复制到片内RAM,
- 然后cpu从0地址取出第一条指令执行。
-
第003节:编写第一个程序点亮LED
-
怎么让GPF4输出1/0的方法:
-
先配置为输出引脚
-
设置状态
\-
设置GPFCON[9:8]=0b01(0b表示二进制:9为0,8为1),GPF4配为输出
-==>把0x100写入GPFCON,即写到地址0x5600,0050上 -
设置GPFDAT[4]=1:输出高电平,led熄灭
-==>把0x10写到地址0x5600,0054上 -
设置GPFDAT[4]=0:输出低电平,led点亮
-==>把0写到地址0x5600,0054上\- 补充知识:
- 补充知识:
-
-
-
几条汇编代码:
-
LDR(load):读内存命令,\
- LDR RO,[R1]:假设R1的值为x,则读取地址x上的数据(4字节),保存到R0中
-
STR(store):写内存命令\
- STR R0,R[1]:假设R1的值为x,把R0的值写入地址x(4字节)
- B:跳转
-
MOV(move):\
- MOV R0, R1:把R1的值赋给R0,即R0=R1
- MOV R0,#0x100:即把R0=0x100
- LDR R0, =0X12345678:伪指令,它会被拆分为几条真正的RAM指令
- 引入伪指令, “LDR R0,=任意值” 的原因:
-ARM指令一共32位,会有部分字节表示指令,某些存储R0,其余剩余的不足32位,不能表示任意值,只能表示简单值(被称为立即数)。
-
-
安装arm-linux-gcc注意事项以及相关重点:
第004节:汇编与机器码
- CPU寄存器及其别名:
寄存器名 | 别名 | 全称 |
---|---|---|
R1 | ||
R2 | ||
R3 | ||
R4 | ||
R5 | ||
R6 | ||
R7 | ||
R8 | ||
R9 | ||
R10 | ||
R11 | ||
R12 | ||
R13 | sp | stack point:栈指针 |
R14 | lr | link register:保存返回地址 |
R15 | pc | program counter:程序计数器 |
-
详细介绍:\
-
program counter:程序计数器=当前指令+8\
- 流水线:当前执行地址A的指令,已经在对地址A+4的指令进行译码,已经在读取地址A+8(即PC的值)的指令
-
-
反汇编指令理解:
-
0: e59f1014 ldr r1, [pc, #20] ; 1c <halt+0x4>
\- r1=[pc+20]=[8+20]=[0x1c]=0x56000050
-
8: e5810000 str r0, [r1]
\- 把r0即0x100,写入r1对应的内存,0x100–>[0x56000050]:即GPFCON寄存器
-
c: e59f100c ldr r1, [pc, #12] ; 20 <halt+0x8>
\- r1=[pc+12]=[0xc+8+12]=[32]=[0x20]=0x56000054:即GPFDAT寄存器
- GPFCON/GPFDAT在CPU中,都是作为内存
-
完整代码:
led_on.elf: file format elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
0: e59f1014 ldr r1, [pc, #20] ; 1c <halt+0x4>
4: e3a00c01 mov r0, #256 ; 0x100
8: e5810000 str r0, [r1]
c: e59f100c ldr r1, [pc, #12] ; 20 <halt+0x8>
10: e3a00000 mov r0, #0
14: e5810000 str r0, [r1]
00000018 <halt>:
18: eafffffe b 18 <halt>
1c: 56000050 undefined instruction 0x56000050
20: 56000054 undefined instruction 0x56000054
Disassembly of section .ARM.attributes:
00000000 <.ARM.attributes>:
0: 00001941 andeq r1, r0, r1, asr #18
4: 61656100 cmnvs r5, r0, lsl #2
8: 01006962 tsteq r0, r2, ror #18
c: 0000000f andeq r0, r0, pc
10: 00543405 subseq r3, r4, r5, lsl #8
14: 01080206 tsteq r8, r6, lsl #4
18: Address 0x00000018 is out of bounds.
-
练习题:\
- 修改len_on.s到点亮LED2
- 直接修改led_on.bin点亮LED2
-
mov指令机器码:
-
4: e3a00c01 mov r0, #256 ; 0x100
-
故:当代码为mov r0,#0x400,即修改最后的12位立即数(=immed_8循环右移(2*rotate)位)\
- 12位立即数中高4位,表示rotate,低8位:immed_8
-
具体介绍:
-
举一反三:
第005、006节:编程知识_进制-字节序
-
进制:
- 如何快四转化2/8/16进制:
- 8421
- 0b开头:2进制
- 0开头:8进制
- 0x开头:16进制
-
字节序:
- 低位存放低地址:小字节序(little endian)
- 高位存在低地址:大字节序(big endian)
-
位操作:
-
移位:\
- 左移:int a=0x123; int b=a<<2=?
-通过8421来转化为二进制,即a=0001,0010,0011,故b=0100,1000,1100=8421=0x48C=0x123*(2^2)=0x123*4 - 右移:int a=0x123; int b=a>>2=?
-故a=0001,0010,0011; 则b=00,0100,1000=0x48=0x123/4=0x48
- 左移:int a=0x123; int b=a<<2=?
-
取反: 原来为0的位变为1;原来为1的位变为0\
- int a=0x123; int b=~a=0xfffffedc???
-
位与: c=a&b\
- 1 and 1 = 1;
- 1 and 0 = 0;
- 0 and 1 = 0;
- o and 0 = 0;
-
位或:c=a|b\
- 1 or 1 = 1;
- 1 or 0 = 1;
- 0 or 1 = 1;
- o or 0 = 0;
-
置位:\
- int a=0x123,把bit7,8置位
- int b=a|(1<<7)|(1<<8)
-
-
清位:
- int a=0x123,把bit7,8清除
- int b=a&(~(1<<7))&(~(1<<8))
第007节:编写C程序控制LED
- C指针操作:
- 1.所有的变量在内存中都有一块区域
- 可以通过变量/指针来操作内存
第008节:
-
几条汇编代码:
-
LDR(load):读内存命令,\
- LDR RO,[R1]:假设R1的值为x,则读取地址x上的数据(4字节),保存到R0中
-
STR(store):写内存命令\
- STR R0,R[1]:假设R1的值为x,把R0的值写入地址x(4字节)
- B:跳转
-
MOV(move):\
- MOV R0, R1:把R1的值赋给R0,即R0=R1
- MOV R0,#0x100:即把R0=0x100
- LDR R0, =0X12345678:伪指令,它会被拆分为几条真正的RAM指令
- 引入伪指令, “LDR R0,=任意值” 的原因:
-ARM指令一共32位,会有部分字节表示指令,某些存储R0,其余剩余的不足32位,不能表示任意值,只能表示简单值(被称为立即数)。
-
add:\
- add r0,r1, #4==>r0=r1+4
-
sub:\
- sub r0, r1,#4==>r0=r1-4
- sub r0, r1,r2==>r0=r1-r2
-
BL(branch and link):
- bl * * *:
-跳转到* * *;
-并将返回地址(下一条指令的地址)保存在lr寄存器中
- bl * * *:
-
ldm(many):读内存,写入多个寄存器
- ldmia:
-
stm: 把多个寄存器的值写入内存\
- stmdb:
-
过后增加(Increment After)、预先增加(Increment Before)、过后减少(Decrement After)、预先减少(Decrement Before)。
-
举例:
-