15.編寫LED程序及反彙編工具


15.1.硬件工作原理及原理圖查閱
(1)LED物理特性介紹:LED本身有2個接線點,1個是LED的正極,1個是LED的負極。LED這個硬件的功能就是點亮或者不亮,物理上想要點亮一顆LED只需要給它的正負極上加正電壓即可,要熄滅1顆LED只需要去掉電壓即可。
(2)查閱原理圖瞭解板載LED硬件接法:查閱原理圖,發現GEC210開發板上共有6顆LED(4顆在覈心板上D1~D4,2顆在底板上D1和D3);底板D1接法(VDD_5V(5V直流)通過低壓差穩壓芯片(AMS1086CM-3.3)輸出VDD_IO(3.3V直流);即D1正極接3.3V(VDD_IO),負極接地,則該顆LED只要上電就會常亮,即該顆LED是電源指示燈);底板D3接法(D3正極接3.3V,負極接SoC上的1個引腳(GPG0_3));核心板D1~D4的接法(正極接3.3V(VDD_REG1_IO),負極接了SoC上的1個引腳(D1~D4分別對應GPJ2_0~GPJ2_3))。
(3)如何點亮及熄滅LED(GPIO):因爲正極已經定了(3.3V),而負極接在了SoC的引腳上,可以通過SoC中編程來控制負極的電壓值,因此我們可以通過程序控制負極輸出低電平(0V),這樣在正負極上就有了壓差,LED即可點亮。


15.2.數據手冊查閱及相關寄存器瀏覽
(1)GPIO概念的引入:通用輸入輸出(general purpose input output);GPIO就是芯片的引腳(芯片上的引腳有些不是GPIO),作爲GPIO的這類引腳,其功能和特點是可以被編程控制其工作模式和電壓高低等;我們設計電路時就把LED接在了某個GPIO上,這樣我們就可以通過編程控制GPIO的模式和輸入輸出值來操控LED的亮滅。
(2)閱讀數據手冊GPIO部分:當我們想要通過編程操控GPIO來操作LED時,我們首先需要通讀一下S5PV210的數據手冊中有關於GPIO的部分,這部分在數據手冊的Section2.2中。
(3)GPIO相關的寄存器介紹:我們當前要操作的硬件是LED,但是LED實際是通過GPIO來間接控制的,所以我們要操作的硬件是SoC的GPIO,要操作這些GPIO,必須通過設置它們的寄存器(見圖1)。
(4)真正操控LED的硬件主要爲GPJ2CON和GPJ2DAT,點亮LED編程步驟:1.操控GPJ2CON寄存器中,選中output模式;2.操控GPJ2DAT寄存器,相應的位設置爲0。


15.3.從零開始手寫彙編點亮LED
(1)GPxCON和GPxDAT寄存器分析:GPJ2端口共有8個引腳(GPJ2_0~GPJ2_7),相關的重要寄存器爲GPJ2CON和GPJ2DAT;GPJ2CON寄存器可設置8個引腳的工作模式(32/8=4,每個引腳對應4bit,譬如GPJ2_0對應的bit位爲bit0~bit3);譬如給bit0~bit0寫入0b0001,GPJ2_0引腳就工作在輸出模式。
(2)從零開始寫代碼操作寄存器:1.硬件接法和引腳(GPJ2_0、GPJ2_1、GPJ2_2、GPJ2_3),低電平亮/高電平滅;2.GPJ2CON(0xE0200240)寄存器和GPJ0DAT(0xE0200244)寄存器;3.工程管理Makefile、mkv210_image.c、write2sd.sh等文件。
(3)編譯下載運行:編譯時用我們的工程管理,直接make編譯得到led_usb.bin和led_sd.bin;下載運行可使用usb啓動dnw下載,也可以用sd卡燒錄下載。


