FPGA Intellectual Property
PCI Express*, Networking and Connectivity, Memory Interfaces, DSP IP, and Video IP
Intel Support hours are Monday-Fridays, 8am-5pm PST, except Holidays. Thanks to our community members who provide support during our down time or before we get to your questions. We appreciate you!

Need Forum Guidance? Click here
Search our FPGA Knowledge Articles here.
5990 Discussions

Scatter-Gather DMA Controller

Honored Contributor II

Hello everyone,  


To get familiar with the Avalon Streaming Interface, I am trying to use the SGDMA IP to produce an Avalon stream from the extern DDR3 memory and to write this stream back to the memory. Therefore I used this example from http://www.alterawiki.com/wiki/sgdma


The code is working fine until it comes to the while-loop were the code is waiting for the interrupt. I used the debugger to check the registers and settings of the SGDMA device and of the descriptors which looked fine to me.  


I used the Qsys editor to generate the hardware components (I attached a screenshot of the configuration). Furthermore, I amusing the DE5-Net developer board with Quartus 17.  


Has anyone a suggestion what I am doing wrong? If you need more information please let meknow.  





# include "terasic_includes.h"# include "mem_verify.h" # define STATUS_BIT_DONE 0x01# define STATUS_BIT_FAIL 0x02# define STATUS_BIT_SUCCESS 0x04 /* These will gate the data checking near the end of main */ volatile alt_u8 tx_done = 0; volatile alt_u8 rx_done = 0; void transmit_callback_function(void * context){ tx_done++; /* main will be polling for this value being 1 */ } void receive_callback_function(void * context){ rx_done++; /* main will be polling for this value being 1 */ } int main() { alt_u32 *transmit_ptr; alt_u8 temp_transmit; //Let's try to initialize the SGDMA block printf("Initialization of the SGDMA...\n"); /* Open a SG-DMA for MM-->ST and ST-->MM (two SG-DMAs are present) */ alt_sgdma_dev * transmit_DMA = alt_avalon_sgdma_open(SGDMA_NAME); alt_sgdma_dev * receive_DMA = alt_avalon_sgdma_open(SGDMA_0_NAME); /* Needs one allocated descriptor at the end to mark the tail of the list. * Copies are made so that they can be put back on the heap when we are done. * The copies are a superset of the other pointers so by freeing them at the * end we'll be freeing transmit_descriptors and receive_descriptors as well. */ alt_sgdma_descriptor *transmit_descriptors, *transmit_descriptors_copy; alt_sgdma_descriptor *receive_descriptors, *receive_descriptors_copy; alt_u32 return_code; /************************************************************** * Making sure the SG-DMAs were opened correctly * ************************************************************/ if(transmit_DMA == NULL){ printf("Could not open the transmit SG-DMA\n"); return 1; } if(receive_DMA == NULL){ printf("Could not open the receive SG-DMA\n"); return 1; } /************************************************************** * Allocating descriptor table space from main memory. * * Pointers are passed by reference since they will be * * modified by this function. * ************************************************************/ printf("Allocating the descriptor memory..\n"); return_code = descriptor_allocation(&transmit_descriptors, &transmit_descriptors_copy, &receive_descriptors, &receive_descriptors_copy, NUMBER_OF_BUFFERS); if(return_code == 1){ printf("Allocating the descriptor memory failed... exiting\n"); return 1; } /************************************************************** * Allocating data buffers and populating them with data * ************************************************************/ printf("Allocating the data buffers and creating the data...\n"); return_code = create_test_data(transmit_descriptors, receive_descriptors, NUMBER_OF_BUFFERS, BUFFER_LENGTH); if(return_code == 1){ printf("Allocating the data buffers failed... exiting\n"); return 1; } transmit_ptr = transmit_descriptors.read_addr; temp_transmit = IORD_8DIRECT((alt_u32)transmit_ptr, 0); printf("Written data: %u \n", (unsigned int) temp_transmit); transmit_ptr = transmit_descriptors.read_addr; temp_transmit = IORD_8DIRECT((alt_u32)transmit_ptr, 2); printf("Written data: %u \n", (unsigned int) temp_transmit); printf("Transmit_descriptor_ptr: %p \n", &transmit_descriptors); /**************************************************************/ /************************************************************** * Register the ISRs that will get called when each (full) * * transfer completes * ************************************************************/ printf("Setting the callback functions...\n"); alt_avalon_sgdma_register_callback(transmit_DMA, &transmit_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); alt_avalon_sgdma_register_callback(receive_DMA, &receive_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); /**************************************************************/ printf("Starting up the SGDMA transfer\n"); /* Prime the SGDMA engines with the descriptor lists (first one, it's a linked list) */ if(alt_avalon_sgdma_do_async_transfer(transmit_DMA, &transmit_descriptors) != 0){ printf("Writing the head of the transmit descriptor list to the DMA failed\n"); return 1; } if(alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors) != 0){ printf("Writing the head of the receive descriptor list to the DMA failed\n"); return 1; } while(tx_done == 0) {} printf("The transmit SGDMA has completed\n"); while(rx_done == 0) {} printf("The receive SGDMA has completed\n"); verify_stream_data(transmit_descriptors, receive_descriptors, NUMBER_OF_BUFFERS); /************************************************************** * Stop the SGDMAs and free up the descriptor memory * ************************************************************/ alt_avalon_sgdma_stop(transmit_DMA); alt_avalon_sgdma_stop(receive_DMA); free(transmit_descriptors_copy); free(receive_descriptors_copy); /**************************************************************/ return 0; }  


0 Kudos
3 Replies
Honored Contributor II



I looked up the Register Map of the transmit DMA and it seems that the DMA is not streaming the data from the memory to the Avalon ST.  


The content of the status register is 0000_1000 which means that the core has completed processing the descriptor chain.  


The content of the status register is 0111_1000, so interrupts are enabled and the RUN bit is set.  


The content of the next_descriptor_pointer is not changing and only contains the address of the first descriptor.  



Furthermore, I attached the settings of the SGDMAs from the Qsys editor. Do you know what is going wrong?  


Thank you for your help,  


Honored Contributor II



my problem with the DMA on a cyclone V was that I hasn't activated the fpga2sdram bridge at boot (fpga2sdram_handoff in u-boot). I don't know if the stratix does have such a register, may you check the manual... :) 


Good Luck!
Honored Contributor II

Hi Tom, 


Thank you for your answer.  


I found out, that I had connected the CSR Registers and the Read/Write connections for the descriptors in a wrong way. The CSR is now connected to the NIOS data_master. The read/write connections for the descriptors and the read connection for the data are now connected to the DDR3 module.  


Furthermore, I used the wrong memory addresses to initialize and store the descriptors and data in the C code. They have to be stored in the memory range of the DDR3 module (in my case in the first GB of the memory). After changing this, everything is working fine.  


Best regards