Chinaunix首页 | 论坛 | 博客
  • 博客访问: 156477
  • 博文数量: 38
  • 博客积分: 687
  • 博客等级: 上士
  • 技术积分: 426
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-09 10:48
文章分类

全部博文(38)

文章存档

2019年(1)

2016年(1)

2014年(5)

2013年(1)

2012年(8)

2011年(17)

2010年(2)

2009年(3)

我的朋友

分类: 嵌入式

2011-08-21 23:18:59

现在开始写三个驱动,中断,时钟,串口。
本来以为串口可以用16550的驱动,后来发现它不是16550的驱动。原因是因为没看仔细文档。
文档里写着
functionally similar to standard 16C550 devices
就以为是16550了,实际上primeCell的串口。
===
The PrimeCell UART varies from the industry-standard 16C550 UART device as
follows:
receive FIFO trigger levels are 1/8, 1/4, 1/2, 3/4, and 7/8
the internal register map address space, and the bit function of each register differ
the deltas of the modem status signals are not available.
1.5 stop bits not available (1 or 2 stop bits only are supported)
no independent receive clock.
===
VxWorks 自带一个primeCellSio.ch, 试了一下发现用不料,原来它是pl010标准串口的驱动,我们的versatilepb用的是pl011标准的串口。所以在它的基础上改写了一个pl011.ch。

中断本来以为是pl190标准的中断控制器,结果发现也不是,这个主芯片有两个中断控制器,PIC和SIC
PIC是pl190标准的。

编译通过后,可以用如下命令执行
tftp 7c00000 bootrom.bin
go 7c00000

问题1
ram or rom 出了有效范围0x8000000
看打印的R15,正好是0x8000000
首先在bootInit.c加打印
while(1){*(volatile int *)0x101f1000='z';}
发现是fillLongs前后出的问题
然后qemu加-s选项启动,使能gdb。用arm-linux-gdb链接后,可以设断点
nmarm bootrom |grep fill
fillLongs 的值为0x100164,
要在 fillLongs - romInit + ROM_TEXT_ADRS处设断点。
break *0x7c00164
当程序停止在断点处时,就可以观察各个寄存器。发现sp的值异常。
原来是romInit.s不小心把sp初始化的代码给删了。

问题2
qemu: hardware error: pl011_write: Bad offset c
CPU #0:
R00=00000080 R01=000001d3 R02=00000000 R03=00000000
R04=00003510 R05=000000d0 R06=0001adac R07=00e10000
R08=00002580 R09=00000002 R10=0000000f R11=006390f8
R12=00000003 R13=005fff8c R14=101f100c R15=00600268
PSR=000001d3 ---- A svc32
这个就是串口问题了。换个新写的pl011.c就好了。

还有其他问题
Timer with period zero, disabling
sp804.c里,先写t1load寄存器的值,再开timer,就没有上面的问题。
问题变成了
qemu: fatal: Bad mode c

R00=20000193 R01=07bfbfe0 R02=00638454 R03=ffffffcc
R04=00000001 R05=0000016e R06=00000168 R07=0064d520
R08=00636060 R09=0000016a R10=0064d64c R11=0064d420
R12=00000110 R13=07bfbfe0 R14=00000150 R15=006096a4
PSR=f8000193 NZCV A svc32
反汇编一下发现6096a4是在alreadyOnExcStack函数里,大概是中断还有问题。
objdumparm -D vxImage.o >> v.txt

我有一个自己写的串口轮询输出函数bspDbg(),通过加打印的方式在sysHwInit()中加
bspDbg("test 0x%x 0x%x\n", 0x12345678,0xfedcba90);     <== 测试bspDbg()是否正常
bspDbg("sysHwInit [0X10140010]=0X%x\n", *(volatile unsigned int *)0x10140010);  <== 测试ier是否未使能任何中断。
在pl190.c中的ambaIntLvlVecChk()中加
AMBA_INT_REG_READ (AMBA_INT_CSR_PEND, isr);
bspDbg("chk=%x isr=0x%x ier=%x\n",isr, *(volatile int *)0x10140000, *(volatile int *)0x10140010);
<== 测试中断状态寄存器和中断使能寄存器是否正常
===
In:    serial
Out:   serial
Err:   serial
Net:   SMC91111-0
Hit any key to stop autoboot:  0
SMC91111: MAC 52:54:00:12:34:56
Using SMC91111-0 device
TFTP from server 192.168.1.99; our IP address is 192.168.1.91
Filename 'bootrom.bin'.
Load address: 0x7c00000
Loading: #########
done
Bytes transferred = 124920 (1e7f8 hex)
## Starting application at 0x07C00000 ...
test 0x12345678 0xfedcba90
sysHwInit [0X10140010]=0X0
chk=1000 isr=0x1000 ier=3010
===
isr=0x1000 是 串口0中断, isr=0x10 是timer01中断, ier=0x3010说明当前系统只使能了串口1,串口0和timer01中断。
发现打印的数值都很正确。
最后发现chk函数的参数
===
STATUS  ambaIntLvlVecChk
    (
    int* pLevel,  /* ptr to receive old interrupt level */
    int* pVector  /* ptr to receive current interrupt vector */
    )
===
pLevel是老的中断level值,pVector需要的是新的vector值。修改了一下ambaIntLvlVecChk函数就好了。
别忘了把bspDbg的函数声明放在sysLib.c 包含第一个c文件之前,以保证打印正确。
extern void bspDbg(const char *fmt, ...);
去掉bspDbg多余的打印后,
===
Using SMC91111-0 device
TFTP from server 192.168.1.99; our IP address is 192.168.1.91
Filename 'bootrom.bin'.
Load address: 0x7c00000
Loading: #########
done
Bytes transferred = 124816 (1e790 hex)
## Starting application at 0x07C00000 ...
tttttttttttttttttttttttttttttttttttttttttttttttttttttQEMU: Terminated
===
其中字符t是我在usrClock函数中加的打印。
现在时钟和中断都可以工作了。

但是bootrom的banner还没有出来,大概是串口还不工作把。
等等,先把串口的buadrate确认一下。哦,我已经把串口的修改baudrate的代码都去掉了。所以不会是因为baudrate不对而输出不料banner。明天再调串口吧。

调试串口的方法是在还是加打印
在ambaInitChannel     ambaIoctl    ambaTxStartup    primeCellSioInt 里加打印,弄清除在每一步是否都按自己预想的实现了。有没有低级错误,比如打算置1结果清零了。
测试串口的方法是在
all/usrConfig.c 文件里加
printf("hello world\n");
while(1);
加的位置是在这三行之后
    ioGlobalStdSet (STD_IN,  consoleFd);
    ioGlobalStdSet (STD_OUT, consoleFd);
    ioGlobalStdSet (STD_ERR, consoleFd);
如果hello world被正确的输出了,表示printf可以工作。
经过一番调试,printf终于工作了。
一般就基本bootrom就应该可以工作了。

但是我还是遇到一个问题。在usrRoot中,调用 bootAppShellInit 函数后就死机了。程序没有反应了。
还是串口驱动不对。中断中不清除中断标志就好了。

之后,shell就出现了。
但是倒计时的时间不对,似乎实际20秒才等于bootrom中的1秒。是qemu的性能低吗?
想起时钟驱动有个div16,把分频的div16去掉后,时钟就大概正确了。
阅读(2009) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~