greiman / ChRt

ChibiOS/RT for Arduino AVR, SAMD, Due, Teensy 3.x, Teensy 4.0.
88 stars 26 forks source link

Question regarding characteristics of ChRt's main thread ("loop()") #14

Closed metacodez closed 3 years ago

metacodez commented 3 years ago

Dear ChRt team,

I am a newbie to ChibiOS and microcontroller programming. I have got a question regarding ChibiOS's main thread on an Arduino mega. I am using the ChibiOS version with Tag 1.3.0 as of https://github.com/greiman/ChRt/releases/tag/1.3.0 and I am using a NextionDisplay (https://nextion.tech/datasheets/nx4832t035/) connected via serial port to the Ardunio mega using the NextionLibrary (https://github.com/itead/ITEADLIB_Arduino_Nextion). To build everything I use platform.io.

Now I wonder where I am being wrong: The NextionDisplay is controlled by the Arduino over a serial port and signals the Arduino upon any touch events triggered on the NextionDisplay over the serial port. When polling the NextionDisplay touch events in a dedicated ChibiOS thread, no signals coming from the NextionDisplay are caught by the code in the thread, though when I poll for NextionDisplay touch events in the loop() function I get the touch signals correctly while the other threads still being processed. As of my understanding, after having initialized all threads, ChibiOS's main thread ends up in the loop() function similar to Arduino's super-loop (snippet from ChRt.cpp):

void chBegin(void (*mainThread)()) {
  ...
  // ChibiOS/RT initialization
  chSysInit();

  // Call continuation of main thread.
  if (mainFcn) {mainFcn();}

  // loop() becomes main thread.
  while (true) {loop();}
}

For my use case this is a feasible approach, though I would like to know if it is good practice to place legacy serial communication processing (as of the NextionDisplay library) in the main thread (loop()) or are there configuration means to use a dedicated thread when doing such communication (what have I missed)?

Below a snippet on how I created the thread, enabling line 13 and commenting out line 27 does not work, though the other way round enabling line 27 and disabling line 13 works (I get the touch events):

#include "NextionChibiOS.h"

#include <Arduino.h>
#include ...
#include <ChRt.h>

#define THREAD_MEMORY 256

THD_WORKING_AREA(displayArea, THREAD_MEMORY);

static THD_FUNCTION( displayFunction, arg ) {
    while( true ) {
        nexLoop(touchListeners); // NextionDisplay query touch events does not(!) function here
        chThdSleepMilliseconds(100);
    }
}

void startThreads() {
    ch_thread *displayThread = chThdCreateStatic(displayArea, sizeof(displayArea), NORMALPRIO, displayFunction, NULL);
}

void setup() {
   chBegin(startThreads);
}

void loop() {
   nexLoop(touchListeners); // NextionDisplay query touch events does function here
   chThdSleepMilliseconds(100);
}

I wonder which are the differences between the main thread and dedicateltly created threads regarding the thread memory or handling I/O or the like which makes it possible to run the NextionDisplay's nexLoop() function correctly in the ChibiOS's main thread loop() whereas there are constraints making it to fail to read from the serial port in a dedicated thread (as of ... chThdCreateStatic(displayArea, sizeof(displayArea), NORMALPRIO, displayFunction, NULL); ...)?

Maybe you have can help me and give me a hint?

Thank you beforehand & best regards, Siegfried

greiman commented 3 years ago

There may be something in the Nextion library that won't work in a thread. For example dynamic memory fails in threads since malloc/free are not thread safe. Also Arduino delay() causes problems.

I really can't study the Nextion software to find the problem. More things work in loop because the stack is where the Arduino core expects it.

metacodez commented 3 years ago

Great, thanks very much! It was just that information I was looking for, so I now understand why the Nextion code behaves different in the main thread than in a custom created thread, thank you for the quick answer!