Teensy 3.1 to Arduino Mega data transfer - EasyTransfer

Status
Not open for further replies.

mjs513

Senior Member+
This is probably a rehash of an existing topic but I can not seem to find an answer. I am trying to get a 3.x and Arduino mega talking to each other using EasyTransfer. I am working with the simple blink example from the library but it does not seem to work. The connections are relatively simple and I have checked them several times (yes I attached ground to ground. I loaded the receive example on to the teensy using Serial3 and the transmit example onto the mega using serial1. I have also tried the same with a Arduino101 board as well. No luck in getting them to work. Anyone have any experience with this? Any help would be appreciated.

Thanks in advance
Mike
 
Three things come to mind:

  • The Teensy 3.x (and Arduino 101) run at 3.3v and the Mega typically runs at 5v. While the Teensy 3.1/3.2/3.5 are 5v tolerant on digital input pins, the Mega likely won't see the signal if the Teensy only writes 3.3v and the Mega is expecting something closer to 5v. You probably should think about using voltage level shifters to convert the Teensy RX and TX pins from 3.3v to 5v. Note, if you use the Teensy 3.0, Teensy LC, or the Teensy 3.6 without level shifting, you will likely fry your Teensy and release the magic smoke.
  • The code uses Serial. On the Teensy, Serial is only the USB (on the Arduino Uno, the USB port connection monitors the hardware serial line, so if you write to Serial it writes to both the USB monitor and the hardware UART). On the Teensy, you would want to use Serial1 to use the first serial port (on pins 0/1). I've never used a Mega, so I don't know if you need to use either Serial, Serial0, or Serial1.
  • Remember you need to swap RX/TX. The RX line on the Teensy should hook up to the TX line on the Mega, and vice versa.
 
EasyTransfer requires the same data structure definition on both sides. When going between 8 and 32 bit boards, two issues tend to come up.

The size of "int" is 16 bits on AVR and 32 bits on Teensy 3.1 and Arduino 101. Don't use it. Use types like "int16_t" or "uint32_t" which specify exactly the size of your variables.

On 32 bit boards, when you create a struct with different size items, the compiler sometimes adds small dead spots to align the 16 and 32 bit items to 2 and 4 byte boundaries in memory. There's a special packed attribute you can use which forces all items together as they would be on AVR.

Of course, there are all sorts of other things that could be wrong, both software and hardware. When asking for help on forums, think "reproducible" and imagine you might be describing the correct way but actually doing it not quite right due to some small detail or misunderstanding. Showing what you've actually done (code & photos) is usually more effective than merely describing.
 
Last edited:
@PaulStoffregen - Forgot about different sizes and the reason I want to use the Teensy was to get the greater accuracy for gps readings, i.e., float as a 32bit vs 16bit on the mega. Just not thinking. You are also correct I should attach both sketches and the hookups.

@MichaelMeisner - After fixing the size of the ints to be consistent I hooked up a level shifter and still did not work. At this point I decided to connect up two megas to see if it would work with the same board (put back the struct to just ints). Too my surprise it didn't work with the same board types. The hook up is
transmit to receive
Tx1 to Rx2
Rx1 to Tx2
gnd to gnd
power is coming from the usb ports which is serial on both since they are both megas.

Not sure where the problem lies. The led to blink is the default for the board LED which is 13. Either way if I can get the com going between the two megas yours and Pauls comments still apply which I would have missed anyway.

Thanks
Mike
 
@MichaelMeisner - @PaulStoffregen. Just as to close the issue user error on my part - made an erroneous assumption. Tested with 3.x as transmitter or receiver with the mega and it works without the level shifter. No blue smoke and nothing heating up on the board so not sure if really need the level shifter. It works as long as I use consistent size of ints as Paul stated.

I want to use the Teensy to read the GPS data and process it through the TinyGPS++ lib where I am planning on changing all the floats to doubles. Double on the AVR is the same as float based on the Arduino web page for double. Mikhal also has a TinyGPS-13 but it is not as complete as the tinygps++ lib. Going to try and update it to also use GNXXX messages as well as custom messages. Eventually I want the 3.5 or 3.6 process data from the xv-11 lidar for mapping and obstacle avoidance/path finding - great dreams.

thanks for the help
Mike
 
EasyTransfer Variable Structure

Hi all

First, if Paul is reading thins congratulations on getting the rewards out. Can't wait. You and your team need a vacation. :D PS. Came across a post on microPython that someone is looking at porting it over.

I finally got around getting back to this particular project and am running into another problem. Probably again related to sizeof but not sure. Int16 work fine to transfer data from the GPS back to the mega, but as soon as I throw a long or a float into the mix the data is either not transmitted or read. I tried the packed attribute in the structure as follows:

Code:
struct __attribute__((__packed__)) 
 {
  long latitude;
  long longitude;
  int16_t SVS;  
  int16_t HDOP;
  int16_t PDOP;
  int16_t SOG;
  int16_t COG;
  //String time_stamp;
} gpsdata;

Get nothing if I don't use the packed attribute. Both structures are the same. By the way same thing happens when I throw String into the mix.

Any help would be appreciated.

Mike
 
Structure packing rules are probably different between the two systems. Also, while long is 4 bytes on both AVR and 32-bit ARM, you aren't guaranteed that i will be 4 bytes on other systems. For example, on 64-bit arm systems (and 64-bit x86_64 and powerpc), long is 8 bytes.
 
You and your team need a vacation. :D

Yes, we do!

In fact, we're closing PJRC on Friday for a 3-day weekend.

I'm traveling to New York for Maker Faire. Before I leave, I'm struggling to catch up to the most urgent things that were neglected while shipping so many Kickstarter rewards.

Please understand I probably won't get many questions answered until the middle of next week.
 
The alignment rules are different.
Code:
struct {
  long latitude;
  long longitude;
  int16_t SVS;  
  int16_t HDOP;
  int16_t PDOP;
  int16_t SOG;
  int16_t COG;
  //String time_stamp;
} gpsdata;
This has an alignment of 1 / sizeof 18 on AVR vs alignment 4 / sizeof 20 on ARM. With "__attribute__((__packed__)) ", both are 1 / 18.
 
@MichaelMeisner - I was concerned about the size of longs and floats on the two systems so I did a print of sizeof(long)*8 on the mega and the teensy and they were both the same size as well as the float. 32-bits each.

@tni - thanks for the info on alignment and "__attribute__((__packed__)) ", never tried this before. Learning all the time. I did try it with and without the packed attribute so I am not sure why it does not work. Will have to try experimenting.

If I get it solved I will post back, just so its documented. Guess I am going to my first MakerFaire this weekend (never realized it was so close until Paul mentioned it) especially since I live fairly close by. Haven't been over there is about 30 years.

Thanks all for the help
 
A little trick to print sizeof / alignof values at compile time:
Code:
struct {
  long latitude;
  long longitude;
} gpsdata;

struct __attribute__((__packed__)) {
  long latitude;
  long longitude;
} gpsdata_packed;


template<size_t ... T> struct print_ct {
    print_ct() { static_assert(sizeof...(T)==-1,""); }
};

print_ct< sizeof(gpsdata), alignof(gpsdata), 
          sizeof(gpsdata_packed), alignof(gpsdata_packed) > v;

You get a compiler error:
test_sizeof.ino: In instantiation of 'print_ct<T>:: print_ct() [with unsigned int ...T = {8u, 4u, 8u, 1u}]':
...

which has the sizeof / alignof values.
 
Thanks TNI for the sketch it will definitely come in handy. Just did a test on sending just one long from the Teensy to the Mega with the packed structures (on both sides) and nothing came across. Repeated with just int16's for 4 of the other variables and it worked fine. I am beginning to think there is a probable with EasyTransfer for this application. Spending too much time in getting easy transfer to work - think I will try a different approach.

Thanks again for your help.
Mike
 
Is it a bad idea or bad practice to use the packed attribute?
I found out that i can use int8 in my struct when sending data over RFM69 from a Arduino Pro Mini to the Teensy-LC.
Without the packed attribute only 16 and 32 bits work.

At the Arduino forum somebody wrote:
Also, get rid of the "packed" attribute in the structure definition. It may provide unpredictable results when TX and RX units are different processor architectures.

By the way: Do you say "at" or "in" the forum?
 
Last edited:
Is it a bad idea or bad practice to use the packed attribute?

In general, writing out structures in binary on one microprocessor and reading them back on a different microprocessor is fraught with errors because different systems have different rules for the size of basic types, alignment within a structure, etc. The best way is to have a write function that emits the structure field by field, explicitly writing out single bytes, 16/32-bit integers. You would then have a read function that re-packs the structure. Note, that double has a different size/representation on Arm systems compared to AVR systems used in classic Arduinos. In addition int and long are different sizes.

When you use the packed attribute to eliminate the alignment holes, it causes the code to refer to items in the structure to become much more involved and convoluted than using native alignment rules. For example on some systems, if you have a packed 4 byte integer, the compiler may do 4 load bytes, 4 store bytes to the stack, and a single load integer instruction. Or it may do 4 load bytes, and do various logical operations to get the value into a register. And at times, because it isn't use much, it can be a source of bugs within the compiler..
 
Sounds complicated and i guess then its easier to use int16 and send 2 bytes more even if it means draining the battery a bit faster.
 
A lot of times it depends on your code and layout of a structure...

As Michael mentioned, it gets more complicated when you send data between two different types of processors. For example a 16 bit value takes up two bytes. On some processors it will be in memory as <LSB><MSB> and on others it will be <MSB><LSB> So general purpose code needs to understand this and the protocol needs to be set one way or the other and the code setup to read or write in the correct order...

Now as for packing, again it depends on processors, but some (many) processors demand that to access a 32 bit value it must be on a 4 byte boundary... Some I believe handle it, but take longer and others just raise an exception....

So when possible it is best to setup your structures with the largest sized values first, followed by the next sized ones... For example if you had a structure like:
Code:
struct {
   uint8_t  var1;
   uint16_t var2;
   uint16_t var3;
   uint8_t var4;
   uint32_t var5;
}
with PACK(1), this would take 10 bytes? Without packing, probably would take maybe (2+2+2+2+4) = 12 bytes? My first guess was 14, but it dpends as you have to figure how the alignment is for each member and how much padding it takes to get to the natural alignment...
But if you rearranged this, like:
Code:
struct {
   uint32_t var5;
   uint16_t var2;
   uint16_t var3;
   uint8_t  var1;
   uint8_t var4;
}
Then it does not matter if you pack or not pack it...

So if you are sending from a Pro mini to Teensy and you only need 8bits of data, I would assume 8 bit would work fine...

Edit: Not sure about RFM69 or how you are sending the data. But with may playing around with RFM95, I believe I am sending stuff using packets. Not sure how much time difference there is of sending lets say 2 data bytes in a packet versus 10... Let alone 1 vs 2.
 
Last edited:
Rearranging and putting the large values first really works:
Code:
typedef struct {
  uint16_t vcc;       // Battery voltage
  int16_t temp;       // Temperature reading
  uint8_t nodeId;     // Store this nodeId
  uint8_t tx;         // Transmit level
} Payload;
Payload theData;
Payload size is 6 bytes.

Can't believe nowhere else somebody mentioning that.
 
Last edited:
Hi,

Bringing this thread back to life as I had the exact same problem using EasyTransfer to send data from a Teensy3.1 to an Arduino Mega. I did some experiments using the EasyTransfer library examples for Transmit and Receive. The actual code I used was slightly modified, as below:

Receive Code:

PHP:
#include <EasyTransfer.h>

//create object
EasyTransfer ET; 

struct RECEIVE_DATA_STRUCTURE{
  //put your variable definitions here for the data you want to receive
  //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
	int16_t blinks;
	int16_t pause;
};

//give a name to the group of data
RECEIVE_DATA_STRUCTURE mydata;

void setup(){
  Serial1.begin(9600);
  //start the library, pass in the data details and the name of the serial port. Can be Serial, Serial1, Serial2, etc. 
  ET.begin(details(mydata), &Serial1);
  
  pinMode(13, OUTPUT);
  
}

void loop(){
  //check and see if a data packet has come in. 
  if(ET.receiveData()){
    //this is how you access the variables. [name of the group].[variable name]
    //since we have data, we will blink it out. 
    for(int i = mydata.blinks; i>0; i--){
      digitalWrite(13, HIGH);
      delay(mydata.pause * 100);
      digitalWrite(13, LOW);
      delay(mydata.pause * 100);
    }
  }
  
  //you should make this delay shorter then your transmit delay or else messages could be lost
  delay(250);
}

Transmit Code:
PHP:
#include <EasyTransfer.h>

//create object
EasyTransfer ET; 

struct SEND_DATA_STRUCTURE{
  //put your variable definitions here for the data you want to send
  //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
  int16_t blinks;
  int16_t pause;
};

//give a name to the group of data
SEND_DATA_STRUCTURE mydata;

void setup(){
  Serial1.begin(9600);
  //start the library, pass in the data details and the name of the serial port. Can be Serial, Serial1, Serial2, etc.
  ET.begin(details(mydata), &Serial1);
  
  pinMode(13, OUTPUT);
  
  randomSeed(analogRead(0));
  
}

void loop(){
for(int i = 1; i < 6; i++){
	mydata.blinks = i;
	mydata.pause = random(5);
	ET.sendData();  
}
 
  //Just for fun, we will blink it out too
   for(int i = mydata.blinks; i>0; i--){
      digitalWrite(13, HIGH);
      delay(mydata.pause * 100);
      digitalWrite(13, LOW);
      delay(mydata.pause * 100);
    }
  
  delay(5000);
}

These worked fine and little LED's blinked away nicely. Then I added my 'real' struct data to the example structs to give the following:

Revised struct - same format in transmit and receive:


PHP:
struct SEND_DATA_STRUCTURE{
  //put your variable definitions here for the data you want to send
  //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
	float	domeAzimuth;
	int32_t	domeMotorSteps;	
	int32_t	domeTickCount;			
	uint16_t safetyMessage;	
	uint16_t statusMessage;	
	uint16_t settingMessage;	   
	int16_t blinks;
	int16_t pause;
};

//give a name to the group of data
SEND_DATA_STRUCTURE mydata;

No blinking lights - nada, nothing, nowt...........................

Next step was to eliminate the 32 bit values leaving only 16 bit ints and uints. This worked.
Finally I added the packed attribute to my struct definition and IT WORKED!!


Final, working struct definition:

PHP:
struct __attribute__((__packed__)) RECEIVE_DATA_STRUCTURE {
  //put your variable definitions here for the data you want to receive
  //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
	float	domeAzimuth;
	int32_t	domeMotorSteps;	
	int32_t	domeTickCount;			
	uint16_t safetyMessage;	
	uint16_t statusMessage;	
	uint16_t settingMessage;	  
	int16_t blinks;
	int16_t pause;
};

//give a name to the group of data
RECEIVE_DATA_STRUCTURE mydata;

I freely admit to not having a clue about any of this. I have just followed the advice in this thread and I am really grateful it has worked for me. My post is just to - I hope- help anyone else who struggles with EasyTransfer between different architectures.

Regards, Hugh
 
Status
Not open for further replies.
Back
Top