Bit Wisdom

Although I’m not an advanced programmer, I gladly share a few simple optimization tricks and techniques that may be helpful for other beginners.

 

  • Use for loops and arrays when looping through GPIO pins

By storing pin numbers in an array, you can loop through any order of pins, according to their position in the array. This is especially useful when looping through non-consecutive pin numbers (like PWM pins on Arduino Uno).

 

  • Combine mirrored for loops

All ‘Knight Rider’ inspired sketches I’ve seen so far use separate for loops for the two directions of the running LEDs. Using a two-dimensional pin array lets you combine them into one single for loop:

The first index can now be used for toggling between the two directions, as shown in this example code snippet:

 

  • Don’t copy grid states (?)

Many visual simulations need to keep track of both the old and the new state of a pixel grid or LED matrix.  Applying the index toggle trick from the above example makes your code more elegant, and also appears more efficient than copying the content of the previous ‘new state’ array to the ‘old state’ array at the end of every simulation loop.

In this example, we declare a three-dimensional array to hold two states of a 32×64 grid. In addition, two grid-state indexes gi_new and gi_old are declared and initialized.

Now you can simply toggle the values of gi_old and gi_new at the end of the loop that calculates grid[gi_new][*][*] based on the values in grid[gi_old][*][*] .

Caveat: some of my Game of Life sketches actually became slower after I applied this method… Perhaps the compiler prefers the grid copy method after all.

 

  • Try not to waste precious bytes on storing one single bit

When you need to store ON/OFF states of many ‘elements’, like pixels on a monochrome display or LEDs on a matrix, you can reduce the required memory by a factor of 8 (!), just by storing the state of eight consecutive elements in one byte. So, instead of using an array like byte grid[64][128], you better use byte grid[64][16]. [Note that using a boolean array would have no effect, since each boolean also claims a full byte].

The small price for this enormous gain is that your sketch needs to translate a column index on the physical grid to its column byte index in the grid array, as well as its bit position within that byte. Thanks to bit math, this is very easy:

To calculate element (r,c)’s column byte BNR and position POS within that byte, use:

Once you’ve calculated an element’s BNR and POS, you can use the Arduino functions bitRead, bitSet, and bitClear for reading and writing binary values from or to element (r ,c) on the physical grid:

The same technique can be used for efficient storage of 2 or 4-bit variables.