在860里增加TL16C554多串口芯片驱动.docx
- 文档编号:25702430
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:25
- 大小:61.97KB
在860里增加TL16C554多串口芯片驱动.docx
《在860里增加TL16C554多串口芯片驱动.docx》由会员分享,可在线阅读,更多相关《在860里增加TL16C554多串口芯片驱动.docx(25页珍藏版)》请在冰豆网上搜索。
在860里增加TL16C554多串口芯片驱动
在860里增加TL16C554多串口芯片驱动
(一)
一.设备概述
MPC860t有4个SCC(serialcommunicationscontroller串口通讯控制器)和2个SMC(serialmanagementcontroller串口管理控制器),一共可以扩展6个串口。
但笔者开发的通讯控制器项目中,由于考虑到需要扩展8个或更多串口,SCC和SMC扩展显然不能满足要求,需要需求一种新的可扩展的串口芯片。
我们采用两个TL16C554芯片来解决这个问题。
一个TL16C554芯片集成了四个ST16550ACE(异步通讯元件ASYNCHRONOUSCOMMUNICATIONSELEMENT)。
二.串口驱动简介
注意:
此处xxDrv,yyDrv表示一个特定的驱动程序,下同
.ttyDrv虚拟驱动,用以
.管理I/OSystem
.调用实际的驱动程序来管理硬件
.Model
.xxDrv支持:
标准I/OSystem接口
TargetAgent接口
两种模式(中断interrupt,轮巡poll)
.回调CallBacks
允许高层协议来设定驱动怎样收发数据
有两个回调(驱动调用)
getCallback
putCallBack
put回调:
传送一个从设备读到的字符到高层协议
get回调:
从高层协议取得一个字符以便写到设备
代码实现
usrConfig.c一般性代码
sysSerial.c特定执行代码
xxDrv.c设备特定代码
三.详细解说(调用和实现部分)
usrConfig.c,sysSerial.c
注意:
由于我们采用了多种设备实际的驱动(SMC和16C554),所以在sysSerial.c里需要整合,整合的函数包括sysSerialHwInit(),
sysSerialHwInit2(),sysSerialChanGet(),sysSerialReset()
解读usrConfig.c
先看usrConfig.c里与串口有关的部分(前面部分是早期版本的,不予理会),这里调用了ttyDrv(),然后用ttyDevCreate(),sysSerialChanGet()在sysSerials.c里定义,它把设备的编号同一个SIO_CHAN类型的结构关联起来,而这个结构在是至关重要的.(注意,如果系统采用串口调试,则该串口号被保留起来)
ttyDev()作的工作:
调用iosDrvInstall安装ttyDrv到设备表(使用ttyDrv和tyLib的入口)
ttyDevCreate()作的工作:
申请并初始化设备描述
调用tyDevinit()初始化tyLib
初始化selectLib
建立输入输出环行缓冲
创建信号量
调用iosDevAdd()增加设备到设备列表
安装tyLib的程序和输入输出回调
使设备开始中断模式
#ifdefINCLUDE_TYCODRV_5_2
#ifdefINCLUDE_TTY_DEV
if(NUM_TTY>0)
{
tyCoDrv();/*installconsoledriver*/
for(ix=0;ix { sprintf(tyName,"%s%d","/tyCo/",ix); (void)tyCoDevCreate(tyName,ix,512,512); if(ix==CONSOLE_TTY) strcpy(consoleName,tyName);/*storeconsolename*/ } consoleFd=open(consoleName,O_RDWR,0); /*setbaudrate*/ (void)ioctl(consoleFd,FIOBAUDRATE,CONSOLE_BAUD_RATE); (void)ioctl(consoleFd,FIOSETOPTIONS,OPT_TERMINAL); } #endif/*INCLUDE_TTY_DEV*/ #else/*! INCLUDE_TYCODRV_5_2*/ #ifdefINCLUDE_TTY_DEV if(NUM_TTY>0) { ttyDrv();/*installconsoledriver*/ for(ix=0;ix { #if(defined(INCLUDE_WDB)&&(WDB_COMM_TYPE==WDB_COMM_SERIAL)) if(ix==WDB_TTY_CHANNEL)/*don'tuseWDBschannel*/ continue; #endif sprintf(tyName,"%s%d","/tyCo/",ix); (void)ttyDevCreate(tyName,sysSerialChanGet(ix),512,512); if(ix==CONSOLE_TTY)/*initthettyconsole*/ { strcpy(consoleName,tyName); consoleFd=open(consoleName,O_RDWR,0); (void)ioctl(consoleFd,FIOBAUDRATE,CONSOLE_BAUD_RATE); (void)ioctl(consoleFd,FIOSETOPTIONS,OPT_TERMINAL); } } } #endif/*INCLUDE_TTY_DEV*/ #endif/*! INCLUDE_TYCODRV_5_2*/ sysSerialChanGet(): 以下是单独采用860smc时的情况 SIO_CHAN*sysSerialChanGet ( intchannel/*serialchannel*/ ) { if(channel>=chanNum) return((SIO_CHAN*)ERROR); return((SIO_CHAN*)&ppc860Chan[channel]); } 单独采用16c554时为: SIO_CHAN*sysSerialChanGet ( intchannel/*serialchannel*/ ) { if(channel<0|| channel>=(int)(NELEMENTS(sysSioChans))) return(SIO_CHAN*)ERROR; returnsysSioChans[channel]; } 我们必须把两种情况整合. SIO_CHAN*sysSerialChanGet ( intchannel ) { if(channel<0|| channel>=(int)(NELEMENTS(sysSioChans))) return(SIO_CHAN*)ERROR; ifchannel<=1 return(SIO_CHAN*)ppc860Chan[channel] else returnsysSioChans[channel-2]; } sysSerialReset() 关于sysSerialResset,由于16c554和860的smc采用不同的原理,所以其重启也有不同,所以在sysSerialReset()里要考虑两中情况 voidsysSerialReset(void) { /*disableserialinterrupts*/ intDisable(devParas[0].intLevel); } voidsysSerialReset(void) { sysSerialHwInit(); } voidsysSerialReset(void) { sysSerialHwInit(); intDisable(devParas[0].intLevel); } 重中之重: 关于sysSerialHwInit2() sysSerialHwInit2()由usrConfig.c里的usrRoot调用,用于连接中断 smc的如下: voidsysSerialHwInit2(void) { inti;/*anindex*/ /*connectserialinterrupts*/ for(i=0;i { switch(i) { case0: (void)intConnect(IV_SMC1,(VOIDFUNCPTR)ppc860Int, (int)&ppc860Chan[i]); break; case1: (void)intConnect(IV_SMC2_PIP,(VOIDFUNCPTR)ppc860Int, (int)&ppc860Chan[i]); break; default: return; } *CIMR(vxImmrGet())|=(CIMR_SMC1>>i); } } CIMR是一个叫CPIntmaskreg的宏,这里分别开启SMC1和SMC2的中断 #defineCIMR_SMC10x00000010/*SMC1*/ #defineCIMR_SMC2_PIP0x00000008/*SMC2*/ #defineCIMR(base)(CAST(VUINT32*)((base)+0x0948)) 为什么在不在sysSerialHwinit()里调用连接呢? 因为在sysHwInit()执行的时刻内核内存分配算符还没有初始化! 16c554的: voidsysSerialHwInit2(void) { (void)intConnect(INUM_TO_IVEC(devParas[0].vector), st16554MuxInt,(int)&st16554Mux); intEnable(devParas[0].intLevel); } 各位必须注意,16c554中断服务程序是一个多重的,意思是: 所有使用同一中断的8个通道有一样的中断服务程序,这样在st16554MuxInt()处理的时候需要做出相应的判断(具体实现见后面) 经过整合后的sysSerialHwInit2应该是: voidsysSerialHwInit2(void) { inti;/*anindex*/ /*connectserialinterrupts*/ for(i=0;i { switch(i) { case0: (void)intConnect(IV_SMC1,(VOIDFUNCPTR)ppc860Int, (int)&ppc860Chan[i]); break; case1: (void)intConnect(IV_SMC2_PIP,(VOIDFUNCPTR)ppc860Int, (int)&ppc860Chan[i]); break; default: return; } *CIMR(vxImmrGet())|=(CIMR_SMC1>>i); } } voidsysSerialHwInit2(void) { inti;/*anindex*/ /*connectserialinterrupts*/ for(i=0;i<2;i++) { switch(i) { case0: (void)intConnect(IV_SMC1,(VOIDFUNCPTR)ppc860Int, (int)&ppc860Chan[i]); break; case1: (void)intConnect(IV_SMC2_PIP,(VOIDFUNCPTR)ppc860Int, (int)&ppc860Chan[i]); break; default: return; } *CIMR(vxImmrGet())|=(CIMR_SMC1>>i); } (void)intConnect(INUM_TO_IVEC(devParas[0].vector), st16554MuxInt,(int)&st16554Mux); intEnable(devParas[0].intLevel); } 重中之重: 关于sysSerialHwInit() 首先看16554的: voidsysSerialHwInit(void) { inti; for(i=0;i { st16554Chan[i].regDelta=devParas[i].regSpace; st16554Chan[i].regs=devParas[i].baseAdrs; st16554Chan[i].baudRate=CONSOLE_BAUD_RATE; st16554Chan[i].xtal=UART_XTAL_FREQ; st16554Chan[i].level=devParas[i].intLevel; /* *Initialisedriverfunctions,getTxChar,putRcvCharand *channelModeandinitUART. */ st16554DevInit(&st16554Chan[i]); } } devParas结构用存放设备的一些参数 typedefstruct { UINTvector; UINT8*baseAdrs; UINTregSpace; UINTintLevel; }CMA_ST16554_CHAN_PARAS; LOCALCMA_ST16554_CHAN_PARASdevParas[]= { {INT_VEC_COM,(UINT8*)SERIAL_A_BASE_ADR,UART_REG_ADDR_INTERVAL, INT_LVL_COM}, {INT_VEC_COM,(UINT8*)SERIAL_B_BASE_ADR,UART_REG_ADDR_INTERVAL, INT_LVL_COM}, {INT_VEC_COM,(UINT8*)SERIAL_C_BASE_ADR,UART_REG_ADDR_INTERVAL, INT_LVL_COM}, {INT_VEC_COM,(UINT8*)SERIAL_D_BASE_ADR,UART_REG_ADDR_INTERVAL, INT_LVL_COM}, {INT_VEC_COM,(UINT8*)SERIAL_E_BASE_ADR,UART_REG_ADDR_INTERVAL, INT_LVL_COM}, {INT_VEC_COM,(UINT8*)SERIAL_F_BASE_ADR,UART_REG_ADDR_INTERVAL, INT_LVL_COM}, {INT_VEC_COM,(UINT8*)SERIAL_G_BASE_ADR,UART_REG_ADDR_INTERVAL, INT_LVL_COM}, {INT_VEC_COM,(UINT8*)SERIAL_H_BASE_ADR,UART_REG_ADDR_INTERVAL, INT_LVL_COM} }; 从SERIAL_A_BASE_ADR到SERIAL_H_BASE_ADR表示两个16c554的8个通道的基地址。 INT_VEC_COM和INT_LVL_COM是通道所用中断的矢量和中断号,各位可以看到8个通道(4X2)所用的通道一样.当然可以在设计电路的时候选择不同的通道,但这对有限的中断是浪费. UART_REG_ADDR_INTERVAL是寄存器的步长,或者叫间隔,等于8. SysSerialHwInit先对st16554Chan结构做一些初始化(st16554Chan(i)对应相应的通道),设置寄存器步长regDelta,基地址regs,波特率baudRate,时钟晶振频率xtal,中断号intLevel 然后调用xxDrv里的st16554DevInit,关于xxDevInit在xxDrv.c详解里详细介绍. 使用smc的SysSerialHwInit要复杂许多 voidsysSerialHwInit(void) { inti;/*anindex*/ /*enableserialI/Oontheboard*/ *BCSR1&=~(BCSR1_RS232_EN_L); /*Ifrunningan823oran850,useonlySMC1*/ if(((*BCSR3&BCSR3_DBID_MASK)==BCSR3_823DB_MASK)|| ((*BCSR3&BCSR3_DBID_MASK)==BCSR3_850DB_MASK)) { chanNum=1; } if(chanNum==2) *BCSR1&=~(BCSR1_RS232_2_EN_L); /*intializethechipsdevicedescriptors*/ for(i=0;i { UINT32regBase; /*BRGCLKfreq(Hz)*/ ppc860Chan[i].clockRate=BRGCLK_FREQ; /*IMMRreghasbaseadr*/ ppc860Chan[i].regBase=vxImmrGet(); regBase=ppc860Chan[i].regBase; /*useBRG1forchannel1andBRG2forchannel2*/ ppc860Chan[i].bgrNum=(i+1); /*SMCwiredforrs232*/ ppc860Chan[i].uart.smcNum=(i+1); /*initthenumberofTBDs*/ ppc860Chan[i].uart.txBdNum=ppc860SmcParms[i].smcTbdNum; 0 /*initthenumberofRBDs*/ ppc860Chan[i].uart.rxBdNum=ppc860SmcParms[i].smcRbdNum; /*transmitBDbaseadrs*/ ppc860Chan[i].uart.txBdBase=(SMC_BUF*) (MPC860_REGB_OFFSET+ ppc860SmcParms[i].smcTbdOff); /*receiveBDbaseadrs*/ ppc860Chan[i].uart.rxBdBase=(SMC_BUF*) (MPC860_REGB_OFFSET+ ppc860SmcParms[i].smcRbdOff); /*txbufbase*/ ppc860Chan[i].uart.txBufBase=(u_char*) (MPC860_DPRAM_BASE(regBase) +ppc860SmcParms[i].smcTxBufOff); /*rxbufbase*/ ppc860Chan[i].uart.rxBufBase=(u_char*) (MPC860_DPRAM_BASE(regBase) +ppc860SmcParms[i].smcRxBufOff); /*transmitbuffersize*/ ppc860Chan[i].uart.txBufSize=ppc860SmcParms[i].smcTxBufSz; /*DPRAMaddrofSMC1params*/ ppc860Chan[i].uart.pSmc=(SMC*)((UINT32)PPC860_DPR_SMC1 (MPC860_DPRAM_BASE(regBase)) +(i*0x100)); /*SMCMR1forSMC1*/ ppc860Chan[i].uart.pSmcReg=(SMC_REG*) ((UINT32)MPC860_SMCMR1(regBase) +(i*0x10)); /*Maskinterrupts*/ ppc860Chan[i].uart.pSmcReg->smcm=0; ppc860Chan[i].pBaud=(UINT32*)((UINT32)MPC860_BRGC1(regBase) +(i*4)); ppc860Chan[i].channelMode=0; /*selectRS232pins*/ *MPC860_PBPAR(regBase)|=0xC0<<(i*4); /*setittonormaloperations*/ *MPC860_SDCR(regBase)=SDCR_RAID_BR5; /*resetthechip*/ ppc860DevInit(&(ppc860Chan[i])); } } 经过整合,应该是
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 860 增加 TL16C554 串口 芯片 驱动