zoukankan      html  css  js  c++  java
  • Raspberry PI 系列 —— 裸机点亮LED灯

    Raspberry PI 系列 —— 裸机点亮LED灯

    背景

    近期刚买了Raspberry PI B+,配置执行了官方提供的Raspbian系统,折腾了一周Linux系统,感觉没啥意思,于是就试着想了解底层的启动流程。通过几天的研究,发现最底层部分的启动是由官方提供的bootcore.bin和start.elf文件来执行(应该是对硬件设备的初始化。如MMU等),之后由下一部分kernel.img的_start接管。

    为了真正验证此流程,于是想利用GPIO控制LED灯,几经折腾最终成功点亮LED,现记录于此。

    外设地址编码

    要想控制GPIO管脚就必须知道GPIO管脚的地址,在ARM架构中外设IO一般採用统一编码。BCM2835将外设地址0x7E00000映射到RAM的0x20000000。如0x7E200000则为0x20200000。以下是总线地址、物理地址、虚拟地址关系图:

    GPIO扩展口

    本次我们要通过板子上预留的GPIO管脚来控制LED灯,这里必须了解这些管脚的含义,B+版本号的GPIO口扩展到了40脚,下图是B与B+的GPIO管脚差别:

     

    GPIO寄存器

    在BCM2835中,共同拥有54个GPIO管脚。当中GPIO寄存器有GPFSELn、GPSETn、GPCLRn等,以下详细描写叙述这些寄存器的作用:

    ·        寄存器 GPFSEL0 ~ GPFSEL5 ---- 功能寄存器,指定管脚为输入、输出等,  3位决定一个管脚:

    o   000 = GPIO Pin 9 is aninput

    o   001 = GPIO Pin 9 is anoutput

    o   100 = GPIO Pin 9 takesalternate function 0

    o   101 = GPIO Pin 9 takesalternate function 1

    o   110 = GPIO Pin 9 takesalternate function 2

    o   111 = GPIO Pin 9 takesalternate function 3

    o   011 = GPIO Pin 9 takesalternate function 4

    o   010 = GPIO Pin 9 takesalternate function 5

    当中:(寄存器---地址---描写叙述)

    * GPFSEL0 --- 0x7E200000 --- 决定GPIO0-GPIO9管脚的功能

    * GPFSEL1 --- 0x7E200004 --- 决定GPIO10-GPIO19管脚的功能

    * GPFSEL2 --- 0x7E200008 --- 决定GPIO20-GPIO29管脚的功能

    * GPFSEL3 --- 0x7E20000c --- 决定GPIO30-GPIO39管脚的功能

    * GPFSEL4 --- 0x7E200010 --- 决定GPIO40-GPIO49管脚的功能

    * GPFSEL5 --- 0x7E200014 --- 决定GPIO50-GPIO53管脚的功能

    ·        寄存器 GPSET0 - CPSET1 ---- 设为1, 每一位决定一个管脚

    o   0 = No effect

    o   1 = Set GPIO pin n

    当中:(寄存器---地址---描写叙述)

    * GPSET0 --- 0x7E20001C --- 决定GPIO0-GPIO31管脚

    * GPSET1 --- 0x7E200020 --- 决定GPIO32-GPIO53管脚

    ·        寄存器 GPCLR0 - GPCLR1 ---- 设为0, 每一位决定一个管脚

    o   0 = No effect

    o   1 = Clear GPIO pin n

    当中:(寄存器---地址---描写叙述)

    * GPSET0 --- 0x7E200028 --- 决定GPIO0-GPIO31管脚

    * GPSET1 --- 0x7E20002C --- 决定GPIO32-GPIO53管脚

    样例 --- 设置GPIO16为低电平

    不多说了。该介绍的,前面已经介绍过了。直接上代码:

     

    .section .init

    .globl _start

    _start:

     

    ldr r0,=0x20200000

     

    /* Set GPIO16 to output mode(001) */

    mov r1,#1

    lsl r1,#18

    str r1,[r0,#4] /* GPFSEL1(决定GPOI10 - GPIO19) */

     

    /* Clear GPIO16 */

    mov r1,#1

    lsl r1,#16

    str r1,[r0,#40] /* GPCLR0(决定GPOI0 - GPIO31) */

     

    /*

    * Loop over this forevermore

    */

    loop$:

    b loop$

    结果:

    总结

    经过了多次的尝试最终点亮了LED灯。尽管如今想起。可能非常easy,当这毕竟是零的突破,在这一小步中,掌握了非常多知识,如总线地址、物理地址的关系,怎样看GPIO寄存器,ARM的汇编指令等等,有了这一步的成功我就能进行很多其它复杂的实验。

  • 相关阅读:
    Sharding-Jdbc 自定义分库分表-复合分片算法自定义实现
    sklearn:Python语言开发的通用机器学习库
    php验证码--图片
    ListView中的Item点击事件和子控件的冲突或者item点击没有反应的解决的方法
    【转载】C# Graphics类具体解释
    Oracle之外键(Foreign Key)使用方法具体解释(二)- 级联删除(DELETE CASCADE)
    职业生涯-小公司和大公司的不同(持续更新)
    视音频数据处理入门:AAC音频码流解析
    让人非常easy误解的TCP拥塞控制算法
    Redis资料整理
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/6970667.html
Copyright © 2011-2022 走看看