Teensy works for some time then stops

Status
Not open for further replies.

nevyn

New member
Teensy code is working but seems to stop running after a few minutes

The project is to convert a G guage electric loco from track dc power to battery + rc control


Goals include
* Motor control speed and direction
* Motor current monitoring for safety and as an input to sound routines
* Sound (not yet implemented)
* chuff driven by some combination of motor load axle sensor
* playable simulated whistle by rc
* bell and other thematic sounds (all aboard etc) from wav files on the sdcard plan is to use a pt8211 board

Current hardware setup is:
PPM from a orangeR610X to pin 23 using pulse position
Teensy 3.5
pins 33-35 are connected to a L298N motor driver. with 35 being pwm enable

The Teensy seems to stop executing code after a period of time. I'm wondering if it's a stack crash or something but it's all quite small. I have the following sketch running on a Teensy 3.5 programming using teensyduino:

Code:
#include <PulsePosition.h>

// ppm channel order for dsm2/dsmx
#define AILCHAN 1
#define ELECHAN 2
#define THRCHAN 3
#define RUDCHAN 4
#define AUXCHAN 5
#define GEARCHAN 6

//pin definitions for motor control
#define MCDIR1 33 // connected to inA 1
#define MCDIR2 34 // connected to inA 2
#define MCPPM 35  //connected to L298 inA enable

  int8_t numchans=0; // number of channels + 1
  float rcvals[7]; //  The orange R610x only outputs 6 channels if we change to frsky this will need to be 17. 

// Create PulsePosition and define a pin for the RX                        
PulsePositionInput myIn; 
#define RCPPMINPUT 23    // recieves PPM from Orange R610x

void setup() {
  myIn.begin(RCPPMINPUT);
  pinMode(MCDIR1, OUTPUT);
  pinMode(MCDIR2, OUTPUT);
}


void getrcvalues() {
  // Every time new data arrives, store it in an array
  // to the Arduino Serial Monitor.
  uint8_t num = myIn.available();
  // Check if there is new data
  if (num > 0) {
       numchans = num;
       for (int8_t i = 1; i<=numchans; i++) {
       rcvals[i] = myIn.read(i); 
    };
  };
}

void printrcvalues() {
  //only print if we have data.
  //Serial.println(numchans);
  for(int i=1; i<=numchans; i++){
    Serial.print("\t");    
    Serial.print(rcvals[i]);
  };
  Serial.println();
}

void controlmotor(int8_t dir, uint16_t speed) {
switch (dir) {
    case 1: // set forward
    analogWrite(MCPPM, speed);
    digitalWrite(MCDIR1, HIGH);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING FORWARD");
    break;
    case 0 : //set stop
    analogWrite(MCPPM, 0);
    digitalWrite(MCDIR1, HIGH);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING FISHIN'");
    break;
    case -1 : //set reverse
    analogWrite(MCPPM, speed);
    digitalWrite(MCDIR1, HIGH);
    digitalWrite(MCDIR2, LOW);
   // Serial.println("GOING BACkWARD");
    break;
    default ://set stop
    analogWrite(MCPPM, 0);
    digitalWrite(MCDIR1, LOW);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING NOWHERE");
    break;
  }
}

void loop() {
  getrcvalues(); 

  //Decode the aux channel and use it to set direction
  int8_t motdir;
  if (rcvals[AUXCHAN]>1800) 
      motdir=1;
    else if (rcvals[AUXCHAN] <1300)
      motdir = -1;
    else 
      motdir = 0;
   
  float throttle = (rcvals[THRCHAN]-1110)/3.34;
  
  controlmotor(motdir, throttle);

  if (false) { 
  printrcvalues();
  Serial.print(motdir);
  Serial.print("   ");
  }
//  Serial.print(rcvals[THRCHAN]);
//  Serial.print("   ");
//  Serial.println(throttle);
  
}


Help or advice on how to determine what's going on would be greatly appreciated.
 
If numchans is 7 or greater, this statement:
Code:
       rcvals[i] = myIn.read(i);
will overwrite past the end of the rcvals array.

Turn on the code that runs printrcvalues and look at what it prints just before the code crashes.

Pete
 
Annoyingly it seems to be fine on my desk today without the Hbridge board and the loco.

you may however be on the right relying on
uint8_t num = myIn.available();
not returning more than 6 might not be safe.

I seem to remember a lot of 0's on the bottom of the terminal when it crashed at least one time
 
Classic buffer overflow bug. The array is only 7 items. When you write to the 8th location, you're overwriting whatever other info happens to be in the memory after the array. Not good.
 
Ok, I updated it with some safety checks... does this look better?


Code:
#include <PulsePosition.h>

#define MAXCHANS  7 // this is nchannels + 1 because the values are in a 1 based array
                    //  The orange R610x only outputs 6 channels if we change to frsky this will need to be 17. 
int8_t numchans=MAXCHANS;   
float rcvals[MAXCHANS];

// ppm channel order for dsm2/dsmx
#define AILCHAN 1
#define ELECHAN 2
#define THRCHAN 3
#define RUDCHAN 4
#define AUXCHAN 5
#define GEARCHAN 6

//pin definitions for motor control
#define DEBUG_MOTOR 0  // set to 1 to print motor stuff
#define MCDIR1 33 // connected to inA 1
#define MCDIR2 34 // connected to inA 2
#define MCPPM 35  //connected to L298 inA enable

// Create PulsePosition and define a pin for the RX                        
PulsePositionInput myIn; 
#define RCPPMINPUT 23    // recieves PPM from Orange R610x

void setup() {
  myIn.begin(RCPPMINPUT);
  pinMode(MCDIR1, OUTPUT);
  pinMode(MCDIR2, OUTPUT);
}


void getrcvalues() {
  // Every time new data arrives, store it in an array
  // to the Arduino Serial Monitor.
  uint8_t num = myIn.available();
  // Check if there is new data
  if (num > 0) {
       if(num > MAXCHANS){
         numchans=MAXCHANS; //reset the global to MAXCHANS
         Serial.print(num);
         Serial.println(" <== ppm availible exceeds max channels");
         // read the myIn discarding the data as the frame is probably bogus
         for (int8_t i = 1; i<=num; i++) {
           myIn.read(i); 
         }
       }
       else {
               numchans=num;
               for (int8_t i = 1; i<=num; i++) {
               rcvals[i] = myIn.read(i); 
         }; 
       }
  };
}

void printrcvalues() {
  //only print if we have data.
  //Serial.println(numchans);
  for(int i=1; i<=numchans; i++){
    Serial.print("\t");    
    Serial.print(rcvals[i]);
  };
  Serial.println();
}

void controlmotor(int8_t dir, uint16_t speed) {
switch (dir) {
    case 1: // set forward
    analogWrite(MCPPM, speed);
    digitalWrite(MCDIR1, HIGH);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING FORWARD");
    break;
    case 0 : //set stop
    analogWrite(MCPPM, 0);
    digitalWrite(MCDIR1, HIGH);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING FISHIN'");
    break;
    case -1 : //set reverse
    analogWrite(MCPPM, speed);
    digitalWrite(MCDIR1, HIGH);
    digitalWrite(MCDIR2, LOW);
   // Serial.println("GOING BACkWARD");
    break;
    default ://set stop
    analogWrite(MCPPM, 0);
    digitalWrite(MCDIR1, LOW);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING NOWHERE");
    break;
  }
}

void loop() {
  getrcvalues(); 
  
  
  //Decode the aux channel and use it to set direction
  int8_t motdir;
  if (rcvals[AUXCHAN]>1800) 
      motdir=1;
    else if (rcvals[AUXCHAN] <1300)
      motdir = -1;
    else 
      motdir = 0;
   
  float throttle = (rcvals[THRCHAN]-1110)/3.34;
  
  controlmotor(motdir, throttle);

  if (numchans>0) {
    printrcvalues();
    if(DEBUG_MOTOR) {
      Serial.print(motdir);
      Serial.print("   ");
      Serial.print(rcvals[THRCHAN]);
      Serial.print("   ");
      Serial.println(throttle);
    }
  }
}
 
Ok, I updated it with some safety checks... does this look better?

No.

Because if num == MAXCHANS you will still modify rcvals[MAXCHANS].

And write past the end of the array.

Either change the sanity check or declare rcvals[MAXCHANS + 1] to reflect the 1 based nature of the channel index.
 
Valid Critques.. I had some trouble with a using a define so I changed it to a const int8_t
here's the current code.

I
https://gist.github.com/firstnevyn/0255d4702d28d7f3d017b232193123b1

Code:
#include <PulsePosition.h>

//  The orange R610x only outputs 6 channels if we change to frsky this will need to be 16 
const int8_t maxchans = 6 ;// this is nchannels 
int8_t numchans = maxchans;   
float rcvals[(maxchans+1)];

// ppm channel order for dsm2/dsmx
#define AILCHAN 1
#define ELECHAN 2
#define THRCHAN 3
#define RUDCHAN 4
#define AUXCHAN 5
#define GEARCHAN 6

//pin definitions for motor control
#define DEBUG_MOTOR 0  // set to 1 to print motor stuff
#define MCDIR1 33 // connected to inA 1
#define MCDIR2 34 // connected to inA 2
#define MCPPM 35  //connected to L298 inA enable

// Create PulsePosition and define a pin for the RX  /MAX                      
#define DEBUGRC 0
PulsePositionInput myIn; 
#define RCPPMINPUT 23    // recieves PPM from Orange R610x

void setup() {
  myIn.begin(RCPPMINPUT);
  pinMode(MCDIR1, OUTPUT);
  pinMode(MCDIR2, OUTPUT);
  Serial.println("Hi there we started...");
}


void getrcvalues() {
  // Every time new data arrives, store it in an array
  int8_t num = myIn.available();
  // Check if there is new data
  if (num > 0) {
    
    numchans=num;
    for (int8_t i = 1; i <=maxchans; i++) {
      rcvals[i] = myIn.read(i); 
    }

    if(num > maxchans){
      numchans=maxchans; //reset the global to maxchans
      Serial.print(num);
      Serial.println(" <== ppm availible exceeds maxchans channels");
      // read the myIn discarding the data as the frame is probably bogus
      for (int8_t i = maxchans; i<=num; i++) {
        myIn.read(i); 
      }
    }
  }
}

void printrcvalues() {
  //only print if we have data.
  //Serial.println(numchans);
  for(int i=1; i<=maxchans; i++){
    Serial.print("\t");    
    Serial.print(rcvals[i]);
  }
  Serial.println();
}

void controlmotor(int8_t dir, int16_t speed) {
switch (dir) {
    case 1: // set forward
    analogWrite(MCPPM, speed);
    digitalWrite(MCDIR1, HIGH);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING FORWARD");
    break;
    case 0 : //set stop
    analogWrite(MCPPM, 0);
    digitalWrite(MCDIR1, HIGH);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING FISHIN'");
    break;
    case -1 : //set reverse
    analogWrite(MCPPM, speed);
    digitalWrite(MCDIR1, LOW);
    digitalWrite(MCDIR2, HIGH);
   // Serial.println("GOING BACkWARD");
    break;
    default ://set stop
    analogWrite(MCPPM, 0);
    digitalWrite(MCDIR1, LOW);
    digitalWrite(MCDIR2, LOW);
    //Serial.println("GOING NOWHERE");
    break;
  }
}

void loop() {
  getrcvalues();
  //Decode the aux channel and use it to set direction
  int8_t motdir;
  if (rcvals[AUXCHAN]>1800) 
      motdir=1;
    else if (rcvals[AUXCHAN] <1300)
      motdir = -1;
    else 
      motdir = 0;
   
  float throttle = (rcvals[THRCHAN]-1110)/3.34;

  controlmotor(motdir, throttle);

  if (DEBUGRC) {
    printrcvalues();
  }
  if(DEBUG_MOTOR) {
    Serial.print(numchans);
    Serial.print("   ");
    Serial.print(maxchans);
    Serial.print("   ");
    Serial.println(throttle);
  }
}
 
Status
Not open for further replies.
Back
Top