基于双TL16C554和嵌入式linux的串口扩展

发表时间:2021/5/14   来源:《中国电业》2021年2月第4期   作者:谭敏
[导读] 为了增加水电站监控系统中通讯管理机的RS485接口数量,提高其通讯能力,提出了一种利用双TL16C554芯片进行8通道扩展串口的设计方法
        谭敏
        (株洲中车机电科技有限公司,湖南         株洲 412001)
        摘要:为了增加水电站监控系统中通讯管理机的RS485接口数量,提高其通讯能力,提出了一种利用双TL16C554芯片进行8通道扩展串口的设计方法。其通过逻辑芯片将8路中断信号改良为2路中断信号,修改linux2.6内核下成熟的8250系列串口驱动实现方式及创建双TL16C554芯片的设备数据结构,解决了多中断源造成ARM处理器中断占时过长的问题,也可以替代当前市场上价格高的多串口通讯管理机解决方案。按照该方法设计的SDP-9028通讯管理机性能好、成本低,成功的应用到市场项目中,能完全满足项目中对串口传输的要求。
        关键词:监控系统 RS485 扩展串口 中断源
1、前言
        计算机监控系统是水电站整个发电系统中重要的部分,它对于提高水电站的自动化水平,提高水电站的供电质量和安全运行水平,提高水电站的劳动生产率和经济效益具有显著的效果。而水电站计算机监控系统中各个设备之间的通信好坏直接影响到监控系统能否正常工作,水电站能否稳定运行[1]。
        水电站监控系统包括各种子系统,如直流供电系统、机组保护系统、机组调速系统、机组励磁系统、集水井排水井控制系统、水力监测数据采集系统和闸门监控系统等,每个子系统中都有一定的现场控制设备与之对应,因此在电站运行现场中存在大量的控制设备,例如微机保护装置、GPS对时装置、电能采集装置、直流供电监测装置、机组转速监控仪、机组温度巡检仪、机组励磁和调速装置、机组同期装置和水位监测装置等一系列设备[2]。从各个厂商的专业领域优势和产品的采购运行成本考虑,一个电站往往有好多设备供应商,而不同厂商的设备采用的通讯接口和规约存在着差异,这就导致了同一监控系统中设备之间的通讯不兼容的问题。另外,作为监控后台的主机所支持的通讯接口种类和数量有限,而现场设备数目众多,所以后台无法同时与现场所有设备直接相连[3];另一方面,RS485串行总线接口采用二差分平衡方式传输数据,抗共模干扰能力较强,简单易用,可以满足工业恶劣环境的通讯要求。
        目前我国水电站监控系统中现场设备广泛提供RS485通讯接口。通讯管理机具有多个串行总线接口和网络接口,它可以把站内各种设备的数据按照协议分类以总线的方式采集汇总,然后整理以一个标准的格式上传给后台监控计算机,同时接收监控运行命令,解析后准确下传到对应设备。市场上能满足通讯性能要求的多串口通讯管理机价格较贵,利用单TL16C554实现四通道串口的扩展成功应用方案比较多,但是当需要扩展8个以上的串口时候,按照以往的设计方案难度大大增加,往往会选择较高成本的其它实现方案。本文介绍一种利用双TL16C554在嵌入式linux系统中实现8通道串口的设计方法。
2、简介
        1)、TL16C554芯片介绍
        TL16c554是TI公司生产的4通道异步通信集成芯片,它的每个通道都能独立的从外部设备或者MODEN接收数据,进行串行接口到并行接口的转换,同时它也能将处理器的并行数据转化为串行数据转发出去。外部处理器在读写操作时可以随时查询每个通道的完整性,监视各种命令的执行及任何发生的错误。主要有如下特点:
        集成4个增强型TL16C550异步通讯组件及可控逻辑功能;在FIFO模式下,每个异步通讯组件的发送器及接收器经16字节的FIFO缓冲,以减少系统处理器的中断次数;保持寄存器与移位寄存器的存在使得系统处理器与串行数据之间不需要精确的同步;针对高达1M波特率的工作,时钟频率可高达16MHz,可编程波特率发生器允许对所有输入基准时钟除以1到(216-1)之间的任何数据并且产生一个16倍的内部时钟;可以对串行数据流增加或者从删除标准异步通讯位(开始位、停止位和奇偶检验位);独立的发送、接收、线路状态和数据组中断控制;完全可编程的串行接口特性;三态输出为双向数据总线和控制总线提供TTL驱动特性;其它检测和故障分析能力。
        TL16C554一共具有12个内部寄存器。通过这些寄存器的设置来实现通讯参数的设置、线路和MODEM状态的访问,中断的管理和数据的发送,接收。说明如下表:
       
        2)、设备驱动介绍
        Linux的外设可以分为3类:字符设备、块设备和网络设备。串口设备是一种终端字符设备,即TTY设备。在系统中其体系架构如图2.1:
        TTY体系分为:TTY核心、TTY线路规划、TTY驱动三部分。TTY核心从用户空间获取要发送给TTY设备的数据,然后把数据传递给TTY线路规划,它对数据进行处理后,负责把数据传递到TTY驱动程序,TTY驱动程序负责格式化数据,并通过硬件发送出去;从硬件接收到的数据向上通过TTY驱动,进入TTY线路规程,再进入TTY核心,最后被用户获取。Tty驱动与tty核心之间也可以直接传输数据[4]。
        
        图 2.1 TTY设备体系结构和数据流
        设备驱动编写工作主要为完成板级(Low_level)的数据结构和功能函数,以对接上层的函数接口和硬件的直接操作。Linux 2.6引用一套新的驱动管理和注册机制:platform_device和platform_driver,设备资源用platform_device表示,驱动用platform_driver进行注册。platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform_device提供的标准接口进行申请并使用。通过platform机制开发底层驱动的大致流程如下。
        
        图 2.2 驱动开发流程
