ZYNQ平台下UART和AXIDMA的封装

一、来源介绍

  1. 参考韦东山的直播视频课
  2. 基本思想学习自Linux驱动

二、串口驱动

#ifndef __UART_DRIVER_H_
#define __UART_DRIVER_H_

#include "stdint.h"

struct UART_Device{
	// 名称
	char *name;
	// UART对象指针、波特率、数据位数、有无校验位、停止位数、中断优先级、中断触发方式
	int (*init)(struct UART_Device *pDev, int baud, int datas, char prity, int stop, char priority, char trigger);
	// UART对象指针、发送数据、发送长度、等待时间
	int (*send)(struct UART_Device *pDev, uint8_t *data, int len, int timeout_ms);
	// UART对象指针、接收数据、接收长度、等待时间
	int (*recv)(struct UART_Device *pDev, uint8_t *data, int *len, int timeout_ms);
	// 私有数据
	void *priv_data;
};

struct UART_Device * Get_UART_Device(char *name);

#endif
/*********************************************************************************************************/
#include "uart_driver.h"
#include "string.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"

#include "xscugic.h"
#include "xuartps.h"

/****************************************************************************/
/*
 * ZYNQ-UART实现
 */

#define RECV_BUFFER_SIZE	128
#define UART_RX_QUEUE_ITEM_SIZE	(sizeof(MSG_HEAD)+RECV_BUFFER_SIZE)
#define UART_RX_QUEUE_LENGTH	5

struct UART_Drv_Data{
	XScuGic * gic_handle;				// GIC
	XUartPs * uart_handle;				// UART
	int uart_device_id;					// UART-ID
	int uart_int_irq_id;				// UART-IRQ-ID
	XUartPs_Handler callback;			// Callack
	uint8_t rxdata[RECV_BUFFER_SIZE];	// recv-buffer(for recv func)
	SemaphoreHandle_t xTxSem;			// Tx done semaphore
	QueueHandle_t xRxQueue;				// Rx msg queue
	/*
	 * 引入循环缓冲区,接收时将数据拷贝到循环缓冲区,发送消息队列,根据长度取出数据
	 * 不引入循环缓冲区,消息队列=消息头+数据,解析消息们根据长度取出数据
	 * 两者看来资源消耗都差不多
	 */
};
typedef struct MSG_HEAD{
	int src_id;
	int dst_id;
	int length;
} MSG_HEAD;

// 成员定义
// 内核中初始化Timer使用的GIC对象,如果采用另外一个对象初始化UART/DMA,将会导致软件定时器失效
extern XScuGic xInterruptController;
XUartPs Uart_Ps0;
#define UART_DEVICE_ID		XPAR_XUARTPS_0_DEVICE_ID				// 串口设备ID
#define UART_INT_IRQ_ID		XPAR_XUARTPS_1_INTR						// 串口中断ID

