ZYNQ SOC案例开发:AXI DMA使用解析及环路测试

一、axi dma介绍
本篇博文讲述axi dma的一些使用总结,硬件ip子系统搭建与sdk c代码封装参考米联客zynq教程。若想让zynq的ps与pl两部分高速数据传输,需要利用ps的hp(高性能)接口通过axi_dma完成数据搬移,这正符合pg021 axi dma v7.1 logicore ip product guide中介绍的axi dma的应用场景:the axi dma provides high-speed data movement between system memory and an axi4-stream-based target ip such as axi ethernet.
如图,axi dma主要包括memory map和 stream两部分接口,前者连接ps子系统,后者则连接带有流接口的pl ip核。
其最简单的事直接寄存器模式(simple dma),这里需要注意地址对齐的问题:当没有使能地址重对齐的情况下,如果axi memory map数据位宽是32bit,则搬移数据所在地址必须在0x0,0x4,0x8等起始地址上。接下来关注dma ip核配置界面主要参数:
axi dma可以有两个传输方向:读通道和写通道,依次为mm2s和s2mm方向。也就是说“读”和“写”是dma主动对cpu发起的操作。重点查看以下几个参数:
1 width of buffer length register:
在直接寄存器模式下,它指定在mm2s_length和s2mm_length寄存器的有效比特数。mm2s_length寄存器指定了mm2s通道传输数据字节数,当cpu写入非零值时开始进行ps到pl的数据搬移,而s2mm_length对应另一个数据流方向。比特数直接与对应寄存器可写入的最大数直接相关,传输最大字节数= 2^(width of buffer length register)。此处保持默认14bit,也就是说启动dma传输的最大数据量是16384byte。
2 memory map data width:
该参数指定了memory map侧数据接口宽度,选定32bit后搬移数据所在内存地址必须与4对齐。
3 max burst size:
之前在讲解ps子系统内部的dma时介绍过dma的burst概念,即分批次传输数据块。官方ip核文档解释为:
理解起来burst size确定了突发周期的最大数值,也就是burst size越大,突发粒度越大(单次传输的数据个数越多)。这与ps端dma有所区别,显然与 ps dma的burst length意义相近。笔者也进行过尝试,当启动传输数据量相同时,burst size设置较大情况下,每批次传输数据量更多。
二、axi dma loop ip子系统
在利用zynq搭建系统时,经常需要利用各种ip核做所谓的“计算加速”,将重复性高 计算量大 占用较大cpu资源的底层处理交给各个ip核完成。这时ps ->dma ->pl -> dma -> ps的环路架构非常适用。这里使用axi stream data fifo代替自定义ip核作为演示,硬件ip子系统如下:
三、sdk 官方demo解析
首先分析下官方的demo。
/******************************************************************************
*
* copyright (c) 2010 - 2016 xilinx, inc. all rights reserved.
*
* permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the software), to deal
* in the software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the software, and to permit persons to whom the software is
* furnished to do so, subject to the following conditions:
*
* the above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the software.
*
* use of the software is limited solely to applications:
* (a) running on a xilinx device, or
* (b) that interact with a xilinx device through a bus or interconnect.
*
* the software is provided as is, without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. in no event shall
* xilinx be liable for any claim, damages or other liability,
* whether in an action of contract, tort or otherwise, arising from, out of
* or in connection with the software or the use or other dealings in the
* software.
*
* except as contained in this notice, the name of the xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this software without prior written authorization from xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xaxidma_example_simple_intr.c
*
* this file demonstrates how to use the xaxidma driver on the xilinx axi
* dma core (axidma) to transfer packets.in interrupt mode when the axidma core
* is configured in simple mode
*
* this code assumes a loopback hardware widget is connected to the axi dma
* core for data packet loopback.
*
* to see the debug print, you need a uart16550 or uartlite in your system,
* and please set -ddebug in your compiler options. you need to rebuild your
* software executable.
*
* make sure that memory_base is defined properly as per the hw system. the
* h/w system built in area mode has a maximum ddr memory limit of 64mb. in
* throughput mode, it is 512mb. these limits are need to ensured for
* proper operation of this code.
*
*
*
* modification history: * * ver who date changes * ----- ---- -------- ------------------------------------------------------- * 4.00a rkv 02/22/11 new example created for simple dma, this example is for * simple dma,added interrupt support for zynq. * 4.00a srt 08/04/11 changed a typo in the rxintrhandler, changed * xaxidma_dma_to_device to xaxidma_device_to_dma * 5.00a srt 03/06/12 added flushing and invalidation of caches to fix crs * 648103, 648701. * added v7 ddr base address to fix cr 649405. * 6.00a srt 03/27/12 changed api calls to support mcdma driver. * 7.00a srt 06/18/12 api calls are reverted back for backward compatibility. * 7.01a srt 11/02/12 buffer sizes (tx and rx) are modified to meet maximum * ddr memory limit of the h/w system built with area mode * 7.02a srt 03/01/13 updated ddr base address for ipi designs (cr 703656). * 9.1 adk 01/07/16 updated ddr base address for ultrascale (cr 799532) and * removed the defines for s6/v6. * 9.2 vak 15/04/16 fixed compilation warnings in the example * *
* ***************************************************************************
*/
/***************************** include files *********************************/
#include xaxidma.h
#include xparameters.h
#include xil_exception.h
#include xdebug.h
#ifdef xpar_uartns550_0_baseaddr
#include xuartns550_l.h /* to use uartns550 */
#endif
#ifdef xpar_intc_0_device_id
#include xintc.h
#else
#include xscugic.h
#endif
/************************** constant definitions *****************************/
/*
* device hardware build related constants.
*/
#define dma_dev_id xpar_axidma_0_device_id
#ifdef xpar_axi_7sddr_0_s_axi_baseaddr
#define ddr_base_addr xpar_axi_7sddr_0_s_axi_baseaddr
#elif xpar_mig7series_0_baseaddr
#define ddr_base_addr xpar_mig7series_0_baseaddr
#elif xpar_mig_0_baseaddr
#define ddr_base_addr xpar_mig_0_baseaddr
#elif xpar_psu_ddr_0_s_axi_baseaddr
#define ddr_base_addr xpar_psu_ddr_0_s_axi_baseaddr
#endif
#ifndef ddr_base_addr
#warning check for the valid ddr address in xparameters.h, /
default set to 0x01000000
#define mem_base_addr 0x01000000
#else
#define mem_base_addr (ddr_base_addr + 0x1000000)
#endif
#ifdef xpar_intc_0_device_id
#define rx_intr_id xpar_intc_0_axidma_0_s2mm_introut_vec_id
#define tx_intr_id xpar_intc_0_axidma_0_mm2s_introut_vec_id
#else
#define rx_intr_id xpar_fabric_axidma_0_s2mm_introut_vec_id
#define tx_intr_id xpar_fabric_axidma_0_mm2s_introut_vec_id
#endif
#define tx_buffer_base (mem_base_addr + 0x00100000)
#define rx_buffer_base (mem_base_addr + 0x00300000)
#define rx_buffer_high (mem_base_addr + 0x004fffff)
#ifdef xpar_intc_0_device_id
#define intc_device_id xpar_intc_0_device_id
#else
#define intc_device_id xpar_scugic_single_device_id
#endif
#ifdef xpar_intc_0_device_id
#define intc xintc
#define intc_handler xintc_interrupthandler
#else
#define intc xscugic
#define intc_handler xscugic_interrupthandler
#endif
/* timeout loop counter for reset
*/
#define reset_timeout_counter 10000
#define test_start_value 0xc
/*
* buffer and buffer descriptor related constant definition
*/
#define max_pkt_len 0x100
#define number_of_transfers 10
/* the interrupt coalescing threshold and delay timer threshold
* valid range is 1 to 255
*
* we set the coalescing threshold to be the total number of packets.
* the receive side will only get one completion interrupt for this example.
*/
/**************************** type definitions *******************************/
/***************** macros (inline functions) definitions *********************/
/************************** function prototypes ******************************/
#ifndef debug
extern void xil_printf(const char *format, ...);
#endif
#ifdef xpar_uartns550_0_baseaddr
static void uart550_setup(void);
#endif
static int checkdata(int length, u8 startvalue);
static void txintrhandler(void *callback);
static void rxintrhandler(void *callback);
static int setupintrsystem(intc * intcinstanceptr,
xaxidma * axidmaptr, u16 txintrid, u16 rxintrid);
static void disableintrsystem(intc * intcinstanceptr,
u16 txintrid, u16 rxintrid);
/************************** variable definitions *****************************/
/*
* device instance definitions
*/
static xaxidma axidma; /* instance of the xaxidma */
static intc intc; /* instance of the interrupt controller */
/*
* flags interrupt handlers use to notify the application context the events.
*/
volatile int txdone;
volatile int rxdone;
volatile int error;
/*****************************************************************************/
/**
*
* main function
*
* this function is the main entry of the interrupt test. it does the following:
* set up the output terminal if uart16550 is in the hardware build
* initialize the dma engine
* set up tx and rx channels
* set up the interrupt system for the tx and rx interrupts
* submit a transfer
* wait for the transfer to finish
* check transfer status
* disable tx and rx interrupts
* print test status and exit
*
* @param none
*
* @return
* - xst_success if example finishes successfully
* - xst_failure if example fails.
*
* @note none.
*
******************************************************************************/
int main(void)
{
int status;
xaxidma_config *config;
int tries = number_of_transfers;
int index;
u8 *txbufferptr;
u8 *rxbufferptr;
u8 value;
txbufferptr = (u8 *)tx_buffer_base ;
rxbufferptr = (u8 *)rx_buffer_base;
/* initial setup for uart16550 */
#ifdef xpar_uartns550_0_baseaddr
uart550_setup();
#endif
xil_printf(/r/n--- entering main() --- /r/n);
config = xaxidma_lookupconfig(dma_dev_id);
if (!config) {
xil_printf(no config found for %d/r/n, dma_dev_id);
return xst_failure;
}
/* initialize dma engine */
status = xaxidma_cfginitialize(&axidma, config);
if (status != xst_success) {
xil_printf(initialization failed %d/r/n, status);
return xst_failure;
}
if(xaxidma_hassg(&axidma)){
xil_printf(device configured as sg mode /r/n);
return xst_failure;
}
/* set up interrupt system */
status = setupintrsystem(&intc, &axidma, tx_intr_id, rx_intr_id);
if (status != xst_success) {
xil_printf(failed intr setup/r/n);
return xst_failure;
}
/* disable all interrupts before setup */
xaxidma_intrdisable(&axidma, xaxidma_irq_all_mask,
xaxidma_dma_to_device);
xaxidma_intrdisable(&axidma, xaxidma_irq_all_mask,
xaxidma_device_to_dma);
/* enable all interrupts */
xaxidma_intrenable(&axidma, xaxidma_irq_all_mask,
xaxidma_dma_to_device);
xaxidma_intrenable(&axidma, xaxidma_irq_all_mask,
xaxidma_device_to_dma);
/* initialize flags before start transfer test */
txdone = 0;
rxdone = 0;
error = 0;
value = test_start_value;
for(index = 0; index txbufferptr[index] = value;
value = (value + 1) & 0xff;
}
/* flush the srcbuffer before the dma transfer, in case the data cache
* is enabled
*/
xil_dcacheflushrange((uintptr)txbufferptr, max_pkt_len);
#ifdef __aarch64__
xil_dcacheflushrange((uintptr)rxbufferptr, max_pkt_len);
#endif
/* send a packet */
for(index = 0; index
status = xaxidma_simpletransfer(&axidma,(uintptr) rxbufferptr,
max_pkt_len, xaxidma_device_to_dma);
if (status != xst_success) {
return xst_failure;
}
status = xaxidma_simpletransfer(&axidma,(uintptr) txbufferptr,
max_pkt_len, xaxidma_dma_to_device);
if (status != xst_success) {
return xst_failure;
}
/*
* wait tx done and rx done
*/
while (!txdone && !rxdone && !error) {
/* nop */
}
if (error) {
xil_printf(failed test transmit%s done,
receive%s done/r/n, txdone? : not,
rxdone? : not);
goto done;
}
/*
* test finished, check data
*/
status = checkdata(max_pkt_len, 0xc);
if (status != xst_success) {
xil_printf(data check failed/r/n);
goto done;
}
}
xil_printf(axi dma interrupt example test passed/r/n);
/* disable tx and rx ring interrupts and return success */
disableintrsystem(&intc, tx_intr_id, rx_intr_id);
done:
xil_printf(--- exiting main() --- /r/n);
return xst_success;
}
#ifdef xpar_uartns550_0_baseaddr
/*****************************************************************************/
/*
*
* uart16550 setup routine, need to set baudrate to 9600 and data bits to 8
*
* @param none
*
* @return none
*
* @note none.
*
******************************************************************************/
static void uart550_setup(void)
{
xuartns550_setbaud(xpar_uartns550_0_baseaddr,
xpar_xuartns550_clock_hz, 9600);
xuartns550_setlinecontrolreg(xpar_uartns550_0_baseaddr,
xun_lcr_8_data_bits);
}
#endif
/*****************************************************************************/
/*
*
* this function checks data buffer after the dma transfer is finished.
*
* we use the static tx/rx buffers.
*
* @param length is the length to check
* @param startvalue is the starting value of the first byte
*
* @return
* - xst_success if validation is successful
* - xst_failure if validation is failure.
*
* @note none.
*
******************************************************************************/
static int checkdata(int length, u8 startvalue)
{
u8 *rxpacket;
int index = 0;
u8 value;
rxpacket = (u8 *) rx_buffer_base;
value = startvalue;
/* invalidate the destbuffer before receiving the data, in case the
* data cache is enabled
*/
#ifndef __aarch64__
xil_dcacheinvalidaterange((u32)rxpacket, length);
#endif
for(index = 0; index if (rxpacket[index] != value) {
xil_printf(data error %d: %x/%x/r/n,
index, rxpacket[index], value);
return xst_failure;
}
value = (value + 1) & 0xff;
}
return xst_success;
}
/*****************************************************************************/
/*
*
* this is the dma tx interrupt handler function.
*
* it gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. otherwise, if a completion interrupt
* is present, then sets the txdone.flag
*
* @param callback is a pointer to tx channel of the dma engine.
*
* @return none.
*
* @note none.
*
******************************************************************************/
static void txintrhandler(void *callback)
{
u32 irqstatus;
int timeout;
xaxidma *axidmainst = (xaxidma *)callback;
/* read pending interrupts */
irqstatus = xaxidma_intrgetirq(axidmainst, xaxidma_dma_to_device);
/* acknowledge pending interrupts */
xaxidma_intrackirq(axidmainst, irqstatus, xaxidma_dma_to_device);
/*
* if no interrupt is asserted, we do not do anything
*/
if (!(irqstatus & xaxidma_irq_all_mask)) {
return;
}
/*
* if error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((irqstatus & xaxidma_irq_error_mask)) {
error = 1;
/*
* reset should never fail for transmit channel
*/
xaxidma_reset(axidmainst);
timeout = reset_timeout_counter;
while (timeout) {
if (xaxidma_resetisdone(axidmainst)) {
break;
}
timeout -= 1;
}
return;
}
/*
* if completion interrupt is asserted, then set the txdone flag
*/
if ((irqstatus & xaxidma_irq_ioc_mask)) {
txdone = 1;
}
}
/*****************************************************************************/
/*
*
* this is the dma rx interrupt handler function
*
* it gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. otherwise, if a completion interrupt
* is present, then it sets the rxdone flag.
*
* @param callback is a pointer to rx channel of the dma engine.
*
* @return none.
*
* @note none.
*
******************************************************************************/
static void rxintrhandler(void *callback)
{
u32 irqstatus;
int timeout;
xaxidma *axidmainst = (xaxidma *)callback;
/* read pending interrupts */
irqstatus = xaxidma_intrgetirq(axidmainst, xaxidma_device_to_dma);
/* acknowledge pending interrupts */
xaxidma_intrackirq(axidmainst, irqstatus, xaxidma_device_to_dma);
/*
* if no interrupt is asserted, we do not do anything
*/
if (!(irqstatus & xaxidma_irq_all_mask)) {
return;
}
/*
* if error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((irqstatus & xaxidma_irq_error_mask)) {
error = 1;
/* reset could fail and hang
* need a way to handle this or do not call it
*/
xaxidma_reset(axidmainst);
timeout = reset_timeout_counter;
while (timeout) {
if(xaxidma_resetisdone(axidmainst)) {
break;
}
timeout -= 1;
}
return;
}
/*
* if completion interrupt is asserted, then set rxdone flag
*/
if ((irqstatus & xaxidma_irq_ioc_mask)) {
rxdone = 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.
*
******************************************************************************/
static int setupintrsystem(intc * intcinstanceptr,
xaxidma * axidmaptr, u16 txintrid, u16 rxintrid)
{
int status;
#ifdef xpar_intc_0_device_id
/* initialize the interrupt controller and connect the isrs */
status = xintc_initialize(intcinstanceptr, intc_device_id);
if (status != xst_success) {
xil_printf(failed init intc/r/n);
return xst_failure;
}
status = xintc_connect(intcinstanceptr, txintrid,
(xinterrupthandler) txintrhandler, axidmaptr);
if (status != xst_success) {
xil_printf(failed tx connect intc/r/n);
return xst_failure;
}
status = xintc_connect(intcinstanceptr, rxintrid,
(xinterrupthandler) rxintrhandler, axidmaptr);
if (status != xst_success) {
xil_printf(failed rx connect intc/r/n);
return xst_failure;
}
/* start the interrupt controller */
status = xintc_start(intcinstanceptr, xin_real_mode);
if (status != xst_success) {
xil_printf(failed to start intc/r/n);
return xst_failure;
}
xintc_enable(intcinstanceptr, txintrid);
xintc_enable(intcinstanceptr, rxintrid);
#else
xscugic_config *intcconfig;
/*
* initialize the interrupt controller driver so that it is ready to
* use.
*/
intcconfig = xscugic_lookupconfig(intc_device_id);
if (null == intcconfig) {
return xst_failure;
}
status = xscugic_cfginitialize(intcinstanceptr, intcconfig,
intcconfig->cpubaseaddress);
if (status != xst_success) {
return xst_failure;
}
xscugic_setprioritytriggertype(intcinstanceptr, txintrid, 0xa0, 0x3);
xscugic_setprioritytriggertype(intcinstanceptr, rxintrid, 0xa0, 0x3);
/*
* connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
status = xscugic_connect(intcinstanceptr, txintrid,
(xil_interrupthandler)txintrhandler,
axidmaptr);
if (status != xst_success) {
return status;
}
status = xscugic_connect(intcinstanceptr, rxintrid,
(xil_interrupthandler)rxintrhandler,
axidmaptr);
if (status != xst_success) {
return status;
}
xscugic_enable(intcinstanceptr, txintrid);
xscugic_enable(intcinstanceptr, rxintrid);
#endif
/* enable interrupts from the hardware */
xil_exceptioninit();
xil_exceptionregisterhandler(xil_exception_id_int,
(xil_exceptionhandler)intc_handler,
(void *)intcinstanceptr);
xil_exceptionenable();
return xst_success;
}
/*****************************************************************************/
/**
*
* this function disables the interrupts for dma engine.
*
* @param intcinstanceptr is the pointer to the intc component instance
* @param txintrid is interrupt id associated w/ dma tx channel
* @param rxintrid is interrupt id associated w/ dma rx channel
*
* @return none.
*
* @note none.
*
******************************************************************************/
static void disableintrsystem(intc * intcinstanceptr,
u16 txintrid, u16 rxintrid)
{
#ifdef xpar_intc_0_device_id
/* disconnect the interrupts for the dma tx and rx channels */
xintc_disconnect(intcinstanceptr, txintrid);
xintc_disconnect(intcinstanceptr, rxintrid);
#else
xscugic_disconnect(intcinstanceptr, txintrid);
xscugic_disconnect(intcinstanceptr, rxintrid);
#endif
}
xaxidma_example_simple_intr.c
主函数中依次完成了:dma初始化,建立中断系统,使能dma中断,初始化标志位及发送数据,启动dma传输以及数据检测。中断部分的内容与ps dma非常相近,传输完成后进入的中断函数中仅置位了发送或接收完成标志位:
static void txintrhandler(void *callback)
{
u32 irqstatus;
int timeout;
xaxidma *axidmainst = (xaxidma *)callback;
/* read pending interrupts */
irqstatus = xaxidma_intrgetirq(axidmainst, xaxidma_dma_to_device);
/* acknowledge pending interrupts */
xaxidma_intrackirq(axidmainst, irqstatus, xaxidma_dma_to_device);
/*
* if no interrupt is asserted, we do not do anything
*/
if (!(irqstatus & xaxidma_irq_all_mask)) {
return;
}
/*
* if error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((irqstatus & xaxidma_irq_error_mask)) {
error = 1;
/*
* reset should never fail for transmit channel
*/
xaxidma_reset(axidmainst);
timeout = reset_timeout_counter;
while (timeout) {
if (xaxidma_resetisdone(axidmainst)) {
break;
}
timeout -= 1;
}
return;
}
/*
* if completion interrupt is asserted, then set the txdone flag
*/
if ((irqstatus & xaxidma_irq_ioc_mask)) {
txdone = 1;
}
}
/*****************************************************************************/
/*
*
* this is the dma rx interrupt handler function
*
* it gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. otherwise, if a completion interrupt
* is present, then it sets the rxdone flag.
*
* @param callback is a pointer to rx channel of the dma engine.
*
* @return none.
*
* @note none.
*
******************************************************************************/
static void rxintrhandler(void *callback)
{
u32 irqstatus;
int timeout;
xaxidma *axidmainst = (xaxidma *)callback;
/* read pending interrupts */
irqstatus = xaxidma_intrgetirq(axidmainst, xaxidma_device_to_dma);
/* acknowledge pending interrupts */
xaxidma_intrackirq(axidmainst, irqstatus, xaxidma_device_to_dma);
/*
* if no interrupt is asserted, we do not do anything
*/
if (!(irqstatus & xaxidma_irq_all_mask)) {
return;
}
/*
* if error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((irqstatus & xaxidma_irq_error_mask)) {
error = 1;
/* reset could fail and hang
* need a way to handle this or do not call it
*/
xaxidma_reset(axidmainst);
timeout = reset_timeout_counter;
while (timeout) {
if(xaxidma_resetisdone(axidmainst)) {
break;
}
timeout -= 1;
}
return;
}
/*
* if completion interrupt is asserted, then set rxdone flag
*/
if ((irqstatus & xaxidma_irq_ioc_mask)) {
rxdone = 1;
}
}
intrhandler
 dma启动传输部分如下,调用库函数xaxidma_simpletransfer。以第一个为例,是将rxbufferptr为数据首地址,max_pkt_len为字节数,xaxidma_device_to_dma为传输方向启动dma传输数据。max_pkt_len不能超过之前ip核配置参数指定的16384byte,xaxidma_device_to_dma和xaxidma_dma_to_device依次指pl-> dma ->ps以及ps->dma -> pl方向,也就是pl就是其中的device。dma启动函数只有一个地址,这是与ps端dma最大的区别,因为数据搬移的另一侧是带有无地址的流接口的ip核,该侧“地址”由硬件连接决定。
