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 //函式呼叫返回