【Linux】x210 一步步點亮LED

看朱老師的視頻,一點點記錄

 

 

1 LED硬件工作原理及原理圖查閱(硬件有關)

1.1 原理圖是在底板x210bv3中查詢

 

 

 

 

查閱原理圖,發現開發板上一共有5顆LED。其中一顆D26的接法是:正極接5V,負極接地。因此這顆LED只要上電就會常亮。因此我們分析這顆LED是電源指示燈。

剩下4顆LED的接法是:正極接3.3V,負極接了SoC上的一個引腳(GPIO),具體詳細接法是:

D22:GPJ0_3

D23:GPJ0_4

D24:GPJ0_5

D25:PWMTOUT1(GPD0_1)    [PWMTOUT1接在了核心板x210cv3,利用好pdf 閱讀器中的搜索功能]

 

1.2 分析如何點亮及熄滅LED(GPIO)

分析:LED點亮的要求是:正極和負極之間有正向電壓差。

思考:在開發板上如何爲LED製造這個電壓差讓它點亮呢?

解答:因爲正極已經定了(3.3V),而負極接在了SoC的引腳上,可以通過   SoC中編程來控制負極的電壓值,因此我們可以通過程序控制負極輸 出低電平(0V),這樣在正負極上就有了壓差,LED即可點亮。

數據手冊查閱及相關寄存器瀏覽

2.1 GPIO概念的引入

GPIO:general purpose input output 通用輸入輸出

GPIO就是芯片的引腳(芯片上的引腳有些不是GPIO,只有一部分是),作爲GPIO的這類引腳,他的功能和特點是可以被編程控制它的工作模式,也可以編程控制他的電壓高低等。

通過之前的分析我們知道,我們設計電路時就把LED接在了一個GPIO上,這樣我們就可以通過編程控制GPIO的模式和輸入輸出值來操控LED亮還是滅;如果你當時設計電路時把LED接在非GPIO上那就不可能了。

 

2.2 閱讀數據手冊中有關部分(S5PV210_UM_REV1.1)

當我們想要通過編程操控GPIO來操作LED時,我們首先需要通讀一下S5PV210的數據手冊中有關於GPIO的部分,這部分在數據手冊的Section2.2中。

 

 

 

 

GPJ0CON[0] 就是GPJ0CON_0

[3:0]  —— bit3 ~ bit0   4位

 bit3 ~ bit0,設置的不同分別有7種模式

 

2.3 GPIO相關的寄存器介紹

回憶下之前說過的,軟件操作硬件的接口是:寄存器。

我們當前要操作的硬件是LED,但是LED實際是通過GPIO來間接控制的,所以當前我們實際要操作的設備其實是SoC的GPIO。要操作這些GPIO,必須通過設置他們的寄存器。

 

查閱數據手冊(S5PV210_UM_REV1.1)可知,GPJ0相關的寄存器有以下:

GPJ0CON, (GPJ0 control)GPJ0控制寄存器,用來配置各引腳的工作模式

GPJ0DAT, (GPJ0 data)當引腳配置爲input/output模式時,寄存器的相 應位和引腳的電平高低相對應。

GPJ0PUD, (pull up down)控制引腳內部弱上拉、下拉

GPJ0DRV, (driver)配置GPIO引腳的驅動能力

GPJ0CONPDN,(記得是低功耗模式下的控制寄存器)

GPJ0PUDPDN  (記得是低功耗模式下的上下拉寄存器)

注:在驅動LED點亮時,應該將GPIO配置爲output模式。

 

實際上真正操控LED的硬件,主要的有:GPJ0CON, GPJ0DAT 這麼2個。

如何點亮LED,編程的步驟是:

1、操控GPJ0CON寄存器中,選中output模式

2、操控GPJ0DAT寄存器,相應的位設置爲0

3.從零開始手寫彙編點亮LED

3.1 GPxCON、GPxDAT寄存器分析

GPJ0端口一共有8個引腳,分別記住:GPJ0_0 ~ GPJ0_7,相關重要寄存器就是GPJ0CON和GPJ0DAT

GPJ0CON寄存器中設置8個引腳的工作模式(32/8=4,每個引腳可以分到4位,譬如GPJ0_0對應的bit位爲bit0~bit3,GPJ0_3對應的位爲bit12~bit15。工作方法是:給相應的寄存器位寫入相應的值,該引腳硬件就會按照相應的模式去工作。譬如給bit12~bit15寫入0b0001,GPJ0_3引腳就成爲輸出模式了)

 

3.2 從零開始寫代碼操作寄存器

需要哪些先決條件才能寫呢?

1. 硬件接法和引腳:GPJ0_3 GPJ0_4 GPJ0_5 低電平亮/高電平滅;

2. GPJ0CON(0xE0200240)寄存器和GPJ0DAT(0xE0200244)寄存器;

3. 工程管理:Makefile等。

根據以上分析,我們就知道代碼的寫法了,代碼所要完成的動作就是:

把相應的配置數據寫入相應的寄存器即可。

3.3 怎麼寫?

先將朱老師寫好的led文件(1.leds_s)中的 三個文件(Makefile、mkv210_image、write2sd)複製到自己的文件夾(2.leds_s)裏,然後新建一個.S文件(led.S),在這個文件裏寫程序。具體的程序怎麼寫、爲什麼這麼寫,在這個文件後面都有註釋。

3.4 編譯、下載、運行看結果

編譯時用我們的工程管理,直接make編譯得到led.bin和210.bin

下載運行可以用usb啓動dnw下載;也可以用sd卡燒錄下載,根據自己的情況用一般都用usb下載,因爲方便。用usb啓動dnw下載,則運行led.bin文件

注意:開發板上按下電源鍵之後4顆LED默認都是半亮的,當我們下載程序後其中3顆變的很亮,這說明我們的程序已經運行了。

 

3.5 總結和回顧(軟件控制硬件思想、寄存器意義、原理圖數據手冊的作用)

軟件到底是怎麼控制硬件的?爲什麼程序一運行硬件就能跟着動?

軟件編程控制硬件的接口就是:寄存器

 

4.問題及解決

問題1 後綴名沒改

應該創建文件名爲2.leds_s.S ,而我創建爲2.leds_s.S.txt。

問題2 不細心

編程的時候把r0寫成了ro 。

問題3 編譯得到led.bin和210.bin,運行哪一個?

用usb啓動dnw下載,則運行led.bin文件;

用sd卡燒錄下載,則運行210.bin文件。

 

5 程序分析

目的:讓3個LED(GPJ0_3、GPJ0_4、GPJ0_5)全亮。(2.leds_s)

 

 

 

 

第一步:把0x11111111寫入0xE0200240(GPJ0CON)位置。

原因:  應該將GPJ0_3、GPJ0_4、GPJ0_5這3個引腳設置爲輸出模式,其餘5個引腳無所謂,故乾脆把8個引腳(GPJ0CON_0~GPJ0CON_7)全設置爲輸出模式。

 

第二步:把0x0寫入0xE0200244(GPJ0DAT)位置。

原因:  實際上只需要將GPJ0DAT的8個bit中的bit3—bit5設置爲0,其餘  bit位是0是1無所謂,所以乾脆都設置爲0,即00000000,即0x0。

 

6.問題提出:如何只點亮中間1顆(兩邊是熄滅的)LED(3.leds_s)

  分析:  程序其實就是寫了GPJ0CON和GPJ0DAT這2個寄存器而已,功能更  改也要從這裏下手。GPJ0CON寄存器不需要修改,GPJ0DAT中設置  相應的輸出值即可。

  直接解法:  GPJ0DAT = 0x28    代碼見<3.led_s>

  目的:只讓中間的LED(GPJ0_4)亮,另外兩個(GPJ0_3、GPJ0_5)熄。

  程序分析:

 

第一步:把0x11111111寫入0xE0200240(GPJ0CON)位置。把8個引腳全設置 爲輸出模式,代碼不變

 

第二步:把0x28寫入0xE0200244(GPJ0DAT)位置。

原因:  將GPJ0DAT的8個bit中的bit4設置爲0,bit3和bit5爲1,其餘幾  位是0是1無所謂(因爲我只需要用bit3,bit4,bit5),那我就將  其餘幾位都設置爲0,即00101000,即0x28。

 

小結: 1.這樣寫可以完成任務。

     2.這樣寫有缺陷。缺陷就是需要人爲的去計算這個特定的設置值,而   且看代碼的也不容易看懂。

解決方案:在寫代碼時用位運算去讓編譯器幫我們計算這個特定值。

 

7.使用位運算實現功能

7.1常用位運算:位與(&)  位或(|)  位非(取反 ~) 移位(左移<<  右移>>)

7.2 目的:  中間亮兩邊滅

直接解法:  GPJ0DAT = 0x28

位運算:  ldr r0, = ((1<<3) | (1<<5))

分析:  1左移3位爲1000,1左移5位爲100000,1000和100000進行位或  運算,得到0b00101000,即0x28

0b00101000  // 在00101000前面加個0b,代表00101000是二進制

 

還可以這樣,ldr r0, = ((1<<3) | (0<<4) | (1<<5))

別人一看就知道,哪個亮哪個滅,bit3和bit5滅,bit4亮

 

7.3 擴展一下:如何只熄滅中間1顆而點亮旁邊2顆

ldr r0, = ((0<<3) | (1<<4) | (0<<5))

 

8 彙編編寫延時函數並實現LED閃爍效果

8.1閃爍效果原理分析

閃爍 = 亮 + 延時 + 滅 + 延時 + 亮 + 延時 ······

8.2 彙編編寫延時函數

彙編編寫延時函數的原理,用一個寄存器存放一個數字,然後在循環中每個循環裏給數字減1,然後再判斷這個數字的值是否爲0.如果爲0則停止循環,如果不爲0則繼續循環。

 

// 延時函數:函數名:delay

delay:

ldr r2, =9000000

ldr r3, =0x0//這兩句是初始化

delay_loop:

sub r2, r2, #1 //r2 = r2 - 1

cmp r2, r3 //cmp會影響Z標誌位,如果r2等於r3則Z=1,    

//下一句中eq就會成立

bne delay_loop //這三句是函數體

mov pc, lr //函數調用返回

 

8.3 用匯編寫死循環也很簡單

flash:

亮-延時-滅-延時... //循環體

b flash

 

8.4 彙編編寫及調用函數的方式

彙編中整個彙編的主程序是一個死循環,這個死循環是我們彙編程序的主體,類似於C中的main函數。其他函數必須寫在這個主死循環程序的後面(死循環外),不然會出錯。

彙編編寫delay延時函數時,要注意函數的初始化和函數體的位置,不能把初始化寫在了循環體內。

彙編中調用函數用bl指令,子函數中最後用mov pc, lr來返回。

 

編程操控一個硬件的步驟:

1 分析硬件工作原理

2 分析原理圖

3 分析數據手冊

4 找到相關的SFR

5 寫代碼設置寄存器得到想要的效果

9.自己做的。板子上有4顆LED的(還有個在GPD0_1),四個燈依次點亮

1.分析硬件工作原理(底板x210bv3)

 

1.觀察第四個燈D25:PWMTOUT1

所以要查覈心板x210cv3,[PWMTOUT1接在了核心板x210cv3,利用好pdf閱讀器中的搜索功能],發現PWMTOUT1對應的就是GPD0_1

2.分析數據手冊

在S5PV210_UM_REV1.1中查找GPIO對應的SFR——GPJ0、GPD0

4.找到相關的SFR

然後相關的SFR爲GPJ0_CON、GPJ0_DAT、GPD0_CON、GPD0_DAT

5 寫代碼設置寄存器得到想要的效果  文件名<9.leds_s>和<11.leds_swang>

1.觀察第四個燈D25:PWMTOUT1

所以要查覈心板x210cv3,[PWMTOUT1接在了核心板x210cv3,利用好pdf閱讀器中的搜索功能],發現PWMTOUT1對應的就是GPD0_1

2.分析數據手冊

在S5PV210_UM_REV1.1中查找GPIO對應的SFR——GPJ0、GPD0

4.找到相關的SFR

然後相關的SFR爲GPJ0_CON、GPJ0_DAT、GPD0_CON、GPD0_DAT

5 寫代碼設置寄存器得到想要的效果  文件名<9.leds_s>和<11.leds_swang>

 

1.觀察第四個燈D25:PWMTOUT1

 

所以要查覈心板x210cv3,[PWMTOUT1接在了核心板x210cv3,利用好pdf閱讀器中的搜索功能],發現PWMTOUT1對應的就是GPD0_1

2.分析數據手冊

在S5PV210_UM_REV1.1中查找GPIO對應的SFR——GPJ0、GPD0

4.找到相關的SFR

然後相關的SFR爲GPJ0_CON、GPJ0_DAT、GPD0_CON、GPD0_DAT

5 寫代碼設置寄存器得到想要的效果  文件名<9.leds_s>和<11.leds_swang>

/*
 *文件名: 9.leds_s
 *作者:
 *描述: 流水燈-四個燈依次點亮
*/


#define GPJ0CON 0xE0200240
#define GPJ0DAT 0xE0200244
#define GPD0CON 0xE02000A0
#define GPD0DAT 0xE02000A4


.global _start //用.global把_start鏈接屬性改爲外部,這樣其他文件就可以看見_start了
_start:
//第一步:把0x11111111寫入0xE0200240(GPJ0CON)位置。意思是把8個引腳全設置爲輸出模式,代碼不變。
ldr r0, =0x11111111 //從後面的=可以看出用的是ldr僞指令,因爲需要編譯器來判斷這個數
ldr r1, =GPJ0CON //是合法立即數還是非法立即數。一般寫代碼都用ldr僞指令
str r0, [r1] //寄存器間接尋址功能是把r0中的數寫入到r1中的數爲地址的內存中去

//第二步:把0x1111寫入0xE02100A0(GPD0CON)位置。
ldr r0, =10000 //ldr r0, =(1<<4)
ldr r1, =GPD0CON
str r0, [r1]

flash:
//第1步:第一顆燈亮
//ldr r0, = ((0<<3) | (1<<4) | (1<<5))
ldr r0,= GPD0DAT
ldr r1,= 1111 //ldr r1,= (1<<1)
str r1,[r0]
ldr r0, = ~(1<<3) //1000  位取反   爲 0111
ldr r1, =GPJ0DAT
str r0,[r1] //把0寫入到GPJ0DAT寄存器中,引腳即輸出低電平,LED點亮
//然後:延時
bl delay 

//第2步:第二顆燈亮
ldr r0,= GPD0DAT
ldr r1,= 1111
str r1,[r0]
ldr r0, = ~(1<<4)
ldr r1, =GPJ0DAT
str r0,[r1] //把0寫入到GPJ0DAT寄存器中,引腳即輸出低電平,LED點亮
//然後:延時
bl delay 

//第3步:第三顆燈亮
ldr r0,= GPD0DAT
ldr r1,= 1111
str r1,[r0]

ldr r0, = ~(1<<5)
ldr r1, =GPJ0DAT
str r0, [r1] //把0寫入到GPJ0DAT寄存器中,引腳即輸出低電平,LED點亮
//然後:延時
bl delay 

//第4步:第四課燈亮
ldr r0, =1101 //ldr r0, =(0<<1)
ldr r1, =GPD0DAT
str r0, [r1]
ldr r0,= GPJ0DAT
ldr r1,= (1<<3)|(1<<4)|(1<<5)
str r1,[r0]
//然後:延時
bl delay 

b flash

// 延時函數:函數名:delay
delay:
ldr r2, =9000000
ldr r3, =0x0
delay_loop:
sub r2, r2, #1 //r2 = r2 - 1
cmp r2, r3 //cmp會影響Z標誌位,如果r2等於r3則Z=1,下一句中eq就會成立
bne delay_loop
mov pc, lr //函數調用返回

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