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.

Task execution suspended when using scatter gather DMA

Other Parts Discussed in Thread: SYSBIOS

Hi

After receiving a lot of helpful input in the TM4C Microcontrollers Forum, one open issue which is related to the TI RTOS remains unsolved. Therefore Amit Ashara suggested to also post this question here. I hope someone can help me:

In my application, I have an external input providing a signal that will contain irregular bursts of pulses with frequencies ranging between 20kHz and 2Mhz. My goal is to detect the start and end of these bursts. 

Detecting the start is as simple as configuring an Interrupt on the rising edge of the signal. To find the end of the burst I use a timer that is loaded with the equivalent of 55us on every rising edge of the input signal. This means that the interrupt of the timer running out will signal the end of a burst. In order to avoid servicing an interrupt at a very high rate I used a scatter gather DMA to copy the timer load value into the GPTM_TAV register on each rising edge of the input signal. For this to work indefinitely I configured the task list to loop itself upon completion. 

Here is the relevant code:

uint32_t GPTM_ILR= TIMER_DMA_LOAD_PEROID;

// Temporary storage for the first uDMA primary task, for scatter-gather looping
static tDMAControlTable uDMAsg_LoopTask;

static tDMAControlTable uDMAsg_TaskList[] =
{

	//
	// Task 1: copy source buffer to timer interval load
	//
	uDMATaskStructEntry(1,
						UDMA_SIZE_32,
						UDMA_SRC_INC_NONE,
						&GPTM_ILR,
						UDMA_DST_INC_NONE,
						(void*)(TIMER5_BASE + TIMER_O_TAV),
						UDMA_ARB_1,
						UDMA_MODE_PER_SCATTER_GATHER
				),


	//
	// Task 2: loop
	//
	uDMATaskStructEntry(
	                4,
	                UDMA_SIZE_32,
	                UDMA_SRC_INC_32,
	                &uDMAsg_LoopTask,
	                UDMA_DST_INC_32,
	                &(B134_332_DMAControlTable[UDMA_CH14_GPIOE & 0x1f]),
	                UDMA_ARB_4,
	                UDMA_MODE_MEM_SCATTER_GATHER
	        )
};

void initMLSFallingEdgeDetection(){
	// initialize dma channel

	uDMAChannelDisable(UDMA_CH14_GPIOE & 0xffff); // Ensure channel is disabled before modifying register
	uDMAChannelAssign(UDMA_CH14_GPIOE);
	uDMAChannelAttributeDisable((UDMA_CH14_GPIOE & 0xffff)|UDMA_PRI_SELECT,UDMA_ATTR_ALL);
	uDMAChannelAttributeDisable((UDMA_CH14_GPIOE & 0xffff)|UDMA_ALT_SELECT,UDMA_ATTR_ALL);
	

	uDMAChannelScatterGatherSet(UDMA_CH14_GPIOE & 0xffff, 2, uDMAsg_TaskList, true);

	// Copy the primary control structure from the uDMA controltable
	uDMAsg_LoopTask.pvDstEndAddr = B134_332_DMAControlTable[UDMA_CH14_GPIOE & 0xffff].pvDstEndAddr;
	uDMAsg_LoopTask.pvSrcEndAddr = B134_332_DMAControlTable[UDMA_CH14_GPIOE & 0xffff].pvSrcEndAddr;
	uDMAsg_LoopTask.ui32Control = B134_332_DMAControlTable[UDMA_CH14_GPIOE & 0xffff].ui32Control;
	uDMAsg_LoopTask.ui32Spare = B134_332_DMAControlTable[UDMA_CH14_GPIOE & 0xffff].ui32Spare;


}

void ISR_GPIOPortE(){
	GPIOIntClear(MLS_GPIO_PORT,MLS_GPIO_INT_FLAG);
	g_mlsDirtyFlag=1;
        Timer_start(g_mlsTimer);
	GPIODMATriggerEnable(MLS_GPIO_PORT, MLS_GPIO_PIN);
	uDMAChannelEnable(UDMA_CH14_GPIOE & 0xffff);
}

void ISR_Timer5(){

	g_mlsDirtyFlag=1;
	uDMAChannelDisable(UDMA_CH14_GPIOE & 0xffff);
	GPIODMATriggerDisable(MLS_GPIO_PORT,MLS_GPIO_PIN);
	GPIOIntClear(MLS_GPIO_PORT,MLS_GPIO_INT_FLAG);

}

This all works fine with one exception: Task execution gets suspended during the time the uDMA channel is enabled. (Irrespective of the presence or absence of toggling bursts on the inputsignal) 

Here is what I observe on the logic analyzer by toggling GPIOs at the beginning and end of every task, timer interrupt and in the idle loop:

