Teensy 3.6 GPS rfm69 conflicts

Status
Not open for further replies.

GLMc

Member
I am trying to record GPS using the Adafruit ultimate gps breakout at 10 Hz and two Adafruit rfm69 transmitters running at ~8 Hz. GPS and radios work separately and record to the builtin SD card so it appears the conflict is between the radio and the gps. (In loop() I comment out the eight GPS lines or all the other lines) It will run through a few cycles then hang, usually when the gps should read, then the serial monitor goes offline and I have to push the program button to upload again. I tried putting "noInterrupts" before the gps while statement (and interrupts afterwards) but that won't compile.
I am using windows 10, IDE 1.8.1, and gps code clipped out of the Adafruit example.
Thanks for any help.

HTML:
/* 

#include <RFM69.h>    //get it here: https://www.github.com/lowpowerlab/rfm69
#include <SPI.h>
#include <SD.h>
#include <Adafruit_GPS.h>
//*********************************************************************************************
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
//*********************************************************************************************
#define NETWORKID     100  //the same on all nodes that talk to each other
#define NODEID        1

//Match frequency to the hardware version of the radio on your Feather
#define FREQUENCY      RF69_915MHZ
#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 Feather M0
#define RFM69_CS      10
#define RFM69_IRQ     14
#define RFM69_IRQN    14
#define RFM69_RST     15
                   Sd2Card card;
                   SdVolume volume;
                   SdFile root;

        char c;//This will read the NMEA sentence as a series of characters.
        String NMEA1;String Sgps;
        String Slat;String Slong;String Sspd;String Sang;
        String S1;String Stime;
        String TotStr;
        Adafruit_GPS GPS(&Serial1);

#define GPSECHO  true
#define LOG_FIXONLY false  
boolean usingInterrupt = false;//I should learn to use interrupts
void useInterrupt(boolean); byte i; 

File myFile;
const int chipSelect = BUILTIN_SDCARD;
RFM69 radio = RFM69(RFM69_CS, RFM69_IRQ, IS_RFM69HCW, RFM69_IRQN);
byte Tin; byte Tcent; byte Tout; byte nit=0;char charNam[10]="SD100.txt";
int tim;byte k1;byte k2;unsigned long reft;
//________________________________________________________________
void setup() {

  Serial.begin(SERIAL_BAUD);
  delay(5000);
  Serial.println("Feather RFM69HCW Receiver");

  // Hard Reset the RFM module
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, HIGH);
  delay(100);
  digitalWrite(RFM69_RST, LOW);
  delay(100);

  // Initialize radio
  if (radio.initialize(FREQUENCY, NODEID, NETWORKID)) {
    Serial.print("radio initialized ");
  }
  if (IS_RFM69HCW) {
    radio.setHighPower();    // Only for RFM69HCW & HW!
  }
  radio.setPowerLevel(31); // power output ranges from 0 (5dBm) to 31 (20dBm)

  radio.encrypt(ENCRYPTKEY);

  Serial.print("\nListening at ");
  Serial.print(FREQUENCY == RF69_433MHZ ? 433 : FREQUENCY == RF69_868MHZ ? 868 : 915);
  Serial.println(" MHz");

  pinMode(8, OUTPUT); pinMode(10, OUTPUT);

    Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
                 tim=micros();
                 byte SDx= tim%(tim/1000);
                 Serial.println(tim);
                 Serial.println(SDx);
                 randomSeed(SDx);
                 byte randNumber=(random(65,85));
                 Serial.println(randNumber);
                 charNam[2]=randNumber;
                 charNam[4]=65;          
                 myFile = SD.open(charNam, FILE_WRITE);delay(1000);
byte GPSon=1;
if (GPSon==1){
          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_10HZ);  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);
                  Serial1.end();delay(100);//Terminate Serial1 then open at the set baud rate
                  Serial1.begin(57600);delay(100);
                  GPS.begin(57600);delay(100);
         Serial.println("gps restarted");
      }               
}
//____________________________________________________________________
void loop() 
{
  
// Serial.print(millis());
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
//Serial.print(c);
 }
// Serial.print(millis());
NMEA1=GPS.lastNMEA();
Serial.println(NMEA1);myFile.println(NMEA1);

 reft=millis();
           while(millis()-reft<80)
           {
                //check if something was received (could be an interrupt from the radio)
                if (radio.receiveDone())
                {
                  Serial.print(millis()); Serial.print(",");
                  Serial.print(radio.RSSI);Serial.print(",");
                  Serial.print(radio.SENDERID);
                     for(k1=0;k1<6;k1++){
                     Serial.print(",");  
                     Serial.print(radio.DATA[k1]);
                     Serial.print(radio.DATA[k1]);      
                     }
  Serial.println("");myFile.println(".");
                }
               }
    if (millis()/(nit+1) > 180000)
                {
                myFile.close();delay(100);
                nit++;Serial.println(nit);
                Serial.println("file closed"); 
                charNam[4]++;
                       if (charNam[4]==90)
                       {
                       charNam[4]=65;
                       charNam[2]++;
                       } 
                       Serial.println(charNam);                
                myFile = SD.open(charNam, FILE_WRITE);
                delay(100); 
                               
                }
                        
}
 
I'm not sure the Adafruit_GPS library is supported on the Teensy... it does not appear in the list of libraries that can be installed with the Teensy board package for the IDE.

The major problem is trying to print the raw NMEA data every time through loop. Instead, this sketch shows how to wait for a complete fix to arrive. Then it prints the current location to the SD file, if it's valid. You can print any of the fix pieces you want to the SD file. This is much more efficient than saving the raw NMEA characters.

You also have to check for GPS data very frequently. This usually means that you can't use delay. Instead, compare millis() with a timestamp, and when the difference is greater than the interval you want, do the timed task. Then reset the timestamp to wait another interval.

This also means that you can't print too much information. Eventually, the processor spends all its time waiting for printed characters to be sent. Then GPS characters will be lost. Uncommenting the print of millis() would cause it to lose GPS data.

Here's a version of your sketch that uses NeoGPS:

Code:
#include <NMEAGPS.h>
NMEAGPS gps;
gps_fix fix;
#define gpsPort Serial1

//*********************************************************************************************
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
//*********************************************************************************************

#define NETWORKID     100  //the same on all nodes that talk to each other
#define NODEID        1

//Match frequency to the hardware version of the radio on your Feather
#define FREQUENCY      RF69_915MHZ
#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 Feather M0
#define RFM69_CS      10
#define RFM69_IRQ     14
#define RFM69_IRQN    14
#define RFM69_RST     15

#include <RFM69.h>    //get it here: https://www.github.com/lowpowerlab/rfm69
RFM69 radio(RFM69_CS, RFM69_IRQ, IS_RFM69HCW, RFM69_IRQN);

//____________________________________________________________________


#include <SPI.h>
#include <SD.h>
Sd2Card card;
SdVolume volume;
SdFile root;
File myFile;
const int chipSelect = BUILTIN_SDCARD;
char charNam[10]="SD100.txt";

unsigned long lastCloseTime;

//____________________________________________________________________


void setup() {

  Serial.begin(SERIAL_BAUD);
  Serial.println("Feather RFM69HCW Receiver");

  // Hard Reset the RFM module
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, HIGH);
  delay(100);
  digitalWrite(RFM69_RST, LOW);
  delay(100);

  // Initialize radio
  if (radio.initialize(FREQUENCY, NODEID, NETWORKID)) {
    Serial.print("radio initialized ");
  }
  if (IS_RFM69HCW) {
    radio.setHighPower();    // Only for RFM69HCW & HW!
  }
  radio.setPowerLevel(31); // power output ranges from 0 (5dBm) to 31 (20dBm)

  radio.encrypt(ENCRYPTKEY);

  Serial.print("\nListening at ");
  Serial.print(FREQUENCY == RF69_433MHZ ? 433 : FREQUENCY == RF69_868MHZ ? 868 : 915);
  Serial.println(" MHz");

  // Initialize SD
  pinMode(8, OUTPUT); pinMode(10, OUTPUT);

  Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }

  Serial.println("initialization done.");
  int tim=micros();
  byte SDx= tim%(tim/1000);
  Serial.println(tim);
  Serial.println(SDx);
  randomSeed(SDx);

  byte randNumber = random('A','U');
  Serial.println(randNumber);
  charNam[2]=randNumber;
  charNam[4]='A';          
  myFile = SD.open(charNam, FILE_WRITE);

  // Initialize GPS
  gpsPort.begin(9600);//Base baud rate so we can talk to gps
  Serial.println("start gps");
  gps.send_P( &gpsPort, F("PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0") ); // RMC only
  gps.send_P( &gpsPort, F("PMTK220,100")   ); // Update frequency 10Hz
  gps.send_P( &gpsPort, F("PGCMD,33,0")    ); // No antenna status updates
  gps.send_P( &gpsPort, F("PMTK251,57600") ); // baud rate
                  //Can go to adafruit_gps.h to see these settings

  delay(1000); // wait for baud rate setting to take effect
  gpsPort.end();delay(100);//Terminate gpsPort then open at the set baud rate
  gpsPort.begin(57600);
  Serial.println("gps restarted");

  lastCloseTime = millis();
}

//____________________________________________________________________

void loop() 
{
  
// Serial.print(millis());

  // Check for GPS characters
  if (gps.available( gpsPort )) {

    // A new fix is available, update the current fix structure
    fix = gps.read();

    // Save some of the new fix on the SD card
    if (fix.valid.location) {
      myFile.print  ( "Loc=" );
      myFile.print  ( fix.latitude(), 6 );
      myFile.print  ( ',' );
      myFile.println( fix.longitude(), 6 );
    }
  }

  // Check if something was received (could be an interrupt from the radio)
  if (radio.receiveDone()) {
    Serial.print(millis()); Serial.print(",");
    Serial.print(radio.RSSI);Serial.print(",");
    Serial.print(radio.SENDERID);
    for(byte k1=0; k1<6; k1++){
      Serial.print(",");  
      Serial.print(radio.DATA[k1]);
      Serial.print(radio.DATA[k1]);      
    }
    Serial.println();
    myFile.println(".");
  }

  // Check if it's time to create a new file
  if (millis() - lastCloseTime > 180000) { // 3 minutes
    lastCloseTime = millis();

    myFile.close();
    Serial.println("file closed"); 
    charNam[4]++;
    if (charNam[4]=='Z') {
      charNam[4]='A';
      charNam[2]++;
    } 
    Serial.println(charNam);                
    myFile = SD.open(charNam, FILE_WRITE);
  }

}

If you want to try it, NeoGPS is available from the link above, or from the IDE Library Manager, under the menu Sketch->Include Library -> Manage Libraries.

Cheers,
/dev
 
I could be wrong, but I am guessing the Adafruit library may work fine with the Teensy.

I wonder if it is simply something like the radio code being starved for processing time.

That is your code us hanging around waiting for GPS information in the loop:

Code:
  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
    //Serial.print(c);
  }

Maybe the main loop may work better if it was reorganized such that you check both the newNMEAreceived and the radio.receiveDone() flags without hanging in loops.
Warning edited on fly don't know if it compiles let alone works...

Code:
void loop()
{

  // Serial.print(millis());
  c = GPS.read(); //read a character from the GPS
  if (GPS.newNMEAreceived()) { //We have a new GPS 
    // Serial.print(millis());
    NMEA1 = GPS.lastNMEA();
    Serial.println(NMEA1); myFile.println(NMEA1);
  }
  //check if something was received (could be an interrupt from the radio)
  if (radio.receiveDone())
  {
    Serial.print(millis()); Serial.print(",");
    Serial.print(radio.RSSI); Serial.print(",");
    Serial.print(radio.SENDERID);
    for (k1 = 0; k1 < 6; k1++) {
      Serial.print(",");
      Serial.print(radio.DATA[k1]);
      Serial.print(radio.DATA[k1]);
    }
    Serial.println(""); myFile.println(".");
  }

  if (millis() / (nit + 1) > 180000)
  {
    myFile.close(); delay(100);
    nit++; Serial.println(nit);
    Serial.println("file closed");
    charNam[4]++;
    if (charNam[4] == 90)
    {
      charNam[4] = 65;
      charNam[2]++;
    }
    Serial.println(charNam);
    myFile = SD.open(charNam, FILE_WRITE);
    delay(100);

  }

}
 
Thanks to both of you for the ideas. I just picked these up so have not tried your ideas yet but will report back as soon as I test. Re the Adafruit library I was pretty confident since it works perfectly when running just gps. Re the timing my idea was to let the gps drive the system so it waits until a gps is received, which then takes 15 ms to read the data. If I miss radio data during this time that is OK as long as an interrupt does not cause a problem. Following the gps it then loops to pick up radio signals for 80 ms, leaving what appears on the scope to be plenty of margin to return to wait for the next gps. The Low Power Labs' library seems to be quite different from the Radio Head library so I ran the same code using the RH library. In the several minutes of testing that I have done so far there have been NO hangups. So a lot to chew on here. Thanks again... will let you know how I fare.
 
KurtE, this code looks much better and is the way I started but was not clear how it would work. It seems like if a gps signal is coming in, but not complete, it moves on to the radio and checks to see if a message has arrived. If it has, the radio downloads, then goes on back to the gps. In testing, I have missed a couple of gps and it did hang up once but I don't attach much significance to that until I have tested thoroughly. So I will continue testing and see if it is all reliable.
/dev, I have installed the neoPix library but have not tested your code yet. Note that in my code I have the print(c) commented out. That was for diagnostics and leads to all kinds of problems like java overflowing. The reason I used the "while" for the radio was to give priority to the gps, missing radio data occasionally. I am not convinced either your code or KurtE's do that but they may, given the radio data is 1/10th of the gps. Thanks to both... I think I am near a working solution.
 
Status
Not open for further replies.
Back
Top