zynq的串口发送中断总是不能进入中断函数 . . . 看了好几天. 找不到原因了. 后来用了官方的串口中断示例代码也不行…
后来终于找到原因了…我的妈呀. 卡了我好几天, 原来是中断函数里面有个函数指针指向了Null.
if(rec_data == CMD_TOOL_ACK ) { // If tool change acknowledged
hal.stream.read = serialGetC; // and restore normal input.
}
else if (!hal.stream.enqueue_rt_command((char)rec_data))
{
fifo_push(&rxbuffer, (char)rec_data);
}
这个hal.stream.enqueue_rt_command 因为没有初始化, 导致指向的是Null. 执行过后就停止了.中断也不再进入了. C语言真的是要命啊.这种也不报异常,全靠人工逐行排查…
不知道C++能不能补货到这种异常.
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);