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++

dma questions

Altera_Forum
Honored Contributor II
1,846 Views

Hey! I'm runing some test using the DMA controller. I started with the simplest one, trying to copy some datas from an onchip memory to another. I'm using this code.  

static volatile int rx_done = 0; static void done_rx (void* handle, void* data) { rx_done++; printf ("Transfer RX successful!\n"); } static void done_tx (void* handle, void* data) { printf ("Transfer TX successful!\n"); } void char_tx_rx() { char *send="87654321"; int length=strlen(send); printf ("length=%i\n", length); int rc; alt_dma_txchan txchan; alt_dma_rxchan rxchan; void* rx_buffer = (void*) (ONCHIP_MEMORY2_1_BASE); /* 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 receive request */ if ((rc = alt_dma_rxchan_prepare (rxchan,rx_buffer,length,done_rx,NULL)) < 0) { printf ("Failed to post read request, reason = %i\n", rc); exit (1); } /* Post the transmit request */ if ((rc = alt_dma_txchan_send (txchan,send,length,done_tx ,NULL)) < 0) { printf ("Failed to post transmit request, reason = %i\n", rc); exit (1); } /* wait for transfer to complete */ while (!rx_done); printf("send: \n"); int i; for(i=0;i<length;i++) printf ("%c",send); char *p; p=rx_buffer; printf("\nreceived: \n"); for(i=0;i<length;i++) printf ("%c",*(p+i)); alt_dma_rxchan_close(rxchan); alt_dma_txchan_close(txchan); }  

 

After some hard work(i've started with the integer function which is presented in the next post) i managed to make it work.  

The question here are :  

1) why, if I transmit all the tx buffer( tx_length=length) and set the dma to receive, lets say, only half of the datas(rx_length=length/2) the done_functions are called in the same order as when I transmit and receive the whole buffer( done_tx and then done_rx).  

2) And when I transmit half of the buffer(tx_length=length/2) and want to receive the whole buffer it works( i transmit what i want, but i also receive how much I want and I was expecting some problems here) ?
0 Kudos
9 Replies
Altera_Forum
Honored Contributor II
543 Views

I will continue with the rest of the code and the questions here. 

This was the first function i made, because in the future project in hich I want to use DMA I think i will need integers. 

void int_tx_rx() { int send={1,2,3,4,5,6,7,8,9,10,11,12}; int length=sizeof(send)/sizeof(int); printf("length=%i\n", length); int rc; alt_dma_txchan txchan; alt_dma_rxchan rxchan; void* rx_buffer = (void*) (ONCHIP_MEMORY2_1_BASE); /* 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); } else { if( alt_dma_txchan_ioctl(txchan,ALT_DMA_SET_MODE_32,NULL) <0 ) printf("failed to set RX_MODE_32\n"); } /* Create the receive channel */ if ((rxchan = alt_dma_rxchan_open("/dev/dma_0")) == NULL) { printf ("Failed to open receive channel\n"); exit (1); } else { if( alt_dma_rxchan_ioctl(rxchan,ALT_DMA_SET_MODE_32,NULL) <0) printf("failed to set TX_MODE_32\n"); } /* Post the receive request */ if ((rc = alt_dma_rxchan_prepare (rxchan,rx_buffer,length*sizeof(int),done_rx,NULL)) < 0) { printf ("Failed to post read request, reason = %i\n", rc); exit (1); } /* Post the transmit request */ if ((rc = alt_dma_txchan_send (txchan,send,length*sizeof(int),done_tx ,NULL)) < 0) { printf ("Failed to post transmit request, reason = %i\n", rc); exit (1); } /* wait for transfer to complete */ while (!rx_done); printf("send \n"); int i; for(i=0;i<length;i++) printf ("%i \r",send); int *p; //p=(void*) ONCHIP_MEMORY2_1_BASE; p=rx_buffer; printf("\nreceived \n"); for(i=0;i<length;i++) printf ("%i \r",*(p+i)); alt_dma_rxchan_close(rxchan); alt_dma_txchan_close(txchan); }  

 

Here I have some serious problems. The code is sometimes working, but only in this configuration, when I transmit exactly 12 int's(any int value). 

The questions here are: 

1) Apparently I'm not setting the data transfer to 32bites. I deduced this from the need to multiply the length by the size of int. 