15.4.彙編實現LED閃爍效果
(1)閃爍效果原理分析:閃爍 = 亮 + 延時 + 滅 + 延時 + 亮 + 延時…。
(2)延時函數原理:在彙編中實現延時即用一些沒有目的的代碼來執行消耗時間,達到延時的效果。
(3)彙編編寫延時函數:用某個寄存器存放某個數字,然後在循環中每個循環裏給數字減1,然後再判斷這個數字的值是否爲0.如果爲0則停止循環,如果不爲0則繼續循環。
(4)彙編編寫及調用函數:彙編中整個彙編的主程序是死循環,該死循環是我們彙編程序的主體,類似於C中的main函數;其它函數必須寫在該主死循環程序外面,不然會出錯。
(5)總結:彙編編寫delay延時函數時,要注意函數的初始化和函數體的位置,不能把初始化寫在了循環體內;彙編中調用函數用bl指令,子函數中最後用mov pc, lr來返回。


15.5.彙編實現流水燈效果
(1)流水燈原理分析:流水燈又叫跑馬燈,即挨着的LED依次點亮熄滅(同時只有1顆LED亮)。
(2)流水燈編寫:用位取反操作符來輕鬆愉快的實現單顆LED點亮流水效果。
(3)編程操控某個硬件的步驟:1.分析硬件工作原理;2.分析原理圖;3.分析數據手冊;4.找到相關的SFR;5.寫代碼設置寄存器得到想要的效果。


