This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/TM4C1294NCPDT: Semaphore in SPI DMA causing overflow Error

Part Number: TM4C1294NCPDT

Tool/software: TI-RTOS

Hi,

Code:

void task()

{

DmaInit()

While(1){

Semaphore_pend();

}

}

void DmaInit(){

SPIRX(); //in ping pong mode

SPITX(); //in ping pong mode

SPIDMAInterrupt(); //dma tx and rx interrupt;

}

IniHandler(){

//ping pong reconfigure for tx and rx

count++;

semaphore_post();

}

int main()

{

Task_init();

return 0;

}

The above is the outline of the code and the device configured as slave device.

The problem I am getting is I cannot post a semaphore inside the SPI dma handler.

Each ping and pong buffer size is 64 bytes. if I send minimum to 128bytes of data, the semaphore post working fine.

if I send more than 128 bytes(adding ping and pong) I am getting the below error.

assertion failure: A_overflow: Count has exceeded 65535 and rolled over.

xdc.runtime.Error.raise: terminating execution

The error says that the semaphore post is keep on posting, but if I disable the semaphore post and check the count value is giving 2 multiples each time I initiate a transfer.

That means without semaphore post, N number of data's are received and transmitted.

Question:

1. Why after posting semaphore post, the above error is triggering?

2.Once the semaphore post is enabled, the count value is also incrementing N times. But without semaphore, it increasing in multiples of 2.

which means that working fine.

3. Can you give any suggestions to handle the DMA received data's in ping and pong buffers.

I have attached the code for reference.

spi_dma.c
/*
 * analog_input.c
 *
 *  Created on: 14-Jul-2017
 *      Author: Balasubramani.C
 */

#include <ioc_main.h>


#define SSI_TXBUF_SIZE          1024
#define SSI_RXBUF_SIZE          64

uint8_t pui8ControlTable[1024];

uint8_t ui8DMATxBufferpri[SSI_TXBUF_SIZE];
uint8_t ui8DMATxBufferalt[SSI_TXBUF_SIZE];

uint8_t ui8DMAPrimary_Buffer[SSI_RXBUF_SIZE];
uint8_t ui8DMASecondary_Buffer[SSI_RXBUF_SIZE];

uint8_t ui8SendBuf[SSI_TXBUF_SIZE];
uint8_t ui8ReceivedBuf[SSI_RXBUF_SIZE];

uint32_t ui8counter = 0;
uint32_t receivebuffCount = 0;
uint32_t receiveadded[2];
//*****************************************************************************
//
// The interrupt handler for uDMA errors.  This interrupt will occur if the
// uDMA encounters a bus error while trying to perform a transfer.  This
// handler just increments a counter if an error occurs.
//
//*****************************************************************************
void uDMAErrorHandler(void)
{
    uint32_t ui32Status;

    //
    // Check for uDMA error bit
    //
    ui32Status = uDMAErrorStatusGet();

    //
    // If there is a uDMA error, then clear the error and increment
    // the error counter.
    //
    if(ui32Status)
    {
        uDMAErrorStatusClear();
    }
}

/**
 *******************************************************************************
 * @file 		analog_input.c
 * @ingroup     analog_input
 *
 * @handler     ioc_RxBufferProcessing(uint8_t *ui8buffer)
 *
 * @brief
 *           	This function will get a buffer from the task and add the entire
 *           	buffer data's and print in the CCS console. This function is used
 *           	to verify the received data to SPI DMA.
 *
 * @param       ui8buffer		Pointer to array
 *
 * @return      NULL
 *
 ******************************************************************************/

uint32_t ioc_RxBufferProcessing(uint8_t *ui8buffer)
{
	uint8_t i;
	uint32_t ui32AddedData = 0;
	for(i = 0; i < SSI_RXBUF_SIZE; i++)
	{
		ui32AddedData = ui32AddedData + *(ui8buffer+i);
	}

	return ui32AddedData;
//   System_printf("Added received data : %d\n", ui32AddedData);
//    System_flush();
}



