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

130 阅读6分钟

第001节:辅线1_硬件知识_LED原理图

  • 实现点亮LED的步骤:\

    • 1.看原理图,确定控制led的引脚\

      • 通过主芯片使用引脚输出:3.3V点亮led;0V熄灭led。
        -接法:
        这里写图片描述
      • 引脚驱动能力不足:使用三极管,
      • 接法介绍:
        -接法1:
        这里写图片描述
        -接法2:
        这里写图片描述
    • 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
R13spstack point:栈指针
R14lrlink register:保存返回地址
R15pcprogram 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
    • 取反: 原来为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寄存器中
    • ldm(many):读内存,写入多个寄存器

      • ldmia:
    • stm: 把多个寄存器的值写入内存\

      • stmdb:
    • 过后增加(Increment After)、预先增加(Increment Before)、过后减少(Decrement After)、预先减少(Decrement Before)。

    • 举例:
      这里写图片描述
      这里写图片描述

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