Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
12 years ago

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's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored 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's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored 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)

    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();
    }

    After transferred through ethernet, by simple TCP IP program to draw FFT graph. I've got only some partial data.

    			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);

    Please see the following picture

    Thank you...
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    My question:

    I couldn't get full transfer mSGDMA Memory with nios, Am I missed something?

    Please help... thank you..
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored 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's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored 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

    /*
     * 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;
    }

    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

    			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);

    After: In MM to TCP IP Task

    			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's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Note: I do IORD_32DIRECT to copy mSGDMA memory...

    when I failed with memcpy...
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored 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.