1. 程式人生 > >裸機程式二:GPIO點亮led燈 彙編

裸機程式二:GPIO點亮led燈 彙編

開發板:  JZ2440 V3 + EasyOpenJTAG

參考資料:《CPU三星S3C2440A晶片手冊.pdf

        JZ2440_V3電路圖.pdf

使用匯編程式碼點亮led燈,主要是設定gpio GPCONGPDAT暫存器,使用開發版資料中的原始碼:

@******************************************************************************
@ File:led_on.S
@ 功能:LED點燈程式,點亮LED1
@******************************************************************************       
            
.text
.global _start
_start:     
            LDR     R0,=0x56000050      @ R0設為GPFCON暫存器。此暫存器
                                        @ 用於選擇埠B各引腳的功能:
                                        @ 是輸出、是輸入、還是其他
            MOV     R1,#0x00000100        
            STR     R1,[R0]             @ 設定GPF4為輸出口, 位[8:7]
            
            LDR     R0,=0x56000054      @ R0設為GPBDAT暫存器。此暫存器
                                        @ 用於讀/寫埠B各引腳的資料
            MOV     R1,#0x00000000      @ 此值改為0x00000010,
                                        @ 可讓LED1熄滅
            STR     R1,[R0]             @ GPF4輸出0,LED1點亮
MAIN_LOOP:
            B       MAIN_LOOP

然後是Makefile:

led_on.bin : led_on.S
        #編譯但不連結
        arm-linux-gcc -g -c -o led_on.o led_on.S
        #連結並指定入口地址
        arm-linux-ld -Ttext 0x0000000 -g led_on.o -o led_on_elf
        arm-linux-objcopy -O binary -S led_on_elf led_on.bin
clean:
        rm -f   led_on.bin led_on_elf *.o

最後啟動openocd,並在另一個命令列中通過telnet登陸openocd,如下:

$ telnet localhost 4444
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> halt //中斷裝置執行
> load_image ./led_on.bin //下載bin檔案
72 bytes written at address 0x00000000
downloaded 72 bytes in 0.005064s (13.885 KiB/s)
> resume 0x0 //從地址0x0恢復裝置執行
> halt
s3c2440.cpu: target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0x00000014
MMU: disabled, D-Cache: disabled, I-Cache: disabled
> 

板子預設led1是亮的,修改上訴程式碼,關閉led1,重新燒寫執行,發現led1熄滅一會兒又會被點亮,這是由於我們沒有關閉看門狗,導致系統復位了

1、組合語言是否區分大小寫

組合語言的語句是不區分大小寫的,編譯軟體會自動識別這些語句,但是彙編程式中使用者定義的變數、標號等,將區分其大小寫,程式設計時要注意這些區別

2、指令ldrmov的區別

ARMRISC結構,資料從記憶體到CPU之間的移動只能通過L/S指令來完成,也就是ldr/str指令。

比如想把資料從記憶體中某處讀取到暫存器中,只能使用ldr

ldr r0, 0x12345678

就是把0x12345678這個地址中的值存放到r0中。

mov不能幹這個活,mov只能在暫存器之間移動資料,或者把立即數移動到暫存器中,這個和x86這種CISC架構的晶片區別最大的地方。

x86中沒有ldr這種指令,因為x86mov指令可以將資料從記憶體中移動到暫存器中。

另外還有一個就是ldr偽指令,雖然ldr偽指令和ARMldr指令很像,但是作用不太一樣。ldr偽指令可以在立即數前加上=,以表示把一個地址寫到某暫存器中,比如:

ldr r0, =0x12345678

這樣,就把0x12345678這個地址寫到r0中了。所以,ldr偽指令和mov是比較相似的。只不過mov指令限制了立即數的長度為8位,也就是不能超過512。而ldr偽指令沒有這個限制。如果使用ldr偽指令時,後面跟的立即數沒有超過8位,那麼在實際彙編的時候該ldr偽指令是被轉換為mov指令的。

ldr偽指令和ldr指令不是一個同東西。

所以上述程式碼可以用str代替mov,如下:

LDR     R0,=0x56000050      @ R0設為GPFCON暫存器。此暫存器
                            @ 用於選擇埠B各引腳的功能:
                            @ 是輸出、是輸入、還是其他
@MOV    R1,#0x00000100</span>        
STR     R1,=0x00000100</span>
STR     R1,[R0]             @ 設定GPF4為輸出口, 位[8:7]
            
LDR     R0,=0x56000054      @ R0設為GPBDAT暫存器。此暫存器
                            @ 用於讀/寫埠B各引腳的資料
@MOV    R1,#0x00000000</span>      @ 此值改為0x00000010,
STR     R1,=0x00000000</span>      @ 此值改為0x00000010,

3ARM暫存器

ARM共有3732位暫存器,其中31個為通用暫存器,6個為狀態暫存器.這些暫存器不能被同時訪問,但在任何時候,通用暫存器R0~R14,程式計數器PC,一個或兩個狀態暫存器都是可訪問的.

通用暫存器

通用暫存器包括R0~R15,可以分為3:

(1)未分組暫存器R0~R7

(2)分組暫存器R8~R14

(3)程式計數器PC(R15)

暫存器R13ARM指令中常用作堆疊指標,   使用者也可使用其他的暫存器作為堆疊指標,而在Thumb指令集中,某些指令強制性的要求使用R13作為堆疊指標.

暫存器R13ARM指令中常用作堆疊指標,但這只是一種習慣用法,使用者也可使用其他的暫存器作為堆疊指標。而在Thumb指令集中,某些指令強制性的要求使用R13作為堆疊指標。

由於處理器的每種執行模式均有自己獨立的物理暫存器R13,在使用者應用程式的初始化部分,一般都要初始化每種模式下的R13,使其指向該執行模式的棧空間。這

樣,當程式的執行進入異常模式時,可以將需要保護的暫存器放入R13所指向的堆疊,而當程式從異常模式返回時,則從對應的堆疊中恢復,採用這種方式可以保證異常發生後程序的正常執行。

R14稱為連結暫存器(Link Register),當執行子程式呼叫指令(BL),R14可得到R15(程式計數器PC)的備份.

在每一種執行模式下,都可用R14儲存子程式的返回地址,當用BLBLX指令呼叫子程式時,將PC的當前值複製給R14,執行完子程式後,又將R14的值複製回PC,即可完成子程式的呼叫返回。以上的描述可用指令完成。

暫存器R16

暫存器R16用作CPSR(Current

Program Status Register,當前程式狀態暫存器)CPSR可在任何執行模式下被訪問,它包括條件標誌位、中斷禁止位、當前處理器模式標誌位,以及其他一些相關的控制和狀態位。

每一種執行模式下又都有一個專用的物理狀態暫存器,稱為SPSR(Saved Program Status Register,備份的程式狀態暫存器),當異常發生時,SPSR用於儲存CPSR的當前值,從異常退出時則可由SPSR來恢復CPSR

由於使用者模式和系統模式不屬於異常模式,它們沒有SPSR,當在這兩種模式下訪問SPSR,結果是未知的