void UartPs_Intr_CallBack_Handler(void *CallBackRef, u32 Event, u32 EventData)
{
	struct UART_Device *pDev = (struct UART_Device *)CallBackRef;
	struct UART_Drv_Data *data = pDev->priv_data;
	XUartPs *uart_ps = data->uart_handle;
	uint8_t *rx_data = data->rxdata;
	uint8_t msgBuf[UART_RX_QUEUE_ITEM_SIZE];
	MSG_HEAD *pMsgHead = (MSG_HEAD *)msgBuf;
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;

	/* All of the data has been sent */
	if (Event == XUARTPS_EVENT_SENT_DATA) {
		// 释放信号量
		xSemaphoreGiveFromISR(data->xTxSem, NULL);
	};

	/* All of the data has been received */
	if (Event == XUARTPS_EVENT_RECV_DATA) {
		while(XUartPs_IsSending(uart_ps));
		pMsgHead->src_id = 0x00;
		pMsgHead->dst_id = 0x01;					// 除了固定的值,是否还有更好的写法?
		pMsgHead->length = EventData;				// 但是中断中还是减少函数调用吧
//		memcpy(msgBuf+sizeof(MSG_HEAD), data->rxdata, pMsgHead->length);
		for(int i = 0; i < pMsgHead->length; i++)
		{
			msgBuf[sizeof(MSG_HEAD)+i] = data->rxdata[i];
		}
		// 发送
		xQueueSendFromISR(data->xRxQueue, msgBuf, &xHigherPriorityTaskWoken);
//		if(xHigherPriorityTaskWoken == pdTRUE)
//		{
//			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
//		}
		// 再次接收
		XUartPs_Recv(uart_ps, rx_data, RECV_BUFFER_SIZE);
	}

	/*
	 * 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) {
		if(0 != EventData)								// 避免空闲中断没有数据的情况
		{
			while(XUartPs_IsSending(uart_ps));
			pMsgHead->src_id = 0x00;
			pMsgHead->dst_id = 0x01;					// 除了固定的值,是否还有更好的写法?
			pMsgHead->length = EventData;				// 但是中断中还是减少函数调用吧
	//		memcpy(msgBuf+sizeof(MSG_HEAD), data->rxdata, pMsgHead->length);
			for(int i = 0; i < pMsgHead->length; i++)
			{
				msgBuf[sizeof(MSG_HEAD)+i] = data->rxdata[i];
			}
			// 发送
			xQueueSendFromISR(data->xRxQueue, msgBuf, &xHigherPriorityTaskWoken);
//			if(xHigherPriorityTaskWoken == pdTRUE)
//			{
//				portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
//			}
		}
		// 再次接收
		XUartPs_Recv(uart_ps, rx_data, RECV_BUFFER_SIZE);
	}

	/*
	 * Data was received with an error, keep the data but determine
	 * what kind of errors occurred
	 */
	if (Event == XUARTPS_EVENT_RECV_ERROR) {

	}

	/*
	 * Data was received with an parity or frame or break error, keep the data
	 * but determine what kind of errors occurred. Specific to Zynq Ultrascale+
	 * MP.
	 */
	if (Event == XUARTPS_EVENT_PARE_FRAME_BRKE) {

	}

	/*
	 * Data was received with an overrun error, keep the data but determine
	 * what kind of errors occurred. Specific to Zynq Ultrascale+ MP.
	 */
	if (Event == XUARTPS_EVENT_RECV_ORERR) {

	}
}

int zynq_uart_init(struct UART_Device *pDev, int baud, int datas, char prity, int stop, char priority, char trigger)
{
	int status;
	u32 IntrMask;
	XUartPs_Config *uart_cfg;


	struct UART_Drv_Data *data = pDev->priv_data;
	int device_id = data->uart_device_id;
	int uart_int_irq_id = data->uart_int_irq_id;
	XUartPs *uart_ps = data->uart_handle;
	XScuGic *intc = data->gic_handle;
	XUartPs_Handler callback_func = data->callback;
	uint8_t *rx_data = data->rxdata;

	data->xTxSem = xSemaphoreCreateBinary();
	data->xRxQueue = xQueueCreate(UART_RX_QUEUE_LENGTH, UART_RX_QUEUE_ITEM_SIZE);

	// 1. 实现GIC的初始化和注册异常---应该在所有驱动的最外层实现

	// 2. UART的配置
	uart_cfg = XUartPs_LookupConfig(device_id);
	if (NULL == uart_cfg)
	   return XST_FAILURE;

	status = XUartPs_CfgInitialize(uart_ps, uart_cfg, uart_cfg->BaseAddress);
	if (status != XST_SUCCESS)
	   return XST_FAILURE;

		//设置工作模式:正常模式
	XUartPs_SetOperMode(uart_ps, XUARTPS_OPER_MODE_NORMAL);
		//设置波特率:115200
	XUartPs_SetBaudRate(uart_ps, baud);
		// 设置中断优先级
	XScuGic_SetPriorityTriggerType(intc, uart_int_irq_id, priority, trigger);
		//设置RxFIFO的中断触发等级
	XUartPs_SetFifoThreshold(uart_ps, 4);
		//设置空闲中断
	XUartPs_SetRecvTimeout(uart_ps, 8);
		//设置中断处理函数的回调函数
	XUartPs_SetHandler(uart_ps, (XUartPs_Handler)callback_func, pDev);
		//设置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(uart_ps, IntrMask);

		//注册UART_INT_IRQ_ID中断处理函数到GIC
	XScuGic_Connect(intc, uart_int_irq_id,
				(Xil_ExceptionHandler) XUartPs_InterruptHandler,(void *) uart_ps);
		//使能GIC中的串口中断
	XScuGic_Enable(intc, uart_int_irq_id);

	// 3. 启动一次接收
	XUartPs_Recv(uart_ps, rx_data, RECV_BUFFER_SIZE);

	return 0;
}

