LED燈點(diǎn)亮的案例
有上圖可以看出到匾鸥,開發(fā)板上有三盞LED啼辣,分別通過LED1
纸巷、'LED2'和'LED4'四條線連接者祖,從圖上可以看出如果對(duì)于三盞LED來說,右側(cè)如果為低電平屁商,那么LED將可以被點(diǎn)亮
在開發(fā)板的原理圖上可以搜索到烟很,
LED1
、'LED2'和'LED4'三根線引入到了2440芯片蜡镶,引腳分別為EINT4/GPF4
雾袱、EINT4/GPF5
、EINT4/GPF6
官还。
那以上的原理圖可以看出芹橡,如果將以上的三個(gè)引腳設(shè)置為輸出引腳,并且輸出低電平望伦,那么對(duì)應(yīng)的LED將會(huì)被點(diǎn)亮林说。
如果需要將引腳設(shè)置為輸出引腳并輸出低電平,那么需要配置對(duì)應(yīng)的寄存器屯伞,那么此時(shí)需要閱讀2440芯片手冊述么。
其中這三個(gè)引腳的輸入輸出屬性,需要配置的是GPFCON
寄存器愕掏,他的地址為0x5600 0050
度秘, 如果需要配置EINT4/GPF4
引腳為輸出引腳,需要設(shè)置GPFCON
寄存器的9位和8位為0和1
。如果我們不管其他位剑梳,先設(shè)置其他位為0唆貌,那么9,8兩位為10的情況下垢乙,對(duì)應(yīng)的十六進(jìn)制數(shù)為:0x0000 0100
锨咙。
![寄存器(16bit)設(shè)置內(nèi)容計(jì)算]
已經(jīng)完成了配置為輸出引腳,那么接下來需要配置輸出的內(nèi)容追逮,可以通過GPFDAT
寄存器酪刀,他的地址為0x 5600 0054
,其中GPF7到GPF0
八個(gè)引腳钮孵,分別對(duì)應(yīng)該寄存器的7到0位骂倘。那么以上就是關(guān)于如何點(diǎn)亮開發(fā)板上的LED燈的原理。
為了完成以上操作巴席,可以先使用匯編語言历涝,來講寄存器進(jìn)行設(shè)置。
.text
.global _start
_start:
LDR R0,=0x56000050 @R0設(shè)置為GPFCON寄存器漾唉。此寄存器用于選擇端口B各引腳的功能:是輸出荧库、輸入或者其他
MOV R1,#0x00000100 @設(shè)置R1=0x00000100
STR R1,[R0] @R0中放入R1. 設(shè)置GPF4為輸出引腳,為[9:8]=0b01
@以上完成了GPFCON寄存器的設(shè)置赵刑,此時(shí)GPF4為輸出引腳
LDR R0,=0x56000054 @R0設(shè)為GPBDAT寄存器分衫,此寄存器用于讀取/寫入端口B各引腳的數(shù)據(jù)
MOV R1,#0x00000000 @R1改為0x00000000
STR R1,[R0] @R0中,放入R1般此。GPF4輸出0蚪战,LED1點(diǎn)亮
@此時(shí)設(shè)置GPFDAT0x00000000,然后為0x00000100
MAIN_LOOP:
B MAIN_LOOP
Makefile文件
led_on.bin : led_on.s
arm-linux-gcc -g -c led_on.S -o led_on.o #編譯不鏈接
arm-linux-ld -Ttext 0x00000000 -g led_on.o -o led_on_elf #鏈接
arm-linux-objcopy -O binary -S led_on_elf led_on.bin #轉(zhuǎn)換為二進(jìn)制文件恤煞,也會(huì)將生成的二進(jìn)制文件燒寫到開發(fā)板
clean:
rm -f led_on.bin led_on_elf *.o
執(zhí)行make命令后屎勘,生成的文件結(jié)果
再來看看Makefile
arm-linux-gcc -g -c led_on.S -o led_on.o
:匯編不鏈接
-
-g
:表示調(diào)試信息施籍,不需要調(diào)試的情況下可以不加 -
-c
:表示編譯不鏈接(編譯過程:預(yù)處理居扒、編譯、匯編丑慎、鏈接喜喂,我們直接使用的是匯編語言,所以直接進(jìn)行匯編鏈接就可以生成了可執(zhí)行程序了) -
-o
:表示生成的文件
arm-linux-ld -Ttext 0x00000000 -g led_on.o -o led_on_elf
-
-Ttext 0x00000000
:表示代碼段的地址是0x00000000
2440有兩種啟動(dòng)方式竿裂,一種是Nand啟動(dòng)玉吁,一種是NOR啟動(dòng)
-
Nand啟動(dòng)
- Nand啟動(dòng)的時(shí)候,會(huì)自動(dòng)將Nand Flash的前4k的拷貝到2440中的SRAM中去腻异。
- CPU從SRAM的0地址執(zhí)行进副,因此會(huì)有
Ttext 0x00000000
的選項(xiàng)。
以上兩步有硬件執(zhí)行悔常,無論Nand Flash中是否有內(nèi)容影斑。
-
NOR啟動(dòng)
- 0地址指向Nor flash
- cpu 從0地址取值執(zhí)行
也正是由于這兩種啟動(dòng)方式不同给赞,那么如果把程序燒寫到Nand中可以正常點(diǎn)亮LED,如果燒寫到NOR中矫户,則無法點(diǎn)亮LED了片迅。
arm-linux-objcopy -O binary -S led_on_elf led_on.bin
:生成可執(zhí)行文件
-
-O binary
:聲稱二進(jìn)制文件。
那么我們不可能每次都是用的是匯編語言進(jìn)行開發(fā)皆辽,主要的開發(fā)還是要用C語言柑蛇,那么我們就來看看如何用C語言點(diǎn)亮LED
我們在開發(fā)C語言程序的時(shí)候,一般都是使用main函數(shù)作為入口驱闷,而main函數(shù)僅僅只是一個(gè)函數(shù)而已耻台,那么他一定需要被別人來調(diào)用,同時(shí)將返回值返回給調(diào)用者遗嗽。那么在我們在開發(fā)的時(shí)候LED點(diǎn)亮的時(shí)候粘我,沒有人來調(diào)用我們的函數(shù),所以我么需要自己來做這些工作痹换。
-
硬件方面的初始化
- 關(guān)閉看門狗(看門狗:定時(shí)器征字,默認(rèn)啟動(dòng),倒計(jì)時(shí)娇豫,3秒內(nèi)沒關(guān)閉會(huì)重新啟動(dòng))
- 初始化時(shí)鐘:2440最高為400MHz匙姜,而啟動(dòng)時(shí)候時(shí)鐘只有12MHz,所以需要初始化
- 初始化SDRAM
-
軟件方面的初始化
- 設(shè)置棧 :把棧指針sp指向某塊內(nèi)存
如果是片內(nèi)的SRAM冯痢,不需要初始化就可以使用
如果不是片內(nèi)的SRAM氮昧,而是SDRAM,就需要初始化
- 設(shè)置main函數(shù)的返回地址
- 調(diào)用main
- 清理工作
- 設(shè)置棧 :把棧指針sp指向某塊內(nèi)存
那么硬件和軟件的初始化被稱之為啟動(dòng)文件浦楣,而該啟動(dòng)文件是一個(gè)匯編代碼袖肥,由于我們的程序比較簡單,就不用初始化時(shí)鐘了振劳,并且我們芯片中有SRAM所以也無需初始化SDRAM椎组。硬件初始化部分只需要關(guān)閉看門狗即可。
.text
.global _start
_start:
ldr r0,=0x53000000 @WATCHDOG寄存器的地址
mov r1,#0x0 @r1是這為0
str r1,[r0] @寫入0历恐,禁止WATCHDOG寸癌,否則CPU會(huì)不斷重啟
ldr sp,=1024*4 @設(shè)置堆棧,注意:不能大于4k弱贼,因?yàn)楝F(xiàn)在可用的內(nèi)存只有4k
@Nand Flash中的代碼在復(fù)位后蒸苇,會(huì)被移到內(nèi)部的ram中,此ram只有4k
bl main @調(diào)用c程序中的main函數(shù) 吮旅,bl指令會(huì)跳轉(zhuǎn)到main函數(shù)溪烤,并把返回值放在lr里面
halt_loop: @死循環(huán)作為清理工作
b halt_loop
C語言程序
#define GPFCON (*(volatile unsigned long*)0x56000050)
#define GPFDAT (*(volatile unsigned long*)0x56000054)
//volatile是讓編譯器不要做優(yōu)化
//此處宏定義相當(dāng)于(long *)0x56000050把這個(gè)數(shù)值強(qiáng)轉(zhuǎn)為指針。第一個(gè)*是起到解引用的作用,為了給地址內(nèi)的內(nèi)容賦值
int main()
{
GPFCON = 0x00000100; //設(shè)置GPF4為輸出口檬嘀,為[9:8] = 0b01
GPFDAT = 0x00000000; //GPF4輸出0莺葫,LED1點(diǎn)亮。
return 0;
}
Makefile
led_on_c.bin : crt0.S led_on_c.c
arm-linux-gcc -g -c -o crt0.o crt0.S
arm-linux-gcc -g -c -o led_on_c.o led_on_c.c
arm-linux-ld -Ttext 0x0000000 -g crt0.o led_on_c.o -o led_on_c_elf
arm-linux-objcopy -O binary -S led_on_c_elf led_on_c.bin
arm-linux-objdump -D -m arm led_on_c_elf > led_on_c.dis
clean:
rm -f led_on_c.dis led_on_c.bin led_on_c_elf *.o
arm-linux-objdump -D -m arm led_on_c_elf > led_on_c.dis
:聲稱反匯編代碼
那么我們來看看反匯編后的代碼
led_on_elf: file format elf32-littlearm
Disassembly of section .text:
00000000 <start>:
0: e3a00453 mov r0, #1392508928 ; 0x53000000
4: e3a01000 mov r1, #0 ; 0x0 @關(guān)閉看門狗
8: e5801000 str r1, [r0]
c: e3a0da01 mov sp, #4096 ; 0x1000 @設(shè)置棧
10: eb000000 bl 18 <main> @調(diào)用main函數(shù)
00000014 <halt_loop>:
14: eafffffe b 14 <halt_loop>
00000018 <main>:
18: e1a0c00d mov ip, sp
1c: e92dd800 stmdb sp!, {fp, ip, lr, pc} @把四個(gè)寄存器保存在了棧里面枪眉,并設(shè)置會(huì)報(bào)錯(cuò)
20: e24cb004 sub fp, ip, #4 ; 0x4
24: e3a03456 mov r3, #1442840576 ; 0x56000000
28: e2833050 add r3, r3, #80 ; 0x50
2c: e3a02c01 mov r2, #256 ; 0x100
30: e5832000 str r2, [r3]
34: e3a03456 mov r3, #1442840576 ; 0x56000000
38: e2833054 add r3, r3, #84 ; 0x54
3c: e3a02000 mov r2, #0 ; 0x0
40: e5832000 str r2, [r3]
44: e3a03000 mov r3, #0 ; 0x0
48: e1a00003 mov r0, r3
4c: e89da800 ldmia sp, {fp, sp, pc} @main執(zhí)行完捺檬,從棧里面恢復(fù)寄存器
Disassembly of section .comment:
00000000 <.comment>:
0: 43434700 cmpmi r3, #0 ; 0x0
4: 4728203a undefined
8: 2029554e eorcs r5, r9, lr, asr #10
c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1}
10: Address 0x10 is out of bounds.
Disassembly of section .debug_aranges:
00000000 <.debug_aranges>:
0: 0000001c andeq r0, r0, ip, lsl r0
4: 00000002 andeq r0, r0, r2
8: 00040000 andeq r0, r4, r0
...
14: 00000018 andeq r0, r0, r8, lsl r0
...
20: 0000001c andeq r0, r0, ip, lsl r0
24: 004d0002 subeq r0, sp, r2
28: 00040000 andeq r0, r4, r0
2c: 00000000 andeq r0, r0, r0
30: 00000018 andeq r0, r0, r8, lsl r0
34: 00000038 andeq r0, r0, r8, lsr r0
...
Disassembly of section .debug_pubnames:
00000000 <.debug_pubnames>:
0: 00000017 andeq r0, r0, r7, lsl r0
4: 004d0002 subeq r0, sp, r2
8: 006d0000 rsbeq r0, sp, r0
c: 004e0000 subeq r0, lr, r0
10: 616d0000 cmnvs sp, r0
14: 00006e69 andeq r6, r0, r9, ror #28
18: Address 0x18 is out of bounds.
Disassembly of section .debug_info:
00000000 <.debug_info>:
0: 00000049 andeq r0, r0, r9, asr #32
4: 00000002 andeq r0, r0, r2
8: 01040000 tsteq r4, r0
...
14: 00000018 andeq r0, r0, r8, lsl r0
18: 30747263 rsbccs r7, r4, r3, ror #4
1c: 2f00532e swics 0x0000532e
20: 65646f63 strvsb r6, [r4, #-3939]!
24: 6e694c2f cdpvs 12, 6, cr4, cr9, cr15, {1}
28: 65447875 strvsb r7, [r4, #-2165]
2c: 614c2f76 cmpvs ip, r6, ror pc
30: 454c2f62 strmib r2, [ip, #-3938]
34: 6e6f4344 cdpvs 3, 6, cr4, cr15, cr4, {2}
38: 6c6f7274 sfmvs f7, 2, [pc], #-464
3c: 4700432f strmi r4, [r0, -pc, lsr #6]
40: 4120554e teqmi r0, lr, asr #10
44: 2e322053 mrccs 0, 1, r2, cr2, cr3, {2}
48: 01003531 tsteq r0, r1, lsr r5
4c: 00006980 andeq r6, r0, r0, lsl #19
50: 14000200 strne r0, [r0], #-512
54: 04000000 streq r0, [r0]
58: 00003601 andeq r3, r0, r1, lsl #12
5c: 00005000 andeq r5, r0, r0
60: 00001800 andeq r1, r0, r0, lsl #16
64: 554e4700 strplb r4, [lr, #-1792]
68: 33204320 teqcc r0, #-2147483648 ; 0x80000000
6c: 352e342e strcc r3, [lr, #-1070]!
70: 656c0100 strvsb r0, [ip, #-256]!
74: 6e6f5f64 cdpvs 15, 6, cr5, cr15, cr4, {3}
78: 2f00632e swics 0x0000632e
7c: 65646f63 strvsb r6, [r4, #-3939]!
80: 6e694c2f cdpvs 12, 6, cr4, cr9, cr15, {1}
84: 65447875 strvsb r7, [r4, #-2165]
88: 614c2f76 cmpvs ip, r6, ror pc
8c: 454c2f62 strmib r2, [ip, #-3938]
90: 6e6f4344 cdpvs 3, 6, cr4, cr15, cr4, {2}
94: 6c6f7274 sfmvs f7, 2, [pc], #-464
98: 0200432f andeq r4, r0, #-1140850688 ; 0xbc000000
9c: 69616d01 stmvsdb r1!, {r0, r8, sl, fp, sp, lr}^
a0: 0501006e streq r0, [r1, #-110]
a4: 00000065 andeq r0, r0, r5, rrx
a8: 00000018 andeq r0, r0, r8, lsl r0
ac: 00000050 andeq r0, r0, r0, asr r0
b0: 69035b01 stmvsdb r3, {r0, r8, r9, fp, ip, lr}
b4: 0400746e streq r7, [r0], #-1134
b8: Address 0xb8 is out of bounds.
Disassembly of section .debug_abbrev:
00000000 <.debug_abbrev>:
0: 10001101 andne r1, r0, r1, lsl #2
4: 12011106 andne r1, r1, #-2147483647 ; 0x80000001
8: 1b080301 blne 200c14 <__bss_end__+0x1f8bc4>
c: 13082508 tstne r8, #33554432 ; 0x2000000
10: 00000005 andeq r0, r0, r5
14: 10011101 andne r1, r1, r1, lsl #2
18: 11011206 tstne r1, r6, lsl #4
1c: 13082501 tstne r8, #4194304 ; 0x400000
20: 1b08030b blne 200c54 <__bss_end__+0x1f8c04>
24: 02000008 andeq r0, r0, #8 ; 0x8
28: 0c3f002e ldceq 0, cr0, [pc], #-184
2c: 0b3a0803 bleq e82040 <__bss_end__+0xe79ff0>
30: 13490b3b cmpne r9, #60416 ; 0xec00
34: 01120111 tsteq r2, r1, lsl r1
38: 00000a40 andeq r0, r0, r0, asr #20
3c: 03002403 tsteq r0, #50331648 ; 0x3000000
40: 3e0b0b08 fmacdcc d0, d11, d8
44: 0000000b andeq r0, r0, fp
Disassembly of section .debug_line:
00000000 <.debug_line>:
0: 00000032 andeq r0, r0, r2, lsr r0
4: 001a0002 andeqs r0, sl, r2
8: 01020000 tsteq r2, r0
c: 000a0efb streqd r0, [sl], -fp
10: 01010101 tsteq r1, r1, lsl #2
14: 01000000 tsteq r0, r0
18: 74726300 ldrvcbt r6, [r2], #-768
1c: 00532e30 subeqs r2, r3, r0, lsr lr
20: 00000000 andeq r0, r0, r0
24: 00020500 andeq r0, r2, r0, lsl #10
28: 12000000 andne r0, r0, #0 ; 0x0
2c: 2d2d2c2c stccs 12, cr2, [sp, #-176]!
30: 0002022d andeq r0, r2, sp, lsr #4
34: 00330101 eoreqs r0, r3, r1, lsl #2
38: 00020000 andeq r0, r2, r0
3c: 0000001c andeq r0, r0, ip, lsl r0
40: 0efb0102 cdpeq 1, 15, cr0, cr11, cr2, {0}
44: 0101000a tsteq r1, sl
48: 00000101 andeq r0, r0, r1, lsl #2
4c: 6c000100 stfvss f0, [r0], {0}
50: 6f5f6465 swivs 0x005f6465
54: 00632e6e rsbeq r2, r3, lr, ror #28
58: 00000000 andeq r0, r0, r0
5c: 18020500 stmneda r2, {r8, sl}
60: 13000000 tstne r0, #0 ; 0x0
64: 2c808064 stccs 0, cr8, [r0], {100}
68: 01000402 tsteq r0, r2, lsl #8
6c: Address 0x6c is out of bounds.
Disassembly of section .debug_frame:
00000000 <.debug_frame>:
0: 0000000c andeq r0, r0, ip
4: ffffffff swinv 0x00ffffff
8: 7c010001 stcvc 0, cr0, [r1], {1}
c: 000d0c0e andeq r0, sp, lr, lsl #24
10: 0000001c andeq r0, r0, ip, lsl r0
14: 00000000 andeq r0, r0, r0
18: 00000018 andeq r0, r0, r8, lsl r0
1c: 00000038 andeq r0, r0, r8, lsr r0
20: 440c0d44 strmi r0, [ip], #-3396
24: 038d028e orreq r0, sp, #-536870904 ; 0xe0000008
28: 0c44048b cfstrdeq mvd0, [r4], {139}
2c: 0000040b andeq r0, r0, fp, lsl #8
用C語言輪流點(diǎn)亮LED
由之前的原理圖可以看出來,三個(gè)LED分別接到了2440的GPF4
贸铜、GPF5
和GPF6
的三個(gè)引腳堡纬。
我們只需要把這三個(gè)引腳設(shè)置為輸出引腳,輪流輸出0或1即可
首先蒿秦,對(duì)于硬件和軟件的初始化是必不可少的步驟烤镐,依然是:關(guān)閉看門狗、(修改計(jì)時(shí)器頻率棍鳖、初始化SDRAM)炮叶,設(shè)置棧、設(shè)置main函數(shù)的返回值地址渡处、調(diào)用main函數(shù)镜悉、清理工作
.text
.global _start
_start:
ldr r0,=0x530000000
mov r1,#0x0
str r0,[r1]
ldr sp, 1024*4
bl main
halt_loop:
b halt_loop
C代碼:
#define GPFCON (*(volatile unsigned long*) 0x56000050)
#define GPFDAT (*(volatile unsigned long*) 0x56000054)
#define GPF4_out (1<<(4*2)) //左移4*2位,每個(gè)引腳占據(jù)GPFCON的兩位医瘫,所以就是把第4個(gè)2位設(shè)置為01
#define GPF5_out (1<<(5*2))
#define GPF6_out (1<<(6*2))
void wait(volatile unsigned long dly)
{
for(;dly > 0; dly --);
}
int main()
{
unsigned long i = 0;
GPFCON = GPF4_out | GPF5_out | GPF6_out; //將GPF4/5/6都設(shè)為了輸出引腳
while(1)
{
wait(30000);
GPFDAT = (~(i << 4)); //左移4位
if(++i == 8)
i = 0;
}
return 0;
}
按鍵控制LED
.text
.global _start
_start:
ldr r0, =0x53000000
mov r1,#0x0
str r1,[r0]
ldr sp,1024*4
bl main
halt_loop:
b halt_loop
volatile unsigned long* const GPFCON = (volatile unsigned long*)0x56000050;
volatile unsigned long* const GPFDAT = (volatile unsigned long*)0x56000054;
volatile unsigned long* const GPGCON = (volatile unsigned long*)0x56000060;
volatile unsigned long* const GPGDAT = (volatile unsigned long*)0x56000064;
void led_control(unsigned int key, unsigned pos)
{
if(key) *GPFDAT |= (key << pos);
else *GPFDAT &= (key << pos);
}
int main(void)
{
//GPF0 GPF2 GPG3 設(shè)為輸入
*GPFCON &= ~((0x3 << (0 * 2)) | (0x3 << (2 * 2))); // 清零
*GPGCON &= ~(0x3 << (3 * 2));
//GPF4 5 6 設(shè)為輸出
*GPFCON &= ~((0x3 << (4 * 2)) | (0x3 << (5 * 2)) | (0x3 << (6 * 2))); // 清零
*GPFCON |= ((0x1 << (4 * 2)) | (0x1 << (5 * 2)) | (0x1 << (6 * 2)));
while(1){
// 取出按鍵值侣肄,放在變量的最低位
unsigned int b1, b2, b3;
b1 = *GPFDAT & 0x1;
b2 = (*GPFDAT & 0x4) >> 2;
b3 = (*GPGDAT & 0x8) >> 3;
led_control(b1, 4);
led_control(b2, 5);
led_control(b3, 6);
}
return 0;
}