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: Task of lower priority added to stack is not allowing higher priory static task any run time.

Guru 56418 points

Other Parts Discussed in Thread: SYSBIOS, TM4C1294NCPDT

Tool/software: TI-RTOS

Oddly the task module is not allocating tick time slots for each task in the list, case a lower priority task has a [while(1)] loop. The only other unique aspect is (taskFxn(1)) was created statically in the UARTLogger example project. 

Why would a static task entry loose it's higher priority? How to make a task with a while loop Not persistently occupy all task time so (~.IdleTask) gets some MCU time share?   

  • With a return at the bottom of a function call with a [while(1)] loop then (Task.IOT) runs only once and task (~_Idle_loop_E ) persistently runs.

    The tasking module is after 1 pass terminating a lower task priority (8). The task was naturally exited by placing a C++ (return) statement bottom of the while(1) loop prior to the while }.

    What could be going wrong ?,,,,  are switches required in the function declaration to stop premature termination?

    /* Task functions listing */
    var task0Params = new Task.Params();
    task0Params.instance.name = "Task.IOT";
    task0Params.stackHeap = null;
    task0Params.vitalTaskFlag = false;
    task0Params.priority = 8;
    Program.global.task0 = Task.create("&IOTAppLoop_taskFxn", task0Params);

    /* IOT loop.*/
    while(g_bOnline)
    {
    
         Some code
    			 }
    		           }
    		      }
    		  }
                 /* Exit BIOS task
                  * IOTLoopFxn */
                   return;
    	     }
          }
    }
    
    
    /* HQS_IOT END */

  • ROV only shows the task terminated when debug is suspended. The UART logger live events indicate Task module is loading (CtxChg TSK data1= 0:0) Task.IOT but is no longer (bOnline) after the first cloud connection was dropped from the (return;).

    Without the (return;) at the bottom of while loop there are no UART0 Live idle events when Task module seems to never service the higher priority 0 idle logger.

    Why does the task module not control the while loop if there is No (return;)???????????????

  • Task.IOT Live event indicated (CtxChg) only when the task function was immediately returning after not servicing the While loop.

    Task.IOT in not servicing a disconnected loop indicates persistently a Live event (Load, Data1 0.0) and never switches to (CtxChg).

    This same function works great in the application without TI-RTOS. There is some Obscure issue with Tasks and while loops making cloud connections without disconnecting the TCP back ground HAL processes.
  • The IOT.task while(1) loop Task is launched without the BIOS running thus preempting ever calling (BIOS_Start).
    So the static created UARTLogger BIOS idle task never is invoked and no CCS debug Live events COM port data is ever posted. Placing BIOS_start instead of (return) starts the static UARTLogger idle task but Terminates the IOT.task after 1 cycle and COM port Live events are present.
     
    WOW!

  • I was wrong and fooled by bug of RTOS idle thread manager to load (taskFxn) even though it holds priority (1). Comment out BIOS_start and task module (Load IOT.task) terminates the kernel. Uncomment BIOS_start and the IOT.task runs but the idle print Live events task UART0 (taskFxn) never is given any (kernel idle time) to print Live events.

    The static task below is called by static kernel idle thread manager (hidden RTOS task)  (~_knl_Idle_Loop__E) should load task (tskFxn) shown (below).

    /*
     *  ======== taskFxn ========
     *  Task for this function is created statically. See the project's .cfg file.
     */
    Void taskFxn(UArg arg0, UArg arg1)
    {
        unsigned int sleepDur = 100;
        unsigned int id = (unsigned int)arg0;
        unsigned int count = 0;
    
        while (1) {
            Task_sleep(sleepDur);
            Log_print2 (Diags_USER1, "Task %d awake, count = %d", id, count);
            count++;
        }
    }

  • Hi,

    Based on your first comment "Oddly the task module is not allocating tick time slots for each task in the list" I think you have a misunderstanding about the TI-RTOS scheduler (and the probably the majority of other RTOS schedulers). The TI-RTOS scheduler is a preemptive scheduler. So the highest priority thread runs if it ready to run. So if you put a while(1); in a task of priority N, all the other task with priorities 0 - (N) will never run. Note: I included N and not (N-1). The schedule does not do round robin within a priority level (however, there are a simple trick to do this). Higher priority tasks (or Swi or Hwi) will run if ready (or assert for the Hwi/Swi case).


    Does that make sense?

    Todd

  • ToddMullanix said:
    The schedule does not do round robin within a priority level

    Later discovered priority(0) task_loop_E was yet another created static task Hook and not found inside (uartlogging.c), for sysbios stack task monitor etc..

    The thing is the higher priority (1) static (taskFnx) was invoked 1st and often indicated Ready as ROV shows. The lower priority (8)  IOTtaskFxn while(1) loop assumed next highest priority level, seemingly kernel preempting taskFxn (1) for Blocking time and never loading the task. Either that or the static task is violating a sys/bios constraint.

    First look of (task.c) the priority order bug seems to match the condition reported this post and exists near the top few lines.. 

    TI-RTOS text states BIOS_start() call should be the last call but it seems it can be called and still invoke very next few lines of code in the application.

    Nested function call for CCS debug logger Live status print with (BIOS_start) outside of (main.c):

            BIOS_start();
        
            while(1)
            {
                /* Sleep for 50ms */
                Task_sleep(sleepDur);
                Log_print2 (Diags_USER1, "Task %d awake, count = %d", 0, count);
                count++;
            }

  • BIOS_start() must be called in main(). It must be the last thing in main, because it never returns. Why do you think your loop below BIOS_start is being executed?

    The Idle task (priority 0) is created statically during the build. All statically created tasks are in the "ready" state (unless you create with a priority of -1...inactive) when you are in main. Once BIOS_start is called, the highest priority Task runs until it blocks (e.g. Task_sleep, Semaphore_pend with a non-zero timeout and the semaphore is not signaled, etc). 

    Can you please attach the project in question? 

    Todd

  • Also, please note priority 0 is the lowest priority. High number means high priority with TI-RTOS.
  • ToddMullanix said:
    High number means high priority with TI-RTOS.

    Oddly when attempting to assign 0 to any new task the popup messages states it is reserved and the highest priority and 1 would be the next highest priority, logically. Same is true for M3 Hwi interrupt priorities, a smaller value holds a higher priority over a larger value, according to the help text.

  • 0 is reserved for the Idle task.
  • ToddMullanix said:
    BIOS_start() must be called in main().

    The text states BIOS_start must be the last call, if made in (main.c) will not return there if placed outside, never stated it must exist in (main.c). Point is how can a non RTOS task function execute a CCS debug Live diagnostic print unless it first calls BIOS_start and it did, since the while loop never returns to (main.c) as shown in code snip above post and below. Verified again local print works without a BIOS_start in (main.c) but the RTOS IOT print task does return somehow since the task is not to be executed until after BIOS_start. Not sure how the IOT loop below code is returning to (main.c) to execute BIOS_start but seems it must or how does the task load/run???  

    That same basic print loop made as a stand alone task locks up the USB port initialization in my application, Tivaware USB bulk device driver call and stops all execution. It even messes with TCP to get an IP address yet BIOS_Start is last call in (main.c). Put the print loop code back together with client IP assignment and all is happy once again. 

  • Ok checked that again but why reserve the lowest priority ? makes no sense to me when the opposite is typical. Really not matter in this case, thanks for pointing out. :-)
  • Perhaps code is escaping back to (main.c) from while(1) loops during each task sleep time.
  • You are going to have to slow down:) Let's take this a little more methodically.

    1. The lowest task priority is 0. TI-RTOS reserves this for the Idle Task. The Idle task does background actions like CPU load determination (if enabled), Hwi stack checking(if enabled), Power management (if enabled), etc.. You can plug in your own functions into the Idle task.

    2. The number of Task priorities is determined by Task.numPriorities in the .cfg file. If it is not set, it takes a default value of 16 for most devices.

    3. The highest priority in the system is Task_numPriorities - 1.

    4. BIOS_start must be called from main() and it never returns. If you have a test case that proofs otherwise, please attach the full project.

    Let's make sure we are on the same page with the above statements before addressing other questions.

    Todd
  • ToddMullanix said:
    You can plug in your own functions into the Idle task.

    Check again the posted ROV captures indicate that was the method for USER1 diagnostic print task launching.

    ToddMullanix said:
    The number of Task priorities is determined by Task.numPriorities in the .cfg

    Knew about 16 total tasks but not that (1) is considered highest priority, nor is that keeping consistent with HW priority semantics. Priority value is not discussed in the RTOS task priority help text.

    ToddMullanix said:
    BIOS_start must be called from main() and it never returns

    Simply not true and proven task posted above with while(USER1 print). BIOS_Start exists outside of (main.c) and prints debug Live status thus indicates BIOS task is being called.

    ToddMullanix said:
    Let's make sure we are on the same page with the above statements

    The only reason I commented out the static created task in (uartlogging.c) is that it stopped working once I introduced my apps while(1) call prior to BIOS_start. That static task USER1 print task should not have been preempted or disabled when BIOS_start was latter called no matter from where! So it seems there is a relaxed tasks constraint perhaps e.g. didn't even know about.

    Discovered If the USER1 UART print task in not created statically in  (main.c) then BIOS_start can be called outside of (main.c). Perhaps stop doing static tasks in TI examples and instead add example task or stubs to the task module so a follow up programmer can easily merge an application into the task call stack for UIA diagnostic purposes.

    BIOS_start has to be able to call outside of (main.c) order to add ones application while(1) loop into the kernels task control module. Especially the case since the task module thread manager seems to loose control of the virtual task memory space if the task is not statically created in (main.c). Seemingly SYS/BIOS mostly a diagnostic tool in my view should not be taking over TM4C peripheral calls in the way the examples attempt to force feed and PWM0 BIOS initiate call is a good example of what not to do in any way what so ever! The application platform being added to the BIOS kernel mostly for UIA diagnostic purpose typically handles all peripheral configuration, not the other way around. BTW: Several program examples TM4C1294NCPDT arbitrarily add a launch pad static task button scan (not found the example projects) ROV is now preempting 2 after adding 2 new task names to the task module.

  • ToddMullanix said:
    BIOS_start must be called from main() and it never returns

    Statement below found in the help text seems to explain how the create hook has different behavior based on the context of the task placement. The UARTLogger example Live print from a static task created in (main.c) was the culprit leading to any other user application task calls occurring from a dynamic task entry being immediately preempted. It didn't matter the priority of the dynamic task/s they simply did not call.

    My case the second dynamic task (Local Telnet Client) was crashing the BIOS due to EMAC0 link state register test (bHaveLink) not being included inside the IP address assignment (for loop). That was not a problem without the BIOS integrated into the application and even 1 second delay placed various locations in the for loop did not help. So in the past the EMAC link state initialization after Reset must of had less time for link state bounce to effect whatever was crashing the BIOS. The odd thing is TI example Ethernet applications don't check EMAC0 Link State register in the DHCP loop as I have added into the IP address assignment for loops which fixes the LWIP v1.4.1 address assignment inside SYS/BIOS dynamic task calls.

    All is good now and both dynamic tasks run/block and have debug idle diagnostic Live status printing but without a static task existing in (main.c).

    Create: A function that is called when a task is created. This includes tasks that are created statically and those created dynamically using create or construct. For statically created tasks, create hook is called before main() and before interrupts are enabled. For dynamically created or constructed tasks, create hook is called in the same context the task is created or constructed in i.e. if a task is created in main(), the create hook is called in main context and if the task is created within another task, it is called in task context. The create hook is called outside of a Task_disable/enable block and before the task has been added to the ready list.

    Thanks Todd :-)