小灯程序引发的思考

来源:互联网 发布:cad绘图软件 编辑:程序博客网 时间:2024/06/10 07:43

前段时间写了两篇文章,讲了关于GPIO方面的知识,之后继续学习裸机,当然跟刚开始学习编程一样要写helloword,嵌入式方面的话当然要点亮小灯了,哈哈

  • 首先看关于小灯原理图

小灯原理图
从原理图可以看到, nLEDx作为输出,且为低电平时,小灯会亮,对应关系为
nLED_1→GPF4
nLED_2→GPF5
nLED_4→GPF6

  • 其次看下按键原理图
    这里写图片描述
    由于开发板上露出的三个按键标示的是 EINT0, EINT2, EINT11,所以在原理图上搜索这三个关键词,
    关于按键方面的原理图主要分布在3个页面中
    sh1:按键
    sh2 : 描述中断引脚的图
    sh3: 描述地址线,数据线引脚的图
    从图中可以看到按键对应的关系
    S2→GPF0
    S3→GPF2
    S4→GPG3(注意是GPGx, 非GPFx)
    可能上面的图比较乱,初学者不知道切确的连接方法,下图给出了就按键S2的连接方法(原理图换了种方式)
    这里写图片描述
    从上面原理图分析可知, 按键,小灯与GPIO口的对应关系, 接下来,编码需要完成的一个功能是, 按键按下,小灯亮,松开,小灯灭,其控制关系为:
    S2控制nLED_1–>(GPF0↔GPF4)
    S3控制nLED_2–>(GPF2↔GPF5)
    S4控制nLED_4–>(GPG3↔GPF6)

  • 查看数据手册,配置GPIO
    从原理图来看,以S2控制nLED_1–>(GPF0↔GPF4) 来说明, S2按下(GPIO配置为输入, 检测到低电平, 即获得输入值判断为低电平, 那么灯亮, 即GPF4配置为输出,输出电平, 那么灯就亮),接下来必须通过数据手册来获得
    1.如何配置输入输出
    2.如何取GPIO状态, 从GPIO发送高低电平
    由上面的关系可以看到, 控制的是GPFx 与GPGx 族, 就以GPFx说明

第9章 I/O PORTS中
这里写图片描述
上面介绍得知 GPF共有8个口, GPF0->GPF7

这里写图片描述
GPFCON 控制寄存器, 用来配置管脚的输入输出,如上图所示, 比如, GPF0 对应GPFCON寄存器的第0,1位
向0x56000050写00,即配置为输入功能, 写01即为输出功能
这里写图片描述
GPFDAT即状态寄存器, 比如GPF0为输入, 那么外接电路进来的是高电平, GPFDAT的第0位是1
GPF0若为输出,那么如果要向外接电路输出高电平, 那么向GPFDAT的第0位写1
对于GPFUP来讲,是配置芯片GPIO内部上拉电阻用,zj2440在GPIO的外围电路已经配置了上拉电阻,所以对这个寄存器配不配置其实无所谓
知道了如何配置寄存器后,直接贴出代码(参考的韦东山老师的例子,裸机的例子韦老师写的好啊)

  • 例子分析
    这里写图片描述
    例子由三部分组成:
    汇编->程序的入口
    c文件->执行的函数
    Mafile
    1.crt0.S
    这里写图片描述
    1.1位置无关代码,位置相关代码
    这个其实是 系统与编译器之间的暧昧关系,他们两者形成了一个默契,达成了一致
    板子里运行的是linux系统, 而运行的程序是编译器生成的,所以OS与gcc 一拍脑袋,得了,运行的程序就以0x08048290开始运行吧,我们暂且将这个地址简称为地址A
    对于OS: 来一个app让我运行, 我就把它放在我所管理的地址A上运行
    对于gcc:对这个app进行编译,得指定运行地址啊(链接地址),我就运行地址设置为地址A,
    这样OS运行这个app就能正确的运行
    有人会问,那什么是位置无关代码呢?
    答: gcc在编译app这个程序时,app所写的代码根本没有到地址A的信息,既然没有地址信息,也就是说放在系统哪个地方运行的结果应该是一样的, 比如说,app里就写个 a=1, b=2; c =a+b;
    像这种代码,放在哪里都是一个结果。。所谓位置无关
    那什么又是位置相关呢?
    答:还是刚才的例子, gcc在编译这个app的时候, app的代码用到了地址!!!, 既然用到了地址,gcc就必须要提供正确的地址,当然,对于OS来说, gcc早已知道OS是从地址A开始运行的,所以链接地址从地址A开始,这样,app中用到地址的代码就能被正确的使用,对于位置相关, ldr pc, =main给出了很好的例子
    我们知道, 裸机ram地址是从0开始运行,就是说我们要编译出的代码应该从0开始运行,所以考虑到可能存在位置相关的代码,所以在编译的时候需要指定一下链接地址是从0开始的,这样app中凡是用到地址的地方都能正确的被应用
    我们先来看个正确的(指定链接地址从0开始)
    这里写图片描述
    对于ldr pc ,=main 来说, gcc在编译的时候 由于指定了从0地址开始编译, 所以用到地址的代码部分, 即ldr pc, =main翻译成了 两句话, 注意到cpu当执行到第10行的时候, pc被赋值成了0x0000018(编译时指定的),发生跳转,cpu就会跳转到0x0000018这个地址上, 即main的位置
    假设在编译的时候不指定从0开始呢?
    这里写图片描述
    如果是这种情况,当我们把程序down到板子中会使板子,崩溃,如下图
    这里写图片描述
    我们把程序down到板子里运行, 电路逻辑会把代码搬运到sram中执行, cpu从sram的0地址开始执行程序,当执行到ldr pc时, 代码逻辑会将pc的值赋值成很大的数,cpu从而就跳飞了..
    这个很大的数是编译链接造成的,如果链接时指定从0地址开始编译, 那么程序就正确了,所以这个ldr pc, =main这条指令,它依赖于地址, 所以位置有关.. 应用时一定要注意!
    1.2关于流水线, ARM9是三级流水,至于什么是流水线就不多说了,网上可以找到很多的答案
    疑问:
    这里写图片描述
    回答:
    这里写图片描述
    之后就是main函数了,下面的代码部分没什么好说的,网上都能下载到
0 0