硬件
芯片简介
WK2204(DataSheet)是spi扩展uart的芯片,实现spi扩展4路uart,该芯片扩展的uart通道的具备以下功能特点:
- 每个通道的波特率、字长、校验格式可以独立设置,最高可以提供2Mbps 的通信速率
- 每个通道具有收/发独立的256 级FIFO,FIFO 中断可按用户需求进行编程触发方式且具备超时中断功能
- 每个通道可以独立设置IrDA红外通信、RS485自动收发控制、9位网络地址自动识别、软/硬件自动流量控制等高级工作模式
电路设计
典型电路设计如图所示:
- 中断引脚需要外接上拉电阻,典型取值5.1K。驱动收发数据依赖于该中断信号,如果中断信号异常,子串口无法进行正常通信
- 晶振电路,需要和晶振并联1M的电阻
- SPI与CPU(Xavier)的SPI引脚连接,子串口输出TTL电平,与RS信号收发器连接
- RTS引脚(只有子串口2/4具备)在RS485自动收发控制工作模式下,用于控制RS-485收发器的收发转换。
驱动
添加设备树
- WK2204作为SPI从设备,SPI总线最高速率不 能超过10M
- INT和RTS与CPU连接,设备树中需要添加这两个GPIO资源
- 设备树中需添加晶振的频率
添加设备树如下:
spi@3230000{ // cpu是nvidia-jetson
status = "okay";
spi_test@00 {
compatible = "wkmic, wk2124spi";
reg = <0>;
spi-max-frequency = <10000000>;
irq_gpio = <&tegra_main_gpio TEGRA194_MAIN_GPIO(T, 0) IRQ_TYPE_LEVEL_LOW>;
reset_gpio = <&tegra_main_gpio TEGRA194_MAIN_GPIO(M, 3) GPIO_ACTIVE_HIGH>;
};
};
添加驱动
- WK2204官方驱动是基于Rockchip平台和kernel-3.1基础开发的,删除rockchip的相关代码:
-#include <linux/platform_data/spi-rockchip.h>
... ...
//#ifdef CONFIG_OF
-static int rockchip_spi_parse_dt(struct device *dev)
+static int spi_parse_dt(struct device *dev)
... ...
static int wk2xxx_probe(struct spi_device *spi)
{
... ...
+ irq = spi_parse_dt(&spi->dev);
+ if(irq < 0)
+ return 1;
do
{
wk2xxx_read_global_reg(spi,WK2XXX_GENA,dat);
printk(KERN_ERR "wk2xxx_probe() GENA = 0x%X\n",dat[0]); //GENA=0X30
wk2xxx_write_global_reg(spi,WK2XXX_GENA,0xf5);
wk2xxx_read_global_reg(spi,WK2XXX_GENA,dat);
printk(KERN_ERR "wk2xxx_probe() GENA = 0x%X\n",dat[0]); //GENA=0X35
wk2xxx_write_global_reg(spi,WK2XXX_GENA,0xf0);
wk2xxx_read_global_reg(spi,WK2XXX_GENA,dat);
printk(KERN_ERR "wk2xxx_probe() GENA = 0x%X\n",dat[0]); //GENA=0X30
}while(0);
/test spi //
- irq = rockchip_spi_parse_dt(&spi->dev);
- if(irq < 0)
- return 1;
... ...
}
... ...
-static int wk2xxx_resume(struct spi_device *spi)
-{
- #ifdef _DEBUG_WK_FUNCTION
- printk(KERN_ALERT "%s!!--in--\n", __func__);
- #endif
- return 0;
-}
... ...
static struct spi_driver wk2xxx_driver = {
.driver = {
.name = "wk2xxxspi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(rockchip_spi_wk2xxx_dt_match),
},
.probe = wk2xxx_probe,
.remove = wk2xxx_remove,
- .resume = wk2xxx_resume,
}
- WK2204子串口4的RST引脚电平可以自动控制485芯片的收发。官方驱动默认该RST引脚拉高,改为默认拉低:
+#define WK_RS485_FUNCTION
……
static int wk2xxx_startup(struct uart_port *port)//i
{
... ...
#ifdef WK_RS485_FUNCTION
+ // 通道4设置为485功能
+ if (s->port.iobase == 4) {
- wk2xxx_write_slave_reg(s->spi_wk,s->port.iobase,WK2XXX_RS485,0X02); //default high
+ wk2xxx_write_slave_reg(s->spi_wk,s->port.iobase,WK2XXX_RS485,0X03); //default low
wk2xxx_write_slave_reg(s->spi_wk,s->port.iobase,WK2XXX_SPAGE,1);
wk2xxx_write_slave_reg(s->spi_wk,s->port.iobase,WK2XXX_RRSDLY,0X10);
wk2xxx_write_slave_reg(s->spi_wk,s->port.iobase,WK2XXX_SPAGE,0);
}
#endif
... ...
}
- WK2204子串口的波特率由芯片外部晶振分频而来,官方驱动适配11.0592Mhz,以16Mhz晶振为例,改为:
static void wk2xxx_termios( struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
... ...
switch (baud)
{
case 600:
- baud1=0x4;
- baud0=0x7f;
- pres=0;
+ baud1=0x6;
+ baud0=0x81;
+ pres=0xb;
break;
case 1200:
- baud1=0x2;
- baud0=0x3F;
- pres=0;
+ baud1=0x3;
+ baud0=0x40;
+ pres=0x5;
break;
case 2400:
baud1=0x1;
- baud0=0x1f;
- pres=0;
+ baud0=0x9f;
+ pres=0xb;
break;
case 4800:
baud1=0x00;
- baud0=0x8f;
- pres=0;
+ baud0=0xcf;
+ pres=0x5;
break;
case 9600:
baud1=0x00;
- baud0=0x47;
- pres=0;
+ baud0=0x67;
+ pres=0x3;
break;
case 19200:
baud1=0x00;
- baud0=0x23;
- pres=0;
+ baud0=0x33;
+ pres=0x1;
break;
case 38400:
baud1=0x00;
- baud0=0x11;
- pres=0;
+ baud0=0x19;
+ pres=0x1;
break;
case 76800:
baud1=0x00;
- baud0=0x08;
- pres=0;
+ baud0=0x0c;
+ pres=0;
break;
case 1800:
- baud1=0x01;
- baud0=0x7f;
- pres=0;
+ baud1=0x2;
+ baud0=0x2a;
+ pres=0x9;
break;
case 3600:
- baud1=0x00;
- baud0=0xbf;
- pres=0;
+ baud1=0x1;
+ baud0=0x14;
+ pres=0xc;
break;
case 7200:
baud1=0x00;
- baud0=0x5f;
- pres=0;
+ baud0=0x89;
+ pres=0xe;
break;
case 14400:
baud1=0x00;
- baud0=0x2f;
- pres=0;
+ baud0=0x44;
+ pres=0x7;
break;
case 28800:
baud1=0x00;
- baud0=0x17;
- pres=0;
+ baud0=0x21;
+ pres=0xc;
break;
case 57600:
baud1=0x00;
- baud0=0x0b;
- pres=0;
+ baud0=0x10;
+ pres=0x6;
break;
case 115200:
baud1=0x00;
- baud0=0x05;
- pres=0;
+ baud0=0x07;
+ pres=0xb;
break;
case 230400:
baud1=0x00;
- baud0=0x02;
- pres=0;
+ baud0=0x03;
+ pres=0x6;
break;
default:
baud1=0x00;
baud0=0x00;
pres=0;
break;
}
... ...
}
调试
查看启动加载
驱动加载成功,会在/dev下生成4个串口设备:ttysWK0、ttysWK1、ttysWK2、ttysWK3。输入“dmesg | grep wk”或“ls /dev/ttysWK*”,查看驱动是否加载成功,如图所示:
如果驱动加载失败,侦测RST信号是否在驱动加载前拉高。
检查串口通信
Windows系统安装串口调试助手;Ubuntu系统建议使用串口通信工具minicom(参考使用方法)。
数据乱码或丢失
- 检查晶振
- 检查线束
- 侦测INT信号
- 更换调试工具
RS485只能收不能发
- 驱动是否使能485自定收发控制功能
- 示波器侦测RTS信号
系统中断响应异常
如果系统在无数据通信的情况下一直响应中断,如图所示:
检查中断来源,使能中断DEBUG信息(_DEBUG_WK_IRQ),如果寄存器显示芯片未发出中断:
- 检查驱动设置的中断模式,是否低电平触发。
- 示波器侦测数据通信前后的INT引脚电平,如果一直拉低,检查连接的上拉电阻阻值。
思考
4路uart数据接收均通过gpio中断响应,CPU使用率较高。