2) when it worked( earlier today, when my boss came in and I tryed to run the program, it didn't work :oops: ) if I modified the length of the string, I encountered some unexpected transfers(the first or the second half was transfered well, and the other one it had some unknown values). 

 

Does anyone got an ideea about these problems? 

 

Thanks, alex 

0 Kudos
Altera_Forum
Honored Contributor II
543 Views

hello again! 

 

Today i made some modifications to the SOPC project ( i added an external RAM) so i can run some more tests( ram-> onchip memory and onchip->onchip). Now the code and all the software components are on the ram. 

 

The results are strange..to say the least. i observed the following situations: 

onchip->onchip: works almost perfectly, but with a delay of one program run, for both chars and ints.(for ints works from the first run after i change the transfer type from onchip->onchip,and then gets this delay) 

length=10 Transfer TX successful! Transfer RX successful! send 5 6 7 8 9 10 11 12 13 14 received 1 2 3 4 5 6 7 8 9 10 int NOT OK length=10 Transfer TX successful! Transfer RX successful! send 5 6 7 8 9 10 11 12 13 14 received 5 6 7 8 9 10 11 12 13 14 int OK length=10 Transfer TX successful! Transfer RX successful! send 10 11 12 13 14 15 16 17 18 19 received 5 6 7 8 9 10 11 12 13 14 int NOT OK length=10 Transfer TX successful! Transfer RX successful! send 10 11 12 13 14 15 16 17 18 19 received 10 11 12 13 14 15 16 17 18 19 int OK  

 

ram->onchip : works perfectly for chars, but for ints is working only at the first run after i change the transfer type. 

 

the thing is that earlyer this morning, the ram->onchip worked perfectly( for 12 ints) after i made this change in the code: 

 

if ((rc = alt_dma_txchan_send (txchan,send,length*sizeof(int)*2,done_tx ,NULL)) < 0),  

after that it didn't work anymore whith that *2. :confused: 

 

Have a nice day! alex
0 Kudos
Altera_Forum
Honored Contributor II
543 Views

I suspect you've got problems with the data cache.

0 Kudos
Altera_Forum
Honored Contributor II
543 Views

I've tried with a data cache of 4,8,16 Kb...for 8 and 16 the transfer did't work at all, an for 4 it has the same problems as before. 

 

I also added the alt_dcache_flush_all(); instruction at the beginning of the main function. 

0 Kudos
Altera_Forum
Honored Contributor II
543 Views

you need to flush the cache on the source data before you initiate the DMA transfer, and invalidate the cache on the destination data after the transfer. 

Or you can read/write your data using unached memory accesses (see the alt_remap_uncached() ) function. 

Or you can disable the data cache all together and check for any changes.
0 Kudos
Altera_Forum
Honored Contributor II
543 Views

You also need to ensure that the cpu doesn't access parts of the same cachelines while the dma is in progress,

0 Kudos
Altera_Forum
Honored Contributor II
543 Views

hi! thanx for your answers! 

 

@Daixiwen: I've disabled the data cache( using this method http://www.alteraforum.com/forum/showthread.php?t=13192 ) and the result are the same as before. 

 

and another question, based on your answers. I'm using HAL instruction. From what I read this assures cache management. (http://www.altera.com/literature/hb/nios2/n2sw_nii52007.pdf) Am I wrong?
0 Kudos
Altera_Forum
Honored Contributor II
543 Views

I am really not sure the method described in the thread you point to actually works. It is more reliable to set the cache size to "None" in SOPC builder. 

I've never used the DMA core, but I had a quick look at the driver and it doesn't seem to use any cache management functions.
0 Kudos
Altera_Forum
Honored Contributor II
543 Views

@Daixiwen: over the weekend i thought about that method not working to, and this morning you confirmed :). I made the change in SOPC and now it works. Thank you for your advices, I owe you one;)

0 Kudos
Reply