15.6.反彙編的原理和objdump工具
(1)arm-linux-objdump -D led.elf > led_elf.dis(-D表示反彙編;>左邊的是elf的可執行程序;>右邊的是反彙編生成的反彙編程序);objdump是gcc工具鏈中的反彙編工具,作用是由編譯鏈接好的elf格式的可執行程序反過來得到彙編源代碼。
(2)反彙編的原因:1.逆向破解,黑客大神常用的手段;2.調試程序時,反彙編代碼可以幫助我們理解程序(我們學習時使用objdump主要目的是這個),尤其是在理解鏈接腳本、鏈接地址等概念時;3.把C語言源代碼編譯鏈接生成的可執行程序反彙編後得到對應的彙編代碼,可以幫助我們理解C語言和彙編語言之間的對應關係,有助於深入理解C語言。
(3)反彙編文件的格式:彙編(assembly)反彙編(dissembly);標號地址(00000000)、標號名字(<_start>:)、指令地址(標號地址+偏移量(00000000+0))、指令機器碼(e59f0060)、指令機器碼反彙編到的指令(ldr r0, [pc, #96]);ARM彙編中用地址池方式來實現非法立即數。
(4)初識指令地址:下載燒錄執行的bin文件,內部其實是很多條指令機器碼,每條指令機器碼都有對應的地址,該地址是鏈接時ld指定的(ld根據程序員提供的鏈接腳本來指定)。
(5)反彙編工具幫助我們分析鏈接腳本:反彙編的時候得到的指令地址是鏈接器考慮了鏈接腳本之後得到的地址,而我們寫代碼時通過指定連接腳本來讓鏈接器給我們鏈接合適的地址;但有時候我們寫的鏈接腳本有誤(或者我們不知道該鏈接腳本執行效果如何),此時可通過閱讀反彙編文件來分析該鏈接腳本的效果,確認是否達到了我們的目的。


這裏寫圖片描述


15.led_s_v1.0/
led.S
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:編寫LED程序及反彙編工具
 * 功能:彙編實現點亮第1個和第3個LED燈。
 */

#define GPJ2CON 0xE0200280
#define GPJ2DAT 0xE0200284

.global _start                      // 把_start鏈接屬性改爲外部,則外部其它文件可看見_start 
_start:
    // 第1步:將0x00001111寫入0xE0200280位置(GPJ2CON)
    // 即設置GPJ2CON0~GPJ2CON3共4個引腳爲輸出模式
    ldr r0, =((1<<0) | (1<<4) | (1<<8) | (1<<12))   
    ldr r1, =GPJ2CON                // 通過=號看出使用的是ldr僞指令,因爲編譯器可判斷該立即數
    str r0, [r1]                    // 是合法立即數/非法立即數。
                                    // 寄存器間接尋址,把r0中的數寫入到以r1中的數爲地址的內存中去

    // 第2步:將0b00001010寫入0xE0200284位置(GPJ2DAT)
    // 即設置GPJ2DAT0~GPJ2DAT3爲0b00000101
    ldr r0, =((1<<0) | (0<<1) | (1<<2) | (0<<3))
    ldr r1, =GPJ2DAT
    str r0, [r1]

    b .                             // 死循環,程序停留在這裏,.表示當前指針的地址
                                    // 裸機程序是直接在CPU上運行的,CPU會逐行運行裸機程序直至CPU斷電關機
                                    // 如果裸機程序全部被執行完了CPU就會跑飛(跑飛結果未定義)
                                    // 爲了不讓CPU跑飛即在整個裸機程序執行完後添加死循環

15.led_s_v2.0/
led.S
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:編寫LED程序及反彙編工具
 * 功能:彙編實現4個LED燈的閃爍。
 */

#define GPJ2CON 0xE0200280
#define GPJ2DAT 0xE0200284

.global _start                      // 把_start鏈接屬性改爲外部,則外部其它文件可看見_start 
_start:
    // 第1步:將0x00001111寫入0xE0200280位置(GPJ2CON)
    // 即設置GPJ2CON0~GPJ2CON3共4個引腳爲輸出模式
    ldr r0, =((1<<0) | (1<<4) | (1<<8) | (1<<12))   
    ldr r1, =GPJ2CON                // 通過=號看出使用的是ldr僞指令,因爲編譯器可判斷該立即數
    str r0, [r1]                    // 是合法立即數/非法立即數。
                                    // 寄存器間接尋址,把r0中的數寫入到以r1中的數爲地址的內存中去
flash:  
    // 第2步:點亮4個LED燈
    ldr r0, =((0<<0) | (0<<1) | (0<<2) | (0<<3))
    ldr r1, =GPJ2DAT
    str r0, [r1]

    // 第3步:延時
    bl delay                        // 使用bl調用延時函數,會將返回地址保存在lr寄存器中

    // 第4步:熄滅4個LED燈
    ldr r0, =((1<<0) | (1<<1) | (1<<2) | (1<<3))
    ldr r1, =GPJ2DAT
    str r0, [r1]

    // 第5步:延時
    bl delay                        // 使用bl調用延時函數,會將返回地址保存在lr寄存器中

    b flash                         // 繼續循環,使用b跳轉,不保存返回地址到lr寄存器中

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

15.led_s_v3.0/
led.S
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:編寫LED程序及反彙編工具
 * 功能:彙編實現4個LED流水燈。。
 */

#define GPJ2CON 0xE0200280
#define GPJ2DAT 0xE0200284

.global _start                      // 把_start鏈接屬性改爲外部,則外部其它文件可看見_start 
_start:
    // 第1步:將0x00001111寫入0xE0200280位置(GPJ2CON)
    // 即設置GPJ2CON0~GPJ2CON3共4個引腳爲輸出模式
    ldr r0, =((1<<0) | (1<<4) | (1<<8) | (1<<12))   
    ldr r1, =GPJ2CON                // 通過=號看出使用的是ldr僞指令,因爲編譯器可判斷該立即數
    str r0, [r1]                    // 是合法立即數/非法立即數。
                                    // 寄存器間接尋址,把r0中的數寫入到以r1中的數爲地址的內存中去
flash:  
    // 第2步:點亮LED0
    ldr r0, =~(1<<0)
    ldr r1, =GPJ2DAT
    str r0, [r1]
    bl delay                        

    // 第3步:點亮LED1
    ldr r0, =~(1<<1)
    ldr r1, =GPJ2DAT
    str r0, [r1]
    bl delay                        

    // 第4步:點亮LED2
    ldr r0, =~(1<<2)
    ldr r1, =GPJ2DAT
    str r0, [r1]
    bl delay                        

    // 第3步:點亮LED3
    ldr r0, =~(1<<3)
    ldr r1, =GPJ2DAT
    str r0, [r1]
    bl delay                        // 使用bl調用延時函數,會將返回地址保存在lr寄存器中

    b flash                         // 繼續循環,使用b跳轉,不保存返回地址到lr寄存器中

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

發佈了104 篇原創文章 · 獲贊 29 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章