Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20644 Discussions

Words are swapped after DMA transfer

Altera_Forum
Honored Contributor II
1,353 Views

Hello, 

 

I'm trying to copy data from one part of the DDR2 Memory via DMA to the other parts. 

First I fill a part of the DDR2 memory with data (a counter). Then I copy this part to a different part of the DDR2 memory. Where it goes wrong is the third part, the copying of the second part to the third part. All the words are swapped. (So it's not 3,4,5,6 but 3,2,5,4) 

The DDR2 SDRAM is fully tested with memtest and works. 

The DMA controller is connected via a clock crossing bridge to the DDR2 RAM. 

 

Does anyone knows how to solve this?  

 

My code to fill the memory (and the txrxDone function): 

void fill_ddr2_memory_with_counter(int memory_base, int memory_size) { int offset_counter = 0; int data = 0x1; int i; //int memory_max = (memory_size/3); for (i=offset_counter; (i <= (0x1500000)); i+=4) // { IOWR_32DIRECT(memory_base,i, data); //First half data++; } printf("First one third of DDR2 memory filled! \n"); printf("Value of last written data at address 0x%X (offset 0x%X) is 0x%X\n",memory_base+i-4,i-4,IORD_32DIRECT(memory_base,i-4)); } staticvoid txrxDone(void * handle, void * data) { txrx_done = 1; }
0 Kudos
9 Replies
Altera_Forum
Honored Contributor II
608 Views

Code for the first transaction (which works fine.) 

/****************************************************************** * Copy 0 to 1/3th of DDR2 memory to 1/3 to 2/3th of memory * ******************************************************************/ void dma_driver_0_33 () { int i; int rc; //request alt_dma_txchan txchan; alt_dma_rxchan rxchan; void* tx_data = (void*)ALTMEMDDR_1_BASE; /* pointer to data to send */ void* rx_buffer = (void*)(ALTMEMDDR_1_BASE+0x1500004); /* pointer to rx buffer */ txrx_done=0; /* Create the transmit channel */ if ((txchan = alt_dma_txchan_open("/dev/dma_tester")) == NULL) { printf ("Failed to open transmit channel\n"); exit (1); } /* Create the receive channel */ if ((rxchan = alt_dma_rxchan_open("/dev/dma_tester")) == NULL) { printf ("Failed to open receive channel\n"); exit (1); } /* Post the transmit request */ if ((rc = alt_dma_txchan_send (txchan, tx_data, 0x150000, 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, 0x150000, txrxDone, NULL)) < 0) { printf ("Failed to post read request, reason = %i\n", rc); exit (1); } /* wait for transfer to complete */ while (!txrx_done); printf ("First transfer successful!\n"); printf("Content of DDR2 SDRAM after DMA operation\n"); for (i=0x0;i<0x20;i+=4) { printf("Address 0x%X: %x\n",i+(int)tx_data,IORD_32DIRECT((int)tx_data,i)); } //printf("Content of DDR2 SDRAM(offset 0x1500004):after DMA operation\n"); for (i=0x0;i<0x20;i+=4) { // printf("Address 0x%X: %x\n",i+((int)rx_buffer),IORD_32DIRECT((int)rx_buffer,i)); } }
0 Kudos
Altera_Forum
Honored Contributor II
608 Views

Code for the second DMA transaction (where something goes wrong.)  

But it's the same (apart from the addresses) as the other code: 

/****************************************************************** * Copy 1/3 to 2/3th of DDR2 memory to 2/3 to end of memory ******************************************************************/ void dma_driver_33_66 () { int i; int rc; //request alt_dma_txchan txchan; alt_dma_rxchan rxchan; void* tx_data = (void*)ALTMEMDDR_1_BASE+0x1500004; /* pointer to data to send */ void* rx_buffer = (void*)(ALTMEMDDR_1_BASE+0x3000004); /* pointer to rx buffer */ txrx_done=0; /* Create the transmit channel */ if ((txchan = alt_dma_txchan_open("/dev/dma_tester")) == NULL) { printf ("Failed to open transmit channel\n"); exit (1); } /* Create the receive channel */ if ((rxchan = alt_dma_rxchan_open("/dev/dma_tester")) == NULL) { printf ("Failed to open receive channel\n"); exit (1); } /* Post the transmit request */ if ((rc = alt_dma_txchan_send (txchan, tx_data, 0x150000, 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, 0x150000, txrxDone, NULL)) < 0) { printf ("Failed to post read request, reason = %i\n", rc); exit (1); } /* wait for transfer to complete */ while (!txrx_done); printf ("Second transfer successful!\n"); printf("Content of DDR2 SDRAM after DMA operation\n"); for (i=0x0;i<0x20;i+=4) { printf("Address 0x%X: %x\n",i+(int)tx_data,IORD_32DIRECT((int)tx_data,i)); } //IOWR_32DIRECT(rx_buffer, 0, 0x11); printf("Content of DDR2 SDRAM after DMA operation\n"); for (i=0x0;i<0x20;i+=4) { printf("Address 0x%X: %x\n",i+((int)rx_buffer),IORD_32DIRECT((int)rx_buffer,i)); } }
0 Kudos
Altera_Forum
Honored Contributor II
608 Views

Result: 

First one third of DDR2 memory filled! Value of last written data at address 0xD500000 (offset 0x1500000) is 0x540001 First transfer successful! Content of DDR2 SDRAM(offset 0x0) after DMA operation Address 0xC000000: 1 Address 0xC000004: 2 Address 0xC000008: 3 Address 0xC00000C: 4 Address 0xC000010: 5 Address 0xC000014: 6 Address 0xC000018: 7 Address 0xC00001C: 8 Second transfer successful! Content of DDR2 SDRAM after DMA operation Address 0xD500004: 1 Address 0xD500008: 2 Address 0xD50000C: 3 Address 0xD500010: 4 Address 0xD500014: 5 Address 0xD500018: 6 Address 0xD50001C: 7 Address 0xD500020: 8 Content of DDR2 SDRAM after DMA operation Address 0xF000004: 540001 Address 0xF000008: 3 Address 0xF00000C: 2 Address 0xF000010: 5 Address 0xF000014: 4 Address 0xF000018: 7 Address 0xF00001C: 6 Address 0xF000020: 9  

 

The code wouldn't fit into one post, so I had to split it up into 4. 

The problem is shown in bold letters.
0 Kudos
Altera_Forum
Honored Contributor II
608 Views

Have you tried with different buffer addresses and/or shorter dma counts? 

Do you get the same behaviour? 

I'm concerned about the data you read back from 0xF000008: this shows you have an extra 0x0054 16bit data word which misalignes the following accesses. 

Is your DDR memory 32bit native or maybe is it 16bit and then packed by the controller? 

Other idea: try with uncached addresses, although probably the alt_dma functions already remap buffers to uncached memory.
0 Kudos
Altera_Forum
Honored Contributor II
608 Views

Could this be related to mis-aligned burst transfers as described in this knowledge base article (http://www.altera.com/support/kdb/solutions/rd09182009_504.html)? 

 

I think this issue is automatically accounted for when using the newer HPC II version of the Altera memory controllers.
0 Kudos
Altera_Forum
Honored Contributor II
608 Views

Hello thanks for the replies.  

 

The 540001 data @ 0xF000004 (which is the data at address 0xD500000) is swapped with 1. So that's the same as the rest, sorry for not clearing that up. That does tell me something goes wrong when reading though. 

 

My DDR2 SDRAM is 16 bits wide. 

 

The clock crossing is as follows: 

Master-to-slave FIFO : 32 

Slave-to-master FIFO: 64 

Data width: 64 

 

DMA controller: 

32 bit Length register 

FIFO depth: 64 

 

All bursting is disabled. I do use the HPC controller though, since we didn't have the licences for others for Quartus 10.0 when I made it. 

 

Changing addresses to: 

void * tx_data = (void*)ALTMEMDDR_1_BASE; /* pointer to data to send */ void* rx_buffer = (void*)(ALTMEMDDR_1_BASE+0x500004); /* pointer to rx buffer */  

and (second function) 

void* tx_data = (void*)(ALTMEMDDR_1_BASE+0x500004); /* pointer to data to send */ void* rx_buffer = (void*)(ALTMEMDDR_1_BASE+0x1000004); /* pointer to rx buffer */ And length of data transfer to 0x100 gives the following (same) result: 

 

 

 

Content of DDR2 SDRAM after DMA operation Address 0xC500004: 1 Address 0xC500008: 2 Address 0xC50000C: 3 Address 0xC500010: 4 Address 0xC500014: 5 Address 0xC500018: 6 Address 0xC50001C: 7 Address 0xC500020: 8 Content of DDR2 SDRAM after DMA operation Address 0xD000004: 140001 Address 0xD000008: 3 Address 0xD00000C: 2 Address 0xD000010: 5 Address 0xD000014: 4 Address 0xD000018: 7 Address 0xD00001C: 6 Address 0xD000020: 9 Memory compare from starting address 0xC500004 to starting address 0xD000004 with 0x150000 bytes gives 0xFFFFFFEC End of program.  

Using uncached addresses is doing the following right?: 

void* tx_data = (void*)((ALTMEMDDR_1_BASE+0x1000004)| 0x80000000); void* rx_buffer = (void*)((ALTMEMDDR_1_BASE+0x2000004)| 0x80000000);  

 

This gives the same results (different data due different addresses): 

 

Content of DDR2 SDRAM after DMA operation Address 0x8D000004: 400002 Address 0x8D000008: 400003 Address 0x8D00000C: 400004 Address 0x8D000010: 400005 Address 0x8D000014: 400006 Address 0x8D000018: 400007 Address 0x8D00001C: 400008 Address 0x8D000020: 400009 Content of DDR2 SDRAM after DMA operation Address 0x8E000004: 400001 Address 0x8E000008: 400004 Address 0x8E00000C: 400003 Address 0x8E000010: 400006 Address 0x8E000014: 400005 Address 0x8E000018: 400008 Address 0x8E00001C: 400007 Address 0x8E000020: 40000a
0 Kudos
Altera_Forum
Honored Contributor II
608 Views

I cleaned up my code (since it was a total mess). 

DMA transfer code (I tried the alt_dma_txchan_ioctl), but it didn't help so it's commented out at the moment. I also tried out byte transfers in stead of word transfers, but that didn't make a difference either. 

void dma_transfer_general (void* tx_data, void* rx_buffer, alt_u32 length) { int i; int rc; //request alt_dma_txchan txchan; alt_dma_rxchan rxchan; printf("Transfer size: 0x%X\n",(int)length); char dma_name; strcpy(dma_name, "/dev/dma_tester"); txrx_done=0; /* Create the transmit channel */ if ((txchan = alt_dma_txchan_open(dma_name)) == NULL) { printf ("Failed to open transmit channel\n"); exit (1); } /* Create the receive channel */ if ((rxchan = alt_dma_rxchan_open(dma_name)) == NULL) { printf ("Failed to open receive channel\n"); exit (1); } // /* Configure transmit request */ // if ((rc = alt_dma_txchan_ioctl(txchan, ALT_DMA_SET_MODE_32, tx_data)) < 0) // { // printf ("Failed to set tx ioctl to mode_32, reason = %i\n", rc); // exit (1); // } // // /* Configure receive request */ // if ((rc = alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_32, rx_buffer)) < 0) // { // printf ("Failed to set rx ioctl to mode_32, reason = %i\n", rc); // exit (1); // } /* 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); } /* wait for transfer to complete */ while (!txrx_done); /* 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) { 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) { printf("Address 0x%X: %x\n",i+((int)rx_buffer),IORD_32DIRECT((int)rx_buffer,i)); } printf("Memory compare from starting addresses 0x%X and 0x%X \nwith 0x%X bytes gives 0x%X \n",(int)tx_data,(int)rx_buffer,(int)length,(memcmp(tx_data,rx_buffer,(int)length))); }  

 

In main (see my first post for the fill_ddr2 function): 

alt_u32 transfer_size = 0x10; fill_ddr2_memory_with_counter(memory_base,memory_size); dma_transfer_general((void*)ALTMEMDDR_1_BASE,(void*)(ALTMEMDDR_1_BASE+0x1500004),transfer_size); dma_transfer_general((void*)(ALTMEMDDR_1_BASE+0x1500004),(void*)(ALTMEMDDR_1_BASE+0x3000004),transfer_size);
0 Kudos
Altera_Forum
Honored Contributor II
608 Views

This gives as output: 

Transfer size: 0x10 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: 7 Address 0xC00001C: 8 Content of RX DDR2 SDRAM after DMA operation Address 0xD500004: 1 Address 0xD500008: 2 Address 0xD50000C: 3 Address 0xD500010: 4 Address 0xD500014: 540006 Address 0xD500018: 540007 Address 0xD50001C: 540008 Address 0xD500020: 540009 Memory compare from starting addresses 0xC000000 and 0xD500004 with 0x10 bytes gives 0x0 Transfer size: 0x10 Content of TX DDR2 SDRAM after DMA operation Address 0xD500004: 1 Address 0xD500008: 2 Address 0xD50000C: 3 Address 0xD500010: 4 Address 0xD500014: 540006 Address 0xD500018: 540007 Address 0xD50001C: 540008 Address 0xD500020: 540009 Content of RX DDR2 SDRAM after DMA operation Address 0xF000004: 540001 Address 0xF000008: 3 Address 0xF00000C: 2 Address 0xF000010: 540006 Address 0xF000014: 0 Address 0xF000018: 0 Address 0xF00001C: 0 Address 0xF000020: 0 Memory compare from starting addresses 0xD500004 and 0xF000004 with 0x10 bytes gives 0xFFFFFFAC  

The 540006 etc. is old data that I didn't clear yet. 

Clearing it with the following function, makes those values 0. 

memset((void*)memory_base,0x00, memory_size); //Clear memory  

 

0 Kudos
Altera_Forum
Honored Contributor II
608 Views

I fixed my problem by using the following addresses \o/: 

 

dma_transfer_general((void*)ALTMEMDDR_1_BASE,(void*)(ALTMEMDDR_1_BASE+0x1500008),transfer_size);  

dma_transfer_general((void*)(ALTMEMDDR_1_BASE+0x1500008),(void*)(ALTMEMDDR_1_BASE+0x3000008),transfer_size); 

 

I'm not sure why it worked, but it did. Maybe it somehow uses 64 bits addressing in stead of 32, so I had to start at ALTMEMDDR_1_BASE+0x1500008 in stead of  

ALTMEMDDR_1_BASE+0x1500004. (ALTMEMDDR_1_BASE being address 0xC000000). 

 

Thanks for the ideas :).
0 Kudos
Reply