1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Ty for the answer. I'm having different results if I Disable the Cache but I'm still not getting the right results.. I have some questions for you. 1-Parameters port has a TREADY and a TVALID so isn't that assertion to '1' done automatically? And if should I then connect the M_AXIS_MM2S tready and tvalid to gpio ports and assign them to '1' when I want? 2-I'm not understanding this cache thing very well. So I need to flush the Address for which I write the initialize_parameters after I write them to the DDR?I thought flush was to clean a given address \$\endgroup\$ – João Pereira May 14 '15 at 10:27
  • \$\begingroup\$ Tried the ILa probes again and without any modification TDATA is now 000000...00 instead of the value in the printscreen. Do you have any idea on wtf is happening mate? \$\endgroup\$ – João Pereira May 14 '15 at 11:03
  • \$\begingroup\$ 1. The producer (in that case, AXI-DMA) drives tvalid as a mean to say "I've got data ready". The consumer (your IP) drives the tready to say "I'm ready to get data". Your're IP has to drive tready, otherwise if tvalid = '1' and tready = '0' like in your ila picture, the transfer stalls. You can't assign tvalid, you don't have control over it (it's owned by the DMA). You have to connect tready to what you want (not tvalid...). Either you're always ready for data (constant '1'), you use a FIFO to buffer input (connect to !full) or something else. \$\endgroup\$ – Jonathan Drolet May 14 '15 at 14:09
  • \$\begingroup\$ 2. I suggest you read about processor caches, there should be plenty informations on the internet. Basically, external memory is slow, so processors has a cache in-between them and the external memory. When you make a memory access, the cache verifies if that address is in the cache, if yes, returns the data without accessing external memory, if no, transfer from the memory to the cache, then the cache to processor. The problem is when the memory changes and the processor is not responsible, like it happens when you use AXI-DMA (since it's not connected to cache). Same logic applies to write. \$\endgroup\$ – Jonathan Drolet May 14 '15 at 14:12
  • \$\begingroup\$ 3. If the issue is cache-related, the AXI-DMA sends whatever is at that memory location at power-up. As long as you don't power-down the board, the memory location you use for data could be filled with '0' or random data from past program execution. Did you look the M_AXI_GP0 transfers? Do you see SrcAddress in there? \$\endgroup\$ – Jonathan Drolet May 14 '15 at 14:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.