共4条
1/1 1 跳转至页
[转帖]串口驱动编写实例解读(一)
串口驱动(Serial Drivers)编写实例解读(连载:一) <--- 〖回复该帖子〗
串口驱动(Serial Drivers)编写实例解读(连载:一)
[代码步骤:Code Steps]
。初始化
。定义支持的串口通道数
。初始化驱动的设备描述
。写你的设备初始化代码
。写入口程序(entry point routines)
。写ISRs(中断服务程序)来管理设备
。使用模板 wind/target/src/drv/ssio/templateSio.c
注意:串口驱动在VxWorks系统开始的代码里初始化
[设备描述:The Device Descriptor]
。XX_DRV结构每个通道有一个XX_CHAN
。每个XX_CHAN指向SIO_DRV_FUNCS
。SIO_DRV_FUNCS引诱驱动的入口(entry point)
。XX_DRV是xxDrv使用的中心数据结构
。xx_CHAN包括:
。xxDrv需要的通道特定信息
。指向驱动SIO_DRV_FUNCS结构的指针
。例:
/* device and channel structures */
typedef struct
{
/* must be first */
SIO_CHAN sio; /* standard SIO_CHAN element */
/* callbacks */
STATUS (*getTxChar) ();
STATUS (*putRcvChar) ();
void * getTxArg;
void * putRcvArg;
/* register addresses */
volatile char * cr; /* channel control register */
volatile char * dr; /* channel data register */
volatile char * sr; /* channel status register */
volatile char * ms; /* channel modem status register */
volatile char * mc; /* channel modem control register */
volatile short * br; /* channel baud constant register */
/* misc */
int mode; /* current mode (interrupt or poll) */
int baudFreq; /* input clock frequency */
int options; /* Hardware options */
} TEMPLATE_CHAN;
typedef struct
{
TEMPLATE_CHAN portA; /* DUSRAT has two channels */
TEMPLATE_CHAN portB;
volatile char * masterCr; /* master control register */
} TEMPLATE_DUSART;
[SIO_CHAN结构]
。对一般字符驱动,一个指向DEV_FDR的指针被用来在驱动和I/O system 之间通讯
。对一个串口驱动,一个指向SIO_CHAN的指针用来在驱动和高层协议之间通讯
在 wind/target/h/sioLib.h;里,SIO_CHAN如下定义:
typedef struct sio_chan/* a serial channel */
{
SIO_DRV_FUNCS * pDrvFuncs;
/* device data */
} SIO_CHAN;
.由于高层协议不知道驱动的XX_CHAN结构,SIO_CHAN被用来允许一个精心定义的数据类型在协议间交换数据
.ttyDrv通过SIO_DRV_FUNCS里的入口向xxDrv发送信息,而xxDrv通过回调向ttyDrv发送信息
[入口:Entry Points]
xxCallBackInstall() 安装到高层协议的入口(I/O system,target agent(目标代理),等等)
xxPollOutPut() 轮巡模式输出
xxPollInput() 轮巡模式输入
xxIoctl() 支持设备特定的ioctl命令
xxTxStaartup() 初始化一个传输循环(transmit cycle)
[驱动回调安装程序]
int xxCallbackInstall(pSsioChan,callbackType,callback,callbbackArg)
pSioChan 指向SIO_CHAN的指针
callbackType SIO_CALLBACK_GET_TX_CHAR 或 SIO_CALLBACK_PUT_RCV_CHAR
callback 指向回调程序的指针
callbackArg 回调的参数
。初始化SIO_CHAN结构里的特定成员
。返回OK 或 ENOSYS(当callbackType不是上两种中的一种)
/********************************************************************************
templateCallbackInstall - install ISR callbacks to get/put chars
This driver allows interrupt callbacks for transmitting characters
and receiving characters. In general, drivers may support other
types of callbacks too.
*
* RETURNS: OK on success, or ENOSYS for an unsupported callback type.*/
LOCAL int templateCallbackInstall
(
SIO_CHAN * pSioChan, /* channel */
int callbackType, /* type of callback */
STATUS (*callback)(), /* callback */
void * callbackArg /* parameter to callback */
)
{
TEMPLATE_CHAN * pChan = (TEMPLATE_CHAN *)pSioChan;
switch (callbackType)
{
case SIO_CALLBACK_GET_TX_CHAR:
pChan->getTxChar = callback;
pChan->getTxArg = callbackArg;
return (OK);
case SIO_CALLBACK_PUT_RCV_CHAR:
pChan->putRcvChar = callback;
pChan->putRcvArg = callbackArg;
return (OK);
default:
return (ENOSYS);
}
}
[驱动初始化]
。参数是没一个指向XX_DRV的指针
。初始化XX_CHAN
。带你的程序的SIO_DRV_FUNCS
。傀儡回调
。所有设备特定
。重启芯片
/* local variables */
LOCAL SIO_DRV_FUNCS templateSioDrvFuncs =
{
templateIoctl,
templateTxStartup,
templateCallbackInstall,
templatePollInput,
templatePollOutput
};
void templateDevInit
(
TEMPLATE_DUSART * pDusart
)
{
/* initialize each channel"s driver function pointers */
pDusart->portA.sio.pDrvFuncs = &templateSioDrvFuncs;
pDusart->portB.sio.pDrvFuncs = &templateSioDrvFuncs;
/* install dummy driver callbacks */
pDusart->portA.getTxChar = dummyCallback;
pDusart->portA.putRcvChar = dummyCallback;
pDusart->portB.getTxChar = dummyCallback;
pDusart->portB.putRcvChar = dummyCallback;
/* reset the chip */
TEMPLATE_REG_WRITE(pDusart, masterCr,
TEMPLATE_RESET_CHIP);
/* setting polled mode is one way to make the device quiet */
templateIoctl ((SIO_CHAN *)&pDusart->portA, SIO_MODE_SET,
(void *)SIO_MODE_POLL);
templateIoctl ((SIO_CHAN *)&pDusart->portB, SIO_MODE_SET,
(void *)SIO_MODE_POLL);
}
/*******************************************************************************
*
* dummyCallback - dummy callback routine
*
* RETURNS: ERROR.
*/
LOCAL STATUS dummyCallback (void)
{
return (ERROR);
}
※ 作 者: 自由妹妹 01-5-22 下午 05:10:58 ※
关键词: 转帖 串口 驱动 编写 实例 解读
已拜读,请教! <--- 〖回复该帖子〗
我发现在usrSerial.c中定义了TY_NAME_BASE "/tyCo/"
如果我使用scc3做uart串口,设备名是否只能为"/tyCo/x"形式?
还是任意取名tty 设备名,然后该设备名通过一个SIO_CHAN,在xxCallbackInstall函数中传给上层协议,
上层在通过SIO_CHAN调用IOCTL来控制串口驱动.
请你指教,谢谢!
※ 作 者: little 01-5-23 下午 02:31:59 ※
reply little <--- 〖回复该帖子〗
Little:
设备名只要是唯一的就可以了...
另,你用scc3做uart一定使用st16c552或者st16c554吧?
我现有st16c552(可扩展两个串口)的完全驱动程序.正开发st16c554(带4个 ACE,可扩展4个串口)的驱动,
欢迎多多交流...
※ 作 者: 自由妹妹 01-5-23 下午 02:59:45 ※
Re:串口驱动(Serial Drivers)编写实例解读(连载:一) <--- 〖回复该帖子〗
自由妹妹:
拜读了您的程序,受益良多,我想问如果是用1655X系列作的扩展串口卡,可不可以将Vxworks的标准串中驱动直接扩展到自己卡上用呢?
※ 作 者: 化民 01-5-28 上午 07:39:13 ※
Re:Re:串口驱动(Serial Drivers)编写实例解读(连载:一) <--- 〖回复该帖子〗
化民:
VXworks标准的串口驱动是采用SMC(串口通讯控制器)的两个通道,1655x的机制与之不同,故虽然其驱动程序架构相同,但实现起来差异较大.
我现在在把SMC和16c554整合到一起,而且现在已经有阶段性成果,希望我们可以多交流...
另外,我很快会推出一篇关于这个的文章(顺便回击一下论坛上某些人对我的指责),请期待...
自由妹妹
※ 作 者: 自由妹妹 01-5-28 下午 10:23:03 ※
串口驱动(Serial Drivers)编写实例解读(连载:一) <--- 〖回复该帖子〗
大家好,看了大家的高作,有找到亲人的感觉,我现在正在vxworks下进行协议开发,但是对vxworks的机制很是不熟,在对串口驱动的开发中,我扩展了12个串口(用3片16c554),利用epld进行地址译码(地址0x1000开始),中断的合并(把16c554的12个中断合成一个x86的中断),完全按照汇编的方式对串口进行编程。我想做成标准的驱动程序的方式,请大家多多指导。
我的程序如下,有些语句是调试用的,没有一一去掉,请多包涵:
/*初始化函数,iosign为第几个串口,0--11)*/
void comini(int iosign)
{
/*清空原来状态*/
sysInByte(0x1000*iosign+0x1100+lsr);/*read LSR*/
sysInByte(0x1000*iosign+0x1100+msr);/*READ MSR*/
sysInByte(0x1000*iosign+0x1100+iir);/*READ IIR*/
sysInByte(0x1000*iosign+0x1100+rbr);/*READ RBR*/
sysOutByte(0x1000*iosign+0x1100+lcr,0); /* DLAB=0 */
sysOutByte(0x1000*iosign+0x1100+ier,0); /* CLOSE INT */
sysInByte(0x1000*iosign+0x1100+lsr);/*read LSR*/
sysInByte(0x1000*iosign+0x1100+msr);/*READ MSR*/
sysInByte(0x1000*iosign+0x1100+iir);/*READ IIR*/
sysInByte(0x1000*iosign+0x1100+rbr);/*READ RBR*/
sysOutByte(0x1000*iosign+0x1100+lcr,0x80);/*set DLAB=1*/
sysOutByte(0x1000*iosign+0x1100+dlm,0);/*DLM=0*/
sysOutByte(0x1000*iosign+0x1100+dll,0x30);/*DLL=0x0c,set 9600*/
sysOutByte(0x1000*iosign+0x1100+lcr,0x03);/*set n,8,1*/
sysOutByte(0x1000*iosign+0x1100+mcr,0x0b);/*mcr=0x0b,P527*/
sysInByte(0x1000*iosign+0x1100+lsr);/*read LSR*/
sysInByte(0x1000*iosign+0x1100+msr);/*READ MSR*/
sysInByte(0x1000*iosign+0x1100+iir);/*READ IIR*/
sysInByte(0x1000*iosign+0x1100+rbr);/*READ RBR*/
#ifndef ENABLE_FOLLOW
sysOutByte(0x1000*iosign+0x1100+ier,0x03);
#else
sysOutByte(0x1000*iosign+0x1100+ier,0x0b);
#endif
}
再在初始化中循环调用12次,12个串口的初始化就能完成。
用 vectot7 = INUM_TO_IVEC((INT_NUM_IRQ0)+7);
intConnect(vectot7,FunIRQ7,0);
把中断7定向到函数FunIRQ7(),这个函数处理8个串口,另外4个类似
void FunIRQ7() /*com0--7*/
{
unsigned char temp;
#ifdef ENABLE_FOLLOW
unsigned char mymsr;
#endif
int mycnt;
int ionumber;
int i;
unsigned char _flag[8];
for(i=0;i<=7;i++)
_flag[i]=sysInByte(0x1000*i+0x1100+iir);
do
{
for(ionumber=0;ionumber<=7;ionumber++)
{
if((_flag[ionumber]&0x01)==0)
{
do
{
switch(_flag[ionumber]&0x0f)
{
#ifdef ENABLE_FOLLOW
case 0:
/*处理流控*/
break;
#endif
case 4:
case 12:
/*接收数据*/
break;
case 2:
/*发送数据*/
break;
default:
break;
}
}while(((_flag[ionumber]=sysInByte(0x1000*ionumber+0x1100+iir))&0x01)==0);
}
}
for(i=0;i<=7;i++)
_flag[i]=sysInByte(0x1000*i+0x1100+iir);
}while(((_flag[0]&0x01)==0)||((_flag[1]&0x01)==0)||((_flag[2]&0x01)==0)\||((_flag[3]&0x01)==0)||((_flag[4]&0x01)==0)||((_flag[5]&0x01)==0)\||((_flag[6]&0x01)==0)||((_flag[7]&0x01)==0));
}
希望大家多联系,freedom_zj@163.com
※ 作 者: freedomzj 01-6-27 上午 11:18:38 ※
共4条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |