Teensy Backpacks

A while ago you asked me if had any ideas for mounting a t3.6 to the backpack. One possibility is just to lengthen the backpack to fit the T3.6 and extend the headers so that you can get access to the additional pins. It could also give you the ability to make additional backpacks using the other pins as well.

Regards
Mike

Hi Mike, do you mean as a separate product line (i.e. a line of backpacks designed for Teensy 3.0/1/2 and Teensy LC and then a separate product line for Teensy 3.5/6)?

Brian
 
do you mean as a separate product line
Just a redesigned backpack. Just make the current backpack longer to fit the T3.5/6 and extend the headers to match the T3.5/3.6 mounting backpack. If i get some time i can probably sketch it up for you.

Mike
 
@Brian,

I have purchased a few of your backpack pieces, and I am impressed! I was wondering if you might have some code to make your Motion-Backpack output work as a "Tilt-Compensated Compass"? This may known as using "Sensor Fusion" but, I am struggling to find a code that I can convert to use with your Backpack.

I would like the compass to output a value of (0 to 359/360) so that I can use it for North, South Etc. I am replacing an Adafruit 9 Dof found here: https://www.adafruit.com/product/1714. Here is their example code that I have not been able to convert: https://learn.adafruit.com/adafruit-9-dof-imu-breakout

My project is for a GPS guided RC Truck and my current code works well with the Compass outputting degrees from North.

I really like your small, clean Backpack designs and I hope you can help me, even though this may require some code to be written.

Thanks for your Backpack designs and any help you can give,
Mark M.


The Backpack that I am referring to:
Motion Backpack
Integrating an MPU-9250 inertial measurement unit and a BME-280 environmental sensor, this backpack enables you to easily measure your project's motion and altitude. You'll get 3 axis accelerometer, 3 axis gyro, and 3 axis magnetometer data along with pressure, temperature and humidity. Both sensors communicate over I2C, have integrated pullups, and you can select the I2C address for each sensor.
 
Hi Mark,

Thanks! I'm glad you like the backpack designs. I'm planning on writing a series of tutorials around the Motion Backpack and GNSS Backpack in the next few months. In the meantime, here is what you'll need for a tilt compass, please let me know if you have any questions or run into issues.

There are two files attached, Mag_Cal.ino and Tilt_Compass.ino. You need to run Mag_Cal.ino only once; this calibrates the magnetometer on the MPU-9250 by estimating the hard and soft iron corrections. It's absolutely necessary to estimate these before doing any heading estimation, these corrections can be very large. There are instructions displayed to the serial terminal when you run the code - basically you'll slowly move the board in a figure 8 motion until the program is complete. Hard and soft iron corrections will be estimated and saved to the Teensy EEPROM. You should run Mag_Cal.ino any time the magnetic environment of the sensor changes, so if you moved its location within the vehicle, you would likely want to re-calibrate the sensor.

Next, is the Tilt_Compass.ino. This uses the accelerometers to estimate the pitch and roll angles of the sensor, which are used to project the magnetometer data onto a horizontal plane and estimate the yaw angle. Yaw angle is then transformed from a -180 to +180 result to a 0 - 360 result. Finally, because the magnetometer can be pretty noisy, I filter the result as well. All five of these values are available: pitch, roll, yaw (+/- 180), heading (0 - 360), and filtered heading. The +X axis direction is depicted on the Motion Backpack and I use a right handed axis system as depicted here:
https://github.com/bolderflight/MPU9250#sensor-orientation

Best,
Brian
 

Attachments

  • Mag_Cal.ino
    2.4 KB · Views: 108
  • Tilt_Compass.ino
    4.2 KB · Views: 109
Brian,

I tested your provided sketches and I am very happy with the results! I have the output I want and without asking you, you also fixed a problem that I had with my previous compass!

My previous problem was that the compass had random noise in it that would cause the output to jump around 10 or 12 degrees in random directions. Your filter looks like it will smooth the noise and make it a much smaller issue. That is awesome!

Thanks for the help!
Mark
 
Brian,

I tested your provided sketches and I am very happy with the results! I have the output I want and without asking you, you also fixed a problem that I had with my previous compass!

My previous problem was that the compass had random noise in it that would cause the output to jump around 10 or 12 degrees in random directions. Your filter looks like it will smooth the noise and make it a much smaller issue. That is awesome!

Thanks for the help!
Mark

Awesome! You can adjust the filter by changing window_size; larger values will reduce the noise at the expense of slower filter response. For example a value of 100 would have even less noise, but when the car turns, it would take longer for that turn to show up in the filtered data. A value of 1 would provide no filtering. The filter I used is called a first order IIR filter, it's the easiest filter to implement on a microcontroller since it only requires knowledge of its previous output.

Best,
Brian
 
Hi Brian
Got my GNSS board a couple of weeks ago but got sidetracked with another one of my projects. I finally had a chance to try it out. Was a little disappointed in its performance (acquiring a lock and # sats available). Think the patch antenna is a little to small to get a descent lock unless you are under open skies. I did my tests at my desk by the window and tried a couple of different GPS antennas on Neo-8m boards. Finally hooked up a Beiitian BN-280 (it has pps signal broken out) and it worked without any major issue. I used Chris O's modified library and was able to change the PPS rate as well.

Just wanted to let you know for future designs. It has a patch antenna as well but its about twice as large as the one on yours.

Mike
 
Thanks for the feedback! Too bad that you're not getting good satellite performance, let me know if you would like a refund. Works great in my workshop and yard, which is definitely not clear sky, but GNSS receivers are funny that way.

I'm planning on a board (probably a couple of different boards) and at least one would have external antenna. But I don't have a good ETA on it, waiting to get my hands on the uBlox 9 series and get some of these other projects done.
 
Not a problem Brian. Have a whole collection - like you said GPS receivers are funny especially when you use patch antennas I found.
 
Hi Brian
Playing around again with the MPU stuff. Just gave your Tilt_compass.ino file a try and never any angles between 0-90 or 0-90. What should be about 0 reads 90 degrees.

Mike
 
I used the full calibration sketch and just ran the unavAHRS sketch which seemed to have yaw ok. Was curious how close the two would correspond. I can always redo it and double check.
 
Ok - That was it - was the calibration - redid it and now its working. THanks - was just strange.
 
Flash Backpack basics using SerialFlash Library

Hi,
Started using the backpacks. Started with the flash storage one. Following is a basic initialize and test that may be helpful to other first time users. SerialFlash library has examples but tend to be a little complicated and of course are generic and not setup specifically for the bolder backpack. Key concept I missed at first is that this is really two different SPI devices so you need set the CS pin of the chip you are not accessing to INPUT_PULLUP. This code does the following on each chip, does a full erase, creates a file named test, writes data, reads data, checks for file existing, erases file if exists, writes data, reads data.

Code:
#include <SerialFlash.h>

int FlashChipSelect = 16;

bool eraseAllFirst;

int size;

unsigned char id[256];

SerialFlashFile file;

const unsigned long testIncrement = 4096;
float eraseBytesPerSecond(const unsigned char *id) {
  if (id[0] == 0x20) return 152000.0; // Micron
  if (id[0] == 0x01) return 500000.0; // Spansion
  if (id[0] == 0xEF) return 419430.0; // Winbond
  if (id[0] == 0xC2) return 279620.0; // Macronix
  return 320000.0; // guess?
}


const char * id2chip(const unsigned char *id)
{
  if (id[0] == 0xEF) {
    // Winbond
    if (id[1] == 0x40) {
      if (id[2] == 0x14) return "W25Q80BV";
      if (id[2] == 0x15) return "W25Q16DV";
      if (id[2] == 0x17) return "W25Q64FV";
      if (id[2] == 0x18) return "W25Q128FV";
      if (id[2] == 0x19) return "W25Q256FV";
    }
  }
  if (id[0] == 0x01) {
    // Spansion
    if (id[1] == 0x02) {
      if (id[2] == 0x16) return "S25FL064A";
      if (id[2] == 0x19) return "S25FL256S";
      if (id[2] == 0x20) return "S25FL512S";
    }
    if (id[1] == 0x20) {
      if (id[2] == 0x18) return "S25FL127S";
    }
  }
  if (id[0] == 0xC2) {
    // Macronix
    if (id[1] == 0x20) {
      if (id[2] == 0x18) return "MX25L12805D";
    }
  }
  if (id[0] == 0x20) {
    // Micron
    if (id[1] == 0xBA) {
      if (id[2] == 0x20) return "N25Q512A";
      if (id[2] == 0x21) return "N25Q00AA";
    }
    if (id[1] == 0xBB) {
      if (id[2] == 0x22) return "MT25QL02GC";
    }
  }
  if (id[0] == 0xBF) {
    // SST
    if (id[1] == 0x25) {
      if (id[2] == 0x02) return "SST25WF010";
      if (id[2] == 0x03) return "SST25WF020";
      if (id[2] == 0x04) return "SST25WF040";
      if (id[2] == 0x41) return "SST25VF016B";
      if (id[2] == 0x4A) return "SST25VF032";
    }
    if (id[1] == 0x25) {
      if (id[2] == 0x01) return "SST26VF016";
      if (id[2] == 0x02) return "SST26VF032";
      if (id[2] == 0x43) return "SST26VF064";
    }
  }
  return "(unknown chip)";
}

void InitializeSerialFlash(int CSPin)
{
  if ( FlashChipSelect == 16)
  {
    pinMode(15, INPUT_PULLUP);
    pinMode(16, INPUT);
  }
  else
  {
    pinMode(16, INPUT_PULLUP);
    pinMode(15, INPUT);
  }
  Serial.print("Initializing SerialFlash on CS number:");
  Serial.println(CSPin);
  Serial.println();
  if (!SerialFlash.begin(CSPin)) {
    while (1) {
      Serial.println("Unable to access SPI Flash chip");
      delay(1000);
    }
  }
}

void PrintChipInfo()
{
  SerialFlash.readID(id);
  Serial.print("  JEDEC ID:     ");
  Serial.print(id[0], HEX);
  Serial.print(" ");
  Serial.print(id[1], HEX);
  Serial.print(" ");
  Serial.println(id[2], HEX);
  Serial.print("  Part Nummber: ");
  Serial.println(id2chip(id));
  size = SerialFlash.capacity(id);
  Serial.print("Total Size:");
  Serial.println(size);
  Serial.println();

}

void FullErase()
{
  unsigned long startMillis = millis();
  Serial.print("Flash Memory has ");
  Serial.print(size);
  Serial.println(" bytes.");
  Serial.println("Erasing ALL Flash Memory:");
  // Estimate the (lengthy) wait time.
  Serial.print("  estimated wait: ");
  int seconds = (float)size / eraseBytesPerSecond(id) + 0.5;
  Serial.print(seconds);
  Serial.println(" seconds.");
  Serial.println("  Yes, full chip erase is SLOW!");
  SerialFlash.eraseAll();
  unsigned long dotMillis = millis();
  unsigned char dotcount = 0;
  while (SerialFlash.ready() == false) {
    if (millis() - dotMillis > 1000) {
      dotMillis = dotMillis + 1000;
      Serial.print(".");
      dotcount = dotcount + 1;
      if (dotcount >= 60) {
        Serial.println();
        dotcount = 0;
      }
    }
  }
  if (dotcount > 0) Serial.println();
  Serial.println("Erase completed");
  unsigned long elapsed = millis() - startMillis;
  Serial.print("  actual wait: ");
  Serial.print(elapsed / 1000ul);
  Serial.println(" seconds.");
  Serial.println();
}

void OpenEraseWrite( const char *fileName, char buffer[])
{
  SerialFlashFile file = SerialFlash.open(fileName);
  Serial.print("Open Result:");
  Serial.println(file);
  Serial.print("Erasing File:");
  Serial.println(fileName);
  file.erase();
  Serial.print("Writing:");
  Serial.println(buffer);
  file.write(buffer, 12);
  Serial.print("Reading:");
  file.seek(0);
  file.read(buffer, 12);
  Serial.println(buffer);
  Serial.println();
}

void DoFileTest()
{
  Serial.println("_________________________________");
  Serial.println();
  InitializeSerialFlash(FlashChipSelect);

  PrintChipInfo();

  if (eraseAllFirst) {
    FullErase();
  }

  String stringOne = "Example Data in Flash With CS Pin ";
  stringOne += FlashChipSelect;
  char buffer[stringOne.length() + 1];
  stringOne.toCharArray(buffer, stringOne.length() + 1);

  //SerialFlash.remove("test");

  if (SerialFlash.exists("test"))
  {
    Serial.println("File named test already exists");

    OpenEraseWrite("test", buffer);
  }
  else
  {
    Serial.println("test does not exist...creating");
    bool createResult = SerialFlash.createErasable("test", 60000);
    Serial.println("Result of create erasable file named test");
    Serial.println(createResult);
    OpenEraseWrite("test", buffer);
  }
  Serial.println("_________________________________");
  Serial.println();
  Serial.println();
}

void setup() {
  Serial.begin(9600);

  while (!Serial) ;
  delay(100);

  eraseAllFirst = true;

  FlashChipSelect = 16;

  DoFileTest();

  FlashChipSelect = 15;

  DoFileTest();

  eraseAllFirst = false;

  FlashChipSelect = 16;

  DoFileTest();

  FlashChipSelect = 15;

  DoFileTest();
}

void loop() {
  // do nothing after the test
}

Serial Output should be as follows:
_________________________________

Initializing SerialFlash on CS number:16

JEDEC ID: 1 2 20
Part Nummber: S25FL512S
Total Size:67108864

Flash Memory has 67108864 bytes.
Erasing ALL Flash Memory:
estimated wait: 134 seconds.
Yes, full chip erase is SLOW!
............................................................
...............................................
Erase completed
actual wait: 107 seconds.

test does not exist...creating
Result of create erasable file named test
1
Open Result:1
Erasing File:test
Writing:Example Data in Flash With CS Pin 16
Reading:Example Data in Flash With CS Pin 16

_________________________________


_________________________________

Initializing SerialFlash on CS number:15

JEDEC ID: 1 2 20
Part Nummber: S25FL512S
Total Size:67108864

Flash Memory has 67108864 bytes.
Erasing ALL Flash Memory:
estimated wait: 134 seconds.
Yes, full chip erase is SLOW!
............................................................
............................................................
.
Erase completed
actual wait: 121 seconds.

test does not exist...creating
Result of create erasable file named test
1
Open Result:1
Erasing File:test
Writing:Example Data in Flash With CS Pin 15
Reading:Example Data in Flash With CS Pin 15

_________________________________


_________________________________

Initializing SerialFlash on CS number:16

JEDEC ID: 1 2 20
Part Nummber: S25FL512S
Total Size:67108864

File named test already exists
Open Result:1
Erasing File:test
Writing:Example Data in Flash With CS Pin 16
Reading:Example Data in Flash With CS Pin 16

_________________________________


_________________________________

Initializing SerialFlash on CS number:15

JEDEC ID: 1 2 20
Part Nummber: S25FL512S
Total Size:67108864

File named test already exists
Open Result:1
Erasing File:test
Writing:Example Data in Flash With CS Pin 15
Reading:Example Data in Flash With CS Pin 15

_________________________________
 
Last edited:
How do you access the pins on your dual backpack ?

Have you thought of a screw shield

Might be an idea to sell on tindie
 
How do you access the pins on your dual backpack ?

Have you thought of a screw shield

Might be an idea to sell on tindie

The backpacks are meant to work with each other. So, on the dual backpack you could have an SBUS Backpack next to a GNSS Backpack, for example, and have the total stack height less than using the Solo Backpack.

The screw shield is a good idea, thanks!
 
@brtaylor

Hi Brian
Know this is old but went back to look at the pinouts for the backpacks and back plane. Was thinking about putting a T4 on it :) But unfortunately all the pages are gone and I never made a backup copy of them. Anyway you have them laying around that you can package up for me?

Besides the double pack plane I have the MPU9250 and GPS shield. One of the things interested in the volt regulator you use on the back plane?
 
@brtaylor

Hi Brian
Know this is old but went back to look at the pinouts for the backpacks and back plane. Was thinking about putting a T4 on it :) But unfortunately all the pages are gone and I never made a backup copy of them. Anyway you have them laying around that you can package up for me?

Besides the double pack plane I have the MPU9250 and GPS shield. One of the things interested in the volt regulator you use on the back plane?

Here is the Backpack pinout. I'd be curious to know if/what would need to be changed to work with Teensy 4.0. Please let me know if you need additional information.
teensy-backpack-pinout.png

There were two voltage regulators available, the TSR 1-2450 and the R-78E5.0-1.0. They share the same pinout and both supply 5V at 1A. The Traco regulator had a wider voltage range (6.5V - 36V) than the Recom (8V - 28V), but the Recom was lower cost. These both took voltage from screw terminals to a regulated 5V rail to power the Teensy. Each Backpack had an LDO to then take the 5V rail to supply 3.3V power to the sensors, as needed (most of them needed it). The LDO I used was the MCP1700T-3302E/TT - it's a little overkill for most of the sensors, but supplies enough current for the more power-hungry backpacks like the SD card and standardizing on one LDO across the product line let us drive costs down.
 
Here is the Backpack pinout. I'd be curious to know if/what would need to be changed to work with Teensy 4.0. Please let me know if you need additional information.
View attachment 20566

There were two voltage regulators available, the TSR 1-2450 and the R-78E5.0-1.0. They share the same pinout and both supply 5V at 1A. The Traco regulator had a wider voltage range (6.5V - 36V) than the Recom (8V - 28V), but the Recom was lower cost. These both took voltage from screw terminals to a regulated 5V rail to power the Teensy. Each Backpack had an LDO to then take the 5V rail to supply 3.3V power to the sensors, as needed (most of them needed it). The LDO I used was the MCP1700T-3302E/TT - it's a little overkill for most of the sensors, but supplies enough current for the more power-hungry backpacks like the SD card and standardizing on one LDO across the product line let us drive costs down.

Thanks Brian. Looks like from a cursory review at least the MPU-9250 is compatible. PWM for the T4 is only on pins 22/23, 20/21 are non-PWM pins. SCL/SDA are the same pins so that's good. CAN backpack will not work as CAN pins are on 0/1 not 3/4. 7/8 are Serial2 so that's still good. SPI is in the same place so as long as all the shields are 3.3v should work.

Oh, I have the Trac Power regulator (1A) so at least I can plug my batteries in :)
 
@brtaylor
Well just soldered up a new T4.0 and plugged it into the backplane and ran the MPU9250 Basic_i2c test sketch:
Code:
-0.301685	0.100562	-9.601238	0.000209	-0.000200	-0.002534	13.754556	19.972338	-42.936424	30.320993
-0.330417	0.081407	-9.620393	0.000875	-0.000599	-0.001735	15.926328	20.335470	-42.587349	30.317997
-0.301685	0.086196	-9.620393	-0.000723	-0.000599	-0.000537	15.564365	20.335470	-43.285503	30.309013
Looks like its working no problems. The accels behave as they should when I rotate the board so all is good in the world. Now have to find a GPS. Sorry but that's about all I can test with the boards I have. Makes me wish I bought a couple of the other boards when I had the chance.
 
Here is the Backpack pinout. I'd be curious to know if/what would need to be changed to work with Teensy 4.0. Please let me know if you need additional information.

There were two voltage regulators available, the TSR 1-2450 and the R-78E5.0-1.0. They share the same pinout and both supply 5V at 1A. The Traco regulator had a wider voltage range (6.5V - 36V) than the Recom (8V - 28V), but the Recom was lower cost. These both took voltage from screw terminals to a regulated 5V rail to power the Teensy. Each Backpack had an LDO to then take the 5V rail to supply 3.3V power to the sensors, as needed (most of them needed it). The LDO I used was the MCP1700T-3302E/TT - it's a little overkill for most of the sensors, but supplies enough current for the more power-hungry backpacks like the SD card and standardizing on one LDO across the product line let us drive costs down.

As MJS513 said, the CAN pins are in a different location (CRX2/CTX2 is 0/1, CRX1/CTX1 is 23/22).

Pins 7/8 are Serial2 in Teensy 4.x, while they are Serial3 in Teensy 3.x (i.e. you just have to change your code for GNSS, but those pins are in the same location).

Pins 9/10 are not connected to a serial UART (i.e. SBUS RX/TX)

Pins 21/20 are not PWM pins, but pins 0-15, 18-19, and 23-22 are.

The CTS3 (pin 14 for GNSS) is not a CTS pin in Teensy 4.x. Of the pins 0..23, only pin 19 is a CTS pin for Serial3 (pins 14/15 on Teensy 4.x). Unfortunately pin 19 is SCL0, so you have to either use I2C or use hardware flow control. The Teensy 4.0 has one other CTS pin (pin 35 for Serial5 which is pins 21/20) which is in the middle of the SD card pads under the Teensy (i.e. hard to use). The Teensy 4.1 has two other CTS pins, both hard to use (pin 43 in the SD card pins for Serial5, and pin 50 in the flexspi memory card pads for Serial8).

Just as a note, the Teensy 4.x does not have a special 'analog ground'. The pin between VIN and 3.3v is a normal ground pin on the Teensy.
 
Back
Top