/**
 *******************************************************************************
 * @file 		analog_input.c
 * @ingroup     analog_input
 *
 * @handler     AnalogInputADCISRHandler(void)
 *
 * @brief
 *           	This ISR will be invoked from DMA interrupt whenever DMA data
 *           	buffer gets filled by analog input channel data. It will
 *           	generate SPI DMA interrupt for processing analog input data.
 *           	Interrupt source vector number TBD
 *           	depend on Hardware design document.
 *           	To validate this ISR handler in Eval Board, currently vector
 *           	number 23 is assigned as interrupt source.
 *
 * @param		NULL
 *
 * @return      NULL
 *
 ******************************************************************************/
uint32_t ulMode;
uint32_t ui32Status;
uint32_t ui32IntStatus;
void AnalogInputADCISRHandler(void)
{

    //
	// Read the interrupt status of the SSI.
	//
	ui32Status = SSIIntStatus(SSI0_BASE, TRUE);

	SSIIntClear(SSI0_BASE, ui32Status);

	ui32IntStatus = SSIIntStatus(SSI0_BASE, FALSE);



//	*(volatile uint32_t *)(SSI0_BASE + SSI_O_ICR) = SSI_DMARX;

/*	if((uiInt32Status & SSI_RXFF) && (!uDMAChannelIsEnabled(UDMA_CHANNEL_SSI0RX))){
		uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
		uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
	} */

	//
	// Clear any pending status, even though there should be none since no SSI
	// interrupts were enabled.  If SSI error interrupts were enabled, then
	// those interrupts could occur here and should be handled.  Since uDMA is
	// used for both the RX and TX, then neither of those interrupts should be
	// enabled.
	//


	if(ui32Status & SSI_DMARX)
	{
		SSIIntClear(SSI0_BASE, SSI_DMARX);

		//check primary Rx channel
		ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT);

		if(ulMode == UDMA_MODE_STOP) {
		memcpy(ui8ReceivedBuf, ui8DMAPrimary_Buffer, SSI_RXBUF_SIZE);
		uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
				UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR),
				ui8DMAPrimary_Buffer, sizeof(ui8DMAPrimary_Buffer));
		}

		//check Alternate Rx channel
		ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT);
		if(ulMode == UDMA_MODE_STOP)  {
		  memcpy(ui8ReceivedBuf, ui8DMASecondary_Buffer, SSI_RXBUF_SIZE);
		  uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT,
				  UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR),
				  ui8DMASecondary_Buffer, sizeof(ui8DMASecondary_Buffer));

		}
		ui8counter++;
/*		receiveadded[receivebuffCount] = ioc_RxBufferProcessing(ui8ReceivedBuf);
		receivebuffCount++; */
//		if(ui8counter % 8 == 0){
//		receivebuffCount = 0;
		Semaphore_post(Sem_dma_Handle);
//		}
	}

	if(ui32Status & SSI_DMATX)
	{
		SSIIntClear(SSI0_BASE, SSI_DMATX);
		//check primary Tx channel
		ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT);

		if(ulMode == UDMA_MODE_STOP)
		{
			GPIO_toggle(Board_LED0);
			 uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
									 UDMA_MODE_PINGPONG, ui8DMATxBufferpri,
									 (void *)(SSI0_BASE + SSI_O_DR), sizeof(ui8DMATxBufferpri));
		}

		//check alternate Tx channel
		ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT);
		if(ulMode == UDMA_MODE_STOP)
		{
			 GPIO_toggle(Board_LED1);
			uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT,
									UDMA_MODE_PINGPONG, ui8DMATxBufferalt,
									(void *)(SSI0_BASE + SSI_O_DR), sizeof(ui8DMATxBufferalt));
		}
	}


	// TODO memcopy from DMA buffer to Analog input processing buffer
}
/*
void DmaTxSwi()
{

}

void DmaRxSwi()
{


	ui8counter++;
	receiveadded[receivebuffCount] = ioc_RxBufferProcessing(ui8ReceivedBuf);
	receivebuffCount++;
	if((ui8counter % 4) == 0)
	{
		receivebuffCount = 0;
		Event_post(Event_ADC_ISR_Handler, Event_Id_00);
	}
}*/
/**
 *******************************************************************************
 * @file 		analog_input.c
 * @ingroup     analog_input
 *
 * @handler     ioc_DmaAdcInit(void)
 *
 * @brief
 *           	This function will initialize the SPI0 as DMA peripheral
 *           	Create the control table for both Tx and Rx in Ping Pong mode
 *           	to have a continuous data flow.
 *
 * @param       NULL
 *
 * @return      NULL
 *
 ******************************************************************************/
