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

ADC to DDR2 using Avalon-ST

Altera_Forum
Honored Contributor II
1,443 Views

I've been searching the forums for a few examples on how to stream ADC data to DDR2 for awhile now and finally think i've built a system that correctly does this. Im just looking for some validation of my design: 

 

1) I've made my ADC interface into an Avalon-ST interface. The ADC is 14bits wide and samples at a rate of 125MSPS.  

2) Avalon Clock is set to 125MSPS. 

3) ADC, Avalon-ST gets sent to an SGDMA. 

4) For now I have the SGDMA sending the samples into onboard ram, eventually I'd make that the DDR2 stick that comes with my board. 

 

Anway, SOPC/NIOS is totally new to me at this level. I've done simple things but nothing this complex. Does this sound like a legit way of doing things? It should be pretty simple to just read off the on-board ram that is holding the samples. Previously, when I would interact through the PIO interface, it was easy via: 

 

IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE,0x00000011); 

 

But using the SGDMA, im a little confused on how to use descriptors, etc.  

Also, what happens when the onboard ram is full? Is there a write_full signal or should a stick a fifo somewhere? 

 

Thanks
0 Kudos
4 Replies
Altera_Forum
Honored Contributor II
685 Views

You should read the datasheet of sgdma core first. No, there's no full signal as You can transfer only up to 65.5kb of data per descriptor, so You can do the math how many descriptors You'll need to fill the memory. Also remember, that 125MHz Nios system won't be able to work with all the data, as some of Your commands will take more than one cpu instruction.

0 Kudos
Altera_Forum
Honored Contributor II
685 Views

Thanks for the info Socrates. I've come a long way in the past few days using some example code that you or BadOmen posted. Im still a little hazy on my SOPC/ADC driver design though. Attached is a Jpeg and the driver VHDL code.  

 

Lastly, like I mentioned above, I modified the C code that you or BadOmen posted in another thread to read off the onboard ram once it is filled by the ADC and print to the screen via stdout. Unfortunately, it is only printing addresses even though I am de-referencing the memory address pointer. 

 

If you could, can you take a look at the following and attached code? Im not sure what I am doing wrong, but I think I'm pretty close. 

 

Thanks 

 

Matt 

