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燈,雖然現在想起,可能非常簡單,當這畢竟是零的突破,在這一小步中,掌握了很多知識,如總線地址、物理地址的關係,如何看GPIO寄存器,ARM的彙編指令等等,有了這一步的成功我就能進行更多複雜的實驗。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章