(channel 4 just indicates the correct detection of start and end of bursts)

A typical task yields execution by calling Task_sleep(). Here is the code:

/*********************************************************************************************************************//**
 * @brief task used to read the temperature.
 *
 * collectTemperature() is doing the reading/processing.
 *
 * @param arg0 argument 0
 * @param arg1 argument 1
 *************************************************************************************************************************/
Void taskTemperatureFxn(UArg arg0, UArg arg1)
{
    while(runtime)
    {

	RegisterGPIOToToggle(START, TOGGLE_ALL_TASKS);
        collectTemperature();
        UpdateHeater();

        RegisterGPIOToToggle(STOP, TOGGLE_TEMPERATURE);

    	Task_sleep(100);
    	
    }
}

Does anyone have an idea what's causing this issue? What do I need to do to prevent it or how can I further debg it?

Any help is greatly appreciated!

Regards, 

Roman

  • Could you let me know what version of TIRTOS you are using?

    If I understand your question correctly, you are wondering why the Task is suspended while #5 is executing?
    What is graph #5?

    Judah
  • Hi Judah

    i am using TI RTOS 2.10.01.38 in this project.

    Graph 5 shows the input signal connected to GPIO Port E Pin 4. The first rising edge on that signal triggers ISR_GPIOPortE, every following rising edge triggers a DMA transfer of the scatter gather DMA on channel 14.

    Yes, I would expect the tasks to continue execution no matter if the DMA is enabled or disabled. Is that assumption flawed? Or how can I achieve it?

    Regards

    Roman

  • Roman,

    Yes, I think that assumption is ok. I'd expect the Task to continue executing if its not terminated or blocking.

    I assume you create the Task once and never delete the Task right?

    What's interesting and confusing at the same time is...your graphs seem to indicate that Idle continues to run but the Task does not. A Task, if its ready to run, always has higher priority than Idle and should be executing in that case.

    When input signal comes in....Is it executing in just ISR context or does it do something that unblocks a Task or Swi (for example, calling Semaphore_post)?

    I can look to see if there's any critical bug in this area for that release but I cannot explain why your graph is showing up the way it is at the moment.

    Judah
  • Hi Judah
    Thanks for your assessment of my problem! I appreciate your help very much.
    I was also very much confused by the idle task continuing to run.
    Yes I create the tasks once and never delete any of them.
    The only thing I do in ISR_GPIOPortE is clearing the interrupt, starting Timer5 and enabling the DMA Trigger as well as the DMA channel (see lines 58ff of my code posted initially).
    For my further understanding: can you explain what triggers a task execution that was suspended using Task_seep()? Is it the interrupt on Clock tick timer?
    Regards
    Roman
  • Yes, a Task suspended on a Task_sleep is triggered by a Clock tick Timer.

    One thing would be to make sure the Clock Timer is not using Timer5 (Timer that you are using)...that would be a problem.

    Judah
  • Hi Judah

    I checked my Timers: in my config file I specifically use Timers 0 and 1. At runtime I see Timer 2 also being initialized and therefore I assume that's the one that RTOS uses for Clock Ticks. There is therefore no conflict.

    If I break the execution during the time that the tasks do not get executed, and check the Timer2 Registers I observe the following:

    The timer is counting down as it should. However, the RIS and MIS flags are set and do not seem to get serviced. Why would that be the case? (Where can i find the ISR for the clock tick timer, so I could put a breakpoint there?)

    What I don't understand is that Timer 1 which is configured identically to Timer 2 is generating interrupts that sucessfully get serviced:

    What could be the reason for this?

  • Another observation I made is puzzling me:

    As long as the DMA channel 14 is enabled, interrupts on GPIO Port E also don't get serviced:

    Both the GPIOE and the Timer5 interrupt source are enabled in the NVIC:

    Even though their MIS registers show a set bit, they are not marked pending in the NVIC:

    How is it possible that only TImer 2 and GPIO E are affected?

  • Roman,

    I don't know the details of this part. I will have to consult with others.

    Judah
  • Hi Judah
    I could resolve the RTOS part of my issues with the following workaround:
    I defined an additional dummy timer to use Timer2, thus forcing the Clock tick timer to run on Timer3. (see the originally referenced thread for more information)
    This however does seem to be a rather unelegant solution. Is there a better way to force Clock tick timer to a given Timer peripheral?
    Regards
    Roman
  • Roman,

    Yes, you should be able to do this in your .cfg file:

    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    Clock.timerId = 3;

    This should force the Clock to use Timer 3.

    Judah

  • That worked.
    Thanks a lot for your help!
    Regards, Roman