Forum Discussion
mSGDMA stride reads/writes
Has anyone used the Stride feature (available with the extended descriptor)? I using the Qsys PCIe example design on the wiki. When I enable the extended descriptor and stride option, the data transfer gets corrupted and the PCIe bombs out. I know you have to write to a different address to set the GO bit, and have to write to a register to set the stride length. I basically just want to do large transfers to a custom component with a 256 bit interface. I have an SR open with Altera, but they are slower than molasses.
27 Replies
- Altera_Forum
Honored Contributor
I don't see anything wrong. I would probably disable the mSGDMA global interrupt mask before unregistering it's interrupt in destruct_sgdma.
It appears you are trying to perform a ST-->MM transfer using flow control so are you sure the transfer is completing? The transfer according to the descriptor stops when EOP arrives to the write master and that last piece of data is written out to memory. I noticed that you are passing this in as the maximum transfer length when creating the descriptor: 4*NCELL. That has to be specified in bytes if you are not already doing so. Also if that amount of data or more arrives at the write master before the EOP beat comes into the ST port of the write master then it will terminate the transfer earlier. Note that the early termination may happen a few bytes more than 4*NCELL if you have unaligned/aligned transfers enabled in the write master hardware. Note if you don't want to be using ST packets at all then I wouldn't pass in 'DESCRIPTOR_CONTROL_END_ON_EOP_MASK' into the descriptor forming API. - Altera_Forum
Honored Contributor
Hi BadOmen... It's me again...
I do feed signal generator to ADC -> then processed by FFT -> read by mSGDMA ST-MM with nios task (double buffered)
After transferred through ethernet, by simple TCP IP program to draw FFT graph. I've got only some partial data.void ReadStreamTask() { INT8U err; reset_dispatcher(MSGDMA_RX_CSR_BASE); alt_ic_isr_register(MSGDMA_RX_CSR_IRQ_INTERRUPT_CONTROLLER_ID, MSGDMA_RX_CSR_IRQ, msgdma_rx_complete_isr, NULL, NULL); enable_global_interrupt_mask(MSGDMA_RX_CSR_BASE); Semaphore = OSSemCreate(1); Semaphore = OSSemCreate(2); while (1) { if(msgdma_int_rx == 0) { msgdma_int_rx = 1; do{ storage_ptr = (storage_ptr + 1) % 2; OSSemPend(Semaphore, 2, &err); }while(err == OS_ERR_TIMEOUT); IOWR_ALTERA_AVALON_PIO_DATA(PERIPHERAL_SUBSYSTEM_LED_PIO_BASE, 0xff - storage_ptr - 1); construct_standard_st_to_mm_descriptor(desc_rx_ptr, SGDMAMemory, 4*NCELL, DESCRIPTOR_CONTROL_TRANSFER_COMPLETE_IRQ_MASK | DESCRIPTOR_CONTROL_END_ON_EOP_MASK); write_standard_descriptor(MSGDMA_RX_CSR_BASE, MSGDMA_RX_DESCRIPTOR_SLAVE_BASE, desc_rx_ptr); } else if(msgdma_int_rx == 2) { msgdma_int_rx = 0; int i; err = OSSemPost(Semaphore); OSTimeDlyHMSM(0, 0, 0, 5); } } /* * Should not be here as long as while = 1 */ destruct_sgdma(); }
Please see the following picture Thank you...do { read_ptr = (read_ptr + 1) % 2; OSSemPend(Semaphore, 2, &err); } while(err == OS_ERR_TIMEOUT); // printf("------------------------------------------\n%d\n------------------------------------------\n", sizeof(iNetworkRadarData.data)); // printf("Send package 1\n"); length = sizeof(SGDMAMemory)/2; error_code = send(conns->fd, (char*) &length, sizeof(length), 0); error_code = send(conns->fd, (char*) &SGDMAMemory, length, 0); // printf("Send package 2\n"); error_code = send(conns->fd, (char*) &length, sizeof(length), 0); error_code = send(conns->fd, (char*) &SGDMAMemory + length, length, 0); construct_standard_mm_to_st_descriptor(desc_tx_ptr, SGDMAMemory, 4*512, DESCRIPTOR_CONTROL_GENERATE_SOP_MASK | DESCRIPTOR_CONTROL_GENERATE_EOP_MASK); write_standard_descriptor(MSGDMA_TX_CSR_BASE, MSGDMA_TX_DESCRIPTOR_SLAVE_BASE, desc_tx_ptr); // memset(SGDMAMemory, 0, sizeof(SGDMAMemory)); err = OSSemPost(Semaphore); OSTimeDlyHMSM(0,0,0,5); - Altera_Forum
Honored Contributor
My question:
I couldn't get full transfer mSGDMA Memory with nios, Am I missed something? Please help... thank you.. - Altera_Forum
Honored Contributor
So you DMA data from the FFT into memory, then have another DMA transfer to push the recently copied memory locations into the MAC correct? If so have you debugged the first transfer to ensure that it's completing correctly because at least that will narrow down the culprit.
The setup looked ok to me except it doesn't look like you are using interrupts when you construct the descriptor. So there are two layers of interrupt setup that needs to happen, the global interrupts need to be enabled in the control register of the CSR port, but in order for interrupts to fire you have to enable them when constructing the descriptor as well. There are a few interrupt bits in the control field of the descriptor but the one you want is the transfer done interrupt. Some additional info: The early termination interrupt flag is for ST-->MM packet transfers, and it fires (if enabled) when the DMA ends up moving more streaming data than what you specify as the transfer length. In other words the DMA lets you put a cap on the amount of data moved in a ST-->MM transfer in the event that the EOP bit never arrives. There is also an error interrupt as well to let you know if any of the ST-->MM data has any of the error bits asserted. - Altera_Forum
Honored Contributor
Hmmm.. yes you are right.. I use triple speed ethernet example and adds some module for my purpose.
And yes, I have debugged it.. I use mSGDMA MM-ST to check streaming data in Signal Tap, and works fine. But not in TCP IP Yes, I have ISR Callback
Thanks for your additional info.. In the latest, there are some things that I have changed. And it worked for me... Before: Memory Altmemphy DDR After: double Onchip Memory for successive Nios and mSGDMA Before: In MM to TCP IP Task/* * ISR Function when mSGDMA Interrupt happens */ static void msgdma_rx_complete_isr(void *context) { // IOWR_ALTERA_AVALON_PIO_DATA(PERIPHERAL_SUBSYSTEM_LED_PIO_BASE, 0xfd); stop_dispatcher(MSGDMA_RX_CSR_BASE); while(read_stopped(MSGDMA_RX_CSR_BASE) == 0); reset_dispatcher(MSGDMA_RX_CSR_BASE); enable_global_interrupt_mask(MSGDMA_RX_CSR_BASE); msgdma_int_rx = 2; }
After: In MM to TCP IP Taskdo { read_ptr = (read_ptr + 1) % 2; OSSemPend(Semaphore, 2, &err); } while(err == OS_ERR_TIMEOUT); // printf("------------------------------------------\n%d\n------------------------------------------\n", sizeof(iNetworkRadarData.data)); // printf("Send package 1\n"); length = sizeof(SGDMAMemory)/2; error_code = send(conns->fd, (char*) &length, sizeof(length), 0); error_code = send(conns->fd, (char*) &SGDMAMemory, length, 0); // printf("Send package 2\n"); error_code = send(conns->fd, (char*) &length, sizeof(length), 0); error_code = send(conns->fd, (char*) &SGDMAMemory + length, length, 0); construct_standard_mm_to_st_descriptor(desc_tx_ptr, SGDMAMemory, 4*512, DESCRIPTOR_CONTROL_GENERATE_SOP_MASK | DESCRIPTOR_CONTROL_GENERATE_EOP_MASK); write_standard_descriptor(MSGDMA_TX_CSR_BASE, MSGDMA_TX_DESCRIPTOR_SLAVE_BASE, desc_tx_ptr); // memset(SGDMAMemory, 0, sizeof(SGDMAMemory)); err = OSSemPost(Semaphore); OSTimeDlyHMSM(0,0,0,5);do { read_ptr = (read_ptr + 1) % 2; OSSemPend(Semaphore, 2, &err); } while(err == OS_ERR_TIMEOUT); // length = sizeof(SGDMAMemory)/2; alt_u32 memory; for(i = 0; i < 512; i++) { if(read_ptr == 0) memory = IORD_32DIRECT(SGDMA_MEM_0_BASE + i*sizeof(alt_u32), sizeof(alt_u32)); else memory = IORD_32DIRECT(SGDMA_MEM_1_BASE + i*sizeof(alt_u32), sizeof(alt_u32)); } length = 4*1024/8; for(i = 0; i <4; i++) { error_code = send(conns->fd, (char*) &length, sizeof(length), 0); error_code = send(conns->fd, (char*) memory + i*length, length, 0); } err = OSSemPost(Semaphore); OSTimeDlyHMSM(0,0,0,5); - Altera_Forum
Honored Contributor
Note: I do IORD_32DIRECT to copy mSGDMA memory...
when I failed with memcpy... - Altera_Forum
Honored Contributor
If you use IORD_32DIRECT or IOWR_32DIRECT you have to be careful of caching. For example if you use malloc to allocate a buffer and then access it using those cache bypassing macro you might have a coherency issue. Memory allocated from the heap might have already been cached and still persistent in the cache so if you perform a cache bypass to a location that is already cached then you'll have a coherency issue. To avoid this issue you should invalidate the cache for the address range that malloc returns to you to ensure you don't run into this corner case.