Electronic Design

Variable Overlaying Simplifies Firmware Design

In many instances of microcontroller firmware design, it's necessary, or desirable, to take four individual bytes and access them as if they were a single 32-bit variable, maybe as a pair of 16-bit variables, or even some other combination. One way to merge the four bytes into a single 32-bit variable would require reading the least-significant byte into the 32-bit location, then shift-left by "8," then OR in the next byte, then shift-left by "8,"...etc.—until the 32-bit variable contains all four bytes.

While this certainly works, it takes a considerable amount of instructions and CPU overhead. However, another approach can be used to create a "zero-code-overhead" technique. This technique involves "fooling" the compiler to cause it to overlay the variables on top of each other.

The following example shows specifically how to do this on one certain microcontroller. These instructions may vary for your particular microcontroller, but the concept remains the same. First, using the #pragma statement, create some variables like this:

#pragma abs_address:0x00
unsigned long LongVariable;
#pragma end_abs_address

#pragma abs_address:0x00
unsigned char FourByteArray\[4\];
#pragma end_abs_address

#pragma abs_address:0x00
unsigned char Byte0;
#pragma end_abs_address

#pragma abs_address:0x01
unsigned char Byte1;
#pragma end_abs_address

#pragma abs_address:0x02
unsigned char Byte2;
#pragma end_abs_address

#pragma abs_address:0x03
unsigned char Byte3;
#pragma end_abs_address

On this particular microcontroller, the #pragma statements above force the variables into specific locations in RAM. Notice that the #pragma statements seem to conflict because the addresses appear to overlap. The fact that they do overlap is the basis of this technique.

In your firmware, you can now access individual bytes of a 32-bit variable by using the "Byte0," "Byte1,"...etc., references. Likewise, you can load up a 32-bit variable with individual bytes simply by writing each Byte0, Byte1, ...etc., variable.

By using the #pragma for the FourByteArray, you can also reference the bytes of the 32-bit variable as if they were members of an array. In addition, you can create a relative pragma instead of an absolute one, or declare the variable as a record comprising four bytes. But this latter technique potentially changes how code will be compiled (endian issues) and potentially confuses the self-documentation properties of the code. Here's an example:

(1) Declare the #pragmas as shown above.

(2) Create an unsigned char variable "peek"

(3) Next in your firmware, add:

LongVariable = 0x12345678; // put a breakpoint on this line!
peek = Byte0;
peek = Byte1;
peek = Byte2;
peek = Byte3;
peek = FourByteArray\[1\];
Byte0 = 0xDE;
Byte3 = 0xEF;
FourByteArray\[1\] = 0xAD;
FourByteArray\[2\] = 0xBE;

(4) Put a breakpoint at the first line, then single-step the firmware in the debugger.

(5) Monitor "peek" in the watch window, and watch memory locations "0..3" in the memory watch window as you single-step. You will see the individual bytes of the variables being manipulated as other variables are referenced.

Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.