Forum Discussion
Altera_Forum
Honored Contributor
12 years agoI have some working code that continuously takes in serial data to on-chip ram from 2 stream-to-memory sgdma's, and puts the serial data in a circular buffer in ddr memory.
The code puts the two stream-to-memory sgdma's in park mode, and the descriptor points back to itself for continuous operation. A call back is registered for the completion of each stream-to-memory descriptor to start the data transfer to the ddr3 circular buffer. The ddr3 transfer is done with a memory-to-memory sgdma with and single descriptor chain. The descriptor chain is rebuilt after each transfer. Comments are more than welcome... // CWstream1_DMA SGDMA callback function // * After each descriptor is processed (1600 bytes), the data is transfered to DDR3 memory in a circular buffer void CWstream1_callback_function(void * context) { // tx tells the circular buffer which sgdma was processed tx=0; alt_avalon_sgdma_do_async_transfer(DDR3_DMA, &DDR3_DMA_desc[0]); } // CWstream2_DMA SGDMA callback function // * After each descriptor is processed (1600 bytes), the data is transfered to DDR3 memory in a circular buffer void CWstream2_callback_function(void * context) { IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 1); // tx tells the circular buffer which sgdma was processed tx=1; alt_avalon_sgdma_do_async_transfer(DDR3_DMA, &DDR3_DMA_desc[0]); } // DDR3_DMA callback function // * Re-initialize the descriptor for the next memory transfer // * Check the memory position to see if the circular buffer needs to start over void DDR3_callback_function(void * context) { // update the write address of the circular buffer write_addr = write_addr + 0x640; if (write_addr >= 0x3e80) { DDR3_write_addr = DDR3_BASE; write_addr = 0; } else DDR3_write_addr = DDR3_BASE + write_addr; // Check which sgdma was processed so we can know where to read the data from if (tx == 1) { alt_avalon_sgdma_construct_mem_to_mem_desc(&DDR3_DMA_desc[0], &DDR3_DMA_desc[1], CW_DAQ1_write_addr, DDR3_write_addr, 1600, 0, 0); IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 3); IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 4); } else { alt_avalon_sgdma_construct_mem_to_mem_desc(&DDR3_DMA_desc[0], &DDR3_DMA_desc[1], CW_DAQ2_write_addr, DDR3_write_addr, 1600, 0, 0); IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 2); } DDR3_DMA_desc[0].control=128; DDR3_DMA_desc[1].control=0; } // Main code entry // * Write a message to the LCD display for fun // * Initialize pushbutton callbacks // * Clear memory space // * Start DMA engines // * Sit in a while loop and wait for callbacks int main(void) { // Initialize circular DDR3 transfer variables write_addr = 0; // This is a software reset to the ping-pong selector hardware counter. // Pull this low and then return to the high state will reset the counter to 0. IOWR_ALTERA_AVALON_PIO_DATA(PIO_PROGRAM_BASE, 0); // Reset the sgdma controller // This is a software reset, - not sure if needed // The documentation states this is a last resort control, so we should remove this if we can. // Embedded Peripherals IP User Guide, pg 25-12 IOWR_32DIRECT(SGDMA_ST1_BASE, 16, 0x10000); IOWR_32DIRECT(SGDMA_ST2_BASE, 16, 0x10000); usleep(1000); IOWR_32DIRECT(SGDMA_ST1_BASE, 16, 0x10000); IOWR_32DIRECT(SGDMA_ST2_BASE, 16, 0x10000); usleep(1000); // Open the CW streaming scatter-gather DMA controllers CWstream_DMA1 = alt_avalon_sgdma_open("/dev/sgdma_st1"); if(CWstream_DMA1 == NULL) printf("Could not open the CW SG-DMA1\n"); CWstream_DMA2 = alt_avalon_sgdma_open("/dev/sgdma_st2"); if(CWstream_DMA2 == NULL) printf("Could not open the CW SG-DMA2\n"); // Open the Memory transfer to circular buffer scatter-gather DMA controller DDR3_DMA = alt_avalon_sgdma_open("/dev/sgdma_ddr3"); if(DDR3_DMA == NULL) printf("Could not open the DDR3 SG-DMA\n"); // Set the write addresses for data transfers CW_DAQ1_write_addr = (alt_u32 *)(DAQ1_MEM_BASE); CW_DAQ2_write_addr = (alt_u32 *)(DAQ2_MEM_BASE); DDR3_write_addr = (alt_u32 *)(DDR3_BASE); // Set up the CW stream 1 descriptor // The descriptor points back to itself for continuous operation // The PARK bit of the control register must be set in order to re-use the descriptor (done in the callback registration)r alt_avalon_sgdma_construct_stream_to_mem_desc(&CWstream_DMA1_desc[0], &CWstream_DMA1_desc[0], CW_DAQ1_write_addr, 1600, 0); // Set the OWNED_BY_HW bit to 1 on desc[0] CWstream_DMA1_desc[0].control=128; // Set up the CW stream 2 descriptor alt_avalon_sgdma_construct_stream_to_mem_desc(&CWstream_DMA2_desc[0], &CWstream_DMA2_desc[0], CW_DAQ2_write_addr, 1600, 0); CWstream_DMA2_desc[0].control=128; // Set up DDR3 1 descriptor alt_avalon_sgdma_construct_mem_to_mem_desc(&DDR3_DMA_desc[0], &DDR3_DMA_desc[1], CW_DAQ1_write_addr, DDR3_write_addr, 1600, 0, 0); // Set the OWNED_BY_HW bit to 1 on desc[0], and set the bit to 0 on desc[1] // This stops the descriptor chain at desc[1] and flags an interrupt for its callback function DDR3_DMA_desc[0].control=128; DDR3_DMA_desc[1].control=0; // Register callback functions // CWstream1 callback // The PARK_MASK allows prevent the OWNED_BY_HW bit from being cleared after the descriptor is processed alt_avalon_sgdma_register_callback(CWstream_DMA1, &CWstream1_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK ), NULL); // CWstream2 callback alt_avalon_sgdma_register_callback(CWstream_DMA2, &CWstream2_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); //DDR3 callback alt_avalon_sgdma_register_callback(DDR3_DMA, &DDR3_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); usleep(1000); IOWR_ALTERA_AVALON_PIO_DATA(PIO_PROGRAM_BASE, 1); // Start the CW transfers alt_avalon_sgdma_do_async_transfer(CWstream_DMA1, &CWstream_DMA1_desc[0]); alt_avalon_sgdma_do_async_transfer(CWstream_DMA2, &CWstream_DMA2_desc[0]); // Sit in a while loop while callbacks happen while (1) { } // Should not reach this code printf("\nExit\n\n"); return 0; }