Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12589 Discussions

About DMA problem..please help me

Altera_Forum
Honored Contributor II
3,668 Views

hi all 

I have try the altera memory test project with Nios II IDE.. 

but always display "-Testing memory using DMA"... http://forum.niosforum.com/work2/style_emoticons/<#EMO_DIR#>/sad.gif  

the dma might be already open.. 

and didn`t display "Memory at 0x%X Okay"....... 

 

so...I found the code at nios forum...it should be work  

but it always display"wait for transfer to complete"...why? 

look like the same problem with memory test !? 

 

I use Quartus II 5.1 SP2 & Nios II IDE 5.1 SP1 

the exception address is sram_0 at SOPC Builder 

the program memory & .rodata & .rwdata & heap memory & stack memory are sdram_0 

 

and I sure I have connect the DMA read & write master with sdram_0 & avalon tristate bridge in the SOPC builder 

 

this is the code...please help me  

thanks.... 

# include <stdio.h># include "system.h"# include "sys/alt_dma.h"# include "alt_types.h" 

 

/* Create the transmit channel */ 

static volatile int rx_done = 0; 

 

/* ready handler*/ 

static void done (void* handle, void* data) 

rx_done++; 

 

int main (int argc, char* argv[], char* envp[]) 

int rc; 

alt_u8 Inbuf[1024], Outbuf[1024]; 

alt_dma_txchan txchan; 

alt_dma_rxchan rxchan; 

 

void* tx_data = (void*) &Inbuf[0]; /* pointer to data to send */ 

void* rx_buffer = (void*) &Outbuf[0]; /* pointer to rx buffer */ 

 

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

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

exit (1); 

/* Create the receive channel */ 

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

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

exit (1); 

/* Post the transmit request */ 

if ((rc = alt_dma_txchan_send (txchan,tx_data,1024,NULL,NULL)) < 0) 

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

exit (1); 

/* Post the receive request */ 

if ((rc = alt_dma_rxchan_prepare (rxchan,rx_buffer,1024,done,NULL)) < 0) 

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

exit (1); 

/* wait for transfer to complete */ 

printf ("wait for transfer to complete\n"); 

while (!rx_done); 

printf("Transfer successful!\n"); 

return 0; 

}
0 Kudos
30 Replies
Altera_Forum
Honored Contributor II
1,535 Views

im also having the same kind of problem.. 

the memory test program example (provided in nios eds) stuck at "-testing memory using dma".unfortunately i didnt see anybody reply to your thread.. and i know this is an old thread, but have you found the solution to it? Im stuck with it like two weeks now finding the solution. please guide me through this if you or somebody else has already solved it.  

 

I dont believe its a physical hardware problem of the memory chip since the bits testing of the sdram does work.. Only the dma didnt work. Seems like it never got the "rx_done" into '1' since the transfer does not complete. I wonder why.. 

 

here is the screen shot of my sopc: 

https://www.alteraforum.com/forum/attachment.php?attachmentid=2382  

 

i tried to attach my full system but its too big. sorry 

 

BTW im using Altera 8.0 version software.
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

I don't see anything wrong with the hardware configuration... Does your design meet timing requirements? 

You could use some signaltap probes on the avalon master busses from the DMA to check if it is doing anything or not.
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

I manage to get DMA transfer complete. but rewrite the code, and it only copy from a single address to buffer.(more like a streaming). 

 

I read from the documentation that this method is supposed to be for peripheral to memory copy..however i give the input to it my 2nd SDRAM base address - which i name it mem_sdram (im using de2-70). So im assuming that it supposed to be copying only the first data to buffer which i declare earlier. 

 

However after the transfer finish..i check the value inside buffer.Its not the same as in mem_sdram

 

 

here is the output: 

Testing DMA! readaddress =4000000, length =0, status =0, control =1f9 dma transfer: 1ms Transaction complete 0:3 1:0 2:0 3:0 it shows there '3' and followed by 0.Im expecting the buffer to be filled with '78'. because at the first 32bits of mem_sdram i have already write it with this command : iowr_32direct(mem_sdram_base,0,0x12345678); 

 

 

Here is my code: 

# define DEPTH 4 # include <stdio.h># include <stddef.h># include <stdlib.h># include "string.h"# include "system.h" # include "sys/alt_dma.h"# include "altera_avalon_dma_regs.h"# include "altera_avalon_dma.h" # include "sys/alt_cache.h"# include "sys/alt_alarm.h"# include "alt_types.h" volatile int dma_complete = 0; void dma_done (void * handle, void * data) { dma_complete = 1; } void check(void) { alt_u32 control, status, readaddress, length; readaddress = IORD_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE); printf ("readaddress =%x, ", readaddress); length = IORD_ALTERA_AVALON_DMA_LENGTH (DMA_BASE); printf ("length =%x, ", length); status = IORD_ALTERA_AVALON_DMA_STATUS (DMA_BASE); printf ("status =%x, ", status); control = IORD_ALTERA_AVALON_DMA_CONTROL (DMA_BASE); printf ("control =%x \n", control); } int main() { printf("Testing DMA!\n"); alt_u8 buffer; //memset(buffer, 0x55, 2024); alt_dcache_flush_all(); alt_dma_rxchan_dev * rx; alt_u32 start,end; IOWR_32DIRECT(MEM_SDRAM_BASE,0,0x12345678); start = alt_nticks(); if ((rx = alt_dma_rxchan_open ("/dev/dma")) == NULL) { printf ("Error: failed to open device"); exit(1); } else { alt_dma_rxchan_ioctl(rx, ALT_DMA_SET_MODE_8, NULL); alt_dma_rxchan_ioctl(rx, ALT_DMA_TX_ONLY_OFF, NULL); alt_dma_rxchan_ioctl(rx, ALT_DMA_RX_ONLY_ON, (void *)MEM_SDRAM_BASE); check(); } int ret; if ((ret = alt_dma_rxchan_prepare (rx,(void *) buffer, DEPTH , dma_done, NULL)) <0) { printf ("Error: failed to post receive request\n"); exit (1); } while (!dma_complete); end = alt_nticks(); printf("dma transfer: %dms\n",(end-start)); /*start = alt_nticks(); memcpy(buffer,(void *)MEM_SDRAM_BASE,DEPTH); end = alt_nticks(); printf("memcpy transfer: %dms\n",(end-start));*/ printf ("Transaction complete \n"); alt_dma_rxchan_close(rx); for(int x=0;x<DEPTH;x++) { printf("%d:%x\n",x,buffer); } printf("---using IORD---\n"); for(int x=0;x<DEPTH;x++) { printf("%d:%x\n",x,IORD_8DIRECT(MEM_SDRAM_BASE,0)); } return 0; }
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

You could have a cache problem. The CPU could be reading its data cache instead of the buffer in memory. 

Try to create a second pointer:alt_u8 *uncached_buffer = alt_remap_uncached(buffer,DEPTH);and when you print the contents of the buffer, read the data with uncached_buffer[x], and see if you have different results.
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

 

--- Quote Start ---  

You could have a cache problem. The CPU could be reading its data cache instead of the buffer in memory. 

Try to create a second pointer:alt_u8 *uncached_buffer = alt_remap_uncached(buffer,DEPTH);and when you print the contents of the buffer, read the data with uncached_buffer[x], and see if you have different results. 

--- Quote End ---  

 

 

alt_u8 *uncached_buffer = alt_remap_uncached(buffer,depth)

gave compile error : invalid conversion from `volatile void*' to `alt_8*' 

 

so i change it to 

volatile void * uncached_buffer = alt_remap_uncached(buffer,depth); 

 

but now the "uncached_buffer" variable cannot be read.
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

Sorry, try this:alt_u8 *uncached_buffer = (alt_u8 *)alt_remap_uncached(buffer,DEPTH);

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

 

--- Quote Start ---  

Sorry, try this:alt_u8 *uncached_buffer = (alt_u8 *)alt_remap_uncached(buffer,DEPTH); 

--- Quote End ---  

 

 

cool.. it works like a charm .. thank you Daixiwen 

 

here is the code (in case somebody else having the same problem): 

 

# define DEPTH 100 # include <stdio.h># include <stddef.h># include <stdlib.h># include "string.h"# include "system.h" # include "sys/alt_dma.h"# include "altera_avalon_dma_regs.h"# include "altera_avalon_dma.h" # include "sys/alt_cache.h"# include "sys/alt_alarm.h"# include "alt_types.h" volatile int dma_complete = 0; void dma_done (void * handle, void * data) { dma_complete = 1; } void check(void) { alt_u32 control, status, readaddress, length; readaddress = IORD_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE); printf ("readaddress =%x, ", readaddress); length = IORD_ALTERA_AVALON_DMA_LENGTH (DMA_BASE); printf ("length =%x, ", length); status = IORD_ALTERA_AVALON_DMA_STATUS (DMA_BASE); printf ("status =%x, ", status); control = IORD_ALTERA_AVALON_DMA_CONTROL (DMA_BASE); printf ("control =%x \n", control); } int main() { printf("Testing DMA!\n"); alt_u8 buffer; alt_u8 * ubuffer = (alt_u8 *)alt_remap_uncached(buffer,DEPTH); memset(ubuffer, 0x55, DEPTH * 2); //alt_dcache_flush_all(); alt_dma_rxchan_dev * rx; alt_u32 start,end; IOWR_32DIRECT(MEM_SDRAM_BASE,0,0x12345678); start = alt_nticks(); if ((rx = alt_dma_rxchan_open ("/dev/dma")) == NULL) { printf ("Error: failed to open device"); exit(1); } else { alt_dma_rxchan_ioctl(rx, ALT_DMA_SET_MODE_8, NULL); alt_dma_rxchan_ioctl(rx, ALT_DMA_TX_ONLY_OFF, NULL); alt_dma_rxchan_ioctl(rx, ALT_DMA_RX_ONLY_ON, (void *)MEM_SDRAM_BASE); check(); } int ret; if ((ret = alt_dma_rxchan_prepare (rx,(void *) ubuffer, DEPTH, dma_done, NULL)) <0) { printf ("Error: failed to post receive request\n"); exit (1); } while (!dma_complete); end = alt_nticks(); printf("dma transfer: %dms\n",(end-start)); /*start = alt_nticks(); memcpy(buffer,(void *)MEM_SDRAM_BASE,DEPTH); end = alt_nticks(); printf("memcpy transfer: %dms\n",(end-start));*/ printf ("Transaction complete \n"); alt_dma_rxchan_close(rx); for(int x=0;x<DEPTH;x++) { printf("%d:%x\n",x,ubuffer); } printf("---using IORD---\n"); for(int x=0;x<DEPTH;x++) { printf("%d:%x\n",x,IORD_8DIRECT(MEM_SDRAM_BASE,0)); } return 0; } i found that this line , memset(ubuffer, 0x55, depth * 2); 

is somehow also affect the output.. 

 

-if i comment this line the output is not correct. //seems like we have to initialize the ubuffer first 

 

-if i change it to memset(ubuffer, 0x0, depth * 2);, the output is incorrect 

 

-if i change it to memset(ubuffer, 0x0, depth); -- somehow the length which must be set has to be double the size of the buffer we need. 

 

:p so many mystery that i still dont understand about this dma controller provided by altera in sopc.. 

 

rite now im back to trying the transfer from memory to memory with dma controller provided with sopc. 

 

memcpy works best without bug for me. somehow the disadvantage is that i have to wait until memcpy operation finish b4 i can do other operation. With dma controller, i can tell it to copy a certain block of memory and do other operation. if the copy operation is done (can check it with flag) i can continue what i want todo with the copied data. 

 

 

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

There could still be a cache problem, because with your memcpy statement, you are using the cached address, and as a result the NIOS CPU may not immediately write the cache contents to the buffer area. After that you read and display the uncached values, so they could be different than what was written by memcpy. 

I wouldn't recommend to keep the memset with DEPTH*2. You are writing on the stack in a space that was probably allocated for something else, and it could trigger all kind of unexplainable bugs in your code.
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

....continue from previous post ... 

 

this is an example of a larger chunk transfer using dma from ssram_0 to buffer (allocated in sdram_0) 

 

