一、来源介绍
- 参考韦东山的直播视频课
- 基本思想学习自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;
}
四、一些亟待解决的问题
- AXI-DMA驱动验证采用AXI-LOOP的结构,在第二次send的时候没有触发中断,没有recv到相应数据,第三次send触发了中断,recv到了第二次send的数据,后续就差了一拍,可能需要再研究一下。
- 可能的原因是只有调用recv的时候才会启动一次接收的传输,这个时候传输已经完成,因此还是需要在中断处理函数中启动下一次接收,这样的recv函数实现需要改变,一种处理方法是中断处理函数中将接收到的数据拷贝到循环缓冲区,recv函数如果循环缓冲区中存在数据,则拷贝数据到out并返回数据长度、如果不存在数据则直接返回。另一种处理方法是外界注册循环缓冲区到该设备中,在main中判断数据是否有效,进行后续处理,并且此时的数据直接从循环缓冲区中得到,这样recv函数并没有实际用途,可以定义为一个空函数。