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

Changing DMA stread read to stream write

Altera_Forum
Honored Contributor II
2,414 Views

Hello, I have the following fully functional code that gives as output: 

Content of TX DDR2 SDRAM after DMA operation 

Address 0xC000000: 1 

Address 0xC000004: 2 

Address 0xC000008: 3 

Address 0xC00000C: 4 

Address 0xC000010: 5 

Address 0xC000014: 6 

Address 0xC000018: 0 

Address 0xC00001C: 0 

Content of RX DDR2 SDRAM after DMA operation 

Address 0xD000008: 1 

Address 0xD00000C: 1 

Address 0xD000010: 1 

Address 0xD000014: 1 

Address 0xD000018: 1 

Address 0xD00001C: 1 

Address 0xD000020: 0 

Address 0xD000024: 0 

 

I would now like to change this to a stream write. So swap it around. But how exactly should I change the code in the two boxes below, because I've tried but it doesn't seem to work :S: 

 

The following datasheet http://www.altera.com/literature/hb/...w_nii52004.pdf (http://www.altera.com/literature/hb/nios2/n2sw_nii52004.pdf) states the following 

If you are using the Avalon Memory-Mapped® (Avalon-MM) DMA device to transmit to hardware (not memory-to-memory transfer), call the alt_dma_txchan_ioctl()function with the request argument set to ALT_DMA_TX_ONLY_ON. 

 

the following is what i now use for stream reads. 

 

alt_dma_txchan_ioctl(txchan, ALT_DMA_SET_MODE_32, NULL); alt_dma_txchan_ioctl(txchan, ALT_DMA_TX_ONLY_OFF, NULL); alt_dma_txchan_ioctl(txchan, ALT_DMA_RX_ONLY_OFF, NULL);  

and 

alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_32, NULL); alt_dma_rxchan_ioctl(rxchan, ALT_DMA_RX_ONLY_ON, rx_buffer); alt_dma_rxchan_ioctl(rxchan, ALT_DMA_TX_ONLY_OFF, NULL);  

void dma_transfer_stream_read (void* tx_data, void* rx_buffer, alt_u32 length, int dma_picked) { int i; int rc; //request alt_dma_txchan txchan; alt_dma_rxchan rxchan; printf("Transfer size: 0x%X\n",(int)length); char dma_name; // printf("Please enter your dma name /dev/dma_tester .\n"); ///dev/dma_write or /dev/dma_read // scanf("%s",dma_name); if(dma_picked == 1) strcpy(dma_name, "/dev/dma_tester"); else if(dma_picked == 2) strcpy(dma_name, "/dev/dma_write"); else if(dma_picked ==3) strcpy(dma_name, "/dev/dma_read"); else {printf("No DMA controller picked!"); exit(1);} // strcpy(dma_name, "/dev/dma_read"); txrx_done=0; if((txchan = alt_dma_txchan_open(dma_name)) == NULL) { printf("Failed to open transmit channel\n"); exit (1); } else { alt_dma_txchan_ioctl(txchan, ALT_DMA_SET_MODE_32, NULL); alt_dma_txchan_ioctl(txchan, ALT_DMA_TX_ONLY_OFF, NULL); alt_dma_txchan_ioctl(txchan, ALT_DMA_RX_ONLY_OFF, NULL); } if((rxchan = alt_dma_rxchan_open(dma_name)) == NULL) { printf("Failed to open receive channel\n"); exit (1); } else { alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_32, NULL); alt_dma_rxchan_ioctl(rxchan, ALT_DMA_RX_ONLY_ON, rx_buffer); alt_dma_rxchan_ioctl(rxchan, ALT_DMA_TX_ONLY_OFF, NULL); /*If you are using the Avalon-MM DMA device to receive from hardware(not memory-to-memory transfer), call the alt_dma_rxchan_ioctl() function with the request argument set to ALT_DMA_RX_ONLY_ON.*/ } /* Post the transmit request */ if ((rc = alt_dma_txchan_send (txchan, tx_data, length, 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, length, txrxDone, NULL)) < 0) { printf ("Failed to post read request, reason = %i\n", rc); exit (1); } //printf("DMA_CONTROL_REG: 0X%8X\n", IORD_32DIRECT(DMA_TESTER_BASE, 24)); /* wait for transfer to complete */ printf("Waiting on DMA..."); while (!txrx_done) printf("."); printf(" Done!\n"); /* Close channels */ alt_dma_txchan_close(txchan); alt_dma_rxchan_close(rxchan); printf("Content of TX DDR2 SDRAM after DMA operation\n"); for (i=0x0;i<0x20;i+=4) //for (i=0xFFFFD4;i<0x1000000;i+=4) { printf("Address 0x%X: %x\n",i+(int)tx_data,IORD_32DIRECT((int)tx_data,i)); } printf("Content of RX DDR2 SDRAM after DMA operation\n"); for (i=0x0;i<0x20;i+=4) //for (i=0xFFFFD4;i<0x1000000;i+=4) { printf("Address 0x%X: %x\n",i+((int)rx_buffer),IORD_32DIRECT((int)rx_buffer,i)); } }  

In main: 

dma_transfer_stream_read((void*)ALTMEMDDR_1_BASE,(void*)(ALTMEMDDR_1_BASE+0x1000008),transfer_size,1); //read 

 

Thanks in advance.
0 Kudos
6 Replies
Altera_Forum
Honored Contributor II
1,367 Views

I can change it from read to write by doing the following: 

IOWR_32DIRECT(DMA_TESTER_BASE, 24,0x2FC); 

printf("WRITE_DMA_CONTROL_REG: 0X%8X\n", IORD_32DIRECT(DMA_TESTER_BASE, 24)); 

But then it messes up the read transfers, so I need to do this via the drivers in stead of the registers (like it says in the datasheet) 

 

From the datasheet (Embedded Peripherals IP User Guide) : 

if your program uses the hal device driver to access the dma controller, accessing the device registers directly interferes with the correct behavior of the driver. 

 

If I change it to this: 

 

alt_dma_txchan_ioctl(txchan, ALT_DMA_SET_MODE_32, null); 

alt_dma_txchan_ioctl(txchan, ALT_DMA_TX_ONLY_ON, tx_data); 

 

alt_dma_txchan_ioctl(txchan, ALT_DMA_RX_ONLY_OFF, null); 

and 

 

alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_32, null); 

alt_dma_rxchan_ioctl(rxchan, ALT_DMA_RX_ONLY_OFF, null); 

alt_dma_rxchan_ioctl(rxchan, ALT_DMA_TX_ONLY_OFF, null); 

the register simple remains at FC and I get a normal memory copy... 

0 Kudos
Altera_Forum
Honored Contributor II
1,367 Views

In your first post, for read you set the transaction end correctly: 

alt_dma_rxchan_ioctl(rxchan, ALT_DMA_RX_ONLY_ON, rx_buffer); alt_dma_rxchan_ioctl(rxchan, ALT_DMA_TX_ONLY_OFF, NULL); For write, you don't: 

alt_dma_txchan_ioctl(txchan, ALT_DMA_TX_ONLY_OFF, NULL); alt_dma_txchan_ioctl(txchan, ALT_DMA_RX_ONLY_OFF, NULL);  

 

.....As I'm just having the same error, now I'm going to check whether I have the same mistake in my project. :D
0 Kudos
Altera_Forum
Honored Contributor II
1,367 Views

 

--- Quote Start ---  

You shouldn't call alt_dma_*tx*chan_ioctl with parameter ALT_DMA_*RX*_ONLY_OFF. 

I assume you have not strictly swapped all tx vs rx? 

--- Quote End ---  

 

The txchan has a rx and a tx side, so does the rxchan. 

 

I've created one of the following scenarios so far. 

DMA control register : 0xFC (normal transaction) 

DMA control register : 0x1FC (Read stream) 

DMA control register : 0x2FC (Value for write stream, but the controller 'hangs' , so it never completes.) 

 

Edit: Oh nevermind the following, you mean I don't set the write end of the Read transaction correctly (even though it works and the DMA control registers is correctly set to 1FC), I suppose:). This is what the datasheet says though: 

//If you are using the Avalon-MM DMA device to receive from hardware (not memory-to-memory transfer), call the alt_dma_rxchan_ioctl() function with the request argument set to ALT_DMA_RX_ONLY_ON. 

 

Hi, 

 

The stuff in my first post is for reads, that works fine as far as I know. For writes I created a new functions that is the same but with just those parameters changed. I think/thought the parameters should be set the following way, but that doesn't work. 

 

alt_dma_txchan_ioctl(txchan, ALT_DMA_SET_MODE_32, null); 

alt_dma_txchan_ioctl(txchan, ALT_DMA_TX_ONLY_ON, tx_data); 

alt_dma_txchan_ioctl(txchan, ALT_DMA_RX_ONLY_OFF, null); 

and 

 

alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_32, null); 

alt_dma_rxchan_ioctl(rxchan, ALT_DMA_RX_ONLY_OFF, null); 

alt_dma_rxchan_ioctl(rxchan, ALT_DMA_TX_ONLY_OFF, null); 

 

But the DMA register just stays on no tx stream (and no rx stream). 

0 Kudos
Altera_Forum
Honored Contributor II
1,367 Views

I think I found the root of the problem. 

It is simply not possible to write stream from memory to memory, since the DMA controller only has 1 control register. The set-up for the read channel will overwrite the set-up for the write channel.
0 Kudos
Altera_Forum
Honored Contributor II
1,367 Views

Sorry, I'm always a bit faster in writing than in thinking, had to remove my stupid remarks there... 

 

So, then it should work when you swap the initialization? 

Setting the RX to OFF, before setting TX to on? 

 

I'm still struggling with the details and impacts of the concept... 

(Currently, I have an alt_dma_rxchan_prepare() that won't return) :confused:
0 Kudos
Altera_Forum
Honored Contributor II
1,367 Views

 

--- Quote Start ---  

Sorry, I'm always a bit faster in writing than in thinking, had to remove my stupid remarks there... 

 

So, then it should work when you swap the initialization? 

Setting the RX to OFF, before setting TX to on? 

 

I'm still struggling with the details and impacts of the concept... 

(Currently, I have an alt_dma_rxchan_prepare() that won't return) :confused: 

--- Quote End ---  

 

Well it's not working here yet either, but that's one thing to keep in mind. You can't set the register twice, since the second time it will overwrite the first time. So for streaming reading it has to be this: 

if((txchan = alt_dma_txchan_open(DMA_WRITE_NAME)) == NULL) { printf("Failed to open transmit channel\n"); exit (1); } if((rxchan = alt_dma_rxchan_open(DMA_WRITE_NAME)) == NULL) { printf("Failed to open receive channel\n"); exit (1); } else { alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_32, NULL); alt_dma_rxchan_ioctl(rxchan, ALT_DMA_TX_ONLY_OFF, NULL); alt_dma_rxchan_ioctl(rxchan, ALT_DMA_RX_ONLY_ON, ????); //rx_buffer or tx_data }  

As for the return, do you have the length of the data in words? And the addresses as well (or even doublewords). 

So length should be 0x0,0x4,0x8 etc. 

And addresses the same (or in my case 0x0,0x8,0x10 etc. are valid).
0 Kudos
Reply