USART task On SAME70 not running

I am on the SAME70 microcontroller board. I wanted to test working with tasks by having one which reads serial data from a certain sensor and two others which just contain NOPs. I confirmed that the wiring to the board is correct. I setup these tasks in the MP Lab editor, and the tasks which reads the USART data is in the task called app_anemometer. This is its code:

void APP_ANEMOMETER_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    app_anemometerData.state = APP_ANEMOMETER_STATE_INIT;



    /* TODO: Initialize your application's state machine and other
     * parameters.
     */
}

Anemometer_INFO* Anemometer_info;
uint8_t Anemometer_values[101];

void APP_ANEMOMETER_Tasks ( void )
{
    /* Check the application's current state. */
    switch ( app_anemometerData.state )
    {
        /* Application's initial state. */
        case APP_ANEMOMETER_STATE_INIT:
        {
            bool appInitialized = true;
            app_anemometerData.usartHandle = DRV_USART_Open(DRV_USART_INDEX_0, 0);
            
            if (appInitialized)
            {
                app_anemometerData.state = APP_ANEMOMETER_STATE_SERVICE_TASKS;
            }
            break;
        }

        case APP_ANEMOMETER_STATE_SERVICE_TASKS:
        {
            //while(1){
                if (DRV_USART_ReadBuffer(app_anemometerData.usartHandle, &Anemometer_values, 1) == true){
                    Anem_Process(Anemometer_info,(char*)Anemometer_values); // parse it into fields
                    //vTaskDelay(10000);
                    __builtin_nop();
                }
                
                //xQueueSend( eventQueue, &app_user_inputData.eventInfo, portMAX_DELAY );
                __builtin_nop();
            //}
            break;
        }

        /* TODO: implement your application state machine.*/


        /* The default state should never be executed. */
        default:
        {
            /* TODO: Handle error in application's state machine. */
            break;
        }
    }
}

Once the program hits the the line to read the serial data, it leaves the task (as It should as I believe the task gets blocked) but the task never runs again. I am assuming its getting blocked but I don’t know why as it should unblock when it receives data.

First comment, tasks should normally be a loop, and not just run off the end. If the task doesn’t have anything more to do, it should delete itself.

FreeRTOS doesn’t repeatedly call tasks, but calls them once, and expects them to loop and kill themselves when they are done.

Second, tasks if they don’t have anything to do need to block, and not just loop for something to do. If they don’t block, they will keep taking time and not let the other tasks run.

The one possible exception to this is Priority Level 0 tasks, which can either periodically yield, or you can have the configUSE_TIME_SLICING which will make the Priority 0 tasks cycle through and take turns.

To your first comment:
I put the tasks in a loops at the start but noticed that even without the loop the tasks keeps getting called (I used the debugger). I think MP Lab has code somewhere that keeps it in a loop but I will place the tasks in a loop just to be safe anyway. However my issue does not go away when I do this.

To your second comment:
I didn’t think of that thank you. However I thought the scheduler gives every task a set amount of time to each task and switches it out constantly? Or am I thinking of a different type of scheduler. In any case it seems my test example is bad. How do I force a task to block a task again? I am new to freeRTOS.

EDIT:

I did a test where I made the serial reading task the only task and it does still not work. It gets stuck in a loop in the prvCheckTasksWaitingTermination function.

You are thinking of a different type of scheduler. FreeRTOS will always be running the highest priority ready task. If there are several tasks with the same priority, and configUSE_TIME_SLICING is true (which is the default) then every tick the scheduler will move to the next ready task at that priority level.

You ALWAYS want tasks that don’t have something useful to do to find a way to block until they do. This often says that some operations move into interrupt drivers.

If DRV_USART_ReadBuffer is a drive designed for FreeRTOS, then it might do that internally, but I find few suppliers actually do that.

One big question is if this IDE is actually designed to produce FreeRTOS tasks, are you providing things like task priority and stack requirements to this editor, and it is somewhere generating calls to the create task functions and the top level function for the tasks (since you function has that wrong signature).

I have high confidence that this IDE is meant to work with freeRTOS. You can edit all the settings in the editor like this:

I was following a tutorial when I was writing this code and based on the explicit statements there it seems DRV_USART_ReadBuffer has an internal system to block the task. When I stepped through the function with the debugger it also seemed to be calling freeRTOS functions so I think it does work with it. I’m just not sure why it isn’t getting unblocked as I confirmed that port receives data.

Yes, it definitely seems to be a FreeRTOS aware IDE, if the issue is that their function doesn’t seem to work the way it should would seem to be a support case for their support.

Ok so I discovered the issue. This is really aggravating but I am slowly learning to take debuggers with a grain of salt:

I was trying to confirm that the data was being read by placing a break points in the if statement following a successful read. Since the debugger was not stopping on those lines I assumed they were not running. By instead having the program print to serial and later printing the values directly, I discovered that for some reason the debugger is not breaking at my break points when the code is indeed working correctly. Any clue why it chooses to skip it? Thank you for the other advice you have me anyway, I will keep them in mind.

One reason might be enabled optimization building the application. The other … a problem of the debugger / IDE ?

I’ll second Hartmut’s suspicion. Optimizations on the Cortex M can very seriously confuse debuggers. A compiler for Cortex may for example inline complete functions or unfold loops. If you try to match assembly code with source code, you’ll be in for a good number of surprises.

There are basically two ways to write code that reliably allows breakpoints, but both require rewriting your code at least temporarily:

  1. Add the following block of code:
{
    volatile unsigned long aDummyToSetABPhere = 97;
}

and set your breakpoint on that instruction;

Add the code

asm(" BKPT ");

which will break unconditionally.