再来看看搬移数据内存首地址rxbufferptr和txbufferptr.从下边的定义可见mem_base_addr是ddr_base_addr加上一段偏移量的结果,ddr基地址数值从xparameters.h中查看。
四、函数重用封装
官方的代码比较乱,都写在main函数里,米联客教程init_intr_sys()函数完成整个中断系统的建立,将官方demo中main函数dma测试之前关于中断部分的代码全部封装其中,包括dma中断初始化,中断控制器初始化,使能中断异常,连接dma发送与接收中断,dma中断使能五个过程。
五、axi总线信号ila波形分析
axi stream主要接口:
tdata:数据tkeep:字节有效指示tlast:帧尾指示tready:准备就绪tvalid:数据有效指示
mm2s方向一旦tvalid拉高则触发ila抓取信号波形。一帧数据有64个,每个数据32bit(4byte),一共正好为c代码中max_pkt_len数值,即256byte。
其中他keep信号比较关键。如当stream位宽为16bit,传输数据量为255byte时,tkeep信号在最后一个stream数据对应位置是2'b01指示第128个16bit数中最后一个数的高字节为upsize过程中无效填充数据。
后续本人会利用system generator设计算法ip,之后集成到ip integerator中作为cpu外设进行板级验证。继续学习!


塑料外壳应用超声波焊接的优势是什么
CoolRunner-II CPLD实现GPS系统
名爵全新MG5正式上市,年轻人首辆车的最佳选择
销量过于惨淡 Xbox One日本销量被PS4碾压 微软可不轻易服输
辊锻机飞轮轴承位磨损的原因及修复方法
ZYNQ SOC案例开发:AXI DMA使用解析及环路测试
MLCC价格只涨不跌_需警惕价格操纵
【PCBA方案开发设计】无刷电机和数字气压传感器的打气泵方案
STM32 Power Shield用于IoT设备的超低功耗监控板
一阶电路的全响应和三要素法
基于单片机的TM卡水表控制系统设计
何时使用 Fly-Buck 解决方案更好
我国卫星移动通信系统情况分析
华为荣耀畅玩7X发布会精彩盘点回顾:配置、外观、拍照、续航汇总,价格1299起步
最新的两款小米手机,小米6和小米max2你喜欢小的还是大的?
开关电源如何调节电压?
电源模块可靠性测试方式介绍
CPU综述
navicat的数据迁移工具
利用声发射技术研究铸态Ti46Al8Nb合金疲劳寿命