Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12603 Discussions

SGDMA Callback fires more often than i restart the SGDMA

Altera_Forum
Honored Contributor II
1,014 Views

Hi,  

 

i have some trouble with SGDMA and TSE. I guess the problem is in the callback function(_ISR_HanderRX) of the RX-SGDMA. Ok let's explain this stuff a little bit: 

 

After first init of the RX-SGDMA the _ISR_HandlerRX function should be called when the descriptor chain is completed. In the ISR_HandlerRX function the Interrupt should be cleared and the tcp/ip stack shall be informed that a new packed has arrived. Then the tcp/ip stack will call the _ReadPacket function and after running this code, the RX-SGDMA shall be reseted for the next turn. 

Problem is, the counters in these functions show me, that the _ISR_HandlerRX functions is called way more often than the _ResetRX function, can anyone explain me why this is happening, i thought that i stopped the interrupt in the ISR_HandlerRx function??? 

 

Here is the Code, also appended as txt-file. 

 

Thx Christian 

 

 

static void _ISR_HandlerRX(void * context, u_long intnum) { aCounter++; //testcounter a // Interrupt clearen und Run-Bit zurücksetzen IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE, ALTERA_AVALON_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK & ~ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK); // inform TCP/IP stack about new packet IP_OnRx(); bCounter++; //testcounter b } static int _ReadPacket(unsigned Unit, U8 *pDest, unsigned NumBytes) { volatile UInt32 ulPacketLengthFromSgdmaRX = 0x00, i = 0x00; volatile UChar8 * pRxBuff = NULL; cCounter++; //testcounter c ulPacketLengthFromSgdmaRX = pSgdmaDescriptor.actual_bytes_transferred; if(IORD_ALTERA_TSEMAC_RX_CMD_STAT(TSE_MAC_BASE) & ALTERA_TSEMAC_RX_CMD_STAT_RXSHIFT16_MSK && ulRxPacketSize > 0) ulPacketLengthFromSgdmaRX -= 2; // when the shift option is used, the length read from the status word is 2 bytes larger than the real frame size, adjust counter! if(NumBytes == ulPacketLengthFromSgdmaRX) { /* test for errors */ if (((pSgdmaDescriptor.status) & ( ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK | // crc error ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK | // parity error ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK | // overflow error ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK | // sync error ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK | // end of package error ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK | // end of package error ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK )) // start of package error == 0) { pRxBuff = pUncachedPtrRx + 2; // pointer to the first field, where the data begins while(NumBytes) // copy all data { pDest = *pRxBuff++; i++; NumBytes--; } } } dCounter++; //testcounter d _ResetRx(); return 0; } static int _ResetRx(void) { volatile alt_u32 timeout=0, ulSgdmaCtrl = 0x00; eCounter++; //testcounter e /*SGDMA RX Softwarereset*/ IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK); IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,0); memset((void*) cRxBufferTmp, 0x00, BUFF_SIZE); memset((void*) &pSgdmaDescriptor , 0x00, sizeof(alt_sgdma_descriptor)); //pUncachedPtrRx = alt_remap_uncached((void*)cRxBufferTmp, BUFF_SIZE); /* rx-sgdma descriptor konstruieren */ alt_avalon_sgdma_construct_stream_to_mem_desc ((alt_sgdma_descriptor *) &pSgdmaDescriptor , // descriptor I want to work with (alt_sgdma_descriptor *) &pSgdmaDescriptor , // pointer to "next" (UInt32 *)pUncachedPtrRx, // starting write_address 0, // read until EOP 0); // don't write to constant address /* register callback for rx-sgdma */ alt_avalon_sgdma_register_callback ((alt_sgdma_dev *) pRxSgdmaDev, (alt_avalon_sgdma_callback) &_ISR_HandlerRX, /* callbackfunction for the interrupt */ (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), /* interrupt if chain completed */ NULL); /* Make sure SGDMA controller is not busy from a former command */ while ((IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK)) { if(timeout++ == ALTERA_TSE_SGDMA_BUSY_TIME_OUT_CNT) return ENP_RESOURCE; // avoid being stuck here } IOWR_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE, 0xff); //clear status register (look at documentation of sgdma status reg) /* SGDMA operation invoked for RX (non-blocking call) */ if(alt_avalon_sgdma_do_async_transfer((alt_sgdma_dev *) pRxSgdmaDev, (alt_sgdma_descriptor *) &pSgdmaDescriptor ) != 0) return -1; ulSgdmaCtrl = IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE); // read SGDMA Ctrl Register IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE, ulSgdmaCtrl | ALTERA_TSE_SGDMA_INTR_MASK); //write SGDMA Ctrl Regs fCounter++; //testcounter f return 0; }
0 Kudos
3 Replies
Altera_Forum
Honored Contributor II
248 Views

I don't see the second descriptor being set up anywhere. Is the "OWNED_BY_HW" bit cleared in the second descriptor so it is not processed? 

 

If it is set, the DMA controller is probably already processing the second descriptor when you clear the run bit and executing a random transfer then throwing another interrupt.
0 Kudos
Altera_Forum
Honored Contributor II
248 Views

Hi, 

 

I've never used the SGDMA before but one thing I noticed while taking a quick look at the code: 

 

In _resetrx you are trying to reset the SGDMA by writing ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK once. But I think it must be done twice. Doesn't it?! 

 

I guess that's not solving your problem but maybe it's causing trouble too. 

 

Regards 

 

 

ADDITION: Do you really need the software reset? Quoting the embedded ip user guide: 

 

--- Quote Start ---  

Executing a software reset when a DMA transfer is active may 

result in permanent bus lockup until the next system reset. 

Hence, Altera recommends that you use the software reset as 

your last resort. 

--- Quote End ---  

0 Kudos
Altera_Forum
Honored Contributor II
248 Views

The Own-By Bit of the second descriptor is cleared, so that shouldn't be the problem.  

 

I also deleted the Software-Reset of the SGDMA. I thought so too, that the SW-Reset isn't necessary. 

 

I also think we found the problem within the TCP/IP Stack. I'll try to set up a second descriptor chain for RX, seems also that one Rx Chain limited the speed extremly. So let's hope for the best.  

 

I'll report if my new idea works.
0 Kudos
Reply