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,下面是總線位址、實體位址、虛拟位址關系圖:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0NXYFhGd192UvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcFTOXRGd4dkYoFjMjZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DO4IDNxgTMxEDNygDM0EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
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
mov r1,#1
lsl r1,#18
str r1,[r0,#4]
mov r1,#1
lsl r1,#16
str r1,[r0,#40]
loop$:
b loop$
結果:
總結
經過了多次的嘗試終于點亮了LED燈,雖然現在想起,可能非常簡單,當這畢竟是零的突破,在這一小步中,掌握了很多知識,如總線位址、實體位址的關系,如何看GPIO寄存器,ARM的彙編指令等等,有了這一步的成功我就能進行更多複雜的實驗。