MKR1310 FreeRTOS SAMD21 Issues

Hi everyone,

I've recently started a project with the Arduino MKR1310 and I'm struggling with the RTOS implementation for the SAMD21 processors.

According to the Arduino home page (freertos_samd21) this board should be compatible with the implementation from BriscoeTech.

I've tested the basic examples with MKR1000 and it works fine. However, with this model, the firmware is not loading. The serial port simply goes away and everything seems to be frozen. I already attempted to put some led blinking during the setup() but even that doesn't work, which from my point of view could indicate that this is something related to the bootloader. Maybe the freertos implementation is writing to some register that it shouldn't? How can I debug this issue? I really want to have freertos running in order to schedule the publishing via LoRa and others without stopping the main tasks.

Thank you in advance,

Fernando Fontes

Hi @juliofontes

FreeRTOS isn't connected in anyway to the bootloader, therefore it's most likely that your program has simply crashed, preventing the native USB and any further uploads from working.

If you're currently unable to upload code, just double tap the reset button two times in quick succession. This will put your board into bootloader mode. Select the new COM port in the Arduino IDE menu (Tools->Port->COMx), then attempt to upload as normal. You should be able to always recover the board this way.

Hi @MartinL,
Thank you for the reply. I know how to get the device again ready to be programmed using the method mentioned. But that’s not the issue. The issue is that every time I upload the demo sketch it will break.

Best regards,

@juliofontes Might I ask which demo sketch you're trying to get running?

Yes,
I'm trying to run this sketch: Arduino-FreeRTOS-SAMD21/Basic_RTOS_Example.ino at master · BriscoeTech/Arduino-FreeRTOS-SAMD21 · GitHub.

//**************************************************************************
// FreeRtos on Samd21
// By Scott Briscoe
//
// Project is a simple example of how to get FreeRtos running on a SamD21 processor
// Project can be used as a template to build your projects off of as well
//
//**************************************************************************

#include <FreeRTOS_SAMD21.h>

//**************************************************************************
// Type Defines and Constants
//**************************************************************************

#define  ERROR_LED_PIN  13 //Led Pin: Typical Arduino Board
//#define  ERROR_LED_PIN  2 //Led Pin: samd21 xplained board

#define ERROR_LED_LIGHTUP_STATE  HIGH // the state that makes the led light up on your board, either low or high

// Select the serial port the project should use and communicate over
// Some boards use SerialUSB, some use Serial
#define SERIAL          SerialUSB //Sparkfun Samd21 Boards
//#define SERIAL          Serial //Adafruit, other Samd21 Boards

//**************************************************************************
// global variables
//**************************************************************************
TaskHandle_t Handle_aTask;
TaskHandle_t Handle_bTask;
TaskHandle_t Handle_monitorTask;

//**************************************************************************
// Can use these function for RTOS delays
// Takes into account processor speed
// Use these instead of delay(...) in rtos tasks
//**************************************************************************
void myDelayUs(int us)
{
  vTaskDelay( us / portTICK_PERIOD_US );  
}

void myDelayMs(int ms)
{
  vTaskDelay( (ms * 1000) / portTICK_PERIOD_US );  
}

void myDelayMsUntil(TickType_t *previousWakeTime, int ms)
{
  vTaskDelayUntil( previousWakeTime, (ms * 1000) / portTICK_PERIOD_US );  
}

//*****************************************************************
// Create a thread that prints out A to the screen every two seconds
// this task will delete its self after printing out afew messages
//*****************************************************************
static void threadA( void *pvParameters ) 
{
  
  SERIAL.println("Thread A: Started");
  for(int x=0; x<100; ++x)
  {
    SERIAL.print("A");
    SERIAL.flush();
    myDelayMs(500);
  }
  
  // delete ourselves.
  // Have to call this or the system crashes when you reach the end bracket and then get scheduled.
  SERIAL.println("Thread A: Deleting");
  vTaskDelete( NULL );
}

//*****************************************************************
// Create a thread that prints out B to the screen every second
// this task will run forever
//*****************************************************************
static void threadB( void *pvParameters ) 
{
  SERIAL.println("Thread B: Started");

  while(1)
  {
    SERIAL.println("B");
    SERIAL.flush();
    myDelayMs(2000);
  }

}

//*****************************************************************
// Task will periodically print out useful information about the tasks running
// Is a useful tool to help figure out stack sizes being used
// Run time stats are generated from all task timing collected since startup
// No easy way yet to clear the run time stats yet
//*****************************************************************
static char ptrTaskList[400]; //temporary string buffer for task stats

