Teensy library routines lock up with data loggin application

Status
Not open for further replies.
I am using the Teensy 3.6 to perform data logging, my logging rate is 2 kBytes/sec, so not exactly high, and I wish to deploy this into the field to monitor weather patterns so do not want to be standing over it 24/7. When I use the SD library (even the SDFat library), after 5 minutes or so the Teensy locks up, in the SD routine when I am writing data and requires an external reset to get it going again.

I am not a C++ expert and most of these libraries seem to be written in that, also there are no debug tools so I am kind of stuck.


I have noticed when I enable the serial communications (Serial Com 4) to run in parallel with accesses to the SD Card, it seems to lock up quicker.
I guess maybe the interrupt could be a suspect cause. Has anyone explored this.
My sensor is connected to COM4.


I am using the following code init the SD card

Code:
  Serial.println("Initialising SD card...");
  if (!SD.begin(chipSelect)) {
      lcd.setCursor(0,1);
      lcd.print("SDCard Init Fail");
      Serial.println("SDCard initialisation failed!");
      // wait here in an infinite loop
      while(1) {
      }
  }  
  fname = "mylog.txt";
  myFile  = SD.open(fname, FILE_WRITE);
  myFile.close();


And using this routine to write data to the SD card

Code:
      myFile  = SD.open(fname, FILE_WRITE | O_APPEND);
      if (myFile) {
          blk_cntr++;
          Serial.println(blk_cntr);
          lcd.setCursor(0,1);
          lcd.print("                ");
          lcd.setCursor(0,1);
          lcd.print(blk_cntr);

          for (p1=0; p1<SIZEOF; p1++) {
            myFile.println(ww_buf[p1]);
          }
          myFile.close();
        }


Please note that I have also tried the SDFat library and SDEx proposed solutions in other forum threads and they gave me the same problems. A lock up during the myFile.print() routine.
 
Last edited by a moderator:
With snippets of code details get lost - like is this the T_3.6 Native SD card? Why enable Serial4? Is that for sensor communication? What is the sensor? What is SIZEOF the size of and is it proper or miscalculated?

The other thing about the forum rule at the page top - is that getting to a smaller piece of code to post - removing the 'extra' stuff may point to the problem.

First idea would be to do something like this to show if it is the SD I/O:
Code:
      myFile  = 1; // SD.open(fname, FILE_WRITE | O_APPEND);
      if (myFile) {
          blk_cntr++;
          Serial.println(blk_cntr);
          lcd.setCursor(0,1);
          lcd.print("                ");
          lcd.setCursor(0,1);
          lcd.print(blk_cntr);

          for (p1=0; p1<SIZEOF; p1++) {
            [B]Serial.println(ww_buf[p1]);[/B]
            // myFile.println(ww_buf[p1]);
          }
          // myFile.close();
        }
 
Here is an entire sketch that will lock up, it is an example sketch, since I am not allowed to share the actual sketch in the public domain.

The sensor communicates to the Teensy via Serial4.
100 packets are sent per second. Each packet is 14 bytes (2 header, int aa, int bb, int cc), each int is 4 bytes.

Actually the packets are sent in intervals (8ms, 8ms, 8ms, 8ms, 8ms, 8ms, 8ms, 8ms, 8ms, 28ms) repeat, and I use a different header to signal
when the 28ms occurs and perform the write to the SD card in that interval.

Serial1 is used for messaging when a PC is connected on the USB port.


And I have written code to close the file, then open a new file with an incremental name every minute, but this still locks up.

I want to deploy this to the field for at least 48 hours of logging, and the lock up usually occurs within the 1st hour.


Code:
#include <LiquidCrystal.h>
#include <Encoder.h>
#include <EEPROM.h>
#include <SPI.h>
#include <SD.h>

// --------------------------------------------------------------------------------------------------

#define BUILTIN_SDCARD 254
const int chipSelect = BUILTIN_SDCARD;
char fname[6] = "a1.txt";
File myfile;


// --------------------------------------------------------------------------------------------------

#define REINTERPRET(type,val) (*((type*)&(val)))
#define NO_MENU_ITEMS 10
float settings_flt[NO_MENU_ITEMS];

// --------------------------------------------------------------------------------------------------
// Pins and Stuff

#define ENC_A 2
#define ENC_B 3
#define POT 35
#define LCD_RS 21
#define LCD_EN 20
#define LCD_D4 16
#define LCD_D5 15
#define LCD_D6 14
#define LCD_D7 13
#define LCD_BL 38
#define LED 13

// LCD
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

// Define Rotary Encoder Pins 
Encoder myEnc(ENC_A, ENC_B);

// Push Button Settings
#define btn_SELECT 26
#define btn_LEFT 27
#define btn_UP 28
#define btn_DOWN 29
#define btn_RIGHT 30
#define btn_NONE -1
#define pin_LED 13
#define btn_RUN 100
#define btn_STOP 100    // used for stopping logging to the SD card
#define btn_PROGRAM 200
#define btn_DEFAULT 300
#define pin_TST 4
#define pin_TST1 5


// ----------------------------------------------------------------------------------

// execute every 10-20 ms, reads and debounces the push buttons

int debounce() {

  static byte buttons_d2[5];
  static byte buttons_d1[5];
  static byte buttons_d0[5];
  static byte cntr = 0;
  
  for (int ii=0; ii<5; ii++) {
      buttons_d2[ii] = buttons_d1[ii];
      buttons_d1[ii] = buttons_d0[ii];
  } 
  
  buttons_d0[0] = (byte)digitalRead(btn_SELECT);
  buttons_d0[1] = (byte)digitalRead(btn_LEFT);
  buttons_d0[2] = (byte)digitalRead(btn_UP);
  buttons_d0[3] = (byte)digitalRead(btn_DOWN);
  buttons_d0[4] = (byte)digitalRead(btn_RIGHT);

  //Serial1.print(buttons_d0[0]);

  // check for button press only
  
  if (buttons_d2[0] == 0 and buttons_d1[0] == 0 and buttons_d0[0] == 1) {
    cntr = 0;
    return btn_SELECT;
  }
  
  if (buttons_d2[1] == 0 and buttons_d1[1] == 0 and buttons_d0[1] == 1) {
    cntr = 0;
    return btn_LEFT;
  }
  
  if (buttons_d2[2] == 0 and buttons_d1[2] == 0 and buttons_d0[2] == 1) {
    cntr = 0;
    return btn_UP;
  }
  
  if (buttons_d2[3] == 0 and buttons_d1[3] == 0 and buttons_d0[3] == 1) {
    cntr = 0;
    return btn_DOWN;
  }
  
  if (buttons_d2[4] == 0 and buttons_d1[4] == 0 and buttons_d0[4] == 1) {
    cntr = 0;
    return btn_RIGHT;
  }

  // The following 2 are for holding down the button

  // Select run mode
  if (buttons_d2[0] == 0 and buttons_d1[0] == 0 and buttons_d0[0] == 0) {
    cntr++;
    if (cntr == 100) {
      cntr = 0;
      return btn_RUN;
    }
  }

  // Program the EEPROM mode
  if (buttons_d2[4] == 0 and buttons_d1[4] == 0 and buttons_d0[4] == 0) {
    cntr++;
    if (cntr == 100) {
      cntr = 0;
      return btn_PROGRAM;
    }
  }
  
  if (buttons_d2[1] == 0 and buttons_d1[1] == 0 and buttons_d0[1] == 0) {
    cntr++;
    if (cntr == 100) {
      cntr = 0;
      return btn_DEFAULT;
    }
  }

  return(btn_NONE);
}

// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial4.begin(115200, SERIAL_8N1);
  analogWrite(LCD_BL, 128); // on LCD backlight to 50%
  
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("   My EVAL      ");
  lcd.setCursor(0,1);
  lcd.print(" 31 May 2019    ");
  delay(2000);

  // Push Buttons
  pinMode(btn_SELECT, INPUT_PULLUP);
  pinMode(btn_LEFT, INPUT_PULLUP);
  pinMode(btn_UP, INPUT_PULLUP);
  pinMode(btn_DOWN, INPUT_PULLUP);
  pinMode(btn_RIGHT, INPUT_PULLUP);
  pinMode(pin_LED, OUTPUT);
  pinMode(pin_TST, OUTPUT);
  pinMode(pin_TST1, OUTPUT);

  // LCD Backlight
  analogWrite(LCD_BL, 128); // on LCD backlight to 50%
  
  // -----------------------------------------------------------------------------
  // Read the EEPROM
  uint64_t val0;
  uint8_t val1;
  //char line[100];
  for (int ii=0; ii<NO_MENU_ITEMS; ii++){
      val0 = 0;
      val1 = 0;
      for (int jj=7; jj>=0; jj--) {
          EEPROM.get(ii*8+jj,val1);
          val0 = (val0<<8) | (val1);
      }
      settings_flt[ii] = REINTERPRET(float,  val0);
  }
  

  lcd.clear();
  lcd.print("Run Mode");
  delay(1000);
  
  Serial.println("---------------------------");
  Serial.println("Setup Done");
  Serial.println("---------------------------");
  Serial.println("");

  Serial.println("Initialising SD card...");
  if (!SD.begin(chipSelect)) {
      lcd.setCursor(0,1);
      lcd.print("SDCard Init Fail");
      Serial.println("SDCard initialisation failed!");
      // wait here in an infinite loop
      while(1) {
      }
  }

  myfile = SD.open(fname, FILE_WRITE);
  myfile.close();
  
  Serial.println("SDCard Open");
  lcd.setCursor(0,1);
  lcd.print("SDCard Open");
  
  // flush the serial port
  Serial4.clear();
}

// -------------------------------------------------------------------------------------------------

#define SIZEOF 100  // must be in multiples of 10
long aa_buf[SIZEOF];
int bb_buf[SIZEOF];
int cc_buf[SIZEOF];
int dd_buf[SIZEOF];

//puts data into buffer, transfers data at specified times
void log_data (long get_time, int a1, int b1, int c1, byte last_meas_ind) { 

  static int big_ptr = 0;
  static int ptr = 0;
  static int last_meas_flag = 0;
  static int p1;

  if (last_meas_flag == 1){

      aa_buf[ptr] = get_time;
      bb_buf[ptr] = a1;
      cc_buf[ptr] = b1;
      dd_buf[ptr] = c1;
      ptr++;
      if (ptr == SIZEOF) {
          ptr = 0;
          write_to_sdcard();
      }
  }
  else {
      last_meas_flag = last_meas_ind;
  }
}

// -------------------------------------------------------------------------------------------------

void write_to_sdcard () { 

  static int blk_cntr = 0;
  static int p1;
  
  digitalWrite(pin_TST1, HIGH);
  myfile  = SD.open(fname, FILE_WRITE | O_APPEND);
  if (myfile) {
      blk_cntr++;
      Serial.println(blk_cntr);
      lcd.setCursor(0,1);
      lcd.print("                ");
      lcd.setCursor(0,1);
      lcd.print(blk_cntr);

      for (p1=0; p1<SIZEOF; p1++) {
        myfile.print(aa_buf[p1]);
        myfile.print(" ");
        myfile.print(bb_buf[p1]);
        myfile.print(" ");
        myfile.print(cc_buf[p1]);
        myfile.print(" ");
        myfile.println(dd_buf[p1]);
      }
      myfile.close();
    }
    digitalWrite(pin_TST1, LOW);
}


// -------------------------------------------------------------------------------------------------