int zynq_uart_send(struct UART_Device *pDev, uint8_t *out, int len, int timeout_ms)
{
	struct UART_Drv_Data *data = (struct UART_Drv_Data *)pDev->priv_data;
	XUartPs *uart_ps = data->uart_handle;

	XUartPs_Send(uart_ps, out, len);			//	完成一次突发发送或发送完成(<64字节)

	// 等待发送完成
	if(pdFALSE == xSemaphoreTake(data->xTxSem, timeout_ms))
	{
		return -1;
	}

	return 0;
}

int zynq_uart_recv(struct UART_Device *pDev, uint8_t *out, int *len, int timeout_ms)
{
	struct UART_Drv_Data *data = (struct UART_Drv_Data *)pDev->priv_data;
	static uint8_t msgBuf[UART_RX_QUEUE_ITEM_SIZE];
	int data_len = 0;

	// 接收消息队列消息
	if(pdFALSE == xQueueReceive(data->xRxQueue, &msgBuf, timeout_ms))
	{
		return -1;
	}

	// 解析纯数据
	MSG_HEAD *pMsgHead = (MSG_HEAD *)msgBuf;
	if( (0x00 == pMsgHead->src_id) && (0x01 == pMsgHead->dst_id) )			// 固定值
	{
		data_len = pMsgHead->length;
		if(data_len <= 0 || data_len > RECV_BUFFER_SIZE )
		{
			return -1;
		}
		memcpy(out, msgBuf+sizeof(MSG_HEAD), data_len);
		*len = data_len;
	}

	return 0;
}

struct UART_Drv_Data zynq_uart0_data = {
	.gic_handle = &xInterruptController,
	.uart_handle = &Uart_Ps0,
	.uart_device_id = UART_DEVICE_ID,
	.uart_int_irq_id = UART_INT_IRQ_ID,
	.callback = UartPs_Intr_CallBack_Handler,
	// 后续成员在其他地方初始化
};

struct UART_Device g_zynq_uart0 = {
	.name = "zynq_uart0",
	.init = zynq_uart_init,
	.send = zynq_uart_send,
	.recv = zynq_uart_recv,
	.priv_data = &zynq_uart0_data,
};

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


// 全局的UART_Device结构体数组
struct UART_Device *g_uart_devs[] = {&g_zynq_uart0};

struct UART_Device * Get_UART_Device(char *name)
{
	int i = 0;
	for(i = 0; i < sizeof(g_uart_devs)/sizeof(g_uart_devs[0]); i++)
	{
		if(0 == strcmp(name, g_uart_devs[i]->name))
		{
			return g_uart_devs[i];
		}
	}
	return NULL;
}

三、AXI-DMA驱动封装

#ifndef __AXIDMA_DRIVER_H_
#define __AXIDMA_DRIVER_H_

#include "stdint.h"

