02-單片機入門_點燈
通過彙編代碼點亮LED
先看看原理圖-看點燈需要操作哪一些GPIO端口
在原理圖中有三個LED , 分别是 nLED_1 , nLED_2 , nLED_4
同時nLED_1中的n,表示低電平有效

這三個LED配置設定連接配接的GPIO端口是:GPF4 , GPF5, GPF6
看使用者手冊,這3個GPIO端口怎麼操作
配置GPF4 , GPF5 , GPF6 為輸出端口
配置GPFDAT 的 4, 5 ,6 位為0(nLED_1低電平有效)
編寫代碼
led_on.S
.text
.global _start
_start:
/* 配置GPF4,GPF5,GPF6為輸出引腳
* 把=0x1500寫到位址0x56000050
*/
ldr r1, =0x56000050
ldr r0, =0x1500 /* mov r0, #0x1500 */
str r0, [r1]
/* 設定GPF4,GPF5,GPF6輸出低電平
* 把0寫到位址0x56000054
*/
ldr r1, =0x56000054
ldr r0, =0 /* mov r0, #0 */
str r0, [r1]
/* 死循環 */
halt:
b halt
Makefile
all:
arm-linux-gcc -c -o led_on.o led_on.S
arm-linux-ld -Ttext 0 led_on.o -o led_on.elf
arm-linux-objcopy -O binary -S led_on.elf led_on.bin
arm-linux-objdump -D led_on.elf > led_on.dis
clean:
rm *.bin *.o *.elf
進行編譯,生成led_on.bin
通過openjtag刷入nand flash,将開發闆啟動項撥向Nand flash,打開電源,3個LED點亮
再通過openjtag将led_on.bin刷入nor flash,以nor flash啟動,也是正常點亮
通過C語言代碼點亮LED
C語言的函數需要用到棧傳遞參數(棧就是一片記憶體空間),這裡就需要看看jz2440在單片機模式下的記憶體布局
先講講nor flash 和 nand flash 在非指令模式下的簡單差別
nor flash | nand flash |
---|---|
可存儲代碼,像硬碟一樣 | 可存儲代碼,像硬碟一樣 |
可執行代碼,但無法修改norFlash的資料(可讀,可執行) | 不能執行代碼,需要把代碼複制到SRAM(SRAM像記憶體條一樣)執行 |
在上表中,包含了3個硬體:
- Nor flash:
- 1)可以像固态硬碟一樣存儲資料,
- 2)從nor flash啟動之後,nor flash也像包含代碼的記憶體空間,可以執行代碼,
- 3)由于nor flash本身是存儲代碼的,為了讓其上的資料不被破壞,在其記憶體空間上無法進行寫操作,
- 4)JZ2440上nor flash的大小為2M
- Nand flash:
- 1)可以單純的了解為PC上的固态硬碟,
- 2)在JZ440上Nand flash大小為256M
- SRAM :
- 1)片内記憶體(可讀,可寫,可執行),
- 2)在JZ2440上SRAM大小為4K
在JZ2440中,也有像PC上記憶體條一樣的硬體,叫做SDRAM,但是需要初始化,暫時就當這個硬體不存在
再說到C語言函數的棧,是需要可被修改的(能被進行寫操作)
1)在之前的點亮3個LED的例子中,有nor啟動和nand啟動
nor啟動:
- Nor Flash的基位址為0,片内RAM位址為0x4000 0000;
- CPU讀出Nor上第1個指令(前4位元組),執行;
- CPU繼續讀出其它指令執行。
nand啟動:
- 片内4k RAM基位址為0,Nor Flash不可通路;
- 2440硬體把Nand前4K内容複制到片内的RAM,然後CPU從0位址取出第1條指令執行
2)目前需要編寫C語言的函數,需要棧,而棧是往下增長的,是以nor flash啟動和nand flash啟動,棧的設定如下
3)怎麼判斷是Nor 啟動還是Nand Flash啟動
從Nor Flash 和 Nand Flash啟動的差別是啥:
- 從Nor Flash啟動:0位址在Nor Flash的位址空間上,0位址不可修改
- 從Nand Flash啟動: 0位址在SRAM的位址空間上,0位址可被修改
通過判斷0位址是否被修改,來判斷是從nor啟動還是nand啟動
4)關閉看門狗
2440裡面有個看門狗定時器,開發闆上電後,需要在一定時間内“喂狗”(設定相應的寄存器),否則就會重新開機開發。這裡直接關閉看門狗
編寫如下
start.S
.text
.global _start
_start:
/* 關閉看門狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
/* 設定記憶體: sp 棧 */
/* 分辨是nor/nand啟動
* 寫0到0位址, 再讀出來
* 如果得到0, 表示0位址上的内容被修改了, 它對應ram, 這就是nand啟動
* 否則就是nor啟動
*/
mov r1, #0
ldr r0, [r1] /* 讀出原來的值備份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND啟動 */
ldr sp, =0x40000000+4096 /* 先假設是nor啟動 */
moveq sp, #4096 /* nand啟動 */
streq r0, [r1] /* 恢複原來的值 */
bl main
halt:
b halt
led.c
void delay(volatile int d)
{
while (d--);
}
int main(void)
{
volatile unsigned int *pGPFCON = (volatile unsigned int *)0x56000050;
volatile unsigned int *pGPFDAT = (volatile unsigned int *)0x56000054;
int val = 0; /* val: 0b000, 0b111 */
int tmp;
/* 設定GPFCON讓GPF4/5/6配置為輸出引腳 */
*pGPFCON &= ~((3<<8) | (3<<10) | (3<<12));
*pGPFCON |= ((1<<8) | (1<<10) | (1<<12));
/* 循環點亮 */
while (1)
{
tmp = ~val;
tmp &= 7;
*pGPFDAT &= ~(7<<4);
*pGPFDAT |= (tmp<<4);
delay(100000);
val++;
if (val == 8)
val =0;
}
return 0;
}
Makefile
all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 start.o led.o -o led.elf
arm-linux-objcopy -O binary -S led.elf led.bin
arm-linux-objdump -D led.elf > led.dis
clean:
rm *.bin *.o *.elf *.dis