T4.1 Intermitent Crashes with Teensy Threads

Sprintf - Print to String (not Serial) - is likely a huge complex bit of code with local storage perhaps. Easy to believe re-entering it in progress would be prone to fail.

That is one noted item not included in the .yield testing done ... and interrupting it across two threads I would not have tried ... though intended to add it on one.
 
Short answer is no. Sprintf goes to serial and as I mentioned should be wrapped in a serial mutex

Oh, I saw your comment about Serial.print, but I did not realize that stand-alone sprintf with a passed string also uses serial. I thought only Serial.printf used serial. Good to know that sprintf is not thread safe without locks. I've got a lot of refactoring to do.

On your IMU question above, the MPU9250 and other commercial IMUs do not work well for rockets. Their sensor fusion algorithms are highly dependent on the accelerometer to provide an earth frame of reference. That works well for things that go horizontal (like cars and drones) or for robots, but when a rocket takes off it pegs the z axis of the accelerometer and trashes any earth reference. Also, the MPU9250 and other accelerometers are limited to 16G. Most of our flights are above 20G and many above 30G. So, the only way to have reliable data on a rocket is to use higher quality accelerometers and gyros and integrate your 3D position using quaternions at 400hz sampling.

@defragster, I think the yields were a red herring. In my test sketch I did not use any yields and I got it to crash in the same random way my code crashes.
 
Oh, I saw your comment about Serial.print, but I did not realize that stand-alone sprintf with a passed string also uses serial. I thought only Serial.printf used serial. Good to know that sprintf is not thread safe without locks. I've got a lot of refactoring to do.

On your IMU question above, the MPU9250 and other commercial IMUs do not work well for rockets. Their sensor fusion algorithms are highly dependent on the accelerometer to provide an earth frame of reference. That works well for things that go horizontal (like cars and drones) or for robots, but when a rocket takes off it pegs the z axis of the accelerometer and trashes any earth reference. Also, the MPU9250 and other accelerometers are limited to 16G. Most of our flights are above 20G and many above 30G. So, the only way to have reliable data on a rocket is to use higher quality accelerometers and gyros and integrate your 3D position using quaternions at 400hz sampling.

@defragster, I think the yields were a red herring. In my test sketch I did not use any yields and I got it to crash in the same random way my code crashes.

Very good point with the expected acceleration on a rocket vs car/drones etc. Should have registered that since you are using the ADXL375 versus the ADXL345!!! Wondering to self how something like the Madgewick or Mahoney or even DCM filters would work on a rocket. would really like to try it but impossible to launch anything in the NYC anymore.
 

This link is for a small, dependency-free and thread-safe implementation of printf/sprintf/etc. by Marco Paland.

https://github.com/mpaland/printf

I use this library, which is fork of Marco's printf() and implements a number of PRs that were made to Marco but never complete. Like the original, it is dependency-free and thread-safe.

https://github.com/embeddedartistry/arduino-printf

In a very simple test case, these implementations reduce code size by about 8 KB relative to the default printf().
 
Last edited:
Joe, thanks for thread safe library. I will bookmark that for future considerations. For now, I pulled out over 300 sprintf references in my code and replaced them with my simple hacks (below), since all I am doing is converting a limited set of floats, ints, longs, and bytes to strings. If any other travels come across this thread the functions below are crude but very lightweight, so double-check how you are using them.

Code:
void iToStr(int x, char res[20], int d)
{
    if(x == 0) {
      strcpy(res,"0");
      if(d==2) strcpy(res,"00");
      if(d==3) strcpy(res,"000");
      return;
    }
    bool neg = false;
    if(x < 0) {
      x = x * -1;
      neg = true;
    }
    
    int i = 0;
    while (x) {
        res[i++] = (x % 10) + '0';
        x = x / 10;
    }
     while (i < d)
        res[i++] = '0';
    reverse(res, i);
    res[i] = '\0';
    if(neg) {
      char temp1[20];
      strcpy(temp1,"-");
      strcat(temp1,res);
      strcpy(res,temp1);
    }
    
}

void bToStr(byte x, char res[20], int d)
{
    if(x == 0) {
      strcpy(res,"0");
      return;
    }
  
    int i = 0;
    while (x) {
        res[i++] = (x % 10) + '0';
        x = x / 10;
    }
     while (i < d)
        res[i++] = '0';
    reverse(res, i);
    res[i] = '\0';
    
}

void ulongToStr(unsigned long x, char res[20], int d)
{
    if(x == 0) {
      strcpy(res,"0");
      if(d==2) strcpy(res,"00");
      if(d==3) strcpy(res,"000");
      return;
    }
    int i = 0;
    while (x) {
        res[i++] = (x % 10) + '0';
        x = x / 10;
    }
    while (i < d)
        res[i++] = '0';
    reverse(res, i);
    res[i] = '\0';
}

void fToStr(float n, char res[20], int afterpoint)
{
    bool neg = false;
    if(n < 0) {
      n = n * -1;
      neg = true;
    }
    int ipart = (int)n;
    int i = 0;
    float fpart = n - (float)ipart;
    if(ipart == 0) {
      strcpy(res,"0");
      i = 1;
    } else {
      i = intToStr(ipart, res, 0);
    }
    if (afterpoint != 0) {
        res[i] = '.';
        fpart = fpart * pow(10, afterpoint);
        intToStr((int)fpart, res + i + 1, afterpoint);
    }
    if(neg) {
      char temp1[20];
      strcpy(temp1,"-");
      strcat(temp1,res);
      strcpy(res,temp1);
    }
    
}

void reverse(char* str, int len)
{
    int i = 0, j = len - 1, temp;
    while (i < j) {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
        i++;
        j--;
    }
}
 
int intToStr(int x, char str[], int d) //only used for the float function
{
    int i = 0;
    while (x) {
        str[i++] = (x % 10) + '0';
        x = x / 10;
    }
    while (i < d)
        str[i++] = '0';
    reverse(str, i);
    str[i] = '\0';
    return i;
}
 
Joe, thanks for thread safe library. I will bookmark that for future considerations. For now, I pulled out over 300 sprintf references in my code and replaced them with my simple hacks (below), since all I am doing is converting a limited set of floats, ints, longs, and bytes to strings. If any other travels come across this thread the functions below are crude but very lightweight, so double-check how you are using them.

Oh, that's too bad. arduino-printf is very complete, supporting all (?) standard data types and formatting options. It might not seem very appealing now, since you just removed all of those calls to sprintf(), but maybe later you could see if just adding that library fixes the problem with little or no modifications to your code. The library is well-tested and is probably faster than your new functions.
 
Back
Top