因为我的系统要用GPS、GPRS、RS485、RS232等接口,W90N745的GPIO又没那么多,将全部串口引出后IO远远不够我用,就用两片SC16IS752扩展了4个串口。
先说说SC16IS752,这个片子很棒,性能高,价格低:
1. 双串口,并且还有多个GPIO可以用。
2. 每个串口的收和发都有64个字节的FIFO。
3. 带硬件的RS485控制,做485应用时,收和发的切换完全不用CPU干预(这点适合LINUX这样实时性不高的系统)。
4. 和CPU之间SPI和I2C接口通过一个配置引脚可选。
5. 电压3.3V,可以兼容5V的IO,SSOP28超小型封装。
6. 寄存器对16C550向下兼容。
我选择的是SPI接口,因为SPI接口的速度比I2C快很多。
碍于W90N745的IO太少,SPI总线要接FLASH、SD卡、AD、LCD等,SC16IS752的片选不够用了,只好用HC595扩展了8个IO 来用,HC595是一个串行转并行的转换IC,可以直接用SPI接口驱动。这样IO有了,而且非常节省CPU的本身IO口。
但是也带来了一个麻烦,就是选择SC16IS752时,一定要先向SPI写一个字节,把HC595给驱动输出才可以选择SC16IS752,给驱动程序带来不小的困难,并且SPI的操作一定不能被其它SPI的驱动打断,比如,正在操作串口寄存器时,不能被读写FLASH的操作打断,不然所有器件的读写都会出现紊乱。于是在驱动HC595的代码里加了信号量等多重保护,总算互不影响了。
串口驱动,TTY、CUA、UART设备这些非常麻烦,我看了很多网上的介绍,也买了一些书来看,重写了两三次代码都没把串口驱动起来。后来在网上的一篇文章的启发下,在linux/driver/char里找到serial.c作为基础直接改代码,发现的确容易多了,就是改一些底层的寄存器操作和一些架构而已。
里面有两个函数,一个是serial_in,作用是读硬件寄存器,另一个是serial_out,作用是写硬件寄存器,改这两个就比较容易了。
改完后发现,SPI操作一个寄存器时,必须写三个字节才可以,一个字节是驱动HC595,另一个才是寄存器地址和数据,这样的话,效率极低,经过仔细查阅 SC16IS752的文档,发现有一个很有用的功能,就是FIFO操作,一次可以读多个字节,也可以一次写多个字节。于是我又写了另外两个专门操作 FIFO的函数,一个是serial_ins,一个是serial_outs,作用想我不说大家也清楚。在哪里调用呢,经过查找serial.c里的函数,发现所有的读写数据只通过两个函数实现,一个是receive_chars,另一个是transmit_chars。把FIFO操作的两个函数移植到这两个里面就可以了。
还有一点,就是CONFIG_SERIAL_MULTIPORT这个开关,最开始不知道他的含义,在网上也查不太清楚,四个串口,就要把serial.c 复制成4个文件,每个文件操作一个串口,怎么弄怎么麻烦。后来经过多次实验,才发现CONFIG_SERIAL_MULTIPORT这个开关是多串口的开关,就是一个serial.c驱动,就可以供多个功能一样的串口使用。但是打开这个开关后也不是一帆风顺。因为共用了serial_in和 serial_out函数,硬件寄存器操作要在里面区分开。
static _INLINE_ void serial_out(struct async_struct *info, int offset, int value);
info->state->line这个值可以作为端口的区分,然后根据不同的端口进行不同的片选操作。
#define SRS_TABLE_SIZE (4)
struct serial_state rs_table[SRS_TABLE_SIZE] = {
{ 0, BASE_BAUD, 1, 2, STD_COM_FLAGS }, /* ttyS1 */
{ 0, BASE_BAUD, 2, 2, STD_COM_FLAGS }, /* ttyS2 */
{ 0, BASE_BAUD, 3, 2, STD_COM_FLAGS }, /* ttyS3 */
{ 0, BASE_BAUD, 4, 2, STD_COM_FLAGS } /* ttyS4 */
};
就可以定义4个串口设备了,并且共用一个驱动。
阅读(2345) | 评论(0) | 转发(1) |