1 实验任务

本实验任务是使用PS端UART控制器,完成串口中断数据环回的功能。

2 系统框图

在这里插入图片描述

3 硬件设计

3.1 Block Design

  1. 添加ZYNQ7 Processing System IP核
    • (1)在Peripheral I/O页面
      • 1)勾选UART
      • 2)正确选择Bank 0和Bank 1的电压(我使用的开发板UART在MIO48/49,即Bank1,电压为1.8V;刚开始没注意,使用Bank1默认电压3.3V,结果只能发不能收,调试半天也没能定位问题,最后甚至怀疑串口的接收线路有问题)
    • (2)在DDR Configuration页面
      • 1)DDR Controller Configuration下,合理配置Memory Type、Memory Part和Bus Width等参数

在这里插入图片描述

3.2 注意事项

无。

4 软件设计

4.1 注意事项

  1. 同时使能XUARTPS_IXR_RXOVR 和XUARTPS_IXR_TOUT,以支持不定长数据接收;
  2. 调试串口和业务串口最好分开,否则会有干扰
    • (1)刚开始不懂,在程序中加入很多调试信息(printf打印函数),结果收发数据出现各种问题
    • (2)本例使用的开发板只有一个串口,无法区分调试串口和业务串口,所以尽量不用printf打印函数

4.2 函数详解

  1. XUartPs_Recv函数
    • (1)函数功能:从RX FIFO接收数据
    • (2)函数实现:
      • 1)禁用所有中断
      • 2)设置缓冲区参数,包括请求接收的字节数、剩余待接收的字节数和指向下一个要接收的字节的指针
      • 3)调用XUartPs_ReceiveBuffer函数,该函数完成数据接收功能并返回实际接收的字节数
      • 4)恢复中断使能
      • 5)接收XUartPs_ReceiveBuffer函数的返回值并返回
  2. XUartPs_ReceiveBuffer函数
    • (1)函数功能:以轮询或中断驱动模式从RX FIFO接收数据存入缓冲区
    • (2)函数实现:
      • 1)从RX FIFO读取数据,如果RX FIFO不空且仍有数据需要读取到缓冲区中,则从RX FIFO中读取数据存入缓冲区(Loop until there is no more data in RX FIFO or the specified number of bytes has been received
      • 2)更新缓冲区指针和剩余字节数
      • 3)返回实际读取的字节数
  3. XUartPs_SetRecvTimeout函数
    • (1)设置超时计数器的超时周期(即初始值)
    • (2)重启超时计数器(加载初始值并开始递减)
      • 1)在程序下载完成后会立即收到一个超时中断,并打印"Rx timeout, receive 0 bytes."

4.3 工程源码

/************************** Include Files ***********************************/

#include "xparameters.h"
#include "xuartps.h"
#include "xscugic.h"
#include "stdio.h"

/************************** Constant Definitions ****************************/

#define UART_DEVICE_ID		XPAR_XUARTPS_0_DEVICE_ID
#define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID
#define UART_INTR_ID		XPAR_XUARTPS_1_INTR

#define BUFFER_SIZE 		64   // 接收缓冲区大小
#define FIFO_TRIGGER_LEVEL  32   // FIFO触发阈值
#define RECV_TIMEOUT        4    // 接收超时时间(单位:波特率时钟周期)

#define DEBUG				0

/************************** Function Prototypes *****************************/

s32  UartPsInit(XUartPs *UartPsInstPtr, XUartPsFormat* UartFormatPtr);
s32  SetupInterruptSystem(XScuGic *IntcInstPtr, XUartPs *UartPsInstPtr);
void UartIntrHandler(void *CallBackRef);

/************************** Variable Definitions ****************************/

XUartPs UartInst;
XScuGic IntcInst;

u8 RxBuffer[BUFFER_SIZE] = { 0 };  // 接收缓冲区

int RxDataLength = 0;  // 接收到的数据长度

XUartPsFormat UartFormat = {
		XUARTPS_DFT_BAUDRATE,     // 115200
		XUARTPS_FORMAT_8_BITS,
		XUARTPS_FORMAT_NO_PARITY,
		XUARTPS_FORMAT_1_STOP_BIT
};

/************************** Function Implementation *************************/

