Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Altera_Forum
Honored Contributor I
1,451 Views

DMA Transfer problem

Hi,  

I am trying to do a simple DMA mem to mem transfer as per the "Chap24: DMA controller core " example. 

I have been at this for almost a week now and it is still not working for me. Can you please help me.  

 

The dma transfer is getting stuck in the "while(!txrx_done)" loop. I am not getting any error messages. 

 

Here is the status of my registers just before it enters the "while loop". 

readaddress =800000, writeaddress =801000, length =80, status =2, control =fc  

 

Here are the details of my setup:  

I am using the DE2 board. 

First in Qsys: DMA Controller 

DMA Read Master -> SDRAM Controller slave 

DMA Write Master -> SDRAM Controller slave 

DMA Control-port Slave-> CPU Data Master 

 

niosii code: 

 

staticvolatileint txrx_done = 0; 

 

 

static 

void txrxdone(void * handle, void * data) 

 

txrx_done = 1; 

 

 

 

init code: 

 

 

alt_dma_txchan txchan; 

alt_dma_rxchan rxchan; 

alt_u32* tx_data = (alt_u32*)0x800000; 

 

 

alt_u32* rx_buffer = (alt_u32*)(0x801000); 

 

 

// Create the transmit channel 

if ((txchan = alt_dma_txchan_open("/dev/dma_0")) == NULL) 

printf ("Failed to open transmit channel\n"); 

exit (1); 

 

 

 

 

// Create the receive channel 

if ((rxchan = alt_dma_rxchan_open("/dev/dma_0")) == NULL) 

printf ("Failed to open receive channel\n"); 

exit (1); 

 

 

 

setting up transfer: 

 

printf("Setting up DMA\n"); 

// Post the transmit request 

if ((rc1 = alt_dma_txchan_send (txchan, 

tx_data, 

128, 

NULL, 

NULL)) < 0) 

printf ("Failed to post transmit request, reason = %i\n", rc1); 

exit (1); 

 

 

 

 

&#12288; 

if ((rc1 = alt_dma_rxchan_prepare (rxchan, 

rx_buffer, 

128, 

txrxDone, 

NULL)) < 0) 

printf ("Failed to post read request, reason = %i\n", rc1); 

exit (1); 

while (!txrx_done); 

 

 

printf ("Transfer successful!\n"); 

 

 

 

Please help! 

0 Kudos
14 Replies
Altera_Forum
Honored Contributor I
37 Views

You have ensured you don't have anything at those locations right? For example it would be really bad if you had a code or data section located at the source or destination address since you code + DMA overwrites those locations.

Altera_Forum
Honored Contributor I
37 Views

Thanks for your note. 

 

As far as I know I don't have anything in this location.  

In this example I am doing nothing else but this, not sure if the CPU is using the same resource. Is there a way to find out if this memory is being used ? 

 

Or is there a safe section of the memory I can try out this in ? Please suggest if there any other test I can do to see the DMA working. It has never worked for me.  

 

 

Regards, 

N
Altera_Forum
Honored Contributor I
37 Views

You could create a linker section in those locations that prevent the linker from placing any sections in there. The lazy way to test this would be to dynamically allocate those two buffers using a malloc to ensure the linker doesn't put anything there. You can't pick a location that could potentially be used by the processor at run time without ensuring precautions are taken. So it's possible that your code is stomping on itself and causing things to go off in the weeds.

Altera_Forum
Honored Contributor I
37 Views

I tired using malloc and also using alt_uncached_malloc - No luck.:( 

 

Still getting stuck in the while loop. 

Here are my DMA settings jus before the While loop: 

readaddress =827418,  

writeaddress =827820,  

length =80,  

status =2,  

control =fc 

 

Is my Qsys setup OK ? 

 

 

Altera_Forum
Honored Contributor I
37 Views

If you use the uncached malloc make sure you pass a pointer to the DMA that is masked with 0x7FFF_FFFF. Uncached pointers have the upper bit set which is the cache bypassing mechanism Nios II uses without an MMU. If you used regular malloc the worst that can happen is a cache coherency issue between the DMA and CPU, that wouldn't cause your waiting loop to get stuck. 

 

I can't tell if your Qsys system is wired up correctly without seeing a screenshot of it.
Altera_Forum
Honored Contributor I
37 Views

Here is my Qsys image.  

 

 

Thanks.
Altera_Forum
Honored Contributor I
37 Views

That looks fine to me, how is the DMA parameterized? I seem to recall some bugs if you attempt to perform 64 or 128 bit transfers but given your system I don't think you would need such a wide DMA.

Altera_Forum
Honored Contributor I
37 Views

Here is my DMA controller settings. 

 

Width of DMA length Register = 13 

Enable Burst Transfer not checked 

FIFO Depth 32 

Construnct FIFO from Mem blocks checked 

Under Advanced - only WORD is clicked.
Altera_Forum
Honored Contributor I
37 Views

Try enabling the 8 and 16 bit options as well. It's been a really long time but I seem to recall a bug occuring when those options are disabled.

Altera_Forum
Honored Contributor I
37 Views

Tried that as well. No Luck.  

 

Next I am planning to strip all the unnecessary peripherals from the system and test again.  

 

I will let you know how that goes. 

 

Thanks.
Altera_Forum
Honored Contributor I
37 Views

After you have a minimal system, if you still see the problem I would simulate the software running on the CPU. You might see something in the simulation that will give you a clue as to what is happening. 

 

Another thing you could try is using the macro file from the DMA driver and write the source, destination, and control fields directly to see if the behavior is any different. I forget what the file is called but it will probably be something like "altera_dma_regs.h".
Altera_Forum
Honored Contributor I
37 Views

Created a minimal system. And used direct commands as you suggested. 

Still no luck :(. No clue on what's going on! I will try to simulate it next. 

I have attached the Qsys screen shot. 

 

 

IOWR_ALTERA_AVALON_DMA_STATUS(DMA_0_BASE, 0x00); 

IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_0_BASE, SDRAM_0_BASE); 

IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_0_BASE, SDRAM_0_BASE+0x1000); 

IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_0_BASE, 128); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_0_BASE, 0x008C); 

printf("Setting up DMA\n"); 

 

while (!(IORD_ALTERA_AVALON_DMA_STATUS(DMA_0_BASE)==0)); 

 

&#12288; 

printf ("Transfer successful!\n"); 

 

Results on the console: 

 

Setting up DMA 

readaddress =800000, writeaddress =801000, length =80, status =2, control =8c  

Altera_Forum
Honored Contributor I
37 Views

After you write the control register I would expect the status register bits [1:0] to be non-zero (either busy transferring or done). As a result you have while (!(non_zero_value == 0)); .... or in other words an infinite loop. You should mask the busy bit and keep looping until it is set: 

 

while ( ((IORD_ALTERA_AVALON_DMA_STATUS(DMA_0_BASE) & ALTERA_AVALON_DMA_STATUS_DONE_MSK) != ALTERA_AVALON_DMA_STATUS_DONE_MSK ) { 

// spin 

 

If that software change still doesn't work run it in the simulation since it'll be easier to debug with the driver out of the way.
Altera_Forum
Honored Contributor I
37 Views

I was able to make the code work on an old Nios II devlopement Kit  

Cyclone II edition.  

 

Thsi means that the problem is probabily related to hardware or Qsys in the DE2 board. It is strange I am able to read and write but DMA access does not work. I will investigate that further.