void ioc_DmaAdcInit(void)
{
	uint16_t ui8Idx = 0;
    uint8_t i = 0;
	//
	// Fill the TX buffer with a simple data pattern.
	//
	for(ui8Idx = 0; ui8Idx < SSI_TXBUF_SIZE; ui8Idx++)
	{
		if((ui8Idx % 64) != 0)
		{
			ui8SendBuf[ui8Idx] = i+1;
			i++;
		}
		else
		{
			i = 0;
			ui8SendBuf[ui8Idx] = i+1;
			i++;
		}
	}

	memcpy(ui8DMATxBufferpri, ui8SendBuf, SSI_TXBUF_SIZE);
	memcpy(ui8DMATxBufferalt, ui8SendBuf, SSI_TXBUF_SIZE);

    /* SSI 0 Configuration */
	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI0);

    //
    // Configure the SSI communication parameters.
    //
    SSIConfigSetExpClk(SSI0_BASE, 120000000 /* SysCtlClockGet() */, SSI_FRF_MOTO_MODE_0,
    					SSI_MODE_SLAVE, 4000000, 8);

    //
    // Enable the SSI for operation, and enable the uDMA interface for both TX
    // and RX channels.
    //
    SSIEnable(SSI0_BASE);

    SSIDMAEnable(SSI0_BASE, SSI_DMA_TX | SSI_DMA_RX );

    SSIClockSourceSet(SSI0_BASE, SSI_CLOCK_SYSTEM);

    IntEnable(INT_UDMAERR);
    IntRegister(INT_UDMAERR, uDMAErrorHandler);

	 //
	 // Enable the SSI peripheral, and configure it to operate even if the CPU
	 // is in sleep.
	 //
	 SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
	 SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);

	 //
	 // Enable the uDMA controller.
	 //
	 uDMAEnable();

	 //
	 // Point at the control table to use for channel control structures.
	 //
	 uDMAControlBaseSet(pui8ControlTable);


    //
    // Put the attributes in a known state for the uDMA SSI1RX channel.  These
    // should already be disabled by default.
    //
    uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0RX,UDMA_ATTR_USEBURST | UDMA_ATTR_REQMASK );
    uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0RX,
    							(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | UDMA_ATTR_REQMASK));

//    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0RX,UDMA_ATTR_USEBURST );
//    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0RX,UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST );
    //
    // Configure the control parameters for the primary control structure for
    // the SSI RX channel.  The primary contol structure is used for the "A"
    // part of the ping-pong receive.  The transfer data size is 8 bits, the
    // source address does not increment since it will be reading from a
    // register.  The destination address increment is byte 8-bit bytes.  The
    // arbitration size is set to 4 to match the RX FIFO trigger threshold.
    // The uDMA controller will use a 4 byte burst transfer if possible.  This
    // will be somewhat more effecient that single byte transfers.
    //
    uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
							  UDMA_ARB_4);
    //
    // Set up the transfer parameters for the SSI RX primary control
    // structure.  The mode is set to ping-pong, the transfer source is the
    // SSI data register, and the destination is the receive "A" buffer.  The
    // transfer size is set to match the size of the buffer.
    //
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
                               UDMA_MODE_PINGPONG,
                               (void *)(SSI0_BASE + SSI_O_DR),
							   ui8DMAPrimary_Buffer, sizeof(ui8DMAPrimary_Buffer));


    //
    // Configure the control parameters for the alternate control structure for
    // the SSI RX channel.  The alternate contol structure is used for the "B"
    // part of the ping-pong receive.  The configuration is identical to the
    // primary/A control structure.
    //
    uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
							  UDMA_ARB_4);
    //
    // Set up the transfer parameters for the SSI RX alternate control
    // structure.  The mode is set to ping-pong, the transfer source is the
    // SSI data register, and the destination is the receive "B" buffer.  The
    // transfer size is set to match the size of the buffer.
    //
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT,
                               UDMA_MODE_PINGPONG,
                               (void *)(SSI0_BASE + SSI_O_DR),
							   ui8DMASecondary_Buffer, sizeof(ui8DMASecondary_Buffer));


    //
       // Put the attributes in a known state for the uDMA SSI1RX channel.  These
       // should already be disabled by default.
       //
    uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX,UDMA_ATTR_USEBURST | UDMA_ATTR_REQMASK );
    uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX,
    							(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | UDMA_ATTR_REQMASK));

//    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX,UDMA_ATTR_USEBURST );
//    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX,UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST );
	//
	// Configure the control parameters for the SSI TX.  The uDMA SSI TX
	// channel is used to transfer a block of data from a buffer to the SSI.
	// The data size is 8 bits.  The source address increment is 8-bit bytes
	// since the data is coming from a buffer.  The destination increment is
	// none since the data is to be written to the SSI data register.  The
	// arbitration size is set to 4, which matches the SSI TX FIFO trigger
	// threshold.
	//
	uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
							  UDMA_SIZE_8 | UDMA_SRC_INC_8 |
							  UDMA_DST_INC_NONE |
							  UDMA_ARB_4);

	//
	// Set up the transfer parameters for the uDMA SSI TX channel.  This will
	// configure the transfer source and destination and the transfer size.
	// Basic mode is used because the peripheral is making the uDMA transfer
	// request.  The source is the TX buffer and the destination is the SSI
	// data register.
	//
	uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
							UDMA_MODE_PINGPONG, ui8DMATxBufferpri,
							   (void *)(SSI0_BASE + SSI_O_DR),
							   sizeof(ui8DMATxBufferpri));

	//
	// Configure the control parameters for the SSI TX.  The uDMA SSI TX
	// channel is used to transfer a block of data from a buffer to the SSI.
	// The data size is 8 bits.  The source address increment is 8-bit bytes
	// since the data is coming from a buffer.  The destination increment is
	// none since the data is to be written to the SSI data register.  The
	// arbitration size is set to 4, which matches the SSI TX FIFO trigger
	// threshold.
	//
	uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT,
							  UDMA_SIZE_8 | UDMA_SRC_INC_8 |
							  UDMA_DST_INC_NONE |
							  UDMA_ARB_4);

	//
	// Set up the transfer parameters for the uDMA SSI TX channel.  This will
	// configure the transfer source and destination and the transfer size.
	// Basic mode is used because the peripheral is making the uDMA transfer
	// request.  The source is the TX buffer and the destination is the SSI
	// data register.
	//
	uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT,
							UDMA_MODE_PINGPONG, ui8DMATxBufferalt,
							   (void *)(SSI0_BASE + SSI_O_DR),
							   sizeof(ui8DMATxBufferalt));

    //
    // Now both the uDMA SSI TX and RX channels are primed to start a
    // transfer.  As soon as the channels are enabled, the peripheral will
    // issue a transfer request and the data transfers will begin.
    //
	uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
	uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);

	//
	// Enable the SSI DMA TX/RX interrupts.
	//
	SSIIntEnable(SSI0_BASE, SSI_DMARX | SSI_DMATX);

}


/**
 *******************************************************************************
 * @file 		analog_input.c
 * @ingroup     analog_input
 *
 * @task        AnalogInputProcessingFunc()
 *
 * @brief
 *      		This task will be invoked from DMA ISR handler for processing
 *      		analog input channel data. This will apply median and CIC filter
 *      		depending upon the configurable median/CIC filter value and
 *      		store output values into analog input local buffer.
 *
 * @param       NULL
 *
 * @return      NULL
 *
 ******************************************************************************/
void AnalogInputProcessingFunc()
{

#ifdef DMA_ADC_TEST
	ioc_DmaAdcInit();
#endif
	while(1)
	{
//		Event_pend(Event_ADC_ISR_Handler, Event_Id_00, Event_Id_NONE,
//											BIOS_WAIT_FOREVER);
		Semaphore_pend(Sem_dma_Handle, BIOS_WAIT_FOREVER);

		System_printf("Post count %d\n", ui8counter);
		System_flush();


		IOC_DEBUG_APP("In Analog Input Processing task\n");
		IOC_DEBUG_APP_FLUSH();

		// TODO Memcopy from DMA buffer to Analog input processing buffer
		// TODO Median Filter/ CIC filter implementation

		/* event post for task monitor task */
		//Event_post(Event_Task_Monitor, Event_Id_00);
	}

}

Below is the snapshot of receiving 256 bytes of data with 64bytes of ping pong buffer, with disabling the semaphore_post in ISR function. The count is captured in Expression in runtime.

Below is the snapshot of Enabling the samephore_post in same code inside ISR

Regards,

Manohar

  • Hi Manohar,

    Is there a reason you did not want to use the SPI driver in TI-RTOS? You can look at the SPI Loopback example to see how it works.

    What type of semaphore did you create...counting or binary?

    What version of TI-RTOS are you using?

    Todd
  • Hi Manohar,

     I don't see your image.

     First of all I don't see you starting the RTOS by calling BIOS_start() in the main(). Is it part of your Task_init()? What does the Task_init() contain?

     I think the error message indicates that your application is calling Semaphore_post() many times without any calls to Semaphore_pend().   This is causing the semaphore count to grow until it overflows.  Since the semaphore_post is done in the ISR which has higher priority than the RTOS task is able to pend, this may mean there are multiple DMA_TX or DMA_RX interrupts occurring before the task is able to execute.

     Can you check your  ui32IntStatus = SSIIntStatus(SSI0_BASE, FALSE) and see if the prior clearing of the interrupt flag bits really happen? I read the below paragraph from the datasheet. It says that to first disable TXDMAE before clearing the interrupt flag.

    If the μDMA is enabled and has completed a data transfer from the Tx FIFO, the DMATXRIS bit is

    set in the SSIRIS register and cannot be cleared by setting the DMATXIC bit in the SSI Interrupt

    Clear (SSIICR) register. In the DMA Completion Interrupt Service Routine, software must disable

    the μDMA transmit enable to the SSI by clearing the TXDMAE bit in the QSSI DMA Control

    (SSIDMACTL) register and then setting the DMATXIC bit in the SSIICR register. This clears the

    DMA completion interrupt. When the μDMA is needed to transmit more data, the TXDMAE bit must

    be set (enabled) again.

     If possible I will also suggest that you start with simpler DMA configuration such as non ping-pong mode. Can you get it to work with 256 bytes of data transfer?

  • Hi Charles,

    I have already tried to send and receive 256 bytes of data and above, its worked fine.

    I have seen the status of Raw Interrupt status,
    ui32IntStatus = SSIIntStatus(SSI0_BASE, FALSE) ;

    This gives the DMATXRIS bit is set initially after enabling the TXDMAE bit in the QSSI DMA Control register.
    This DMATXRIS bit can be cleared in the ISR.

    My Question:
    1. I am configuring my device in slave mode. After Clearing the bit DMATXRIS in ISR, The bit is keep on enabling in a particular interval and ISR clearing the bit again.
    This shows that the DMA Tx buffer is completed without the master device initializing the transfer. why this is happening?
    Without the master initialising the transfer, why DMA Tx completion interrupt is triggering? why No handshake between SPI buffer and DMA buffer?

    2. Since I am using pingpong mode, it wont create any problem in disabling the channel in ISR? because data will be received continuously.



    Regards,
    Manohar.
  • Hi,

    Added information:
    The DMARXRIS bit is not at all disabling, this flag keep on posting the interrupt to occur. Even if I clear the bit by setting 1.


    This is why the semaphore post is keep on posting.


    The BIOS_start function will be called in int main(), In main function the task is created. Inside task function before while loop, the dma is initialised as in the doc I have attached at the beginning.



    Regards,
    Manohar
  • Hi Charles,

    e2e.ti.com/.../361916

    above is the issue I am facing, I cant clear the DMATXRIS and DMARXIS interrupt bits.




    Regards,
    Manohar
  • Hi Manohar,

    I guess you have already tried to first disable the DMA before clearing the DMATX flag according to the datasheet, correct? Did it make a difference?

    Unfortunately, it seems like this problem has been observed/reported by other users as you have pointed out in the link. If possible, can you do away with ping-pong mode as it seems only ping-pong mode having this problem.
  • Hi Charles,

    yes, I had the tried to clear the DMATX flag after disabling the DMA enable bit. But even though I cant clear the interrupt flag.

    Below is the code I am working on DMA in basic mode with SPI as master,

    *********************************************************************************************************
    void ISRfunction()
    {
    uint32_t ui32Status;

    ui32Status = SSIIntStatus(SSI1_BASE, 1);

    SSIIntClear(SSI1_BASE, ui32Status);

    SSIIntClear(SSI1_BASE, SSI_DMATX);

    ui32Counter++;

    }


    void DmaDacInit(void)
    {
    uint16_t ui8Idx = 0;

    //
    // Fill the TX buffer with a simple data pattern.
    //
    for(ui8Idx = 0; ui8Idx < SSI1_TXBUF_SIZE; ui8Idx++)
    {
    DMASSI1TxBuffer[ui8Idx] = ui8Idx + 1;

    }

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);

    //
    // Enable the uDMA controller.
    //
    uDMAEnable();

    //
    // Point at the control table to use for channel control structures.
    //
    uDMAControlBaseSet(pui8ControlTableArr);

    /* SSI 0 Configuration */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI1);


    SSIConfigSetExpClk(SSI1_BASE, 120000000 /* SysCtlClockGet() */, SSI_FRF_MOTO_MODE_0,
    SSI_MODE_MASTER, 4000000, 8);

    //
    // Configure the SSI communication parameters.
    //

    SSIClockSourceSet(SSI1_BASE, SSI_CLOCK_PIOSC);

    //
    // Enable the SSI for operation, and enable the uDMA interface for both TX
    // and RX channels.
    //
    SSIEnable(SSI1_BASE);

    SSIDMAEnable(SSI1_BASE, SSI_DMA_TX);


    uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI1TX, UDMA_ATTR_USEBURST | UDMA_ATTR_REQMASK );

    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI1TX, UDMA_ATTR_HIGH_PRIORITY);

    uDMAChannelControlSet(UDMA_CHANNEL_SSI1TX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_8 |
    UDMA_DST_INC_NONE |
    UDMA_ARB_4);

    uDMAChannelTransferSet(UDMA_CHANNEL_SSI1TX | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC, DMASSI1TxBuffer,
    (void *)(SSI1_BASE + SSI_O_DR),
    sizeof(DMASSI1TxBuffer));


    uDMAChannelEnable(UDMA_CHANNEL_SSI1TX);

    //
    // Enable the SSI DMA TX interrupts.
    //
    IntEnable(INT_SSI1);

    SSIIntEnable(SSI1_BASE, SSI_DMATX);

    }

    void task_tx()
    {

    DmaDacInit();
    while(1)
    {

    }
    }

    int main()
    {
    Task_Params_init(&taskParams);
    taskParams.arg0 = 1000;
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &task0Stack;
    Task_construct(&task0Struct, (Task_FuncPtr)task_tx, &taskParams, NULL);

    /* Start BIOS */
    BIOS_start();

    }

    *******************************************************************************************************

    I am still facing the same issue, Cant clear the DMATX interrupt clear flag. Can you work on the above code? and let me anymore configuration I am missing?

    After calling the below function, the ISR in invoked Next.
    SSIIntEnable(SSI1_BASE, SSI_DMATX);

    Even if I invoke the above function without Enabling the DMAEnable bit set. The ISR is invoked.
    why?


    Regards,
    Manohar
  • Hi Manohar,
    Can you please upload the file that contains the above code?
  • DMA_CODE.zip

    Hi,

    I am using SPI 0 with the below pin configs,

     /*SSI0 */
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

        GPIOPinConfigure(GPIO_PA2_SSI0CLK);
        GPIOPinConfigure(GPIO_PA3_SSI0FSS);
        GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
        GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);

        GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 |
                                        GPIO_PIN_3 | GPIO_PIN_2);

    Please help me with the issue I am facing, I have attached the code along with it.

    Regards,

    Manohar

  • Manohar,

    If you are using TI-RTOS, you cannot use SSIIntRegister if you are making kernel calls in the ISR. You should use Hwi_create (or Hwi_construct). You can look at the SPI driver in TI-RTOS (i.e. tirtos_tivac_2_16_01_14\products\tidrivers_tivac_2_16_01_13\packages\ti\drivers\spi\SPITivaDMA.c) to see how this is done.

    Todd
  • Hi Todd,

    Thank you...

    I have created the ISR function in GUI with interrupt vector number of 23 for SSI0 in actual integrated code. The above code is just a demo code.

    I am not facing issue in calling the ISR after the ISR is initialised, The issue is that I can not clear the interrupt flag register DMATX bit.
    After every transfer is done.
    ***********************************************************************************************************************

    Hi Charles,
    For your information, I am using CCS ver.6 , So you can prefer the same for the above demo code.



    Regards,
    Manohar
  • Hi Manohar,
    Sorry, I have not got a chance to running the code yet. I will try later.
  • Hi Charles,

    I have gone through the Data sheet completely and TI forum, No solution is provided for this issue.

    Can you please make it ASAP.


    Regards,
    Manohar
  • Hi Manohar,
    I will be out of office in the morning shortly. I will try this afternoon. From the forum searches, it seems there is no well defined solution at the moment.
  • Thank you for your support Charles.



    Regards,
    Manohar
  • Hi Manohar,
    I ran your code and could reproduce it where the DMATX bit is not cleared after calling SSIIntClear(SSI0_BASE, ui32Status). But I don't know if I'm just hitting a known issue reported in the other posts that you referenced. I need to investigate a bit more. In the meantime, if you could play with it more for workaround it will be great. Also to make it simpler to debug I will suggest if you can retry the example without the RTOS so we can isolate if the problem has something to do with using the semaphore.
  • Hi Charles,

    I have removed the DMA TX bit in SSIMI register and now using the TXOT bit. This interrupt is triggered if the data is sent out of the serializer and the code I have attached previously working fine now.

    Now I have implemented Ping pong mode for Both TX and RX in Slave mode. I am using only DMARX bit for interrupt to reconfigure.

    TX buffer size - 1024B

    RX buffer size - 64B

    I have attached the code for your reference.

    Additional info:

    I used semaphore post which gives the above error as I said, So I am using Event.

    Issue:

    1.The Event in the added code is posting for only 2 times, even If I send N datas.

    2.The actual Rx buffer size 64B, then pingpong Rx buffer size is 128B, if I send 128B of data, The code working fine.

    3.If I send more than 128B, The RX channel is getting disabled. That you can see in the DMA Enable set bit.

    4.So I am again re-enabling the channel in ISR.

    5. One more issue, Even if I send N bytes of data from master to slave(controller) the Event is only posting for 2 times. That is ensured by using a counter in the task.

    3034.DMA_CODE.zip

    Can you please build the above code and check? why the event is posting for only 2 times?

    Regards,

    Manohar

  • Hi Manohar,
    Glad that you are making good progress. I don't have the bench setup at home to run your code. Plus I'm not an expert on the RTOS contexts. Can you first confirm if you configure your ping-pong DMA setup in a non-RTOS environment, will it work or not?
  • Hi Charles,

    I am working on UART DMA from the default code available, TI developed UART DMA in bare metal code which requires older version of CCS.
    Currently I am using version 6, so I need a older version to test the code.

    After I work on it, I will let you.


    Regards,
    Manohar
  • Hi Charles,

    I have worked on the udma demo code provided by TI, The same DMA TX bit is not cleared in the uart dma example code.
    Instead they are the interrupt from UART to the controller.

    The code performs data transfer by uart through internal loopback, I can see the number of count of interrupt generated in ROV from the counter variables.

    I have monitored the DMA TX interrupt bit, its not cleared when the clear function is called. Its just disabled by disabling the UART interrupt.

    For my purpose I cannot disable the interrupt, because I am configuring the SSI in slave mode. The transfer will be initiated by the external master. So as soon as I re-enable the DMA TX interrupt for another transfer, The controller thinks as interrupt is generated and it calls the ISR function, Even the transfer is not done.



    Regards,
    Manohar
  • 5383.DMA_CODE.zipHi Charles,

    I have found out the issue in the code, but cannot find why this kind of reason triggering the issue in the code.

    The Event or semaphore that I am using to handle the received data causing the issue in clearing the interrupt bit.

    If I replace the event pend with task sleep inside the task, I can print the number of times the interrupt triggered that is correspondingly equal to the buffer size. That means its working fine.

    I have attached you the reference code, Can you try the code by Enabling event pend in task and comment out the task sleep.

    Can you suggest me any alternate way to handle the data received in DMA RX buffer? I am having RX buffer size to be 64B.

    What I have done in the code is, after every 64B of data received in DMA RX buffer, I am posting a Event in ISR and data can b handled in task.

    But this technique is not working. I am not sure that the event post and pend causing the issue all the time. why this event function not allowing the interrupt bit to clear?

    Will it cause any issue? If I continuously post the event in ISR before completing the event pend actions in Task?

    Regards,

    Manohar

  • Hi Charles,

    Try the below code, I have disabled the event pend in task and used a task sleep to the counter value in ISR function.

    I have verified the code, by sending a 1024B of data. the counter value printed is 17.

    RX buffer size - 64B - 16 interrupt

    TX buffer size - 1024B - 1 interrupt

    totally 17 interrupt count is printed.

    If I enable the Event pend inside the task, the interrupt bit is not getting cleared.

    Can you suggest me alternate way to handle the data received in the DMA Rx buffer?

    Regards,

    Manohar

    5857.DMA_CODE.zip

  • Hi MB,

    Just curious have you tried to double clear the interrupt bit by asserting the clear call twice or even try to unpend the stuck bit?
  • Hi Manohar,
    What is the hardware setup to run your code? I tried running the code as is but it is just printing "Counter increment in Task : 0" every 1ms. The reason is that InitSSI0Transfer is not even entered in my case.
  • Hi,
    Yes I have tried all the way to clear the bit by particularly clearing the bit and also by reading the entire masked interrupt status.
    No technique clears the interrupt bit.
  • Hi Charles,

    That because the SPI DMA is configured in slave mode. You have to use external master SPI to initiate the transfer.
    For my purpose, I am using the Aardvark Analyser as master device From the analyser we can transfer as much of data we want.


    Regards,
    Manohar
  • Hi Charles,

    Please suggest me some ways to handle the received data to the DMA buffer from SPI buffer.
    My receive data buffer size is 64B for each ping and pong.

    Previously my method of handling the data is:
    For every DMARX buffer interrupt, The event or semaphore is posted and task executes to handle the data.

    The above method is not working good, because using event or semaphore causing some interrupt clearing problems. That I cannot receive maximum of 128B of data. If I try to receive more that 128B of data, the interrupt bit is cannot be cleared and keep on ISR function is getting triggered.

    Question:
    1. Suggest me some ways to handle the data after every DMA RX buffer gets filled.



    Regards,
    Manohar
  • Hi Manohar,
    I created an external SPI master to send the slave MCU 1024 bytes of data. I can see that with using event_post and event_pend the SSI0IntHandler is getting called repeatedly. The DMARX remains set. Without the event_post and event_pend I do see Counter increment in Task : 17 being printed out. However, I don't know the reason as to why and how the event_post has anything to do with the DMARX bit. Will need to investigate more.
  • Hi Manohar,
    I spent some time debugging and played with different experiments. I found that by commenting out the system_printf() and system_flush() inside your task will make it work. Please give it a try. This is with using the event_post() in the ISR and event_pend() inside the task. What might have happened is that the system_printf() may have taken too much time to print to the console before the next signal from event_post comes in.
  • System_printf data is stored in an internal buffer (I'm assuming you are using SysMin as the underlying system provider). The System_flush will write this data to the CIO buffer. When the CIO buffer is full or there is a '\n' in the data, the target gets halted so CCS can read the data. This messes up real-time. The same thing happens with printf (by default). You can remove the System_flush and then use Tools->ROV->SysMin to look at the System_printf output.

    Of course if you have lots of System_printf calls, this can slow things down also since ASCII management is notoriously slow, but nothing like halting the target.

    Todd
  • Hi Manohar,

    Manohar B said:
    For every DMARX buffer interrupt, The event or semaphore is posted and task executes to handle the data

    Curious do you have the kernel GPTM Clock_tick configured to handle semaphores, assume it uses the ARM M3 IRQ module configuration.

     

    Manohar B said:
    The above method is not working good, because using event or semaphore causing some interrupt clearing problems
  • Hi Charles,
    This resolved my issue, Thank you.

    Now I am facing different issue. That I cannot merge EMAC and DMA calls in the same code. Since both of them using the System clock that is 120Mhz. The DMA only works when the EMAC is disabled. May I know why?
  • Manohar,

    Can you start a new thread on the new question? Keeping threads shorter helps with searching.

    Todd
  • Hi Manohar,
    Glad your problem is solved. About the EMAC/DMA, your colleague had already opened a new thread today.
  • Hi,


    Thank you very much for helping me to resolve the previous issue :)



    Regards,
    Manohar