void taskMonitor(void *pvParameters)
{
    int x;
    int measurement;
    
    SERIAL.println("Task Monitor: Started");

    // run this task afew times before exiting forever
    while(1)
    {
    	myDelayMs(10000); // print every 10 seconds

    	SERIAL.flush();
		SERIAL.println("");			 
    	SERIAL.println("****************************************************");
    	SERIAL.print("Free Heap: ");
    	SERIAL.print(xPortGetFreeHeapSize());
    	SERIAL.println(" bytes");

    	SERIAL.print("Min Heap: ");
    	SERIAL.print(xPortGetMinimumEverFreeHeapSize());
    	SERIAL.println(" bytes");
    	SERIAL.flush();

    	SERIAL.println("****************************************************");
    	SERIAL.println("Task            ABS             %Util");
    	SERIAL.println("****************************************************");

    	vTaskGetRunTimeStats(ptrTaskList); //save stats to char array
    	SERIAL.println(ptrTaskList); //prints out already formatted stats
    	SERIAL.flush();

		SERIAL.println("****************************************************");
		SERIAL.println("Task            State   Prio    Stack   Num     Core" );
		SERIAL.println("****************************************************");

		vTaskList(ptrTaskList); //save stats to char array
		SERIAL.println(ptrTaskList); //prints out already formatted stats
		SERIAL.flush();

		SERIAL.println("****************************************************");
		SERIAL.println("[Stacks Free Bytes Remaining] ");

		measurement = uxTaskGetStackHighWaterMark( Handle_aTask );
		SERIAL.print("Thread A: ");
		SERIAL.println(measurement);

		measurement = uxTaskGetStackHighWaterMark( Handle_bTask );
		SERIAL.print("Thread B: ");
		SERIAL.println(measurement);

		measurement = uxTaskGetStackHighWaterMark( Handle_monitorTask );
		SERIAL.print("Monitor Stack: ");
		SERIAL.println(measurement);

		SERIAL.println("****************************************************");
		SERIAL.flush();

    }

    // delete ourselves.
    // Have to call this or the system crashes when you reach the end bracket and then get scheduled.
    SERIAL.println("Task Monitor: Deleting");
    vTaskDelete( NULL );

}


//*****************************************************************

void setup() 
{

  SERIAL.begin(115200);

  delay(1000); // prevents usb driver crash on startup, do not omit this
  while (!SERIAL) ;  // Wait for serial terminal to open port before starting program

  SERIAL.println("");
  SERIAL.println("******************************");
  SERIAL.println("        Program start         ");
  SERIAL.println("******************************");
  SERIAL.flush();

  // Set the led the rtos will blink when we have a fatal rtos error
  // RTOS also Needs to know if high/low is the state that turns on the led.
  // Error Blink Codes:
  //    3 blinks - Fatal Rtos Error, something bad happened. Think really hard about what you just changed.
  //    2 blinks - Malloc Failed, Happens when you couldn't create a rtos object. 
  //               Probably ran out of heap.
  //    1 blink  - Stack overflow, Task needs more bytes defined for its stack! 
  //               Use the taskMonitor thread to help gauge how much more you need
  vSetErrorLed(ERROR_LED_PIN, ERROR_LED_LIGHTUP_STATE);

  // sets the serial port to print errors to when the rtos crashes
  // if this is not set, serial information is not printed by default
  vSetErrorSerial(&SERIAL);

  // Create the threads that will be managed by the rtos
  // Sets the stack size and priority of each task
  // Also initializes a handler pointer to each task, which are important to communicate with and retrieve info from tasks
  xTaskCreate(threadA,     "Task A",       256, NULL, tskIDLE_PRIORITY + 3, &Handle_aTask);
  xTaskCreate(threadB,     "Task B",       256, NULL, tskIDLE_PRIORITY + 2, &Handle_bTask);
  xTaskCreate(taskMonitor, "Task Monitor", 256, NULL, tskIDLE_PRIORITY + 1, &Handle_monitorTask);

  // Start the RTOS, this function will never return and will schedule the tasks.
  vTaskStartScheduler();

  // error scheduler failed to start
  // should never get here
  while(1)
  {
	  SERIAL.println("Scheduler Failed! \n");
	  SERIAL.flush();
	  delay(1000);
  }

}

//*****************************************************************
// This is now the rtos idle loop
// No rtos blocking functions allowed!
//*****************************************************************
void loop() 
{
    // Optional commands, can comment/uncomment below
    SERIAL.print("."); //print out dots in terminal, we only do this when the RTOS is in the idle state
    SERIAL.flush();
    delay(100); //delay is interrupt friendly, unlike vNopDelayMS
}


