在XPS中提供的UART IP只有Lite(精简版)可用,兼容16550模式的UART IP是要付费的。Lite模式的UART比较简单,但是使用时也带来诸多问题,比如中断只有一种模式,即收发都会触发中断并且无法区分,这个确实比较让人恼火。还好在大多数应用场合影响不大。
UART的收发控制有两种方式,一种是查询方式(polled),另一种是中断方式(Interrupt)。查询方式比较简单,不断查询状态寄存器即可。比较常用的是中断方式,ok,来看一段代码吧:
#include "xparameters.h"
#include "xgpio.h"
#include "xutil.h"
#include "xintc.h"
#include "xuartlite.h"
#include "xuartlite_l.h"
//首先定义中断函数
void uart_rev_handler(void)
{
while(!XUartLite_mIsReceiveEmpty(XPAR_RS232_UART_BASEADDR))
{
buff =XUartLite_RecvByte(XPAR_RS232_UART_BASEADDR);
XUartLite_SendByte(XPAR_RS232_UART_BASEADDR, buff);
}
}
int main()
{
xil_printf("--start the program test---\r\n");
XUartLite_Initialize(&RS232_Uart, XPAR_RS232_UART_DEVICE_ID);
//must enable mb_enable bit
microblaze_enable_interrupts();
XUartLite_EnableInterrupt(&RS232_Uart);
//register the isr
XIntc_RegisterHandler(XPAR_INTC_0_BASEADDR, \
XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR,\
(XInterruptHandler)uart_rev_handler,\
(void *)0);
//must enable XIntc_mMasterEnable
XIntc_mMasterEnable(XPAR_INTC_0_BASEADDR);
//must enable specific interrupt(s) in the interrupt controller.
XIntc_mEnableIntr(XPAR_INTC_0_BASEADDR, \
XPAR_PUSH_BUTTONS_POSITION_IP2INTC_IRPT_MASK\
|XPAR_DIP_SWITCHES_8BIT_IP2INTC_IRPT_MASK\
|XPAR_RS232_UART_INTERRUPT_MASK);
while(1);
return 0;
}
可以看出,在UART中断函数中我们只做了一件事情,就是看接收FIFO中是否有数,如果有数的话就读出来。而不对发送产生的中断做出响应。
需要注意的是,要慎用XPS给出的API驱动函数,因为有些函数在调用的时候当条件不满足时会停下来等待,使得整个程序被挂起。
让我比较困惑的一个问题是:XPS驱动给出的API驱动中有两个函数分别是void XUartLite_SetRecvHandler(XUartLite * InstancePtr, XUartLite_Handler FuncPtr, void * CallBackRef)和void XUartLite_SetSendHandler(XUartLite * InstancePtr, XUartLite_Handler FuncPtr, void * CallBackRef),看介绍是说设置中断函数当中断发生的时候被调用。但是在用这个两个函数的时候却无法正常调用UART中断函数,而且看这两个函数就很奇怪,因为我在系统中用了中断管理模块,所有的中断必须连接到中断管理模块上,但是这两个函数明显没有这个接口,那就不是这么用的!或许是当系统中只有UART中断时直接接到processor上的。Maybe, who konws?