在860里增加TL16C554多串口芯片驱动.docx

上传人:b****8 文档编号:13188463 上传时间:2023-06-11 格式:DOCX 页数:25 大小:61.97KB
下载 相关 举报
在860里增加TL16C554多串口芯片驱动.docx_第1页
第1页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第2页
第2页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第3页
第3页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第4页
第4页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第5页
第5页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第6页
第6页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第7页
第7页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第8页
第8页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第9页
第9页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第10页
第10页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第11页
第11页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第12页
第12页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第13页
第13页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第14页
第14页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第15页
第15页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第16页
第16页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第17页
第17页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第18页
第18页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第19页
第19页 / 共25页
在860里增加TL16C554多串口芯片驱动.docx_第20页
第20页 / 共25页
亲,该文档总共25页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

在860里增加TL16C554多串口芯片驱动.docx

《在860里增加TL16C554多串口芯片驱动.docx》由会员分享,可在线阅读,更多相关《在860里增加TL16C554多串口芯片驱动.docx(25页珍藏版)》请在冰点文库上搜索。

在860里增加TL16C554多串口芯片驱动.docx

在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]));

}

}

经过整合,应该是

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2