作者: zjujoe 转载请注明出处
Email:[email protected]
BLOG:http://blog.csdn.net/zjujoe
由于串口不够用,我们选用了 Exar 公司的 xr 20m 1172 SPI/I 2C 转串口芯片。考虑到速率问题(I 2c 较慢只有100k/400k两种模式),我们采用 SPI接口驱动该芯片。
花了两周的时间, 该芯片可以和 PC 通信了。最近应用组同事拿去连接一个加密芯片,发现不能正常工作。 该加密芯片提供的接口为 19200速率,8 位字节, 奇校验, 1位停止位,CTS/RTC 流控制。硬件同事仔细查看示波器,发现原来我们发出 0x94 时, 校验位时对时错。
考虑到我们的驱动程序确实也只是刚刚能够工作,应该有较大的优化空间, 决定对代码进行一定优化,以辅助问题解决。
首先写一个测试程序,该程序以 Cooked 模式, 8 位字节, 奇校验, 1位停止位, auto rts/cts 流控设置串口,然后写出一个字节 (0x55 或者 0x94)。然后恢复串口设置,最后退出。
通过SPI 接口的时钟来提高 uart 寄存器速率。 Marvell 平台的 ssp 接口有一个分频器,系统有一个寄存器SSCR bit27控制分频器的输入是 26M 还是 13M , 另外同一个寄存器里bit 8-bit19 控制分频数。 SPI输出频率为 ( 13M or 26M ) / SSCR[8-19] + 1。
我们使用系统提供的 3.25M 时钟来计数,计算各种设置下 SPI 读写 uart 寄存器时间:
1) 缺省设置, SSCR[27] = 0, SSCR[8-19]= 0xf, 测量结果:
|
计数 |
time in uS |
write |
5a |
27.69230769 |
read |
52 |
25.23076923 |
2)SSCR[27] = 0, SSCR[8-19]= 0x0, 测量结果:
|
计数 |
time in uS |
write |
19 |
7.692307692 |
read |
14 |
6.153846154 |
3)SSCR[27] = 1, SSCR[8-19]= 0x0, 测量结果:
|
计数 |
time in uS |
write |
17 |
7.076923077 |
read |
12 |
5.538461538 |
性能大概提高了 4-5倍!
遗憾的是发现发送 0x94 正常,但是发送0x55 校验位时好时坏。
Uart 寄存器的特殊之处在于它进行了地址复用:同一个地址对应了多个寄存器,到底是哪一个依赖于三个寄存器的内容:lcr, efr, mcr. 比如, 在 lcr[7] == 1, lcr <> 0xbf 时, 地址 0x0 对应了 DLL 寄存器,在 lcr[7] == 1 时, 地址 0x0 对应了RHR/THR寄存器(读为 RHR, 写为 THR). 这样, 我们在进行读写寄存器时,需要频繁访问 lcr/efr/mcr, 对这三个寄存器进行缓冲可以减少 SPI接口访问, 提高读写效率。
优化前: 整个测试程序 SPI 读操作为: 103 次, 写操作为 240次。其中发送一个字符的 SPI 读操作为 15 次, 写操作为 26次。
优化后:整个测试程序 SPI 读操作为: 24 次, 写操作为 238次。其中发送一个字符的 SPI 读操作为 5 次, 写操作为 27次。
可见读操作大大减少了。写操作数基本不变。
遗憾的是问题依旧。
前面我们提过, 访问一个uart 寄存器可能需要先设置其它寄存器,这导致操作的原子性很难保证,另外,我们是通过 SPI 接口来读写 uart 寄存器的,这导致更加难以保证读写寄存器的原子性。 考虑到我们要在中断处理函数里访问 uart 寄存器,我们利用自旋锁来保证寄存器的原子性。
遗憾的是问题依旧。
跟踪系统寄存器访问发现, 我们目前不需要使用 IER:bit[4-7], ISR:bit[4/5], FCR :bit[4/5], MCR :bit[ 2/5/6 ], 对这些bit 访问需要更多的限制条件(EFR[4] == 1),事实上我们目前不需要。
所以我们修改这几个寄存器的访问限制, 从而节约寄存器访问。
优化后:整个测试程序 SPI 读操作为: 21 次, 写操作为 67次。其中发送一个字符的 SPI 读操作为 4 次, 写操作为 3次。
测试一下,发送 0x55 , 0x94 各 50次, 发现全部正确!