MM2S simple transfer gone wrong

ddrdmavivadoxilinx

I followed some examples and I already managed to make a big S2MM (stream to memory-mapped) transfer via an AXI DMA.

However, now I'm trying the reverse, i.e. to make a simple MM2S transfer to a very simple IP block that I made and the result returned from the block is wrong. Note that the MM2S code is also almost a copy from examples that I found.

I tried debugging with the ILA(integrated Logic Analyzer) tool from Vivado and the result is in attachement.

Can you help me understand why I'm writing the following values:

static void initialize_parameters(u32 SrcAddress){
u32 *BufferPtr;
union float32 thisfloat;

BufferPtr=(u32*)(SrcAddress);
thisfloat.f32=10.0;
BufferPtr[0]=thisfloat.u32;

thisfloat.f32=0.0;
BufferPtr[1]=thisfloat.u32;

thisfloat.f32=10.0;
BufferPtr[2]=thisfloat.u32;

thisfloat.f32=20.0;
BufferPtr[3]=thisfloat.u32;

}

and making a transfer like this:

// Kick off DMA transfers
Status = XAxiDma_SimpleTransfer(&axi_dma, PARAMETERS_ADDR, 4*4, XAXIDMA_DMA_TO_DEVICE);

and the signal parameters_TDATA when tvalid=1 is that thing that we can see in attachement? Also, the final result is incorrect.
What am I doing wrong?
enter image description here

Also, here's a print screen of my block design in Vivado.
Note: I'm working on a Zedboard
enter image description here

Best Answer

It seems to work, well, almost. First error I see is that you do not drive axis_tready. Per the AXI-Stream specification, a data-beat is valid only if both axis_tready and axis_tvalid are '1'. The AXI DMA drives axis_tvalid as expected, but do not complete the transfer of 4 dwords since axis_tready is not driven. However, the general transfer seems to work as expected.

I would bet that you have a cache problem. When initialize_parameters is executed, it writes the data to the cache, and if you start the DMA transfer before the cache is flushed to DDR, you won't read what you wrote, but what was is still in the DDR. I don't have much experience with the Zynq and it's extensive cache system, so you have to figure out yourself how to flush the cache properly. The functions you seek are the flush functions from "xil_cache_l.h", on microblaze I would use Xil_DCacheFlushRange(SrcAddress, 4*4). Looking at the code, it seems to flush L1 and L2 caches on Zynq, so it's probably all you need. If it doesn't work, try writing a megabyte of data, you will be sure the first 4 dwords are flushed that way.

Since you have the ILA for the AXI bus, you should be able to verify if there is a write transaction at address SrcAddress, if there is not before the AXI dma transaction you will know this is a cache issue.

On a side note, when you read using the AXI-DMA, you should do a cache invalidate before reading from the DDR. Otherwise, if you read at SrcAddress, start the DMA Transfer and read again at ScrAddress, you will read the old value still in cache.