struct AXIDMA_Device{
	// 名称
	char *name;
	// AXIDMA对象指针、中断优先级、中断触发方式
	int (*init)(struct AXIDMA_Device *pDev, char priority, char trigger);
	// AXIDMA对象指针、发送数据、发送长度、等待时间
	int (*send)(struct AXIDMA_Device *pDev, uint8_t *data, int len, int timeout_ms);
	// AXIDMA对象指针、接收数据、接收长度、等待时间
	int (*recv)(struct AXIDMA_Device *pDev, uint8_t *data, int *len, int timeout_ms);
	// 私有数据
	void *priv_data;
};

struct AXIDMA_Device * Get_AXIDMA_Device(char *name);


#endif
/********************************************************************************/
#include "axidma_driver.h"
#include "string.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"

#include "xscugic.h"
#include "xaxidma.h"

/****************************************************************************/
/*
 * ZYNQ-AXIDMA实现
 */
#define RECV_BUFFER_SIZE	128
#define AXIDMA_RX_QUEUE_ITEM_SIZE	(sizeof(MSG_HEAD)+RECV_BUFFER_SIZE)
#define AXIDMA_RX_QUEUE_LENGTH	5
#define DDR_BASE_ADDR       XPAR_PS7_DDR_0_S_AXI_BASEADDR   //0x00100000
#define MEM_BASE_ADDR       (DDR_BASE_ADDR + 0x1000000)     //0x01100000
#define TX_BUFFER_BASE      (MEM_BASE_ADDR + 0x00100000)    //0x01200000
#define RX_BUFFER_BASE      (MEM_BASE_ADDR + 0x00200000)    //0x01300000
#define RESET_TIMEOUT_COUNTER   10000

// 内核中初始化Timer使用的GIC对象,如果采用另外一个对象初始化UART/DMA,将会导致软件定时器失效
extern XScuGic xInterruptController;
XAxiDma AxiDma0;
#define DMA_DEV_ID          XPAR_AXIDMA_0_DEVICE_ID
#define RX_INTR_ID          XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
#define TX_INTR_ID          XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID


typedef struct MSG_HEAD{
	int src_id;
	int dst_id;
	int length;
} MSG_HEAD;

struct AXIDMA_Drv_Data{
	XScuGic * gic_handle;				// GIC
	XAxiDma * axidma_handle;			// AXIDMA
	int axidma_device_id;				// AXIDMA-ID
	int axidma_tx_int_id;				// TX-IRQ-ID
	int axidma_rx_int_id;				// RX-INT-ID
	Xil_InterruptHandler tx_intr_handler;
	Xil_InterruptHandler rx_intr_handler;
	uint8_t *rx_buffer_ptr;
	uint8_t *tx_buffer_ptr;
	SemaphoreHandle_t xTxSem;			// Tx done semaphore
//	SemaphoreHandle_t xRxSem;			// Rx done semaphore
	QueueHandle_t xRxQueue;				// Rx msg queue
};

static void tx_intr_handler(void *Callback)
{
	u32 IrqStatus;
	int TimeOut;
	struct AXIDMA_Device *pDev = (struct AXIDMA_Device *)Callback;
	struct AXIDMA_Drv_Data *data = pDev->priv_data;
	XAxiDma *AxiDmaInst = data->axidma_handle;
//	uint8_t *tx_buffer_ptr = data->tx_buffer_ptr;

	IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
	if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
		return;
	}
	if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
		XAxiDma_Reset(AxiDmaInst);
		TimeOut = RESET_TIMEOUT_COUNTER;
		while (TimeOut) {
			if (XAxiDma_ResetIsDone(AxiDmaInst)) {
				break;
			}
			TimeOut -= 1;
		}
		return;
	}
	if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
//		Xil_DCacheInvalidateRange((UINTPTR)tx_buffer_ptr, RECV_BUFFER_SIZE);	// 刷Cache
		// 发送完成,释放信号量
		xSemaphoreGiveFromISR(data->xTxSem, NULL);
	}
}