3、软硬件实现
        1)、硬件设计
       

        图 3.1 硬件设计原理图
        控制器数据总线MD0~MD7连接TL16C554的8位数据总线。六位地址总线(MA1~MA3)三位直接与芯片A0~A2连接,用来寻址芯片内部寄存器,MA4~MA6位经过译码器形成8为片选信号,可以用来片选8个独立的通道,WR、RD读写控制信号连接芯片的相应引脚,独立的复位信号C_RST1和C_RST2低电平的可以复位扩展芯片。四通道的中断信号经过三个或门和触发器合并为一个公共的中断,U1扩展芯片某一个通道的FIFO收到的数据达到了设定值将产生一个高电平中断,当四个独立的通道中断退出时公共中断信号变位低电平,设置外部控制器的高电平产生中断。
        2)、驱动设计
        选择外部控制器为AT91RM9200为例,按照如下设置platform_device[5]:
        1)、声明一个宏PORT,表示一个设备资源
#define PORT(_base,_irq)        \
        {                                                \
                .mapbase                = _base,        \  //通道操作物理地址
                .irq                = _irq,                        \  //中断号
                .uartclk        = 3686400,                \  //芯片外部时钟
                .iotype                = UPIO_MEM,        \ //定义资源的类型
                .regshift = 1, \      //控制器为8位数据模式,由于地址线连接偏移一位。
                .flags                = (UPF_BOOT_AUTOCONF | UPF_IOREMAP ),        \
        }
        2)、实现八个通道资源资源:
static struct plat_serial8250_port exar_data[] = {
        PORT(AT91_CHIPSELECT_5+0x0, AT91RM9200_ID_IRQ0),
        PORT(AT91_CHIPSELECT_5+0x10, AT91RM9200_ID_IRQ0),
        PORT(AT91_CHIPSELECT_5+0x20, AT91RM9200_ID_IRQ0),
        PORT(AT91_CHIPSELECT_5+0x30, AT91RM9200_ID_IRQ0),
        PORT(AT91_CHIPSELECT_5+0x40, AT91RM9200_ID_IRQ1),
        PORT(AT91_CHIPSELECT_5+0x50, AT91RM9200_ID_IRQ1),
        PORT(AT91_CHIPSELECT_5+0x60, AT91RM9200_ID_IRQ1),
        PORT(AT91_CHIPSELECT_5+0x70, AT91RM9200_ID_IRQ1),
        { },
};
static struct platform_device exar_device = {
        .name                        = "serial8250",//定义平台设备的名称
        .id                        = PLAT8250_DEV_EXAR_ST16C554, //用于标志该设备的ID。
        .dev                        = {
        .platform_data        = &exar_data, //定义平台设备的资源。
        },
};
        3)、另外模块函数exar_init()设置控制器SMC的bank5区接口属性:主要有读写时钟周期,数据位数。中断和复位引脚设置和1ms的低电平复位。再利用platform_device_register(&exar_device)注册。最后利用module_init(exar_init)编译到内核驱动模块中。

        选择8250标准串口驱动作为修改模板,模板适用于单TL16C554芯片中断独立的情况,双芯片共中断在数据收发需要做大量的修改才能实现高性能,按照如下设置platform_driver[5]:
1)、创建uart结构体,用于向tty层注册。
static struct uart_driver serial8250_reg = {
        .owner                        = THIS_MODULE,
        .driver_name                = "tl16c554-serial",
        .dev_name                = "ttyB",
        .major                        = 9,//主设备号 静态分配时注意不要与其它设备冲突
        .minor                        = 70,//次设备号
        .nr                        = UART_NR,//串口数8
        .cons                        = SERIAL8250_CONSOLE,
};
在serial8250_init()初始化函数中经过uart_register_driver(&serial8250_reg)进行注册,serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev)实现和设备资源关联,此关联为旧模式,主要实现了tty核心层和板级驱动层所有操作功能的关联,具体设备资源关联在注册platform_drive的probe中实现。
static struct uart_ops serial8250_pops = {
        .tx_empty        = serial8250_tx_empty,//发送为空响应函数
        .set_mctrl        = serial8250_set_mctrl,//设置寄存器值
        .get_mctrl        = serial8250_get_mctrl,//获取寄存器值
        .stop_tx        = serial8250_stop_tx,//停止发送数据
        .start_tx        = serial8250_start_tx,//开始发送数据
        .stop_rx        = serial8250_stop_rx,//停止接收
        .enable_ms        = serial8250_enable_ms,
        .break_ctl        = serial8250_break_ctl,
        .startup        = serial8250_startup,//打开操作函数
        .shutdown        = serial8250_shutdown,//关闭操作函数
        .set_termios        = serial8250_set_termios,//设置通讯参数
        .pm                = serial8250_pm,//电源管理
        .type                = serial8250_type,
        .release_port        = serial8250_release_port,
        .request_port        = serial8250_request_port,
        .config_port        = serial8250_config_port,
        .verify_port        = serial8250_verify_port,
};
        2)、注册platform_driver结构体
static struct platform_driver serial8250_isa_driver = {
        .probe                = serial8250_probe,//加载驱动时实现设备资源和设备驱动的关联
        .remove                = __devexit_p(serial8250_remove),//卸载驱动的操作
        .suspend        = serial8250_suspend,//暂停驱动时操作
        .resume                = serial8250_resume,//重启驱动时操作
        .driver                = {
                .name        = "serial8250",//和uart相同。
                .owner        = THIS_MODULE,
        }}
3)、设置芯片寄存器
        在打开操作函数serial8250_startup和serial8250_set_termios和serial8250_set_mctrl实现芯片参数配置。
4)、收发数据实现
        1)、发送
        发送采用轮询的方式,serial8250_start_tx发送的同时对发送状态进行监视。
        2)、接收
        由于多个中断共用一个中断信号源,控制器设置成上升沿中断不能保证所有的中断被捕获,设置高电平中断的话会出现频繁中断的问题。从和减少中断处理时间考虑出发,本设计通过对每一个扩展芯片增加一个消息和独立的接收线程来实现接收功能。在serial8250_init()初始化函数中实现消息sem、接收线程receive_process创建和中断函数serial8250_interrupt注册。接收过程流程图如下:

图 3.2 多通道接收流程图
        消息初始为空,中断初始为开启,当至少一通道接收数据字节数超过FIFO设置数值或者状态中断。接收中断处理函数屏蔽自身中断使能,抛出处理消息,一直阻塞的接收处理线程对四个通道进行轮询,分中断原因依次处理数据接收或者线路故障或者调制解调器状态中断,中断源引脚信号变低电平或者四通道完全轮询一遍,线程开启中断,阻塞在消息处。2号TL16C554处理过程相同。

        5)、编译配置
        在内核配置中增加如下支持

图 3.3 八通道串口内核config配置
4、结束语
        本设计与一般单芯片扩展的设计方法不同点是每个芯片共享一个中断和专门的接收处理线程,这样大大的减少了控制器的中断CPU消耗,以增加驱动复杂性为代价换取扩展串口通道数量和硬件成本。



5、参考
        [1] 孟丽华.基于STM32F4的RS485通讯管理机的研究[D].河北.河北工业大学.2012.
        [2] 李斌,王晓航,施冲.嵌入式通讯管理装置的设计和实现[J].水电自动化及大坝监测,2004,28 (3):6-8.
        [3] 阮小玲.水电站计算机数字监控系统应用浅析[J].科技致富向导2012,(9):410-411.
        [4] Alessandro?Rubini,Linux Device Driver[M]. O'Reilly Media, Inc, USA,2005.
        [5] 韦东山.嵌入式Linux应用开发[M].北京.人民邮电出版社,2008.
投稿 打印文章 转寄朋友 留言编辑 收藏文章
  期刊推荐
1/1
转寄给朋友
朋友的昵称:
朋友的邮件地址:
您的昵称:
您的邮件地址:
邮件主题:
推荐理由:

写信给编辑
标题:
内容:
您的昵称:
您的邮件地址: