vxWorks下基于TTY中间件的串口驱动开发

好久没更新博客了,最近调了个基于TTY中间件的串口驱动,在此分享一下经验,也做笔记。

首先,定义结构体

typedef struct m8313_Uart_Chan
{
    SIO_CHAN  sio;
    STATUS  (*getChar)();
    STATUS  (*putChar)();
    void *  getCharArg;
    void *  putCharArg;
    unsigned int intLevel;
    unsigned int baund;
    unsigned int errorCount;
    int intrMode;
}M8313_UART_ChAN;

第二步,实现驱动函数的挂接

static SIO_DRV_FUNCS TL16C550C_DrvFuncs = {

	TL16C550C_Ioctrl,
	TL16C550C_StartUp,
	TL16C550C_CallbackInstall,
	TL16C550C_PollInput,
	TL16C550C_PollOutput
};

第三步,实现TTY中间层到驱动层接口函数的挂接

static int TL16C550C_CallbackInstall(SIO_CHAN *	pSioChan,
		                             int callbackType,
		                             STATUS	(*callback)(void *, ...),
		                             void *	callbackArg)
{
	M8313_UART_ChAN *pChan = (M8313_UART_ChAN*)pSioChan;
	switch(callbackType)
	{
	case SIO_CALLBACK_GET_TX_CHAR:
		pChan->getChar = callback;
		pChan->getCharArg = callbackArg;
		return OK;
	case SIO_CALLBACK_PUT_RCV_CHAR:
		pChan->putChar = callback;
		pChan->putCharArg = callbackArg;
		return OK;
	case SIO_CALLBACK_ERROR:
	default:
		return ENOSYS;
	}
}

此函数主要是实现接收数据后,如何把数据交给TTY中间件接口putChar,还有如何从tty中间件接口拿到需要发送的数据接口getChar

第四步,实现发送函数TL16C550C_StartUp,这个函数是驱动层的数据发送函数

static void TL16C550C_SendByte(char byte)
{
	int LocalBusAddr = 0;
	char value = 0;
	int errorCount = 0;
	
	do
	{
		LocalBusAddr = Get_LocalBus_Addr(LSR_REGISTER);
		value = *(unsigned short *)LocalBusAddr;
		errorCount++;
		if(errorCount > 100)
		{
			TL16C550C_Config();
			return;
		}
	}while(!(value&LSR_THRE_MASK));
	
	LocalBusAddr = Get_LocalBus_Addr(LCR_REGISTER);
	value = *(unsigned short *)LocalBusAddr;
	value &= ~LCR_DLAB_MASK;
	*(unsigned short *)LocalBusAddr = value;
	LocalBusAddr = Get_LocalBus_Addr(THR_REGISTER);

	*(unsigned short *)LocalBusAddr = byte;

}

第五步,实现配置函数TL16C550C_Ioctrl,此函数主要是设置串口波特率,模式,请缓冲区,校验位,数据位,停止位,根据不同的芯片进行配置

static int TL16C550C_Ioctrl(SIO_CHAN *pSioChan,int cmd,void *arg)
{
	M8313_UART_ChAN* pChan = (M8313_UART_ChAN*)pSioChan;
	int setArg = (int)arg;

	switch (cmd)
	{
	case SIO_BAUD_SET:
		if(setArg != 0)
		{
			if(setArg < TL16C550C_MIN_BAUD || setArg > TL16C550C_MAX_BAUD)
			{
				return ERROR;
			}
			switch(setArg)
			{
			case 600:
			case 1200:
			case 2400:
			case 4800:
			case 9600:
			case 19200:
			case 38400:
			case 56000:
				pChan->baund = setArg;
				TL16C550C_SetBaund(setArg);
				break;
			default:
				break;
			}
		}
		break;
	case SIO_BAUD_GET:
		*(int *)arg = pChan->baund;
		break;
	case SIO_MODE_SET:
		if(setArg == SIO_MODE_INT) //中断模式
		{
			TL16c550cSio.intrMode = TRUE;
			TL16C550C_ModeSet(SIO_MODE_INT);
		}
		else if(setArg == SIO_MODE_POLL)//查询模式
		{
			TL16c550cSio.intrMode = FALSE;
			TL16C550C_ModeSet(SIO_MODE_POLL);	
		}
		break;
	case SIO_MODE_GET:
		if(TL16c550cSio.intrMode)
		{
			*(int *)arg = SIO_MODE_INT;
		}
		else
		{
			*(int *)arg = SIO_MODE_POLL;
		}
		break;
	case SIO_AVAIL_MODES_GET:
		*(int *)arg = SIO_MODE_INT | SIO_MODE_POLL; 
		break;
	case SIO_HW_OPTS_SET:
		TL16C550C_LCR(setArg);
		break;
	default:
		break;
	}
	return OK;
}

因为查询模式的效率较低,所以很少使用查询模式,在此不再叙述

第六步,挂接驱动程序

static void TL16C550C_Init()
{
	TL16c550cSio.sio.pDrvFuncs = &TL16C550C_DrvFuncs;
	TL16c550cSio.errorCount = 0;
	TL16c550cSio.getChar = dummyCallBack;
	TL16c550cSio.putChar = dummyCallBack;
	TL16c550cSio.intLevel = INUM_IRQ2;
	//配置串口芯片
	TL16C550C_Config();
	TL16c550cSio.intrMode = FALSE;
}

第七步,创建tty设备使能接收中断

void TL16C550C_Open(void)
{
	char devName[16] = {0};

	TL16C550C_Init();
	sprintf(devName, "%s", SERIAL_NAME);
	/*将设备驱动注册到tty驱动*/

	ttyDevCreate(devName, &TL16c550cSio.sio,RECV_BUF_SIZE, SEND_BUF_SIZE);
	//使能串口中断
	intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC(TL16c550cSio.intLevel), (VOIDFUNCPTR)TL16C550C_IntIsr, (int)0);
	intEnable(TL16c550cSio.intLevel);

}

第八步,实现中断接收数据到tty中间层

static void TL16C550C_IntIsr(void)
{
	int LocalBusAddr = 0;
	char status= 0;
	char Value = 0;
	
	LocalBusAddr = Get_LocalBus_Addr(LSR_REGISTER);
	status = *(unsigned short *)LocalBusAddr;
	if(status & (LSR_OE_MASK | LSR_PE_MASK |LSR_FE_MASK))//错误
	{
		//复位串口
		TL16c550cSio.errorCount++;
		
		TL16C550C_Config();
	}
	else if(status & LSR_DR_MASK)
	{
		LocalBusAddr = Get_LocalBus_Addr(LCR_REGISTER);
		Value = *(unsigned short *)LocalBusAddr;
		Value &= ~LCR_DLAB_MASK;
		*(unsigned short *)LocalBusAddr = Value;
		LocalBusAddr = Get_LocalBus_Addr(RBR_REGISTER);
		Value = *(unsigned short *)LocalBusAddr;
		TL16c550cSio.putChar(TL16c550cSio.putCharArg,Value);
	}
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值