Argon breathing white

When I flash this on the device (Via dfu), it simply sits and has breathing white LED. http_send_sessions is located in another file which is included in the project. I am stumped here because I am moving this firmware over from running on an electron (which it ran fine on), and i had to change a few things to get it running (like removing ADCsamplerate, etc), and while doing this I commented out all thread-related stuff, once I had it working on the Argon (all but threading), I simply uncommented those portions of code and now am getting this issue. Here is the relevant code:


STARTUP(System.enableFeature(FEATURE_RESET_INFO));
STARTUP(startupFunction());


SYSTEM_THREAD(ENABLED);
os_mutex_t mutex;

extern void http_send_sessions();

//Separate thread for HTTP requests so as not to block data collection
Thread thread("httpSendSessions", http_send_sessions);

void startupFunction(){
  //Create the mutex
  os_mutex_create(&mutex);

  //Lock mutex to initially block thread
  os_mutex_lock(mutex);
}

void setup()
{
  WiFi.on();
  WiFi.setCredentials("xxxxxxx", "xxxxxxxx");
  // Set up serial port
  // NOTE: SHOULD BE DONE BEFORE ANYTHING ELSE
  SLAVE_SERIAL_CONSOLE.begin(57600);     //initialize uart port
  DBG_SERIAL_CONSOLE.begin(115200);    //initialize debug port

  Particle.connect();

Am I doing something stupid here or does the threading work fundamentally different on the Argon vs the Electron?

What’s in your startupFunction()?
Since you are using AUTOMATIC mode (by default) WiFi.on() and Particle.connect() shouldn’t be needed and may even interfere with the system thread trying to do the same thing at virtually the same time.

This is my startup function:


void startupFunction(){
  //Create the mutex
  os_mutex_create(&mutex);

  //Lock mutex to initially block thread
  os_mutex_lock(mutex);
}

I just tried it with wifi.on and particle.connect completely removed from the code and it acts the exact same. Also just for reference, this is the ‘http_send_sessions’ function referred to by the thread:

void http_send_sessions(){
  while(true){
    //Block until unclocked by update_sessions_array()
    os_mutex_lock(mutex);

    //DBG_SERIAL_CONSOLE.println();
    //DBG_SERIAL_CONSOLE.println("About to populate the json!");
    //Build the string message
    populate_json(json_str);
    //Ready to clear sessions_array() to make room for new data
    clear_sessions_ready = true;        //The session array has been stringified, so we can erase and start filling with new data.
    fill_in_progress = false;           //Session_array can now be updated, but the post still hasnt happened.

    //DBG_SERIAL_CONSOLE.println();
    //DBG_SERIAL_CONSOLE.println("About to go into httpPost!");
    //Send string over HTTP
    httpPost(json_str, "/api/bounceBack");

    lastWifiPost = Time.now();
    memset(json_str, 0, JSON_STRING_SIZE);
    post_in_progress = false;
  }
}

Also the reason I am using threading here is to continue the collection of data while the post is happening.

As it seems the STARTUP() macro is a bad place to lock a mutex.

I have played with your code a bit like this

#define EARLY_LOCK

SYSTEM_MODE(SEMI_AUTOMATIC);
SYSTEM_THREAD(ENABLED);

void startupFunction();
STARTUP(startupFunction());

os_mutex_t mutex;
void startupFunction() {
  System.enableFeature(FEATURE_RESET_INFO);
  os_mutex_create(&mutex);
#ifdef EARLY_LOCK
  os_mutex_lock(mutex);
#endif
}

Thread *thread;

void setup()
{
  Serial.begin();
  delay(1000);
  Serial.println("setup()");
  pinMode(D7, OUTPUT);
  WiFi.on();
  Serial.println("WiFi.on()");
  WiFi.connect();
  waitUntil(WiFi.ready);
  Serial.println("WiFi.ready()");
  Particle.connect();
  waitUntil(Particle.connected);
  Serial.println("Particle.connected()");
  digitalWrite(D7, HIGH);
#ifndef EARLY_LOCK
  os_mutex_lock(mutex);
#endif
  thread = new Thread("testThread", testThread);
}

void loop() {
  static uint32_t ms = 0;
  // tap MODE button to unlock and toggle D7 LED
  if (!digitalRead(BTN)) {
    Serial.println("Button pressed");
    delay(100);
    while(!digitalRead(BTN));
    os_mutex_unlock(mutex);
    delay(100);
  }
  if (millis() - ms < 1000) return;
  ms = millis();
  Serial.print('.');
}

void testThread() {
  while(true) {
    os_mutex_lock(mutex);
    digitalWrite(D7, !digitalRead(D7));
  }
}

When you undefine EARLY_LOCK the code runs as expected, but when you have it defined it will block just the same as your code (breating white) never running setup().

Maybe @rickkas7 can chime in to explain why or if this even is the intended behaviour (IMO it shouldn’t be) - or @peekay123 who has been playing with FreeRTOS too.

One other peculiar thing I also noticed was that even putting the device into Safe Mode after such a lockup was not possible with that firmware on the device - it just kept blinking green (looking for WiFi) forever. I had to USB flash some other firmware before the Argon could make it online again.

2 Likes

Thank you very much!! Completely solved the issue! I am still learning a lot of this so would you say as standard practice it is generally ‘good’ to lock such a mutex at a certain point? I had just assumed it was best to lock it as early as possible. And yes I noticed as well that the wifi credentials were lost after this, however because I generally work with the electron + 3rd party sim, I wasn’t sure if the wifi credentials were actually retained or not (since APN and such settings are not retained on electron).

Actually they aren't lost. After flashing tinker (particle flash --usb tinker -v) my Argon connected just fine without the need to reapply the WiFi credentials.

The time you need to lock the mutex depends on the intent.
In my adapted code I just made sure the mutex was locked before the new thread was spun up - that's all that counts for the intended use of the mutex.

1 Like

Ahhh I understand now, thank you!