linux系统学习1-8:第1个ARM裸板程序及引申

  • 第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。
        -接法:
        linux系统学习1-8:第1个ARM裸板程序及引申_第1张图片
      • 引脚驱动能力不足:使用三极管,
      • 接法介绍:
        -接法1:
        linux系统学习1-8:第1个ARM裸板程序及引申_第2张图片
        -接法2:
        linux系统学习1-8:第1个ARM裸板程序及引申_第3张图片
    • 2.看主芯片手册,确定如何设置/控制引脚
    • 3.写程序

第002节:辅线1_硬件知识_s3c2440启动流程与GPIO操作

  • 知识点:

    • 网络net,同名的net表示连接在一起
    • 网络中的n,常表示低电平有效
    • 怎么让GPF4输出1/0
      • 先配置为输出引脚
      • 设置状态
        linux系统学习1-8:第1个ARM裸板程序及引申_第4张图片
    • 设置GPFCON[9:8]=0b01(0b表示二进制,9为0,8为1),GPF4配置为输出
    • 设置GPFDAT[4]=1:输出高电平,led熄灭
    • 设置GPFDAT[4]=0:输出低电平,led点亮
  • S3C2440框架与启动过程:

    • S3C2440框架图:
      linux系统学习1-8:第1个ARM裸板程序及引申_第5张图片
    • 启动过程:大多数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的方法:

    • 先配置为输出引脚
    • 设置状态
      linux系统学习1-8:第1个ARM裸板程序及引申_第6张图片
      • 设置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上
        • 补充知识:
          linux系统学习1-8:第1个ARM裸板程序及引申_第7张图片
  • 几条汇编代码:

    • 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注意事项以及相关重点:

    • 安装32位库
    • 如何判断ubuntu的版本

第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
    • 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
    • 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 
   4:   e3a00c01    mov r0, #256    ; 0x100
   8:   e5810000    str r0, [r1]
   c:   e59f100c    ldr r1, [pc, #12]   ; 20 
  10:   e3a00000    mov r0, #0
  14:   e5810000    str r0, [r1]

00000018 :
  18:   eafffffe    b   18 
  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
    这里写图片描述
    linux系统学习1-8:第1个ARM裸板程序及引申_第8张图片
  • 故:当代码为mov r0,#0x400,即修改最后的12位立即数(=immed_8循环右移(2*rotate)位)
    • 12位立即数中高4位,表示rotate,低8位:immed_8
  • 具体介绍:
    linux系统学习1-8:第1个ARM裸板程序及引申_第9张图片
  • 举一反三:
    linux系统学习1-8:第1个ARM裸板程序及引申_第10张图片

第005、006节:编程知识_进制-字节序

  • 进制:

    • 如何快四转化2/8/16进制:
    • 8421
      linux系统学习1-8:第1个ARM裸板程序及引申_第11张图片
    • 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
    • 取反: 原来为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)
        linux系统学习1-8:第1个ARM裸板程序及引申_第12张图片
  • 清位:

    • int a=0x123,把bit7,8清除
    • int b=a&(~(1<<7))&(~(1<<8))
      linux系统学习1-8:第1个ARM裸板程序及引申_第13张图片

第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寄存器中
    • ldm(many):读内存,写入多个寄存器

      • ldmia:
    • stm: 把多个寄存器的值写入内存
      • stmdb:
    • 过后增加(Increment After)、预先增加(Increment Before)、过后减少(Decrement After)、预先减少(Decrement Before)。
    • 举例:
      linux系统学习1-8:第1个ARM裸板程序及引申_第14张图片
      linux系统学习1-8:第1个ARM裸板程序及引申_第15张图片

第009节:解析C程序的内部机制

你可能感兴趣的:(linux系列)