int main()
{
	//
	s32 Status;

	// 初始化UART
	Status = UartPsInit(&UartInst, &UartFormat);
	if (Status == XST_FAILURE) {
		printf("Error : uart initialization failed.\n");
		return XST_FAILURE;
	}

	// 设置中断系统
	Status = SetupInterruptSystem(&IntcInst, &UartInst);
	if (Status == XST_FAILURE) {
		printf("Error : setup interrupt system failed.\n");
		return XST_FAILURE;
	}

	// 主循环
	while(1)
	{
		;
	}

	//
	return XST_SUCCESS;
}

/****************************************************************************/

s32 UartPsInit(XUartPs *UartInstPtr, XUartPsFormat* UartFormatPtr)
{
	//
	s32 Status;
	XUartPs_Config *UartConfigPtr;

	// 查找UART配置
	UartConfigPtr = XUartPs_LookupConfig(UART_DEVICE_ID);
	if(NULL == UartConfigPtr)
	{
		return XST_FAILURE;
	}

	// 初始化UART
	Status = XUartPs_CfgInitialize(UartInstPtr, UartConfigPtr, UartConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// 设置UART数据格式
	XUartPs_SetDataFormat(UartInstPtr, UartFormatPtr);

	// 设置UART操作模式
	XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL);

	// 设置接收FIFO触发阈值
	XUartPs_SetFifoThreshold(UartInstPtr, FIFO_TRIGGER_LEVEL);

	// 设置接收超时
	XUartPs_SetRecvTimeout(UartInstPtr, RECV_TIMEOUT);

	// 设置中断掩码,使能FIFO触发中断和接收超时中断
	XUartPs_SetInterruptMask(UartInstPtr, XUARTPS_IXR_RXOVR | XUARTPS_IXR_TOUT);

	//
	return XST_SUCCESS;
}

/****************************************************************************/

s32 SetupInterruptSystem(XScuGic *IntcInstPtr, XUartPs *UartInstPtr)
{
	//
	s32 Status;
	XScuGic_Config *IntcConfigPtr;

	// 初始化中断控制器GIC
	IntcConfigPtr = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfigPtr)
	{
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(IntcInstPtr, IntcConfigPtr, IntcConfigPtr->CpuBaseAddress);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	// 注册异常处理程序
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstPtr);
	Xil_ExceptionEnable();

	// 连接UART中断处理程序
	XScuGic_Connect(IntcInstPtr, UART_INTR_ID, (Xil_InterruptHandler)UartIntrHandler, (void *)UartInstPtr);

	// 使能UART中断
	XScuGic_Enable(IntcInstPtr, UART_INTR_ID);

	//
	return XST_SUCCESS;
}

/****************************************************************************/

void UartIntrHandler(void *CallBackRef)
{
	//
	XUartPs* UartInstPtr = (XUartPs*)CallBackRef;
	u32 IsrStatus;

	// 读取中断状态
	IsrStatus = XUartPs_ReadReg(UartInstPtr->Config.BaseAddress, XUARTPS_IMR_OFFSET);
	IsrStatus &= XUartPs_ReadReg(UartInstPtr->Config.BaseAddress, XUARTPS_ISR_OFFSET);

	// 处理FIFO触发中断
	if ((IsrStatus & (u32)XUARTPS_IXR_RXOVR) != (u32)0) {
		// 读取FIFO中的数据
		RxDataLength = XUartPs_Recv(UartInstPtr, RxBuffer, BUFFER_SIZE);

		// 清除中断状态
		XUartPs_WriteReg(UartInstPtr->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_RXOVR);

		//
#if DEBUG
		printf("Rx trigger, receive %u bytes.\n", RxDataLength);
#endif
	}

	// 处理接收超时中断
	if ((IsrStatus & (u32)XUARTPS_IXR_TOUT) != (u32)0) {
		// 读取FIFO中剩余的数据
		RxDataLength = XUartPs_Recv(UartInstPtr, RxBuffer, BUFFER_SIZE);

		// 清除中断状态
		XUartPs_WriteReg(UartInstPtr->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_TOUT);

		//
#if DEBUG
		printf("Rx timeout, receive %u bytes.\n", RxDataLength);
#endif
	}

	//
	if (RxDataLength > 0) {
		// 处理接收到的数据
		XUartPs_Send(UartInstPtr, RxBuffer, RxDataLength);

		//
		RxDataLength = 0;
	}

	//
	return;
}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