Teensy 3.6 hangs after hours running

Status
Not open for further replies.

GLMc

Member
I am sending temperature array data to teensy SD card along with gps data. It typically runs for 2-3 hours then hangs up, always after it prints out the array data and moves to the gps data. The radio is a RFM69 915 MHz and the gps is the Adafruit Ultimate GPS.
1. Does anyone see a problem with the code that would cause it to infrequently hang?
2. In a post some time ago Paul recommended against using a capacitor to reset but I can't add a chip to this board. Since it is not reliable now is there any reason not to try putting a diode and capacitor on pin 18 so that if it hangs (18 will be low) it drags down the reset?

When it hangs it always prints out the 1234 so has presumably finished the SD card activity and moves on. I have tried moving the disable/enable interrupts around and have even run with them disabled in setup() with no apparent difference.



Code:
#include <RH_RF69.h>  
#include <SPI.h>
//#include <IFCT.h>
//#include <kinetis_flexcan.h>
#include <SD.h>
#include <Adafruit_GPS.h>

//Match frequency to the hardware version of the radio on your Feather
#define RF69_FREQ 915.0  
//#define ENCRYPTKEY    "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
//#define IS_RFM69HCW   true // set to 'true' if you are using an RFM69HCW module
#define SERIAL_BAUD   9600
//for Teensy 3.6 RFM69 Radio for base with CAN bus and BT.
#define RFM69_CS      10
#define RFM69_INT     2
#define RFM69_RST     9
//#define LED           13  // On the 3.6 pin 13 is the rf clock, SCK
File myFile;
File root;
File dir;
File entry;

RH_RF69 rf69(RFM69_CS, RFM69_INT);
int i;byte IDnum=53;int k5;byte cantemp[16];byte b=240;byte b1=1;
const int chipSelect = BUILTIN_SDCARD;
char charNam[11]="AAAAAA.txt";unsigned long reft;unsigned long countms=10;
char charNamlast[11]="AAAAAA.txt";char ctr[2]="A";
char c;//read the NMEA sentence
String NMEA1;
Adafruit_GPS GPS(&Serial3);
#define GPSECHO  true
#define LOG_FIXONLY false  
boolean usingInterrupt = false;
void useInterrupt(boolean);
int tim;byte k1;byte k2;byte gpsprint=0;int batV;
//SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); 
SPISettings settingsrf(4000000, MSBFIRST, SPI_MODE0);
SPISettings settingssd(4000000, MSBFIRST, SPI_MODE0);

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

void setup() {

pinMode(13, OUTPUT); pinMode(18, OUTPUT); 
digitalWrite(18,HIGH);
Serial.begin(SERIAL_BAUD);
Serial3.begin(9600);
delay(1000);

Serial.println("RFM69HCW Transmitter");
  
  // Hard Reset the RFM module
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, HIGH);
  delay(100);
  digitalWrite(RFM69_RST, LOW);
  delay(1000);

  if (!rf69.init()) {
    Serial.println("RFM69 radio init failed");
    while (1);
  }
  Serial.println("RFM69 radio init OK!");
  if (!rf69.setFrequency(RF69_FREQ)) {
    Serial.println("setFrequency failed");
  }

  // If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
  // ishighpowermodule flag set like this:
  rf69.setTxPower(20, true);  // range from 14-20 for power, 2nd arg must be true for 69HCW

  // The encryption key has to be the same as the one in the server
  uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  rf69.setEncryptionKey(key);
  Serial.print("RFM69 radio @");  Serial.print((int)RF69_FREQ);  Serial.println(" MHz");

  if (!SD.begin(chipSelect)) {
    Serial.println("card initialization failed!");
    return;
  }
Serial.println("Program is 'RX_RH_rfm69_3.6_gps_SD_071519'");
Serial.println("card initialized");
delay(1000);
myFile=SD.open(charNam,FILE_WRITE);
Serial.print("file name =   ");Serial.println(charNam);

        GPS.begin(9600);//Base baud rate so we can talk to gps
      //   Serial.println("start gps");
         delay(1000);
            GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);delay(100);
            GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ);  delay(100); 
            GPS.sendCommand(PGCMD_NOANTENNA);delay(100);
            GPS.sendCommand(PMTK_SET_BAUD_57600);delay(100);//Can go to adafruit_gps.h to see these settings
         delay(1000);
                  Serial3.end();delay(100);//Terminate Serial1 then open at the set baud rate
                  Serial3.begin(57600);delay(100);
                  GPS.begin(57600);delay(100);
         Serial.println("gps restarted");
}
//******************************************************
  void loop() {
  delay(1);  

while(!GPS.newNMEAreceived()) { //Keep reading characters in this loop until a good NMEA sentence is received
c=GPS.read(); //read a character from the GPS
}
 NMEA1=GPS.lastNMEA();
 Serial.println(NMEA1);myFile.println(NMEA1); 
readradiodata();
readradiodata();              
   if(millis()>countms+600000){
   countms=millis();           
   myFile.close();delay(100);      
         charNam[5]++;
      if (charNam[5]>89){
          charNam[5]=65;
      }              
         myFile=SD.open(charNam,FILE_WRITE);
         Serial.println(charNam);
      }//Closes save/rename loop  
}//Closes loop()
//______________________________________________
void readradiodata(){
  //delay(50);
  digitalWrite(18,HIGH);
           if (rf69.available()) {
            //Serial.print(millis());

               // Should be a message for us now   
              uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
              uint8_t len = sizeof(buf);
              if (rf69.recv(buf, &len)) {
                                              __disable_irq(); 
  SPI.beginTransaction(settingsrf);
  digitalWrite (10, LOW);
                       
                    Serial.print(millis());myFile.print(millis());
                    Serial.print(",");myFile.print(",");
                       for (k5=0;k5<len;k5++){
                          Serial.print(buf[k5]);myFile.print(buf[k5],DEC);                         
                          if(k5<len){
                            Serial.print(",");myFile.print(",");                        
                      }
                      }
                       Serial.println("");myFile.println("");   
         __enable_irq();
 delay(60);
  Serial.print("1");
  digitalWrite(18,LOW); 
  Serial.print("2");                 
  digitalWrite (10, HIGH);
   Serial.print("3"); 
  SPI.endTransaction();
   Serial.print("4"); //IT ALWAYS HANGS HERE!                            
    }//Closes if received         
  } //Closes if available
}//Closes readradiodata
 
Is this running from non-USB power? AFAIK any problem was only with startup where the cap/chip for power up might have helped - was fixed in software update included in TD_1.46.

What is the reason for : __disable_irq();

That doesn't seem normal and is asking for trouble as that would affect USB output and perhaps SPI.
 
Defragster, it is set up to run with either usb power or 12V through a 5V regulator. Re the disable, before I got the teensy with the SDIO SD I had conflicting issues between the SD and the RFM69, both of which use SPI. I assume both the SDIO and RFM69 use the SD library (wrong???) so would have thought this necessary. It does not matter as far as I can tell whether I use it or not. I will try without them more seriously and carefully. I will also try the reset from pin 18. Probably can't hurt. Thanks, Gary
 
The wrapping of BEGIN and END transaction is designed to isolate/limit SPI usage to that single area of code to intended device with specified settings.

Disable of interrupts over a large area of code messes with clock tick count and other function. As long as the RFM doesn't interrupt and attempt to perform SPI during another ongoing SPI update all should be well. Don't know the device and can't study the code to see ...

Can you isolate the two devices to unique SPI buses?

Only the 12V through 5V reg would have been suspect before TD_1.46, startup init of MCU should have that resolved now.
 
The wrapping of BEGIN and END transaction is designed to isolate/limit SPI usage to that single area of code to intended device with specified settings.

Disable of interrupts over a large area of code messes with clock tick count and other function. As long as the RFM doesn't interrupt and attempt to perform SPI during another ongoing SPI update all should be well. Don't know the device and can't study the code to see ...

Can you isolate the two devices to unique SPI buses?

Only the 12V through 5V reg would have been suspect before TD_1.46, startup init of MCU should have that resolved now.
Re BEGIN and END I thought that would eliminate any conflicts. Re interrupts I think the RFM69 fires an interrupt whenever it receives a transmission which can be a problem if writing to the SD without the SDIO SD lines. I thought these were separate SPI busses, SDIO for the SD card and pins 11-13 for the radio??? Still, I think they both use the SD library so I suppose that can still be an issue.

I will take out the interrupt disables and also see if I can look at the SPI signal just before it stops switching pin 18 (trigger). Thanks again, Gary
 
Indeed the T_3.6 onboard SD card uses unique SDIO interface pins. I'd look for another example of the SDIO myfile writes for clarity on use.

Perhaps it wouldn't be a bad idea to sprintf() the USB Serial data inside the loop to an szBuffer[] and then only write the SD myfile in the loop. Then print the szBuffer[] on exiting that write loop.
 
Interesting thought. I have also thought about writing the data to memory for a few minutes then stop and write to the SD card. I appreciate the help. Gary
 
Writing the SD card in 512 byte blocks minimizes SD buffering and rewrite overhead as well. And USB does full transmits on 64 bytes.
 
I have never written to the buffer like this. Is it simply a matter of a .print of exactly 512 bytes? Is there a way to determine the size of the buffer contents? If so I could monitor that and when I near 512 Bytes stop everything else long enough to be sure it can write the entire buffer. I have the delay after the write so it would have time to write to the card, but I have seen odd writes to SD cards that hundreds of ms (not with the SDIO, though).

I didn't understand the comment about USB doing the full transmit on 64 Bytes. Does the Serial buffer send write in 64 Byte blocks? As you can tell I am not very smart about buffers and have never worked with them directly. Thanks, Gary
 
USB packets each hold 64 bytes of data. A full packet is sent at the next opportunity. A partially filled buffer is allowed to rest some short time allowing for added data to fill the buffer before sending.

Arranging to collect data from a series of varied sized prints to get to exactly 512 bytes would take some management. Can't say I've done it - it seems a local buffer big enough to hold any individual print would be used for sprint() storage.

Then with a pair of 512 byte buffers that local buffer would transfer and repeat with a count up to 512 bytes - that buffer would be sent to write and any remainder would be put into the second now active write buffer repeating as done for the prior buffer gathering the local strings and putting them to the altering 512 buffers.

If the SD write doesn't return until completed - a single 512 byte buffer could be used to then finish the local string as needed and continue the process for more strings now or later. The USB will take care of itself.

Yes SD writes can be fast and sometimes there is a lag of 100 ms to multiple 100's of milliseconds for the write to complete.
 
Defragster, you have prompted a lot of new thoughts... I took out the delays as they are unnecessary and took out the disable statement. It seems the most logical problem would be the radio interrupt when it receives a signal while the gps read is looping, so I am now printing every character during the read. So far, after two hours I have had no hangs so maybe the delay/disable have solved the problem. Regardless, it occurs to me that there is no reason to print out the entire 70+ gps characters. I can use a break and simply print the first 64 characters so only one transmission instead of two. I have been reading more about buffers as I like your approach... can I create a buffer simply creating a char 512 characters long or is there a special designation that has to be used for a buffer?

I am not quite sure how to get rid of the radio interrupt, but I do not believe that is necessary either. Fascinating stuff... thanks, Gary
 
Status
Not open for further replies.
Back
Top