最近在使用zynq7000系列的ps串口的时候,需要使用到emio,遇到了很多问题,表现就是能够进行发送,接收的时候中断没有办法触发,而当能够触发的时候,也出现了很多奇怪的问题,有时候能够正常使用,有时候又不行。经过查找资料和分析,终于解决了。
EMIO的设置问题
我们在使用EMIO进行扩展的时候,操作方式和MIO差不多,只需要在选择的时候选择EMIO。
然后绑定对应的IO口就好了。
重点是:
如果我们选择的是UART0,那么我们的电平就选择LVCMOS33,如果选择的是UART1,那么就选择LVCMOS18
UART中断的问题
最初我就发现我的中断一直在触发,说明某个中断标志位没有清零,我打印了中断状态位,得到的是9,就只能是TX FIFO空中断和接收fifo触发中断两个,但是很奇怪的是,我并没有打开TX FIFO空中断。后面我发现,其实就是XUartPs_Send函数的问题,这个函数会调用XUartPs_SendBuffer函数,
在这函数内部有这样一段注释,
如果接收启用了中断,则启用TX FIFO空中断。
解决办法:
在中断处理函数中加上这么一段:通过给它写值来清除中断,这样就解决了
if(isr_status & (XUARTPS_IXR_TXEMPTY))
{
XUartPs_WriteReg(PsUart1.Config.BaseAddress,XUARTPS_ISR_OFFSET, XUARTPS_IXR_TXEMPTY);
}
以下是完整的中断处理函数
void Ps_Uart1_Intr_Hander(void *CallBackRef){
u32 recv_num = 0 ; //接收数据个数
u32 isr_status=100; //中断状态标志
//读取中断 ID 寄存器,判断触发的是哪种中断
isr_status = XUartPs_ReadReg(PsUart1.Config.BaseAddress,
XUARTPS_IMR_OFFSET);
isr_status &= XUartPs_ReadReg(PsUart1.Config.BaseAddress,
XUARTPS_ISR_OFFSET);
//添加以下这段,清除标志位就可以解决了
if(isr_status & (XUARTPS_IXR_TXEMPTY))
{
XUartPs_WriteReg(PsUart1.Config.BaseAddress,XUARTPS_ISR_OFFSET, XUARTPS_IXR_TXEMPTY);
}
//添加以上这段,清除标志位就可以解决了
//判断中断标志位 RxFIFO 是否触发
if (isr_status & (XUARTPS_IXR_RXOVR | XUARTPS_IXR_RXFULL)){
//读取接收的数据到缓存区
recv_num = XUartPs_Recv(&PsUart1, ps_uart1_recv_buf, 100);
XUartPs_WriteReg(PsUart1.Config.BaseAddress,XUARTPS_ISR_OFFSET, XUARTPS_IXR_RXOVR);
//将缓存区中接收到的数据再发送出去
XUartPs_Send(&PsUart1, ps_uart1_recv_buf, recv_num);
//清空缓存区
memset(ps_uart1_recv_buf, 0, 100);
}
}