void loop()
{
    static int counter100;
    static byte rx_byte;
    static byte rx_bffr[64];
    static int rx_cntr = 0;

    long  a1, b1, c1, mabc;
    static long timems, timems_d;
    byte last_meas_ind = 0;
    
    if (Serial4.available()) {
        
        while (Serial4.available() > 0) {
            rx_byte = Serial4.read();
            rx_bffr[rx_cntr] = rx_byte;
            rx_cntr++;
        }

        if (rx_cntr == 18) {
        
            digitalWrite(pin_TST, HIGH);

            rx_cntr = 0;
            timems_d = timems; 
            timems = millis();
            last_meas_ind = 0;
            if (rx_bffr[1] == 0x5C)
                last_meas_ind = 1;
      
            a1 = b1 = c1 = 0;
      
            for (int ii=0; ii<4; ii++) {
                a1 = rx_bffr[2+ii] | a1<<8;
                b1 = rx_bffr[6+ii] | b1<<8;
                c1 = rx_bffr[10+ii] | c1<<8;
                mabc = rx_bffr[14+ii] | mabc<<8;
            }

            // log data
            long get_time = millis();
            log_data(get_time, a1, b1, c1, last_meas_ind);


            // close file to remove SD card
            int button_press = debounce();
            if (button_press == btn_STOP) {
                myfile.close();
                Serial.println("FILE CLOSED. REMOVE SD CARD.");
                lcd.setCursor(0,1);
                lcd.print("SDCard Closed");
                while(1) {}
            }
            
            counter100++;
            if (counter100 == 100) {
                counter100 = 0;
            }
            digitalWrite(pin_TST, LOW);
        }
    }
    //return;
}
 
Last edited by a moderator:
Try this as a the simple fix - otherwise rx_cntr can go unbounded if a message boundary is crossed on read:

Code:
void loop()
{
    static int counter100;
    static byte rx_byte;
    static byte rx_bffr[64];
    static int rx_cntr = 0;

    long  a1, b1, c1, mabc;
    static long timems, timems_d;
    byte last_meas_ind = 0;
    
    if (Serial4.available()) {
        
        // while (Serial4.available() > 0) {
        [B]while (Serial4.available() > 0 && rx_cntr < 18) {[/B]
            rx_byte = Serial4.read();
            rx_bffr[rx_cntr] = rx_byte;
            rx_cntr++;
        }

        if (rx_cntr == 18) {
        
            digitalWrite(pin_TST, HIGH);

            rx_cntr = 0;
 
char fname[6] = "a1.txt";

Your string dimension of 6 is too short for 6 characters plus the zero terminator. And you say the original program generates new filenames each minute, so better check that the new filenames will fit in the char array and that there is room for the string terminator.
 
char fname[6] = "a1.txt";

Your string dimension of 6 is too short for 6 characters plus the zero terminator. And you say the original program generates new filenames each minute, so better check that the new filenames will fit in the char array and that there is room for the string terminator.

Indeed it is already too short … I looked right at that and miscounted ...
 
Thanks for taking the time to look though. Sometimes one cannot see the forest for the trees, where another set of eyes can.

It seems the fix suggested by defragster was the issue and it had nothing to do with the SD card routines in the first instance.
I have also increased the filename to 10 characters as recommended, and make sure it never exceeds this (including the '\0' string terminator).

It will take me some days to verify that logging works reliably, but for now I guess I could say the problem is solved.
 
Thanks for taking the time to look though. Sometimes one cannot see the forest for the trees, where another set of eyes can.

It seems the fix suggested by defragster was the issue and it had nothing to do with the SD card routines in the first instance.
I have also increased the filename to 10 characters as recommended, and make sure it never exceeds this (including the '\0' string terminator).

It will take me some days to verify that logging works reliably, but for now I guess I could say the problem is solved.

Glad to help.

Note: Hoping this is the extent of the issue - the suggested debug step in post #2 would also have shown it failing as well when the SD code was removed the faulty Serial4 processing in post #3 was needed to actually see the problem - thus the Top of this and all pages is the Forum Rule.

Though actually it may be LOGGING delay to SD that causes messages not to have been parsed on the "==18" boundary so by the time it got to that 19 or more characters ended up in rx_bffr[] , and without that SD code that would not have triggered the issue.

This could still result in issues if processing is held up without a larger Serial4 receive buffer ( it defaults to 40 IIRC ? ) - so that needs to be expanded or a bit more coding to pull in from the buffer while(available) and expect to store one or more ongoing messages in the sketch rx_bffr{} in some fashion.
 
Status
Not open for further replies.
Back
Top