static void rx_intr_handler(void *Callback)
{
	u32 IrqStatus;
	int TimeOut;
	int len;
//	int Status;
	struct AXIDMA_Device *pDev = (struct AXIDMA_Device *)Callback;
	struct AXIDMA_Drv_Data *data = pDev->priv_data;
	XAxiDma *AxiDmaInst = data->axidma_handle;
	uint8_t *rx_buffer_ptr = data->rx_buffer_ptr;
	uint8_t msgBuf[AXIDMA_RX_QUEUE_ITEM_SIZE];
	MSG_HEAD *pMsgHead = (MSG_HEAD *)msgBuf;
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;

	IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);		// 查看中断状态
	XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);		// 应答IRQ
	if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {								// 无中断发生
		return;
	}
	if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {								// 出错
		XAxiDma_Reset(AxiDmaInst);
		TimeOut = RESET_TIMEOUT_COUNTER;
		while (TimeOut) {
			if(XAxiDma_ResetIsDone(AxiDmaInst)) {
				break;
			}
			TimeOut -= 1;
		}
		return;
	}

	if (IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {								// 完成
		Xil_DCacheInvalidateRange((UINTPTR)rx_buffer_ptr, RECV_BUFFER_SIZE);	// 刷Cache
		len = XAxiDma_ReadReg(AxiDmaInst->RegBase+(XAXIDMA_RX_OFFSET*XAXIDMA_DEVICE_TO_DMA),XAXIDMA_BUFFLEN_OFFSET);
		// 构造消息发送
		pMsgHead->src_id = 0x00;
		pMsgHead->dst_id = 0x01;					// 除了固定的值,是否还有更好的写法?
		pMsgHead->length = len;
		for(int i = 0; i < pMsgHead->length; i++)
		{
			msgBuf[sizeof(MSG_HEAD)+i] = data->rx_buffer_ptr[i];
		}
		xQueueSendFromISR(data->xRxQueue, msgBuf, &xHigherPriorityTaskWoken);
		if(xHigherPriorityTaskWoken == pdTRUE)
		{
			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
		}
		// 接收完成,释放信号量
//		xSemaphoreGiveFromISR(data->xRxSem, NULL);
	}

	// 重新启动一次接收
//	Xil_DCacheInvalidateRange((UINTPTR)rx_buffer_ptr, len);	// 刷Cache
//	while(XAxiDma_Busy(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA));		// 等待传输完成
//	Status = XAxiDma_SimpleTransfer(AxiDmaInst,(UINTPTR)rx_buffer_ptr,RECV_BUFFER_SIZE,XAXIDMA_DEVICE_TO_DMA);
//	if(Status != XST_SUCCESS){
//		return;
//	}
}


