最近在学习裸奔ARM11的OK6410 开发板,写了个串口程序,开发环境为Windows 7 64bit + Ubuntu 13.04, 开发环境参照飞凌嵌入式的使用手册搭建。但是裸机代码参考韦东山老师的裸机代码,主要功能是:Win7和开发板通过串口相连,然后Win7 通过串口向开发板发送字符,开发板再将字符原封不动的返回。如果字符是 0 -9 , a - f, A - F, 则以开发板上的4位LED显示,否则,关闭LED灯。程序代码如下:
clock.S : 配置ARM的PLL
.global clock_init
clock_init:
/* 设置Lock_Time */
ldr r0, =0x7E00F000
ldr r1, =0x0000FFFF
str r1, [r0] @APLL_LOCK
str r1, [r0, #4] @MPLL_LOCK
str r1, [r0, #8] @EPLL_LOCK
#define OTHERS 0x7e00f900
ldr r0, = OTHERS
ldr r1, [r0]
bic r1, r1, #0xc0 /* 1100 0000 SYNCMUX设置为 MOUT,且ARM设置为异步模式*/
str r1, [r0]
loop1: /* 等待, 知道CPU进入异步模式 */
ldr r0, =0x7e00f900
ldr r1, [r0]
and r1, r1, #0xf00 /*[11:8] SYNCACK :确认ARM是否进入异步模式 */
cmp r1, #0
bne loop1
/* 配置时钟分频寄存器 */
#define ARM_RATIO 0
#define HCLKX2_RATIO 1
#define HCLK_RATIO 1
#define PCLK_RATIO 3
#define MPLL_RATIO 0
#define CLK_DIV0 0x7E00F020
ldr r0, =CLK_DIV0
ldr r1, = (ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12)
str r1, [r0]
/* 配置APLL : Out = MDIV * Fin / (PDIV * 2^SDIV)*/
#define APLL_CON 0x7E00F00c
#define APLL_CON_VAL ((1 << 31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =APLL_CON
ldr r1, =APLL_CON_VAL [url=home.php?mod=space&uid=88907]@out[/url] = 266 * 12 / (3 * 2^1) = 532MHz
str r1, [r0]
/* 配置MPLL : Out = MDIV * Fin / (PDIV * 2^SDIV)*/
#define MPLL_CON 0x7E00F010
#define MPLL_CON_VAL ((1 << 31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =MPLL_CON
ldr r1, =MPLL_CON_VAL [url=home.php?mod=space&uid=72445]@[/url] Out = 266 * 12 / (3 * 2^1) = 532MHz
str r1, [r0]
/* Initial the CLK_SRC register: select the clock source */
ldr r0, =0x7E00F01c
ldr r1, =0x03 /* select the MPLL and the APLL */
str r1, [r0]
/* return from fucntion call */
mov pc, lr
uart.c : 配置串口,通信波特率为115200, 8个数据位,无校验,1个停止位
#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 init_uart()
{
GPACON &= ~0xff;
GPACON |= 0x22; //0010 : RXD[0] & TXD[0]
/* ULCON0 */
ULCON0 = 0x3;/* Data: 8bit Stop bits: 1 Parity Mode: No */
UCON0 = 0x5; /* 中断请求或者轮询从Uart 接收/发送缓冲区收发数据 选择PCLK作为UART波特率时钟,DIV_VAL = (PCLK / ((b/s) * 16)) - 1 */
UFCON0 = 0x1; /*FIFO enable */
UMCON0 = 0;/* nRTS 无效 */
UBRDIV0 = 35;
UDIVSLOT0 = 0x1;
}
/* UFSTAT0: UART0 的FIFO状态寄存器 */
/**
* bit 14: Tx FIFO Full 发送FIFO满时自动置位
* bit 13-8: Tx FIFO 数据中的数量
*
* bit 6: Rx FIFO Full 接收FIFO满时,该位置1
* bit 5-0: Rx FIFO 数据中的数量。
*/
/**
* URXH0 : 接收缓冲寄存器 0x7F005024
* 低8bit为接收的数据;
*/
char getchar(void)
{
while ((UFSTAT0 & 0x7f) == 0)
;
return URXH0;
}
/**
* UTXH0: 发送缓冲寄存器 低8位为要发送的数据
*/
void putchar(char c)
{
while (UFSTAT0 & (1 << 14))
;
UTXH0 = c;
}
start.S 启动代码
.global _start
.extern clock_init
.extern main
_start:
/* 设置协处理器,设置外设的基地址*/
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15, 0, r0, c15, c2, 4
/* 关闭看门狗 */
ldr r0, =0x7E004000
mov r1, #0
str r1, [r0]
/* 设置时钟 */
bl clock_init
/* 设置堆栈 */
ldr sp, = 8 * 1024
bl main
halt:
b halt
main.c
int main(void)
{
char c;
int i;
LEDCON = 0x1111;
LEDDAT = 0xf;
init_uart();
while (1) {
c = getchar();
int c1;
if (c >= '0' & c <= '9')
c1 = c - '0';
else if (c >= 'A' & c <= 'F')
c1 = c - 'A' + 10;
else if (c >= 'a' & c <= 'f')
c1 = c - 'a' + 10;
else
c1 = 0;
LEDDAT = ~c1 & 0x0f;
putchar(c);
}
}
delay.S /* 没用到,可以直接无视 */
.global clock_delay
/* the udly will be passed by r0 */
clock_delay:
cmp r0, #0
beq loop_end
loop:
ldr r1, =532000 /* 1ms at 532MHz */
inner:
sub r1, r1, #1
cmp r1, #0
bne inner
outter:
sub r0, r0, #1
cmp r0, #0
bne loop
loop_end:
/* return from the function call*/
mov pc, lr
上述写的延时函数有问题,我设置ARM的时钟频率为532MHz,原以为延时函数内层赋值 532000应该为1ms,即使后来ARM开启流水线执行,多条语句一起执行,那么延时应该小于1ms 左右,但是实际代码执行通过LED可知,6个左右的内层循环就将近1S了。百思不得其解啊,莫非延时函数的执行不是ARM内核来执行?
Makefile
CC = arm-linux-gcc
CFLAGS = -c -Wall -fno-stack-protector -fno-builtin
LD = arm-linux-ld
LDFLAGS = -Ttext 0x0 -nostdlib ####-Ttext 如果为0 是烧写到Nand FLASH的起始位置,如果为 0x50000000 是烧写到SDRAM中直接运行
OBJDUMP = arm-linux-objdump
OBJCOPY = arm-linux-objcopy
OBJ = start.o uart.o clock.o main.o delay.o
uart.bin : uart.elf
$(OBJCOPY) -O binary uart.elf uart.bin
cp uart.bin ~/nfs_root/chenchen -f
uart.elf: $(OBJ)
$(LD) $(LDFLAGS) -o uart.elf $(OBJ)
$(OBJDUMP) -d uart.elf > uart.dis
start.o : start.S
$(CC) $(CFLAGS) -o $@ [ DISCUZ_CODE_347 ]lt;
uart.o : uart.c
$(CC) $(CFLAGS) -o $@ [ DISCUZ_CODE_347 ]lt;
main.o : main.c
$(CC) $(CFLAGS) -o $@ [ DISCUZ_CODE_347 ]lt;
clock.o : clock.S
$(CC) $(CFLAGS) -o $@ [ DISCUZ_CODE_347 ]lt;
delay.o : delay.S
$(CC) $(CFLAGS) -o $@ [ DISCUZ_CODE_347 ]lt;
clean:
rm $(OBJ) *.bin *.dis *.elf
在Linux环境下 Make,即可生成可执行文件 uart.bin,通过NFS文件系统,用Uboot的nfs 命令将uart.bin 烧写到0x50000000 内存处,然后再用nand命令,将该段内存烧写到Nand Flash 的起始处。然后断电,上电重新运行,可以看到程序正常运行。
但是,我把链接参数改成 -Ttext 0x50000000, 然后直接将uart.bin 烧写到 0x50000000 处,然后 go 0x500000000可以看到程序运行不正常,串口不能正常收发。我以前利用这种方法写过流水灯,就能正常运行。不知道是什么原因?
求大神指导啊!
|