grbl移植日志第二天移植串口数据接收
zynq的串口发送中断总是不能进入中断函数 . . . 看了好几天. 找不到原因了. 后来用了官方的串口中断示例代码也不行…
zynq的串口中断示例中, 有些bug. 提供的库也不是很好用. 因为封装好的库里面内置了一些固定的逻辑, 里面默认进行了中断的开启和关闭. 用起来并不是很顺手.
因为grbl 有一个循环缓冲队列, 为了实现此数据的上传, 需要在中断中修改此队列的指针.
索性摸索了一下zynq的的uart库, 直接基于寄存器自己写了一个. 要简单简洁的多.
不再需要像下面这使用uart官方提供的函数XUartPs_InterruptHandler, 也就不需要再使用
XUartPs_SetHandler 进行绑定了. 因为 XUartPs_InterruptHandler 中调用了XUartPs_SetHandler 设置的函数.
XScuGic_Connect(gicPtr, XPAR_PS7_UART_0_INTR, Xil_InterruptHandler)XUartPs_InterruptHandler, (void *)xUart0Ptr); XUartPs_SetHandler(xUart0Ptr, (XUartPs_Handler)uartIntrHandler, xUart0Ptr);
据到FIFO
/* Fill the FIFO from the buffer 填充发送数据到TX 的FIFO
*/
XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_FIFO_OFFSET,((u32)InstancePtr->SendBuffer.NextBytePtr[SentCount]));
禁用TXEMPTY中断
//禁用TXEMPTY中断
XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_IDR_OFFSET, ((u32)XUARTPS_IXR_TXEMPTY | (u32)XUARTPS_IXR_TXFULL));
启用TXEMPTY中断
//启用TXEMPTY中断
XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_IER_OFFSET, ((u32)XUARTPS_IXR_TXEMPTY | (u32)XUARTPS_IXR_TXFULL));
读取当前中断寄存器ISR的状态
//读取当前中断寄存器ISR的状态
/** Read the interrupt ID register to determine which* interrupt is active*/
u32 IsrStatus;
IsrStatus = XUartPs_ReadReg(InstancePtr->Config.BaseAddress, XUARTPS_IMR_OFFSET);
IsrStatus &= XUartPs_ReadReg(InstancePtr->Config.BaseAddress, XUARTPS_ISR_OFFSET);
判断是不是FITO TX发送完成触发的中断
//判断是不是FITO TX发送完成触发的中断
if((IsrStatus & ((u32)XUARTPS_IXR_TXEMPTY | (u32)XUARTPS_IXR_TXFULL)) != (u32)0)
{/* Transmit data interrupt */SendDataHandler(InstancePtr, IsrStatus);
}
判断是不是接收溢出或接收空或者接收满的触发的状态.
/* Dispatch an appropriate handler. */
//判断是不是接收溢出或接收空或者接收满的触发的状态.
if((IsrStatus & ((u32)XUARTPS_IXR_RXOVR | (u32)XUARTPS_IXR_RXEMPTY |(u32)XUARTPS_IXR_RXFULL)) != (u32)0){ ReceiveDataHandler(InstancePtr);
}
上面的这些代码都是参考自 xuartps_intr.c,xuartps.c
void XUartPs_InterruptHandler(XUartPs *InstancePtr)
{
.....
}
把官方提供的库XUartPs_InterruptHandler 抄过来
改个名
void MyXUartPs_InterruptHandler(XUartPs *InstancePtr){u32 IsrStatus;Xil_AssertVoid(InstancePtr != NULL);Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);/** Read the interrupt ID register to determine which* interrupt is active*/IsrStatus = XUartPs_ReadReg(InstancePtr->Config.BaseAddress, XUARTPS_IMR_OFFSET);IsrStatus &= XUartPs_ReadReg(InstancePtr->Config.BaseAddress, XUARTPS_ISR_OFFSET);/* Dispatch an appropriate handler. */if((IsrStatus & ((u32)XUARTPS_IXR_RXOVR | (u32)XUARTPS_IXR_RXEMPTY |(u32)XUARTPS_IXR_RXFULL)) != (u32)0) {/* Received data interrupt */
// ReceiveDataHandler(InstancePtr);}if((IsrStatus & ((u32)XUARTPS_IXR_TXEMPTY | (u32)XUARTPS_IXR_TXFULL)) != (u32)0){/* Transmit data interrupt */SendDataHandler(InstancePtr, IsrStatus);}/* XUARTPS_IXR_RBRK is applicable only for Zynq Ultrascale+ MP */if ((IsrStatus & ((u32)XUARTPS_IXR_OVER | (u32)XUARTPS_IXR_FRAMING |(u32)XUARTPS_IXR_PARITY | (u32)XUARTPS_IXR_RBRK)) != (u32)0) {/* Received Error Status interrupt */
// ReceiveErrorHandler(InstancePtr, IsrStatus);}if((IsrStatus & ((u32)XUARTPS_IXR_TOUT)) != (u32)0) {/* Received Timeout interrupt */
// ReceiveTimeoutHandler(InstancePtr);}if((IsrStatus & ((u32)XUARTPS_IXR_DMS)) != (u32)0) {/* Modem status interrupt */
// ModemHandler(InstancePtr);}/* Clear the interrupt status. */XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_ISR_OFFSET, IsrStatus);}
中断管理器中把函数和中断管理器进行连接. 这里连接到的是我上面自己修改过的MyXUartPs_InterruptHandler
Status = XScuGic_Connect(IntcInstancePtr, UartIntrId, (Xil_InterruptHandler) MyXUartPs_InterruptHandler, (void *) UartInstancePtr);