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.

TM4C1294NCPDT: Task blocks or gets stack overflow without apparent reason

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: SYSBIOS

Hello

I have a system with several tasks and sometimes the enclosed task controlling ADC conversions (which has second highest priority) blocks without reasons.

Some other times instead a stack overflow is reported end the micro goes into the error handler directly after program start.

The only way to recover from this issue is to build again the system with all the task's code removed, and then build it again with the code restored.

By doing this the code runs.

Semaphore_Handle Adc_sem;
void Adc_ctrl_task(UArg a0, UArg a1)
{
    Error_Block eb;
    Semaphore_Handle Adc_sem;

    Error_init(&eb);
    Adc_sem = Semaphore_create(0, NULL, &eb);

    assert(Adc_sem != NULL);

    HAL_adc_initialize();
    
    while (FOREVER())
    {
        HAL_adc_conversion_start();
        Task_sleep(1);
    }
}

We are using CCS v10.4.0.00006,

SYSBIOS 6.37.3.35

XDCTOOLS 3.25.6.96

  • EDIT:

    ADC interrupt was zero latency, but still was posting a semaphore. Could this result in weird behavior? Like tasks blocking forever of the stack getting corrupted?

  • Hi,

      I see you create a semaphore Adc_sem but I don't see it being used in your task. Normally, you would insert Semaphore_pend(Adc_sem) inside the while loop. It will block until it receives a Semaphore_post(Adc_sem) in the ISR. 

      Below is an example for TM4C123 using semaphore but the idea is the same. The LedToggle task is pending on Semaphore_pend(LEDSem, BIOS_WAIT_FOREVER) and hence is blocking until the timer generates an interrupt from which Semaphore_post(LEDSem) is issued to unblock the LedToggle task. 

    //----------------------------------------
    // BIOS header files
    //----------------------------------------
    #include <xdc/std.h>  						//mandatory - have to include first, for BIOS types
    #include <ti/sysbios/BIOS.h> 				//mandatory - if you call APIs like BIOS_start()
    #include <xdc/runtime/Log.h>				//needed for any Log_info() call
    #include <xdc/cfg/global.h> 				//header file for statically defined objects/handles
    #include <xdc/runtime/System.h>
    #include <xdc/runtime/Error.h>
    #include <ti/sysbios/hal/Hwi.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    
    
    
    //------------------------------------------
    // TivaWare Header Files
    //------------------------------------------
    #include <stdint.h>
    #include <stdbool.h>
    
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "inc/hw_ints.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/timer.h"
    
    
    //----------------------------------------
    // Prototypes
    //----------------------------------------
    void hardware_init(void);
    void ledToggle(void);
    void Timer_ISR(void);
    
    
    //---------------------------------------
    // Globals
    //---------------------------------------
    volatile int16_t i16ToggleCount = 0;
    Semaphore_Handle LEDSem;
    
    
    //---------------------------------------------------------------------------
    // main()
    //---------------------------------------------------------------------------
    void main(void)
    {
    
        Task_Params TaskParams;
        Task_Handle LedToggleTask;
        Error_Block eb;
        /* Initialize error block and TaskParams to default values */
        Error_init(&eb);
        Task_Params_init(&TaskParams);
        TaskParams.stackSize = 2096;
        TaskParams.priority = 1;
        LedToggleTask = Task_create((Task_FuncPtr)ledToggle, &TaskParams, &eb);
        if (LedToggleTask == NULL) {
        System_abort("Task create failed");
        }
    
        /*
        * Create semaphore with initial count = 0 and default params
        */
        LEDSem = Semaphore_create(0, NULL, &eb);
        if (LEDSem == NULL) {
        System_abort("Semaphore create failed");
        }
    
    
       hardware_init();							// init hardware via Xware
    
       BIOS_start();
    
    }
    
    
    //---------------------------------------------------------------------------
    // hardware_init()
    //
    // inits GPIO pins for toggling the LED
    //---------------------------------------------------------------------------
    void hardware_init(void)
    {
    	uint32_t ui32Period;
    
    	//Set CPU Clock to 40MHz. 400MHz PLL/2 = 200 DIV 5 = 40MHz
    	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
    
    	// ADD Tiva-C GPIO setup - enables port, sets pins 1-3 (RGB) pins for output
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    
    	// Turn on the LED
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 4);
    
    	// Timer 2 setup code
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);			// enable Timer 2 periph clks
    	TimerConfigure(TIMER2_BASE, TIMER_CFG_PERIODIC);		// cfg Timer 2 mode - periodic
    
    	ui32Period = (SysCtlClockGet() /2);						// period = CPU clk div 2 (500ms)
    	TimerLoadSet(TIMER2_BASE, TIMER_A, ui32Period);			// set Timer 2 period
    
    	TimerIntEnable(TIMER2_BASE, TIMER_TIMA_TIMEOUT);		// enables Timer 2 to interrupt CPU
    
    	TimerEnable(TIMER2_BASE, TIMER_A);						// enable Timer 2
    
    }
    
    
    //---------------------------------------------------------------------------
    // ledToggle()
    //
    // toggles LED on Tiva-C LaunchPad
    //---------------------------------------------------------------------------
    void ledToggle(void)
    {
    
    	while(1)
    	{
    		Semaphore_pend(LEDSem, BIOS_WAIT_FOREVER);				// wait for Sem from ISR
    
    		// LED values - 2=RED, 4=BLUE, 8=GREEN
    		if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_2))
    		{
    			GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);
    		}
    		else
    		{
    			GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 4);
    		}
    
    		i16ToggleCount += 1;									// keep track of #toggles
    
    		Log_info1("LED TOGGLED [%u] TIMES",i16ToggleCount);		// send toggle count to UIA
    
    	}
    
    }
    
    
    //---------------------------------------------------------------------------
    // Timer ISR - called by BIOS Hwi (see app.cfg)
    //
    // Posts Swi (or later a Semaphore) to toggle the LED
    //---------------------------------------------------------------------------
    void Timer_ISR(void)
    {
        TimerIntClear(TIMER2_BASE, TIMER_TIMA_TIMEOUT);			// must clear timer flag FROM timer
    
    	Semaphore_post(LEDSem);										// post LEDSwi
    }

    Here is a link to TI-RTOS training. https://training.ti.com/sites/default/files/docs/TI_RTOS_Kernel_Workshop_Student_Guide_rev4.00.pdf. Hope you will find it useful.

    One more comment is that you seem to have an old XDCtools and TI-RTOS. The recommended TI-RTOS version is 2.16.00.08. You can download from http://downloads.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/tirtos/index.html. The recommended XDCtools that works with TI-RTOS version 2.16.00.08 is XDCtools version 3.32.00.06 which you can download from http://downloads.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/rtsc/3_32_00_06/index_FDS.html.

  • Thank you for your reply but this is not the issue.

    The semaphore is used elsewhere and is posted by the ISR, the task is only providing the triggering every 1ms.

    The code using the semaphore is not included. 

    The point is, the task should not block forever on Task_sleep(1).

    Could be the wrong ISR priority messing up the scheduler?

  • Hi,

    By doing this the code runs.

      In your original post you wrote the above and followed by your snippet of code. I thought what you showed was the working code. Or you meant the code wasn't working with Task_sleep(1). 

    The point is, the task should not block forever on Task_sleep(1)

      I agree Task_sleep(1) should change the task from RUNNING state to BLOCKED state for 1ms only. How are you handling the interrupts? Are you using Hwi to manage the interrupt? The interrupts must be managed by TI-RTOS Hwi. If not, the system can crush. Hopefully, this is not the reason for your problem. Please see this post. https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/849627/faq-can-i-update-the-vector-table-with-intregister-when-using-ti-rtos?tisearch=e2e-sitesearch&keymatch=faq%3Atrue.

      For experiment, does it make a difference if you change Task_sleep() to some longer time? Maybe try Task_sleep(10) or Task_sleep(100).

       Also have you tried to increase the task stack size? Which task does ROV show when you have a stack overflow? 

    Could be the wrong ISR priority messing up the scheduler?

    Hwi will always have higher priority than Swi and then Task. 

  • The code shown is the code that sometimes blocks forever or seems to generate a stack overflow.

    The interrupt is managed through Hwi, but as I understand on ARM a priority under 32 makes it zero latency and therefore not under OS control.

    Stack size has been doubled and quadrupled, but sometimes the issue popped up again from time to time.


    Increasing ISR priority from 1 to 100 instead seems to have fixed the problem, but I want to be sure this could have been the issue since the beginning: a ISR not under OS control messing up the scheduler.
    Could this be the case?

  • Hi,

    The interrupt is managed through Hwi, but as I understand on ARM a priority under 32 makes it zero latency and therefore not under OS control.

    I'm  not a TI-RTOS expert and honestly a priority 32 will make it zero latency is new to me. I don't know how you create a zero latency interrupt. Below is what i find from TI-RTOS training with the link I send in my earlier reply. 

    Looking at TI-RTOS configuration, I find the below priority threashold for Hwi-disable() to be 32. I don't know if we are talking about the same thing. 

      I also find the below statements about zero-latency. You are correct that zero-latency interrupt is not under OS control. 

    The Hwi module for the CC13x0 also supports Zero-latency interrupts. These interrupts do not go through the TI-RTOS Hwi dispatcher and therefore are more responsive than standard interrupts, however this feature prohibits its interrupt service routine from invoking any TI-RTOS kernel APIs directly. It is up to the ISR to preserve its own context to prevent it from interfering with the kernel’s scheduler.