/* * NIOSimg.cpp * * Created on: Apr 26, 2010 * Author: suki */ # include <stdio.h># include <stdlib.h># include <stddef.h># include <string.h> # include <system.h># include <io.h> # include <alt_types.h># include "sys/alt_dma.h"# include "sys/alt_cache.h"# include "sys/alt_alarm.h"# include "alt_types.h" # define DEPTH 0x4b000 static volatile int txrx_done = 0; //callback function when DMA transfer done static void txrxDone(void * handle, void * data) { txrx_done = 1; } void initMEM(int base_addr,int len) { for (int i=0;i<len;i++) { IOWR_8DIRECT(base_addr,i,i); } } int main() { printf("testing memory to memory DMA transfer operation of 0x%x bytes\n",DEPTH); alt_8 buffer; //memset((void *)SSRAM_0_BASE,0x7a,0x10);//this write base on byte initMEM(SDRAM_1_BASE,DEPTH); //memset((void *)(SDRAM_1_BASE+0x10),0x33,0x10); memset(buffer,0x33,DEPTH); int rc; //request alt_dma_txchan txchan; alt_dma_rxchan rxchan; void* tx_data = (void*)SDRAM_1_BASE; /* pointer to data to send */ void* rx_buffer = (void*)&buffer; /* pointer to rx buffer */ /* 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); } /* Post the transmit request */ if ((rc = alt_dma_txchan_send (txchan, tx_data, DEPTH, NULL, NULL)) < 0) { printf ("Failed to post transmit request, reason = %i\n", rc); //exit (1); } /* Post the receive request */ if ((rc = alt_dma_rxchan_prepare (rxchan, rx_buffer, DEPTH, txrxDone, NULL)) < 0) { printf ("Failed to post read request, reason = %i\n", rc); //exit (1); } printf("DMA transfer running. . ."); /* wait for transfer to complete */ while (!txrx_done); printf ("Transfer finish!\n"); printf("Verifying transfered data using memcmp. . ."); if (!(memcmp((void*)SDRAM_1_BASE,(void*)&buffer,DEPTH))) printf("Verification succesful!\n"); else printf("Verification failed\n"); // printf("content of buffer\n"); // for (int i=0;i<sizeof(buffer)/2;i++) // printf("%d: %x\n",i,buffer); // this output width ,base on what we declare /*printf("content of ssram_0\n"); for (int i=0;i<sizeof(buffer);i=i+2) { printf("%d: %x\n",i/2,IORD_16DIRECT(SSRAM_0_BASE,i)); } printf("content of sdram_1\n"); for (int i=0;i<sizeof(buffer);i=i+2) { printf("%d: %x\n",i/2,IORD_16DIRECT(SDRAM_1_BASE,i)); } memcpy((void*)SDRAM_1_BASE,(void *)SSRAM_0_BASE,20); printf("content of sdram_1: after memcpy operation\n"); for (int i=0;i<sizeof(buffer);i=i+2) { printf("%d: %x\n",i/2,IORD_16DIRECT(SDRAM_1_BASE,i)); }*/ return 0; } The output: 

testing memory to memory DMA transfer operation of 0x4b000 bytes DMA transfer running. . .Transfer finish! Verifying transfered data using memcmp. . .Verification succesful! cheers, sukiminna.
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

HELLO, thanks for the info. but i am using altera de2 board with one sdram (8Mb)and one sram (512kb). is the same code can be used? by the way, may i know how to configure sram module in sopc? like the setting..? thanks.

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

thank you so much for the code.

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

Hello aprado, do you know how to configure DMA using VHDL in Quartus before we can run the code in NiosII? thanks!

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

Hello, using the Quartus you can instantiate it inside SOPC builder and set all the parameters you need

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

thanks. may i know how? if possible, can you pls provide a simple example? thanks!

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

Look at the first post of this thread, it is very detailed. 

click on the icon in the left side of the ? at quartus to open sopc builder
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

i had done the sopc part. but i am stuck with the vhdl code in Quartus II. i thought we have to write the VHDL in Quartus II in order to be compatible with the sopc. only then, we can run the C code in nios2 ide. am i right? pls advise if i am wrong.

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

 

--- Quote Start ---  

i had done the sopc part. but i am stuck with the vhdl code in Quartus II. i thought we have to write the VHDL in Quartus II in order to be compatible with the sopc. only then, we can run the C code in nios2 ide. am i right? pls advise if i am wrong. 

--- Quote End ---  

 

 

SOPC Builder will generate the VHDL for the entire system which you then compile using Quartus II (as apposed to writing the logic manually). Once you have a programming file created by Quartus II you download the file to the FPGA and then you can communicate with the Nios II processor inside your SOPC Builder system.
0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views

Hi BadOmen, thanks for the reply! really? this is nice! i always thought i have to write the code manually. May I know how to generate the VHDL for the entire system? Thanks!

0 Kudos
Altera_Forum
Honored Contributor II
1,535 Views
0 Kudos
Altera_Forum
Honored Contributor II
1,449 Views

why my system stuck at: 

 

 

--- Quote Start ---  

 

while (!txrx_done); 

printf ("Transfer successful!\n"); 

 

 

 

--- Quote End ---  

0 Kudos
Reply