在ZYNQ上用AXI DMA从DDR中的数组向PL端发送数据,AXI DMA工作在Simple模式下,初始化正常,DMA没有工作在SG模式下,
if (XAxiDma_HasSg(DMAPtr)) {
xil_printf("Device configured as SG mode \r\n");
return XST_FAILURE;
}
程序工作到
status = XAxiDma_SimpleTransfer(&DMAPtr, (UINTPTR) rxbuffer,
MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);
传输失败,失败原因是:在该函数中判断DMA工作在SG模式下,
/* If Scatter Gather is included then, cannot submit
*/
if (XAxiDma_HasSg(InstancePtr)) {
xdbg_printf(XDBG_DEBUG_ERROR, "Simple DMA mode is not"
" supported\r\n");
xil_printf("1");
return XST_FAILURE;
}
想请教一下可能的错误原因
完整代码如下:
/******************************************************************************
****************主程序
*
******************************************************************************/
#include "DMA.h"
#include <stdio.h>
#include "sys_intr.h"
#include "xparameters.h"
#include "netif/xadapter.h"
#include "platform.h"
#include "platform_config.h"
#if defined (__arm__) || defined(__aarch64__)
#include "xil_printf.h"
#endif
#include "lwip/tcp.h"
#include "xil_cache.h"
/* defined by each RAW mode application */
void print_app_header();
int start_application();
int transfer_data();
void tcp_fasttmr(void);
void tcp_slowtmr(void);
/* missing declaration in lwIP */
void lwip_init();
XAxiDma axidma; //XAxiDma实例
XScuGic intc; //中断生成控制器实例
extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;
static struct netif server_netif;
struct netif *echo_netif;
int transfer_data(XAxiDma *DMAPtr) {
int status;
if(start_update_flag){
xil_printf("\r\nStart Waveform Output\r\n");
xil_printf("waveform size is %lu Bytes\r\n",total_bytes);
Xil_DCacheFlushRange((UINTPTR) rxbuffer, MAX_PKT_LEN); //刷锟斤拷Data Cache
status = XAxiDma_SimpleTransfer(&DMAPtr, (UINTPTR) rxbuffer,
MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
// xil_printf("Update DMA Error!\r\n");
// else
// total_bytes = 0;
}
start_update_flag = 0;
return 0;
}
void
print_ip(char *msg, struct ip_addr *ip)
{
print(msg);
xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),
ip4_addr3(ip), ip4_addr4(ip));
}
void
print_ip_settings(struct ip_addr *ip, struct ip_addr *mask, struct ip_addr *gw)
{
print_ip("Board IP: ", ip);
print_ip("Netmask : ", mask);
print_ip("Gateway : ", gw);
}
int init_intr_sys(){
DMA_Intr_Init(&axidma,0); //将ID为0的DMA和DMA实例绑定,并进行初始化
Init_Intr_System(&intc);
Setup_Intr_Exception(&intc);
DMA_Setup_Intr_System(&intc,&axidma,TX_INTR_ID);//setup dma interrpt system
DMA_Intr_Enable(&intc,&axidma);
}
int main()
{
struct ip_addr ipaddr, netmask, gw;
/* the mac address of the board. this should be unique per board */
unsigned char mac_ethernet_address[] =
{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
echo_netif = &server_netif;
init_platform();
init_intr_sys(); //系统初始化
/* initliaze IP addresses to be used */
IP4_ADDR(&ipaddr, 192, 168, 1, 10);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
print_app_header();
lwip_init();
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(echo_netif, &ipaddr, &netmask,
&gw, mac_ethernet_address,
PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\n\r");
return -1;
}
netif_set_default(echo_netif);
/* now enable interrupts */
platform_enable_interrupts();
/* specify that the network if is up */
netif_set_up(echo_netif);
ipaddr.addr = echo_netif->ip_addr.addr;
gw.addr = echo_netif->gw.addr;
netmask.addr = echo_netif->netmask.addr;
print_ip_settings(&ipaddr, &netmask, &gw);
/* start the application (web server, rxtest, txtest, etc..) */
start_application();
/* receive and process packets */
while (1) {
if (TcpFastTmrFlag) {
tcp_fasttmr();
TcpFastTmrFlag = 0;
}
if (TcpSlowTmrFlag) {
tcp_slowtmr();
TcpSlowTmrFlag = 0;
}
xemacif_input(echo_netif); //将网口的数据送到lwip中
transfer_data(&axidma);
}
/* never reached */
cleanup_platform();
return 0;
}
/***************************** Include Files与DMA 相关的函数*****************************/
#include "DMA.h"
volatile int tx_done; //DMA传输中断完成标志位
volatile int error; //DMA发送出错
void tx_intr_handler(void *callback)
{
int timeout;
u32 irq_status;
XAxiDma *axidma_inst = (XAxiDma *) callback;
irq_status = XAxiDma_IntrGetIrq(axidma_inst, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrAckIrq(axidma_inst, irq_status, XAXIDMA_DMA_TO_DEVICE);
if ((irq_status & XAXIDMA_IRQ_ERROR_MASK)) {
error = 1;
XAxiDma_Reset(axidma_inst);
timeout = RESET_TIMEOUT_COUNTER;
while (timeout) {
if (XAxiDma_ResetIsDone(axidma_inst))
break;
timeout -= 1;
}
return;
}
if ((irq_status & XAXIDMA_IRQ_IOC_MASK))
tx_done = 1;
}
/*****************************************************************************/
/*
*
* This function setups the interrupt system so interrupts can occur for the
* DMA, it assumes INTC component exists in the hardware system.
*
* @param IntcInstancePtr is a pointer to the instance of the INTC.
* @param AxiDmaPtr is a pointer to the instance of the DMA engine
* @param TxIntrId is the TX channel Interrupt ID.
* @param RxIntrId is the RX channel Interrupt ID.
*
* @return
* - XST_SUCCESS if successful,
* - XST_FAILURE.if not succesful
*
* @note None.
*
******************************************************************************/
int DMA_Setup_Intr_System(XScuGic * int_ins_ptr,XAxiDma * axidma_ptr, u16 tx_intr_id)
{
int status;
XScuGic_Config *intc_config;
//设置DMA发送中断优先级和触发方式
XScuGic_SetPriorityTriggerType(int_ins_ptr, tx_intr_id, 0xA0, 0x3);
//设置DMA发送中断服务函数
status = XScuGic_Connect(int_ins_ptr, tx_intr_id,
(Xil_InterruptHandler) tx_intr_handler, axidma_ptr);
if (status != XST_SUCCESS) {
return status;
}
XScuGic_Enable(int_ins_ptr, tx_intr_id);
return XST_SUCCESS;
}
void disable_intr_system(XScuGic * int_ins_ptr, u16 tx_intr_id,
u16 rx_intr_id)
{
XScuGic_Disconnect(int_ins_ptr, tx_intr_id);
}
int DMA_Intr_Init(XAxiDma *DMAPtr,u32 DeviceId)
{
int status;
XAxiDma_Config *config=NULL;
config = XAxiDma_LookupConfig(DeviceId); //查看该ID对应的硬件设备的硬件信息
if (!config) {
xil_printf("No config found for %d\r\n", DMA_DEV_ID);
return XST_FAILURE;
}
//将DMA实例和DMA的硬件信息绑定
status = XAxiDma_CfgInitialize(DMAPtr, config);
if (status != XST_SUCCESS) {
xil_printf("Initialization failed %d\r\n", status);
return XST_FAILURE;
}
if (XAxiDma_HasSg(DMAPtr)) {
xil_printf("Device configured as SG mode \r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
int DMA_Intr_Enable(XScuGic * IntcInstancePtr,XAxiDma *DMAPtr)
{
/* Disable all interrupts before setup */
XAxiDma_IntrDisable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
/*
XAxiDma_IntrDisable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
*/
/* Enable all interrupts */
XAxiDma_IntrEnable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
/*
XAxiDma_IntrEnable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
*/
return XST_SUCCESS;
}
/************************程序的其他源文件*********************************/
#include <stdio.h>
#include <string.h>
#include "xil_printf.h"
#include "echo.h"
#include "DMA.h"
#include "xaxidma.h"
#include "lwip/err.h"
#include "lwip/tcp.h"
#if defined (__arm__) || defined (__aarch64__)
#include "xil_printf.h"
#endif
int i;
u8 start_update_flag = 0;
//u8 rxbuffer[MAX_FLASH_LEN]; //锟斤拷DMA锟斤拷锟斤拷锟斤拷锟捷碉拷fifo锟侥碉拷址锟斤拷TX_BUFFER_BASE
u8 rxbuffer[MAX_FLASH_LEN];
//u8 *tx_buffer_ptr = (u8 *)TX_BUFFER_BASE;
u32 total_bytes = 0;
struct tcp_pcb *c_pcb;
void print_app_header()
{
xil_printf("\n\r\n\r-----lwIP TCP wave transfer ------\n\r");
xil_printf("TCP packets sent to port 7 generate wave through ZYNQ\n\r");
}
err_t recv_callback(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err)
{
struct pbuf *q;
// xil_printf("rxbuffer address:%p\n\r",&tx_buffer_ptr[total_bytes]);
/* do not read the packet if we are not in ESTABLISHED state */
if (!p) {
tcp_close(tpcb);
tcp_recv(tpcb, NULL);
return ERR_OK;
}
q = p;
if (q->tot_len == 6 && !(memcmp("update", p->payload, 6))) {
start_update_flag = 1;
} else if (q->tot_len == 5 && !(memcmp("clear", p->payload, 5))) {
start_update_flag = 0;
total_bytes = 0;
xil_printf("Clear received data\r\n");
} else {
while (q->tot_len != q->len) {
memcpy(&rxbuffer[total_bytes], q->payload, q->len);
total_bytes += q->len;
q = q->next;
}
memcpy(&rxbuffer[total_bytes], q->payload, q->len);
total_bytes += q->len;
}
/* indicate that the packet has been received */
tcp_recved(tpcb, p->len);
/* free the received pbuf */
pbuf_free(p);
return ERR_OK;
}
err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
xil_printf("tcp_server: Connection Accepted\r\n");
c_pcb = newpcb;
/* set the receive callback for this connection */
tcp_recv(c_pcb, recv_callback);
tcp_arg(c_pcb, NULL);
return ERR_OK;
}
int start_application()
{
int status;
struct tcp_pcb *pcb;
err_t err;
XAxiDma_Config *config;
//tx_buffer_ptr = (u8 *) rxbuffer; //DMA锟斤拷锟斤拷指锟斤拷指锟斤拷锟轿伙拷锟斤拷锟斤拷
/* create new TCP PCB structure */
pcb = tcp_new();
if (!pcb) {
xil_printf("Error creating PCB. Out of Memory\n\r");
return -1;
}
/* bind to specified @port */
err = tcp_bind(pcb, IP_ADDR_ANY, portsever);
if (err != ERR_OK) {
xil_printf("Unable to bind to port %d: err = %d\n\r", portsever, err);
return -2;
}
/* we do not need any arguments to callback functions */
tcp_arg(pcb, NULL);
/* listen for connections */
pcb = tcp_listen(pcb);
if (!pcb) {
xil_printf("Out of memory while tcp_listen\n\r");
return -3;
}
/* specify callback to use for incoming connections */
tcp_accept(pcb, accept_callback);
xil_printf("TCP server started @ port %d\n\r", portsever);
return 0;
}