//*****************************************************************

Best regards,

Fernando

Hi @juliofontes

Please could you try changing this line:

#define  ERROR_LED_PIN  13 //Led Pin: Typical Arduino Board

to this:

#define  ERROR_LED_PIN  LED_BUILTIN //Led Pin: Typical Arduino Board

Also on the MKR1310, you might need to swap these lines from this:

#define SERIAL          SerialUSB //Sparkfun Samd21 Boards
//#define SERIAL          Serial //Adafruit, other Samd21 Boards

to this:

//#define SERIAL          SerialUSB //Sparkfun Samd21 Boards
#define SERIAL          Serial //Adafruit, other Samd21 Boards

I really don't know anything about this version of freeRTOS but I am familiar with freeRTOS on the ESP32.

I noticed that the tasks only have a stack size of 256 bytes of ram. Is that enough? On a ESP32 I start with 10000 bytes and then use the stack size water mark to get the task size ram use as I develop the task. I then set the stack size to 2000 more bytes then the minimum reported stack size.

Perhaps it is not the case in this version of freeRTOS but on ESP32 putting code in loop() prevents the freeRTOS housekeeping chores from being ran. Also, on a ESP32, loop() is not guarenteed to run, depending upon task load.

I noticed the use of delay(x). On a ESP32 when delay is used it is translated into vTaskDelay(x) which in a task stops the task but does not stop the CPU. Not sure if that is the case with this version of freeRTOS.

Hi @MartinL ,

I’ve attempted that already without success. That’s not the issue. Really weird…

The board don’t even run anything. It gets right out of the way in a bricked state.

Can you cite a reference to backup that claim?

It's not supported by my interpretation of 'main.cpp'. The app_main() function spools up the 'loopTask' task. That task calls setup() and then enters an infinite 'for loop' calling loop() and (conditionally) esp_task_wdt_reset(), and serialEventRun().

So, whether or not there's any code in the user's loop() function, the 'loopTask' task still runs. And whether or not there's any code in the user's loop() function, I don't see anything in there to prevent "housekeeping chores" from running.

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "Arduino.h"
#if (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT) && !ARDUINO_USB_MODE
#include "USB.h"
#if ARDUINO_USB_MSC_ON_BOOT
#include "FirmwareMSC.h"
#endif
#endif

#ifndef ARDUINO_LOOP_STACK_SIZE
#ifndef CONFIG_ARDUINO_LOOP_STACK_SIZE
#define ARDUINO_LOOP_STACK_SIZE 8192
#else
#define ARDUINO_LOOP_STACK_SIZE CONFIG_ARDUINO_LOOP_STACK_SIZE
#endif
#endif

TaskHandle_t loopTaskHandle = NULL;

#if CONFIG_AUTOSTART_ARDUINO
#if CONFIG_FREERTOS_UNICORE
void yieldIfNecessary(void) {
  static uint64_t lastYield = 0;
  uint64_t now = millis();
  if ((now - lastYield) > 2000) {
    lastYield = now;
    vTaskDelay(5); //delay 1 RTOS tick
  }
}
#endif

bool loopTaskWDTEnabled;

__attribute__((weak)) size_t getArduinoLoopTaskStackSize(void) {
  return ARDUINO_LOOP_STACK_SIZE;
}

void loopTask(void *pvParameters)
{
  setup();
  for (;;) {
#if CONFIG_FREERTOS_UNICORE
    yieldIfNecessary();
#endif
    if (loopTaskWDTEnabled) {
      esp_task_wdt_reset();
    }
    loop();
    if (serialEventRun) serialEventRun();
  }
}

extern "C" void app_main()
{
#if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE
  Serial.begin();
#endif
#if ARDUINO_USB_MSC_ON_BOOT && !ARDUINO_USB_MODE
  MSC_Update.begin();
#endif
#if ARDUINO_USB_DFU_ON_BOOT && !ARDUINO_USB_MODE
  USB.enableDFU();
#endif
#if ARDUINO_USB_ON_BOOT && !ARDUINO_USB_MODE
  USB.begin();
#endif
  loopTaskWDTEnabled = false;
  initArduino();
  xTaskCreateUniversal(loopTask, "loopTask", getArduinoLoopTaskStackSize(), NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
}
#endif

I got that from a message from a ESPRESSIF engineer, when I asked about it, on esp32.com several years ago.

I'm getting the exact same issue with the MKR1310, @juliofontes did you manage to solve the problem ? Thanks !

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.