#include "io.h"# include "stdio.h"# include "stdlib.h"# include "system.h"# include "alt_types.h"# include "altera_avalon_sgdma.h"# include "altera_avalon_sgdma_regs.h"# include <sys/alt_cache.h># include <sys/stdio.h># include <math.h> # define NUMBER_OF_BUFFERS 10 /* each direction so double this for the total */# define MINIMUM_BUFFER_LENGTH 50# define MAXIMUM_BUFFER_LENGTH 1500 /* set this to the same value as the min for a fixed size, also don't exceed 65535 */ volatile alt_u8 rx_done = 0; alt_sgdma_dev *DEVICE; alt_sgdma_descriptor *dma_descriptors, *dma_descriptors_copy; void dma_interrupt(void * context) { rx_done=1; /* main will be polling for this value being 1 */ } alt_u8 allocate_descriptors(alt_sgdma_descriptor **dma_descriptors, alt_sgdma_descriptor **dma_descriptors_copy, alt_u32 num_buffers) { void *temp_pointer; temp_pointer = malloc((num_buffers + 2) * ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE); if(temp_pointer==NULL) return 1; *dma_descriptors_copy = (alt_sgdma_descriptor *)temp_pointer; while((((alt_u32)temp_pointer) % ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE) != 0) temp_pointer++; // Limit size @ 32 bytes *dma_descriptors = (alt_sgdma_descriptor *)temp_pointer; dma_descriptors->control = 0; // Set IE_ERROR=0 bit in control register return 0; } alt_u8 allocate_dma_buffers(alt_sgdma_descriptor *dma_descriptors, alt_u32 num_buffers) { alt_u32 i, length = 0; alt_u32 *data_pointer; for(i=0; i<num_buffers; i++){ length = MINIMUM_BUFFER_LENGTH; data_pointer = (alt_u32 *)malloc(length); if(data_pointer == NULL) return 1; alt_avalon_sgdma_construct_stream_to_mem_desc(&dma_descriptors, // descriptor &dma_descriptors, // next descriptor data_pointer, // write buffer location MINIMUM_BUFFER_LENGTH, //(alt_u16)length, // I will wait for End Of Packet instead of fixed length 0); // writes are not to a fixed location } alt_dcache_flush_all(); return 0; } /* Making sure that there will be enough space for code (maximum of 1.5MB) */ int main(){ alt_putstr("Here"); alt_u8 returned = 0; DEVICE = alt_avalon_sgdma_open("/dev/sgdma_0"); if(DEVICE == NULL) { alt_putstr("Could Not Find SGDMA Device"); return 1; } else { alt_putstr("Found SGDMA Device"); } IOWR_ALTERA_AVALON_SGDMA_CONTROL(DEVICE->base,ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK); // Reset SGDMA IOWR_ALTERA_AVALON_SGDMA_CONTROL(DEVICE->base,0x0); IOWR_ALTERA_AVALON_SGDMA_CONTROL(DEVICE->base, ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK); // change park returned = allocate_descriptors(&dma_descriptors, &dma_descriptors_copy, NUMBER_OF_BUFFERS); if(returned) alt_putstr("### ERROR: Failed to allocate memory for descriptors!\n"); returned = allocate_dma_buffers(dma_descriptors,NUMBER_OF_BUFFERS); // Allocate data buffers and construct descriptors if(returned) alt_putstr("### ERROR: Failed to allocate memory for data receive!\n"); alt_avalon_sgdma_register_callback(DEVICE, &dma_interrupt, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); //printf("%d", sizeof(alt_sgdma_descriptor)); // last descriptor needs to point to the first dma_descriptors.next = (alt_sgdma_descriptor *)dma_descriptors; printf("descriptor address: %d \n", dma_descriptors); printf("final descriptor next: %d \n", dma_descriptors.next); if(alt_avalon_sgdma_do_async_transfer(DEVICE, &dma_descriptors) != 0) alt_putstr("FAIL! (Writing the head of the descriptor list to the DMA failed)\n"); int i = 0; int j = 0; for( i = 0; i < 10; i++) { if(alt_avalon_sgdma_do_async_transfer(DEVICE, &dma_descriptors) != 0) alt_putstr("FAIL! (Writing the head of the descriptor list to the DMA failed)\n"); usleep(5000); int k = 0; /// problem area for(j = 0; j < NUMBER_OF_BUFFERS; j++) { printf("%d ", IORD_32DIRECT((&dma_descriptors.write_addr),0)); //alt_putstr(&dma_descriptors.write_addr); dma_descriptors.control = dma_descriptors.control | ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK; } // int k = 0; // for(k = 0; k < NUMBER_OF_BUFFERS; k ++) // { // dma_descriptors.control = dma_descriptors.control | 0b10000001; // } } // // alt_putstr(">>> Starting SGDMA transfers... \n"); // // if(alt_avalon_sgdma_do_async_transfer(DEVICE, &dma_descriptors) != 0) // alt_putstr("FAIL! (Writing the head of the descriptor list to the DMA failed)\n"); // //// while(rx_done == 0) { //// alt_putstr("Something\n"); //// usleep(5000); //// } // // // usleep(500000); // // //alt_putstr(">>> The SGDMA transfer has completed, Done = %u\n",(unsigned int)rx_done); // // // // // // alt_avalon_sgdma_stop(DEVICE); // //free(dma_descriptors_copy); // //free(dma_descriptors); // // // do stuff to transfer the data off // // alt_putstr(" dumping data "); // alt_u32 *data_pointer; // int i = 0; // for(i = 0; i < NUMBER_OF_BUFFERS; i++) // { // data_pointer = dma_descriptors.write_addr; // alt_putstr(&data_pointer); // } //free(dma_descriptors_copy); //free(dma_descriptors); //alt_putstr("Working...\n"); return 0; }
0 Kudos
Altera_Forum
Honored Contributor II
685 Views

Hi, mwb500 :  

 

Now the same issue confused me. How about your ADC avalon interface ?
0 Kudos
Altera_Forum
Honored Contributor II
685 Views

Do a proper debug. 

Are You sure data is written to the memory? I see that You use malloc(), so it places data to .heap. I'd offer to change address to particular place in on-chip ram, so You can use in-system memory content editor and check what data has been copied. 

I'd also offer to do debug inside dma_interrupt(), so You'll be sure it has occoured.
0 Kudos
Reply