int zynq_axidma_init(struct AXIDMA_Device *pDev, char priority, char trigger)
{
	int status;
	XAxiDma_Config *axidma_cfg=NULL;

	struct AXIDMA_Drv_Data *data = pDev->priv_data;
	int device_id = data->axidma_device_id;
	int axidma_tx_int_id = data->axidma_tx_int_id;
	int axidma_rx_int_id = data->axidma_rx_int_id;
	XAxiDma *axidma = data->axidma_handle;
	XScuGic *intc = data->gic_handle;
	Xil_InterruptHandler tx_intr_handler = data->tx_intr_handler;
	Xil_InterruptHandler rx_intr_handler = data->rx_intr_handler;
	uint8_t *rx_buffer_ptr = data->rx_buffer_ptr;
	uint8_t *tx_buffer_ptr = data->tx_buffer_ptr;

	data->xTxSem = xSemaphoreCreateBinary();
//	data->xRxSem = xSemaphoreCreateBinary();
	data->xRxQueue = xQueueCreate(AXIDMA_RX_QUEUE_LENGTH, AXIDMA_RX_QUEUE_ITEM_SIZE);

	// 1. 实现GIC的初始化和注册异常---应该在所有驱动的最外层实现

	// 2. AXIDMA的配置
	axidma_cfg = XAxiDma_LookupConfig(device_id);
	if (NULL == axidma_cfg)
		return XST_FAILURE;

	status = XAxiDma_CfgInitialize(axidma, axidma_cfg);
	if (status != XST_SUCCESS)
		   return XST_FAILURE;

	if(XAxiDma_HasSg(axidma)){
		return XST_FAILURE;
	}
		// 设置中断优先级
	XScuGic_SetPriorityTriggerType(intc, axidma_tx_int_id, priority, trigger);
	XScuGic_SetPriorityTriggerType(intc, axidma_rx_int_id, priority, trigger);
		// 注册中断服务函数
	status = XScuGic_Connect(intc, axidma_tx_int_id,
		            (Xil_InterruptHandler) tx_intr_handler, pDev);
	if (status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	status = XScuGic_Connect(intc, axidma_rx_int_id,
					(Xil_InterruptHandler) rx_intr_handler, pDev);
	if (status != XST_SUCCESS) {
		return XST_FAILURE;
	}
		// 使能GIC-AXIDMA中断
	XScuGic_Enable(intc, axidma_tx_int_id);
	XScuGic_Enable(intc, axidma_rx_int_id);
		// 关闭DMA中断
	XAxiDma_IntrDisable(axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrDisable(axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
		// 使能DMA中断
	XAxiDma_IntrEnable(axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
	XAxiDma_IntrEnable(axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
		// 刷新一下Cache
	Xil_DCacheFlushRange((UINTPTR)rx_buffer_ptr, RECV_BUFFER_SIZE);	// 刷Cache
	Xil_DCacheFlushRange((UINTPTR)tx_buffer_ptr, RECV_BUFFER_SIZE);	// 刷Cache
		// 复位DMA
//	XAxiDma_Reset(axidma);

	// 3. 启动一次接收
	XAxiDma_SimpleTransfer(axidma, (UINTPTR)rx_buffer_ptr, RECV_BUFFER_SIZE, XAXIDMA_DEVICE_TO_DMA);

	return 0;
}

int zynq_axidma_send(struct AXIDMA_Device *pDev, uint8_t *in, int len, int timeout_ms)
{
	struct AXIDMA_Drv_Data *data = (struct AXIDMA_Drv_Data *)pDev->priv_data;
	XAxiDma *axidma = data->axidma_handle;
	uint8_t *tx_buffer_ptr = data->tx_buffer_ptr;

	// 等待发送通道空闲
//	u32 mm2s_status = XAxiDma_ReadReg(axidma->RegBase, XAXIDMA_SR_OFFSET);

//	while(XAxiDma_Busy(axidma, XAXIDMA_DMA_TO_DEVICE));
	memcpy(tx_buffer_ptr, in, len);
	Xil_DCacheFlushRange((UINTPTR) tx_buffer_ptr, len);	// 刷新Cache
	XAxiDma_SimpleTransfer(axidma, (UINTPTR) tx_buffer_ptr, len, XAXIDMA_DMA_TO_DEVICE);

	// 等待发送完成
	if(pdFALSE == xSemaphoreTake(data->xTxSem, timeout_ms))
	{
		return -1;
	}

	return 0;
}

int zynq_axidma_recv(struct AXIDMA_Device *pDev, uint8_t *out, int *len, int timeout_ms)
{
	struct AXIDMA_Drv_Data *data = (struct AXIDMA_Drv_Data *)pDev->priv_data;
	XAxiDma *axidma = data->axidma_handle;
	static uint8_t msgBuf[AXIDMA_RX_QUEUE_ITEM_SIZE];
	int data_len = 0;
	uint8_t *rx_buffer_ptr = data->rx_buffer_ptr;

	// 调试用
	xil_printf("Queue item num:%d\r\n", uxQueueMessagesWaiting(data->xRxQueue));

	// 函数中启动接收
	XAxiDma_SimpleTransfer(axidma,(UINTPTR)rx_buffer_ptr,RECV_BUFFER_SIZE,XAXIDMA_DEVICE_TO_DMA);

	// 接收消息队列消息
	if(pdPASS != xQueueReceive(data->xRxQueue, &msgBuf, timeout_ms))
	{
		xil_printf("queue recv error!\r\n");
		return -1;
	}

	// 解析纯数据
	Xil_DCacheInvalidateRange((UINTPTR) rx_buffer_ptr, RECV_BUFFER_SIZE);	// 刷新Cache
	MSG_HEAD *pMsgHead = (MSG_HEAD *)msgBuf;
	if( (0x00 == pMsgHead->src_id) && (0x01 == pMsgHead->dst_id) )			// 固定值
	{
		data_len = pMsgHead->length;
		if(data_len <= 0 || data_len > RECV_BUFFER_SIZE )
		{
			return -1;
		}
		memcpy(out, msgBuf+sizeof(MSG_HEAD), data_len);
		*len = data_len;
	}

	// 等待接收完成
//	if(pdFALSE == xSemaphoreTake(data->xRxSem, timeout_ms))
//	{
//		return -1;
//	}

	// 拷贝数据
//	Xil_DCacheInvalidateRange((UINTPTR)rx_buffer_ptr, RECV_BUFFER_SIZE);	// 刷Cache
//	data_len = XAxiDma_ReadReg(axidma->RegBase+(XAXIDMA_RX_OFFSET*XAXIDMA_DEVICE_TO_DMA),XAXIDMA_BUFFLEN_OFFSET);
//
//	memcpy(out, rx_buffer_ptr, data_len);
//	*len = data_len;


	return 0;
}

struct AXIDMA_Drv_Data zynq_axidma0_data = {
	.gic_handle = &xInterruptController,
	.axidma_handle = &AxiDma0,
	.axidma_device_id = DMA_DEV_ID,
	.axidma_tx_int_id = RX_INTR_ID,
	.axidma_rx_int_id = TX_INTR_ID,
	.tx_intr_handler = tx_intr_handler,
	.rx_intr_handler = rx_intr_handler,
	.rx_buffer_ptr = (u8 *) RX_BUFFER_BASE,
	.tx_buffer_ptr = (u8 *) TX_BUFFER_BASE,
};



struct AXIDMA_Device g_zynq_axidma0 = {
	.name = "zynq_axidma0",
	.init = zynq_axidma_init,
	.send = zynq_axidma_send,
	.recv = zynq_axidma_recv,
	.priv_data = &zynq_axidma0_data,
};

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



// 全局的AXIDMA_Device结构体数组
struct AXIDMA_Device *g_axidma_devs[] = {&g_zynq_axidma0};

struct AXIDMA_Device * Get_AXIDMA_Device(char *name)
{
	int i = 0;
	for(i = 0; i < sizeof(g_axidma_devs)/sizeof(g_axidma_devs[0]); i++)
	{
		if(0 == strcmp(name, g_axidma_devs[i]->name))
		{
			return g_axidma_devs[i];
		}
	}
	return NULL;
}

四、一些亟待解决的问题

  1. AXI-DMA驱动验证采用AXI-LOOP的结构,在第二次send的时候没有触发中断,没有recv到相应数据,第三次send触发了中断,recv到了第二次send的数据,后续就差了一拍,可能需要再研究一下。
  2. 可能的原因是只有调用recv的时候才会启动一次接收的传输,这个时候传输已经完成,因此还是需要在中断处理函数中启动下一次接收,这样的recv函数实现需要改变,一种处理方法是中断处理函数中将接收到的数据拷贝到循环缓冲区,recv函数如果循环缓冲区中存在数据,则拷贝数据到out并返回数据长度、如果不存在数据则直接返回。另一种处理方法是外界注册循环缓冲区到该设备中,在main中判断数据是否有效,进行后续处理,并且此时的数据直接从循环缓冲区中得到,这样recv函数并没有实际用途,可以定义为一个空函数。
posted @ 2025-08-09 09:49  gramming  阅读(51)  评论(0)    收藏  举报