前面的文章我们已经讲过CPU之间的软中断,PS与PL之间的共享中断,但是共享中断还有一种数据类型也就是PS外设引起的中断。在学习本篇文章的同时一定要学习前面的两篇文章,可以对ZYNQ的中断有一个总体的认知。本篇文章将以UART为例来讲解PS的外设中断的使用。关于UART在ZYNQ的PS端相信大家都使用过print来输出相应的数据。但是UART如何接收数据是不是大家还没有真正的使用过,UART接收数据一般情况下我们使用的是中断来进行相应数据的接收,所以这篇文章我们讲解UART的中断情况下的发射与接收。
工程描述:使用PC机通过串口对PS发送数据,PS端做出相应的相应,并把接受到的数据发送回PS端,从而完成串口的回环校验。
本次实验所用到的软硬件环境如下:
1、VIVADO 2019.1
2、米联客MZ7015FA开发板
这里为了清晰表述,再次引入中断分类:
从上面可以看出共享中断分为PL的中断和PS的IO中断,然后下面的共享中断的详细情况:
从上面可以看出UART1中断的ID是82,这在程序中进行初始化相应的中断时唯一的标识。
这一篇文章我们主要讲解UART中断的例子,引起UART中断的事件类型有很多,这就需要我们对其进行相应的中断类型的操作。而且这里需要注意的一点,这种类型的终端操作调试的时候一般不要使用Debug进行调试,因为这种情况会使得数据传输丢失,当然使用Debug调试还是可以大体验证自己实验的正确性。中断的代码与前面的软中断和PL端的共享中断大体一直,但是需要我们针对UART中断多添加一些额外的内容:
1、设置UART中断类型:IntrMask = XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING |
XUARTPS_IXR_OVER | XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXFULL |
XUARTPS_IXR_RXOVR;
XUartPs_SetInterruptMask(&UartPs, IntrMask);
2、设置串口波特率:XUartPs_SetBaudRate(&UartPs,115200);
3、设置中断服务函数:XUartPs_SetHandler(&UartPs,(XUartPs_Handler)UartHandler,&UartPs);
4、这里需要注意中断发生后一定要接受缓存的数据用来确保下次触发数据的正确性,XUartPs_Recv(&UartPs, RecBuf, 32);
这里PL端只需要例化一个ZYNQ的IP,其他部分不需要进行任何处理,所以PL端我们没有进行相应的设计。其中,Block Design设计如下:
总体代码与前面的两篇博客几乎一样,只是针对UART的协议使用了几个函数用来进行相应的设置。代码如下:
#include
#include "xscugic.h"
#include "xparameters.h"
#include "sleep.h"
#include "xuartps.h"
#define GIC_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID
#define UART1INIR XPAR_XUARTPS_1_INTR
static XScuGic ScuGic;
static XScuGic_Config * ScuGicCfgPtr;
XUartPs UartPs;
XUartPs_Config *Config;
u8 RecBuf[32];
u8 SendBuf[32];
//initial gic & software intr
int initSwIntr();
//callback func
void UartHandler(void *CallBackRef, u32 Event, unsigned int EventData);
int inituart();
int main()
{
int status;
int i;
status = initSwIntr();
status = inituart();
if(status != XST_SUCCESS){
return status;
}
for(i = 0;i < 32;i++)
SendBuf[i] = i;
while(1){
usleep(100000);
}
return 0;
}
int initSwIntr(){
int status;
Xil_ExceptionInit();
ScuGicCfgPtr = XScuGic_LookupConfig(GIC_ID);
status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
if(status != XST_SUCCESS){
return status;
}
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
status = XScuGic_Connect(&ScuGic,UART1INIR,(Xil_ExceptionHandler)XUartPs_InterruptHandler,&UartPs);
if(status != XST_SUCCESS){
return status;
}
XScuGic_Enable(&ScuGic,UART1INIR);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
int inituart(){
int status;
u32 IntrMask;
IntrMask = XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING |
XUARTPS_IXR_OVER | XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXFULL |
XUARTPS_IXR_RXOVR;
Config = XUartPs_LookupConfig(UART_DEVICE_ID);
status = XUartPs_CfgInitialize(&UartPs, Config, Config->BaseAddress);
status = XUartPs_SelfTest(&UartPs);
XUartPs_SetBaudRate(&UartPs,115200);
XUartPs_SetHandler(&UartPs,(XUartPs_Handler)UartHandler,&UartPs);
XUartPs_SetInterruptMask(&UartPs, IntrMask);
XUartPs_SetOperMode(&UartPs, XUARTPS_OPER_MODE_NORMAL);
XUartPs_SetRecvTimeout(&UartPs, 20);
XUartPs_Recv(&UartPs, RecBuf, 32);
return status;
}
void UartHandler(void *CallBackRef, u32 Event, unsigned int EventData){
u32 TotalReceivedCount;
int i;
if (Event == XUARTPS_EVENT_RECV_DATA) {
TotalReceivedCount = EventData;
if(TotalReceivedCount == 32) {
for(i=0;i<TotalReceivedCount;i++)
SendBuf[i] = RecBuf[i];
XUartPs_Send(&UartPs, SendBuf, TotalReceivedCount);
XUartPs_Recv(&UartPs, RecBuf, 32);
TotalReceivedCount=0;
}
}
/*
* Data was received, but not the expected number of bytes, a
* timeout just indicates the data stopped for 8 character times
*/
if (Event == XUARTPS_EVENT_RECV_TOUT) {
TotalReceivedCount = EventData;
for(i=0;i<TotalReceivedCount;i++)
SendBuf[i] = RecBuf[i];
XUartPs_Send(&UartPs, SendBuf, TotalReceivedCount);
XUartPs_Recv(&UartPs, RecBuf, 32);
TotalReceivedCount=0;
}
XUartPs_Recv(&UartPs, RecBuf, 32);
}
大家可以将上面的代码放到自己的开发板中进行相应的调试,验证实验的正确性,现在简要对上面的函数进行说明。
3、XUartPs_SetHandler(UartInstPtr, (XUartPs_Handler)UartPs_Intr_Handler, UartInstPtr)
函数负责设置中断产生后的回调函数为 UartPs_Intr_Handler。
4、 XUartPs_SetInterruptMask(UartInstPtr, IntrMask)
函数负责配置中断类型
6、 XUartPs_SetRecvTimeout(UartInstPtr, 8)
函数设置了空闲超时等待的时间为 8x4 = 32 为 32 个波特率采样时钟,意思就是当串口上超过 32 个波特率采样时
钟没有数据的时候,就会触发一次超时中断,这样可以通知用户程序去读取已经接收到的数据。
为了正常启动接收,不管有没有数据到来,需要先启动一次接收函数 XUartPs_Recv(&UartPs, RecvBuffer,TEST_BUFFER_SIZE)。
为了验证我们实验的正确性,我们对上面的程序进行了下班测试,测试结果如下:
从上面的结果从而验证了实验的正确性。
创作不易,认为文章有帮助的同学们可以关注、点赞、转发支持。为行业贡献及其微小的一部分。对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群: