Packing Data Into Byte Arrays

Embedded applications require special care when it comes to memory usage and allocations. Granted, Arduinos pack enough RAM to generally not be a cause of worry, but what about sending and receiving data between Arduinos?

I'm working on a transponder application that transmits many different sensor readings to a remote Arduino using CC1101 transceivers. These have a maximum packet size of 64 bytes, and though it is possible to send more data over multiple packets, the ideal solution is to pack all the readings into a single packet.


The naive approach

One solution is to use String objects, as this allows simple debugging and intuitive handling of the data being transferred. A naive approach might look something like:

void sendResponse() {
    String ack = "ack ";
    ack += lastVibration;   // Some of these are ints
    ack += ' ';
    ack += readVcc();
    ack += ' ';
    ack += lastRssi;
    ack += ' ';
    ack += lastRoll;        // Most are floats
    ack += ' ';
    ack += lastPitch;
    ack += ' ';
    ack += lastHeading;
    ack += ' ';
    ack += lastTemp;
    ack += ' ';
    ack += lastAltitude;
    ack += ' ';
    ack += lastGyroX;
    ack += ' ';
    ack += lastGyroY;
    ack += ' ';
    ack += lastGyroZ;

    // then send ack

However, this is not only going to create messages that are larger than 64 bytes, it has the potential to wreak havoc on your Arduino by doing a boatload of dynamic allocations as Strings are created and destroyed.


A Better Solution

Since all scalar types in C are simply multiples of byte, we can convert the various data into a byte array. A char is one byte, an int is two bytes, a long is four, a float is four, and so on.

Packing integers is fairly straightforward. Arduino even ships with some helpers to do the lifting for you.

I've used char in place of byte  in the examples, but they are effectually the same.

int someInt = 10023;

// Pack "someInt" into a byte array.
char bytes[2];
bytes[0] = highByte(someInt);
bytes[1] = lowByte(someInt);

// Unpack "bytes" into an int.
int unpackedInt = word(bytes[0], bytes[1]);

// someInt == unpackedInt

This hides away the bitwise operations necessary to make this work, but all we're doing is separating the two bytes that make up an int.

Packing other types might seem daunting, but C has a powerful type called union that makes this a breeze. An in-depth explanation of unions is outside the scope of this post, but essentially, a union is a structure with multiple data types that reference the same location in memory.

float someFloat = 123.45;

typedef union {
    float f;         // Assigning fVal.f will also populate fVal.bytes;
    char bytes[4];   // Both fVal.f and fVal.bytes share the same 4 bytes of memory.
} fVal;

char packed[12];   // Some arbitrary message, note the size.
fVal packedFloat;

packedFloat.f = someFloat;
packed[6] = packedFloat.bytes[0];   // We can put these bytes anywhere in our byte array.
packed[7] = packedFloat.bytes[1];
packed[8] = packedFloat.bytes[2];
packed[9] = packedFloat.bytes[3];

fVal unpackedFloat;
unpackedFloat.bytes[0] = packed[6]; // Reference the same indexes we wrote to.
unpackedFloat.bytes[1] = packed[7];
unpackedFloat.bytes[2] = packed[8];
unpackedFloat.bytes[3] = packed[9];

float unpacked = unpackedFloat.f;

Isn't that neat?



No comments yet! Say something.



SeeedStudio 2.8" TFT Screen with Adafruit's ILI9341 library

There are a ton of very useful shields on the market for Arduinos, but the hardware is just one piece of the puzzle. For example, RadioShack sells SeeedStudio shields, which are pretty well made, but their software libraries have been a little bit rough.

A long while back, I purchased a 2.8" TFT Touch Shield which has laid dormant until I started working on a transponder application for my model rocketry projects. I started out using SeeedStudio's TFT library but it was very slow and not very featureful. For example, sending many draw commands would cause a lot of flickering. You could not change the orientation, either, which is supported by the ILI9341 driver, but not SeeedStudio's library.

After a little bit of searching, I found that Adafruit sells a very similar shield. The key being that the LCD driver chip, the ILI9341, was the same as the SeeedStudio shield. Best of all, Adafruit's driver uses the Adafruit GFX library which is a very nice, and fast, drawing library, with support for many different fonts.


Using the Library

The only real difference between the SeeedStudio shield and Adafruit's is the pin mapping. SeeedStudio has chosen pin 5 as the TFT select pin, and pin 6 as the TFT data/command pin. This means only a tiny change is necessary, as shown in the example below:

#define TFT_DC 6
#define TFT_CS 5

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

This is pretty great news if you want additional font rendering capabilities, the ability to change orientation, or just overall better performance. Give it a try!



No comments yet! Say something.



A Nice, Material Face-lift

Today, I've deployed new versions of the Nice website and documentation, both which make use of the new-hotness: material design.

I really enjoy the larger font and added spacing, and I hope the face-lift will help entice any would-be users into trying out Nice for the first time.

Don't take my word for it, check out the new website!