開發環境
系統:ubuntu 10.04.4
單闆:ok6410
編譯器:arm-linux-gcc-4.3.2
搭建開發環境詳見ubuntu 10.04.4開發環境配置。
目标:實作ok6410 uart0 顯示任意輸入字元
一、編寫源代碼
根據s3c6410手冊編寫代碼,包括源檔案start.S clock.S main.c uart.c uart.h lib.c lib.h Makefile
檔案start.S:
.globl _start
_start:
/* 硬體相關的設定 */
/* Peri port setup */
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff)
/* 關看門狗 */
/* 往WTCON(0x7E004000)寫0 */
ldr r0, =0x7E004000
mov r1, #0
str r1, [r0]
/* 設定棧 */
ldr sp, =8*1024
/* 設定時鐘 */
bl clock_init
bl main
halt:
b halt
檔案clock.S:
.globl clock_init
clock_init:
/* 1.設定LOCK_TIME */
ldr r0, =0x7E00F000 /* APLL_LOCK */
ldr r1, =0x0000FFFF
str r1, [r0]
str r1, [r0, #4] /* MPLL_LOCK */
str r1, [r0, #8] /* EPLL_LOCK */
#define OTHERS 0x7e00f900
@ set async mode /* 當CPU時鐘 != HCLK時,要設為異步模式 */
ldr r0, =OTHERS
ldr r1, [r0]
bic r1, #0xc0
str r1, [r0]
loop1: /* 等待,直到CPU進入異步模式 */
ldr r0, =OTHERS
ldr r1, [r0]
and r1, #0xf00
cmp r1, #0
bne loop1
/* SYNC667 */
/* MISC_CON[19] = 0 */
#define ARM_RATIO 0 /* ARMCLK = DOUTAPLL / (ARM_RATIO + 1) */
#define HCLKX2_RATIO 1 /* HCLKX2 = HCLKX2IN / (HCLKX2_RATIO + 1) */
#define HCLK_RATIO 1 /* HCLK = HCLKX2 / (HCLK_RATIO + 1) */
#define PCLK_RATIO 3 /* PCLK = HCLKX2 / (PCLK_RATIO + 1) */
#define MPLL_RATIO 0 /* DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1) */
ldr r0, =0x7E00F020 /* CLK_DIV0 */
ldr r1, =(ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12)
str r1, [r0]
/* 2.配置時鐘 */
/* 2.1 配置APLL */
/* 2.1.1 設定APLL
* 2.1.2 MUXAPLL
* 2.1.3 SYNC667
* 2.1.4 DIVAPLL
*/
#define APLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =0x7E00F00C
ldr r1, =APLL_CON_VAL
str r1, [r0] /* APLL_CON, FOUTAPL = MDIV * Fin / (PDIV*2^SDIV) = 266*12/(3*2^1) = 532MHz */
/* 2.2 配置MPLL */
/* 2.2.1 設定MPLL
* 2.2.2 MUXMPLL
* 2.2.3 SYNCMUX
* 2.2.4 SYNC667
* 2.2.5 HCLKX2_RATIO
* 2.2.6 PCLK_RATIO
*/
#define MPLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =0x7E00F010
ldr r1, =MPLL_CON_VAL
str r1, [r0] /* MPLL_CON, FOUTMPL = MDIV * Fin / (PDIV*2^SDIV) = 266*12/(3*2^1) = 532MHz */
/* 3.選擇PLL的輸出作為時鐘源 */
ldr r0, =0x7E00F01C
ldr r1, =0x03
str r1, [r0]
mov pc, lr
檔案main.c:
#include "uart.h"
#include "lib.h"
int main()
{
char c;
uart_init();
while(1)
{
// 從序列槽接收資料後,判斷其是否數字或子母,若是則加1後輸出
do {
c = getc();
if (c == '\n' || c == '\r')
{
putc('\n');
putc('\r');
}
else
{
putc(c);
}
} while (c == '\n' || c == '\r');
}
return 0;
}
檔案uart.c:
#define ULCON0 (*((volatile unsigned long *)0x7F005000))
#define UCON0 (*((volatile unsigned long *)0x7F005004))
#define UFCON0 (*((volatile unsigned long *)0x7F005008))
#define UMCON0 (*((volatile unsigned long *)0x7F00500C))
#define UTRSTAT0 (*((volatile unsigned long *)0x7F005010))
#define UFSTAT0 (*((volatile unsigned long *)0x7F005018))
#define UTXH0 (*((volatile unsigned char *)0x7F005020))
#define URXH0 (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0 (*((volatile unsigned short *)0x7F005028))
#define UDIVSLOT0 (*((volatile unsigned short *)0x7F00502C))
#define GPACON (*((volatile unsigned long *)0x7F008000))
void uart_init(void)
{
GPACON &= ~0xff;
GPACON |= 0x22;
/* ULCON0 */
ULCON0 = 0x3; /* 資料位:8, 無較驗, 停止位: 1, 8n1 */
UCON0 = 0x5; /* 使能UART發送、接收 */
UFCON0 = 0x01; /* FIFO ENABLE */
UMCON0 = 0;
/* 波特率 */
/* DIV_VAL = (PCLK / (bps x 16 ) ) - 1
* bps = 57600
* DIV_VAL = (66500000 / (115200 x 16 ) ) - 1
* = 35.08
*/
UBRDIV0 = 35;
/* x/16 = 0.08
* x = 1
*/
UDIVSLOT0 = 0x1;
}
檔案uart.h:
void uart_init(void);
檔案lib.c:
#define UFSTAT0 (*((volatile unsigned long *)0x7F005018))
#define UTXH0 (*((volatile unsigned char *)0x7F005020))
#define URXH0 (*((volatile unsigned char *)0x7F005024))
char getc(void)
{
while ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0);
return URXH0;
}
void putc(char c)
{
while (UFSTAT0 & (1<<14));
UTXH0 = c;
}
檔案lib.h:
void putc(char c);
char getc(void);
檔案Makefile:
2_uart.bin: start.o clock.o main.o uart.o lib.o
arm-linux-ld -Ttext 0x52000000 -o uart.elf $^
arm-linux-objcopy -O binary uart.elf 2_uart.bin
arm-linux-objdump -D uart.elf > uart.dis
%.o : %.S
arm-linux-gcc -o $@ $< -c
%.o : %.c
arm-linux-gcc -o $@ $< -c
clean:
rm *.o uart.elf *.bin uart.dis
二、編譯
編譯後将生成的2_uart.bin拷到ubuntu 的tftp目錄下,tftp配置詳見ubuntu 10.04.4開發環境配置
[email protected]:~$ cd Si/OK6410/2_uart0/
[email protected]:~/Si/OK6410/2_uart0$ ls
clock.S lib.c lib.h main.c Makefile start.S uart.c uart.h
[email protected]:~/Si/OK6410/2_uart0$ make
arm-linux-gcc -o start.o start.S -c
arm-linux-gcc -o clock.o clock.S -c
arm-linux-gcc -o main.o main.c -c
In file included from main.c:3:
lib.h:1: warning: conflicting types for built-in function 'putc'
arm-linux-gcc -o uart.o uart.c -c
arm-linux-gcc -o lib.o lib.c -c
lib.c:12: warning: conflicting types for built-in function 'putc'
arm-linux-ld -Ttext 0x52000000 -o uart.elf start.o clock.o main.o uart.o lib.o
arm-linux-objcopy -O binary uart.elf 2_uart.bin
arm-linux-objdump -D uart.elf > uart.dis
[email protected]:~/Si/OK6410/2_uart0$ ls
2_uart.bin clock.S lib.h main.c Makefile start.S uart.dis uart.h
clock.o lib.c lib.o main.o start.o uart.c uart.elf uart.o
[email protected]:~/Si/OK6410/2_uart0$ cp 2_uart.bin /home/change/work/tftpboot/
三、燒寫測試
我的單闆ok6410中有NAND flash,沒有NOR flash。考慮到大多數電腦沒有并口,也沒有程式設計器,我用u-boot下載下傳程式到記憶體運作。但是單闆的u-boot要支援網卡。
以後會寫一個操作NAND的自我更新程式的,到時下載下傳程式就友善了。
單闆上電:
U-Boot 2012.04.01 (Jan 11 2013 - 14:47:24) for SMDK6410
CPU: [email protected]
Fclk = 532MHz, Hclk = 133MHz, Pclk = 66MHz (ASYNC Mode)
Board: SMDK6410
DRAM: 128 MiB
WARNING: Caches not enabled
Flash: 0 KB
NAND: select s3c_nand_oob_mlc_64
id_data[0] = 0xec id_data[1] = 0xd5 id_data[2] = 0x94 id_data[3] = 0x29 id_data[4] = 0x34 id_data[5] = 0x41 id_data[6] = 0xec id_data[7] = 0xd5 NAND_ECC_NONE selected by board driver. This is not recommended !!
2048 MiB
realpage value:255
page value:255
ret value:0
In: serial
Out: serial
Err: serial
Net: dm9000
Hit any key to stop autoboot: 0
##### 100ask Bootloader for OpenJTAG #####
[n] Download u-boot to Nand Flash
[k] Download Linux kernel uImage
[j] Download root_jffs2 image
[y] Download root_yaffs image
[d] Download to SDRAM & Run
[z] Download zImage into RAM
[g] get file, and write to nand flash 0 block
[f] Format the Nand Flash
[s] Set the boot parameters
[b] Boot the system
[r] Reboot u-boot
[q] Quit from menu
Enter your selection: q
SMDK6410 # printenv
baudrate=115200
bootargs=console=ttySAC0,115200 root=/dev/mtdblock3
bootcmd=nand read 0x50000000 0x60000 0x200000;bootm 0x50000000
bootdelay=5
ethact=dm9000
ethaddr=00:0c:29:4d:e4:f4
gatewayip=172.16.1.1
ipaddr=172.16.1.133
netmask=255.255.255.0
serverip=172.16.1.135
stderr=serial
stdin=serial
stdout=serial
Environment size: 336/524284 bytes
SMDK6410 # ping 172.16.1.135
dm9000 i/o: 0x18000000, id: 0x90000a46
DM9000: running in 16 bit mode
MAC: 00:0c:29:4d:e4:f4
operating at 100M full duplex mode
Using dm9000 device
host 172.16.1.135 is alive
SMDK6410 # tftp 0x52000000 2_uart.bin
dm9000 i/o: 0x18000000, id: 0x90000a46
DM9000: running in 16 bit mode
MAC: 00:0c:29:4d:e4:f4
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 172.16.1.135; our IP address is 172.16.1.133
Filename '2_uart.bin'.
Load address: 0x52000000
Loading: #
done
Bytes transferred = 664 (298 hex)
下面開始測試uart程式,在u-boot輸入指令go 0x52000000,程式便開始運作,并且是一去不複返
SMDK6410 # go 0x52000000
## Starting application at 0x52000000 ...
此時輸入任意字元,測試OK
adfsdQWDF
midfakd3148
ok6410 test
it's ok!