最近調驅動時,調試led時遇到了點問題,因而回過頭來再寫個led裸板程序。在我寫的pcDuino第一個裸板程序uart的基礎上,再寫個led裸板程序仍是很輕鬆的。不少人以爲沒有必要寫什麼pcDuino裸板程序,以爲沒啥意義。我以爲能夠用來熟悉硬件,特別是想作底層驅動開發,以及系統移植,熟悉底層硬件仍是有用的。其實作底層驅動開發,也是跟硬件打交道,硬件相關的操做和裸板程序是同樣的。下面介紹怎樣在pcDuino上跑一個最簡單的led裸板程序。linux
開發環境:web
宿主機:ubuntu 12.04 64位ubuntu
目標機:pcDuino V2ide
編譯器:arm-linux-gnueabihf-gcc (4.6)工具
目標:實現pcDuino上的TX_LED閃爍oop
文檔說明:測試
命令提示符 $ 表示在pcDuino上面運行的指令;ui
命令提示符 # 表示在x86_64的linux主機上運行的指令spa
命令提示符 > 表示在u-boot狀態下運行的指令.net
仔細看pcDuino上的原理圖和pcDuino的手冊,發現兩者不是徹底對應的,仍是以原理圖爲準。根據原理圖知道TX_LED是接到PH15上,能夠當作普通IO口用,不須要連跳線
主要是看手冊30.Port Controller,根據手冊寫led初始化程序主要包括設爲輸出、是能上拉及Multi-Driving寄存器設置。包括start.S、main.c、clock.c、clock.h、Makefile,下面貼出所有代碼
1
2
3
4
5
6
|
.
global
_start
_start
:
ldr
sp
,
=
0x00007f00
b
main
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include "clock.h"
#define PH_CFG1 (*(volatile unsigned int *)0x01c20900)
#define PH_DAT (*(volatile unsigned int *)0x01c2090C)
#define PH_DRI (*(volatile unsigned int *)0x01c20910)
#define PH_PULL (*(volatile unsigned int *)0x01c20918)
void
gpio_init
(
)
{
/*PCDUINO GPIO4--PH9:
*bit[6:4]:PH9_SELECT 001:OUTPUT
*PCDUINO GPIO5--PH10:
*bit[10:8]:PH10_SELECT 001:OUTPUT
*/
PH_CFG1
|=
(
(
0x1
<<
4
)
|
(
0x1
<<
8
)
|
(
0X1
<<
28
)
)
;
PH_DRI
=
0XFFFFFFFF
;
PH_PULL
=
0X55555555
;
}
void
delay
(
)
{
volatile
int
i
=
0x300000
;
while
(
i
--
)
;
}
int
main
(
void
)
{
char
c
;
clock_init
(
)
;
/* 初始化時鐘 */
gpio_init
(
)
;
while
(
1
)
{
PH_DAT
=
0x00
;
delay
(
)
;
PH_DAT
=
0xffff
;
delay
(
)
;
}
return
0
;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#define CPU_AHB_APB0_CFG (*(volatile unsigned int *)0x01c20054)
#define PLL1_CFG (*(volatile unsigned int *)0x01c20000)
#define APB1_CLK_DIV_CFG (*(volatile unsigned int *)0x01c20058)
#define APB1_GATE (*(volatile unsigned int *)0x01c2006C)
void
sdelay
(
unsigned
long
loops
)
{
__asm__
volatile
(
"1:\n"
"subs %0, %1, #1\n"
"bne 1b"
:
"=r"
(
loops
)
:
"0"
(
loops
)
)
;
}
void
clock_init
(
void
)
{
/*AXI_DIV_1[1:0] AXI_CLK_DIV_RATIO 00:/1 AXI Clock source is CPU clock
*AHB_DIV_2[5:4] AHP_CLK_DIV_RATIO 01:/2 AHB Clock source is AXI CLOCK
*APB0_DIV_1[9:8] APB0_CLK_RATIO 00:/2 APB0 clock source is AHB2 clock
*CPU_CLK_SRC_OSC24M[17:16] CPU_CLK_SRC_SEL 01:OSC24M
*/
CPU_AHB_APB0_CFG
=
(
(
0
<<
0
)
|
(
0x1
<<
4
)
|
(
0
<<
8
)
|
(
1
<<
16
)
)
;
/*bit31:PLL1_Enable 1:Enable
*bit25:EXG_MODE 0x0:Exchange mode
*bit[17:16]:PLL1_OUT_EXT_DIVP 0x0:P=1
*bit[12:8]:PLL1_FACTOR_N 0x10:Factor=16,N=16
*bit[5:4]:PLL1_FACTOR_K 0x0:K=1
*bit3:SIG_DELT_PAT_IN 0x0
*bit2:SIG_DELT_PAT_EN 0x0
*bit[1:0]PLL1_FACTOR_M 0x0:M=1
*The PLL1 output=(24M*N*K)/(M*P)=(24M*16*1)/(1*1)=384M is for the coreclk
*/
PLL1_CFG
=
0xa1005000
;
sdelay
(
200
)
;
CPU_AHB_APB0_CFG
=
(
(
0
<<
0
)
|
(
0x1
<<
4
)
|
(
0
<<
8
)
|
(
2
<<
16
)
)
;
//CPU_CLK_SRC_SEL 10:PLL1
/*uart clock source is apb1,config apb1 clock*/
/*bit[25:24]:APB1_CLK_SRC_SEL 00:OSC24M
*bit[17:16]:CLK_RAT_N 0X0:1 The select clock source is pre-divided by 2^1
*bit[4:0]:CLK_RAT_M 0x0:1 The pre-devided clock is divided by(m+1)
*/
APB1_CLK_DIV_CFG
=
(
(
0
<<
5
)
|
(
0
<<
16
)
|
(
0
<<
24
)
)
;
/*open the clock for uart0*/
/*bit16:UART0_APB_GATING 1:pass 0:mask*/
APB1_GATE
=
(
0x1
<<
16
)
;
}
|
1
|
void
clock_init
(
void
)
;
|
1
2
3
4
5
6
7
8
9
|
led
.
bin
:
start
.
S
main
.
c
clock
.
c
arm
-
linux
-
gnueabihf
-
gcc
-
nostdlib
-
c
start
.
S
-
o
start
.
o
arm
-
linux
-
gnueabihf
-
gcc
-
nostdlib
-
c
main
.
c
-
o
main
.
o
arm
-
linux
-
gnueabihf
-
gcc
-
nostdlib
-
c
clock
.
c
-
o
clock
.
o
arm
-
linux
-
gnueabihf
-
ld
-
Ttext
0xD0020010
start
.
o
main
.
o
clock
.
o
-
o
led_elf
arm
-
linux
-
gnueabihf
-
objcopy
-
O
binary
-
S
led_elf
led
.
bin
clean
:
rm
-
rf *
.
o *
.
bin
led_elf *
.
dis
|
1.編譯
change@change :~$ cd Si/A10/2_led/
change@change :~/Si/A10/2_led$ ls
clock.c clock.h main.c Makefile mksunxiboot start.S
change@change :~/Si/A10/2_led$ make
arm-none-linux-gnueabi-gcc -nostdlib -c start.S -o start.o
arm-none-linux-gnueabi-gcc -nostdlib -c main.c -o main.o
arm-none-linux-gnueabi-gcc -nostdlib -c clock.c -o clock.o
arm-none-linux-gnueabi-ld -Ttext 0xD0020010 start.o main.o clock.o -o led_elf
arm-none-linux-gnueabi-objcopy -O binary -S led_elf led.bin
change@change :~/Si/A10/2_led$ ./mksunxiboot led.bin leds.bin
File size: 0x154
Load size: 0x154
Read 0x154 bytes
Write 0x200 bytes
change@change :~/Si/A10/2_led$
其中有個./mksunxiboot led.bin leds.bin要注意,不通過mksunxiboot工具 的.bin文件,pcDuino是運行不了的。這個工具在官網上都有下。如今的處理啓動都很複雜,內有固化有bl0代碼,在跳轉到bl1時須要校驗程序的合法性,這個工具mksunxiboot簡單點少就是給咱們程序加了點頭部,讓處理器可以識別咱們寫的代碼。你能夠分析led.bin和leds.bin的反彙編代碼,就一目瞭然了。這部分感興趣的能夠一塊兒討論。
2.測試
上面生成的leds.bin就能夠放到板子上運行了。爲了避免破會NAND中的系統,直接放到tf卡運行。不用擔憂那個先啓動,看全志手冊就知道pcDuino默認先從tf卡啓動,只有tf卡沒有啓動的引導程序纔會跳到NAND啓動。插上tf卡到PC機
change@change:~/Si/A10/2_led$ sudo dd if=/dev/zero of=/dev/sdb bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB) copied, 0.425886 s, 2.5 MB/s
change@change:~/Si/A10/2_led$ sudo dd if=leds.bin of=/dev/sdb bs=1024 seek=8
0+1 records in
0+1 records out
512 bytes (512 B) copied, 0.00600667 s, 85.2 kB/s
change@change:~/Si/A10/2_led$
而後取下tf卡,插到pcDino上,RX LED就開始閃爍了。若是你手上有led,接到GPIO四、GPIO5也會閃爍。