Tiny Implementation of Conway’s Life…

I had a few minutes, so I thought I’d try making a graphics demo that runs on the tiny little 0.96″ OLED display I mentioned last week. One of the first programs I ever wrote was an implementation of Conway’s Game of Life, having learned about it from Martin Gardner’s Mathematical Games column in Scientific American. I remember that on my old Atari 400, it took a couple of seconds at least per generation, at a resolution of just 40×20 or so. Because of the limited memory (and small size of the display) I decided a 96×64 resolution. There is just enough memory to handle two full sized bit buffers. With a bit more work, I could make it work at the full resolution of the OLED display, but you need to do some of the updates in place, which makes it a bit harder.

//
// a tiny implementation of Conway's Life 
// written by Mark VandeWettering (brainwagon@gmail.com)
// https://brainwagon.org
//

#include "U8glib.h"

#define XSIZE           (128-32)
#define XSIZE_UINT8     (XSIZE/8)
#define YSIZE           (64)

uint8_t current[YSIZE][XSIZE_UINT8] ;
uint8_t next[YSIZE][XSIZE_UINT8] ;

#define MODX(x)         (((x)+XSIZE)%XSIZE)
#define MODY(y)         (((y)+YSIZE)%YSIZE)

#define ISSET(a, x, y) \
        (a[MODY(y)][MODX(x)/8] & (0x1<<(MODX(x)&7)))

#define SET(a, x, y) \
        a[MODY(y)][MODX(x)/8] |= (0x1<<(MODX(x)&7))

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); 

void
init()
{
    int i, j ;
    for (j=0; j<YSIZE; j++)
        for (i=0; i<XSIZE_UINT8; i++)
            current[j][i] = random(256) ;
}

void 
setup()
{
    randomSeed(analogRead(0));
    init() ;
}

void
draw()
{
    u8g.setDefaultBackgroundColor() ;
    u8g.drawBox(0, 0, 128, 64) ;
    u8g.setDefaultForegroundColor() ;
    u8g.drawXBM(16, 0, XSIZE, YSIZE, (const uint8_t *) next) ;
}

void
loop()
{
    int i, j ;

    memset((void *) next, 0, sizeof(next)) ;
    for (j=0; j<YSIZE; j++) {
        for (i=0; i<XSIZE; i++) {
            int sum = 0 ;
            if (ISSET(current, i-1, j-1)) sum ++ ;
            if (ISSET(current, i  , j-1)) sum ++ ;
            if (ISSET(current, i+1, j-1)) sum ++ ;
            if (ISSET(current, i-1, j  )) sum ++ ;
            if (ISSET(current, i+1, j  )) sum ++ ;
            if (ISSET(current, i-1, j+1)) sum ++ ;
            if (ISSET(current, i  , j+1)) sum ++ ;
            if (ISSET(current, i+1, j+1)) sum ++ ;

            if (ISSET(current, i, j)) {
                if (sum == 2 || sum == 3)
                    SET(next, i, j) ;
            } else {
                if (sum == 3)
                    SET(next, i, j) ;
            }
        }
    }
    
    memcpy((void *) current, (void *) next, sizeof(current)) ;

    u8g.firstPage() ;
    do {
        draw() ;
    } while (u8g.nextPage()) ;
}

It works! It initializes the display to random values, and then runs Life. If the display gets boring, just hit the result button….


Discovered a new tool for embedded development: platformio

I’m pretty old school when it comes to development. To me, writing code is something I like to do with vi (the editor that I learned three decades ago) and compile with Makefiles, especially for code that I do myself. In general, I prefer to do my development on either Linux or Mac OS too, so portable tools are my favorite. Increasingly, people have come to rely on complex development environments, many of which include code wizards that generate lots of the boiler plate needed to create applications, complex syntax coloring, and engines to refactor code. These environments are often significantly different from one another, are closed source, or rely on older versions of open source tools (like plugins for eclipse).

This seemed doubly true for this little Freescale development board that has been sitting unused since I purchased it at the last (or was it the one before that) Maker Faire. It is supposedly part of the “mbed” family of dev boards, which is supposed to make development across a variety of similar boards simple. But the reality is a dizzying array of odd products, including a web based IDE that just annoyed and confounded me. So, the board mostly sat unused. I did mention it in my “bucket o’ dev boards” video a couple weeks ago, and I thought “there must be a better way”.

Rather than toil away on my own, I tossed the question to my twitter followers:


Within minutes, @ukscone responded with this suggestion:


I had never heard of platformio, but I quickly read over the quickstart, and was impressed. Basically it’s a fairly simple utility called (appropriately enough) platformio, written in Python, and portable to Windows, Mac OS X and Linux. Compiled within it is knowledge of a large number of supported boards. You can get a list of supported boards by typing “platformio boards”, and you’ll get the output.

Platform: atmelavr
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
flora8                atmega32u4     8Mhz      28Kb    2Kb    Adafruit Flora
trinket3              attiny85       8Mhz      8Kb     512B   Adafruit Trinket 3V/8MHz
trinket5              attiny85       16Mhz     8Kb     512B   Adafruit Trinket 5V/16MHz
btatmega168           atmega168      16Mhz     14Kb    1Kb    Arduino BT ATmega168
btatmega328           atmega328p     16Mhz     28Kb    2Kb    Arduino BT ATmega328
diecimilaatmega168    atmega168      16Mhz     14Kb    1Kb    Arduino Duemilanove or Diecimila ATmega168
diecimilaatmega328    atmega328p     16Mhz     30Kb    2Kb    Arduino Duemilanove or Diecimila ATmega328
esplora               atmega32u4     16Mhz     28Kb    2Kb    Arduino Esplora
ethernet              atmega328p     16Mhz     31Kb    2Kb    Arduino Ethernet
fio                   atmega328p     8Mhz      30Kb    2Kb    Arduino Fio
leonardo              atmega32u4     16Mhz     28Kb    2Kb    Arduino Leonardo
megaADK               atmega2560     16Mhz     248Kb   8Kb    Arduino Mega ADK
megaatmega1280        atmega1280     16Mhz     124Kb   8Kb    Arduino Mega or Mega 2560 ATmega1280
megaatmega2560        atmega2560     16Mhz     248Kb   8Kb    Arduino Mega or Mega 2560 ATmega2560 (Mega 2560)
micro                 atmega32u4     16Mhz     28Kb    2Kb    Arduino Micro
miniatmega168         atmega168      16Mhz     14Kb    1Kb    Arduino Mini ATmega168
miniatmega328         atmega328p     16Mhz     28Kb    2Kb    Arduino Mini ATmega328
atmegangatmega168     atmega168      16Mhz     14Kb    1Kb    Arduino NG or older ATmega168
atmegangatmega8       atmega8        16Mhz     7Kb     1Kb    Arduino NG or older ATmega8
nanoatmega168         atmega168      16Mhz     14Kb    1Kb    Arduino Nano ATmega168
nanoatmega328         atmega328p     16Mhz     30Kb    2Kb    Arduino Nano ATmega328
pro8MHzatmega168      atmega168      8Mhz      14Kb    1Kb    Arduino Pro or Pro Mini ATmega168 (3.3V, 8 MHz)
pro16MHzatmega168     atmega168      16Mhz     14Kb    1Kb    Arduino Pro or Pro Mini ATmega168 (5V, 16 MHz)
pro8MHzatmega328      atmega328p     8Mhz      30Kb    2Kb    Arduino Pro or Pro Mini ATmega328 (3.3V, 8 MHz)
pro16MHzatmega328     atmega328p     16Mhz     30Kb    2Kb    Arduino Pro or Pro Mini ATmega328 (5V, 16 MHz)
robotControl          atmega32u4     16Mhz     28Kb    2Kb    Arduino Robot Control
robotMotor            atmega32u4     16Mhz     28Kb    2Kb    Arduino Robot Motor
uno                   atmega328p     16Mhz     31Kb    2Kb    Arduino Uno
yun                   atmega32u4     16Mhz     28Kb    2Kb    Arduino Yun
digispark-tiny        attiny85       16Mhz     5Kb     512B   Digispark (Default - 16 MHz)
digispark-pro32       attiny167      16Mhz     14Kb    512B   Digispark Pro (16 MHz) (32 byte buffer)
digispark-pro64       attiny167      16Mhz     14Kb    512B   Digispark Pro (16 MHz) (64 byte buffer)
digispark-pro         attiny167      16Mhz     14Kb    512B   Digispark Pro (Default 16 MHz)
engduinov1            atmega32u4     8Mhz      28Kb    2Kb    Engduino 1
engduinov2            atmega32u4     8Mhz      28Kb    2Kb    Engduino 2
engduinov3            atmega32u4     8Mhz      28Kb    2Kb    Engduino 3
lilypadatmega168      atmega168      8Mhz      14Kb    1Kb    LilyPad Arduino ATmega168
lilypadatmega328      atmega328p     8Mhz      30Kb    2Kb    LilyPad Arduino ATmega328
LilyPadUSB            atmega32u4     8Mhz      28Kb    2Kb    LilyPad Arduino USB
168pa16m              atmega168p     16Mhz     15Kb    1Kb    Microduino Core (Atmega168PA@16M,5V)
168pa8m               atmega168p     8Mhz      15Kb    1Kb    Microduino Core (Atmega168PA@8M,3.3V)
328p16m               atmega328p     16Mhz     31Kb    2Kb    Microduino Core (Atmega328P@16M,5V)
328p8m                atmega328p     8Mhz      31Kb    2Kb    Microduino Core (Atmega328P@8M,3.3V)
32u416m               atmega32u4     16Mhz     28Kb    2Kb    Microduino Core USB (ATmega32U4@16M,5V)
1284p16m              atmega1284p    16Mhz     127Kb   16Kb   Microduino Core+ (ATmega1284P@16M,5V)
1284p8m               atmega1284p    8Mhz      127Kb   16Kb   Microduino Core+ (ATmega1284P@8M,3.3V)
644pa16m              atmega644p     16Mhz     63Kb    4Kb    Microduino Core+ (Atmega644PA@16M,5V)
644pa8m               atmega644p     8Mhz      63Kb    4Kb    Microduino Core+ (Atmega644PA@8M,3.3V)
panStampAVR           atmega328p     8Mhz      31Kb    2Kb    PanStamp AVR
protrinket3ftdi       atmega328p     16Mhz     28Kb    2Kb    Pro Trinket 3V/12MHz (FTDI)
protrinket3           atmega328p     12Mhz     28Kb    2Kb    Pro Trinket 3V/12MHz (USB)
protrinket5ftdi       atmega328p     16Mhz     28Kb    2Kb    Pro Trinket 5V/16MHz (USB)
protrinket5           atmega328p     16Mhz     28Kb    2Kb    Pro Trinket 5V/16MHz (USB)
raspduino             atmega328p     16Mhz     30Kb    2Kb    Raspduino

Platform: atmelsam
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
due                   at91sam3x8e    84Mhz     512Kb   32Kb   Arduino Due (Programming Port)
dueUSB                at91sam3x8e    84Mhz     512Kb   32Kb   Arduino Due (USB Native Port)
digix                 at91sam3x8e    84Mhz     512Kb   28Kb   Digistump DigiX
sainSmartDue          at91sam3x8e    84Mhz     512Kb   32Kb   SainSmart Due (Programming Port)
sainSmartDueUSB       at91sam3x8e    84Mhz     512Kb   32Kb   SainSmart Due (USB Native Port)

Platform: freescalekinetis
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
IBMEthernetKit        mk64fn1m0vll12 120Mhz    1024Kb  256Kb  Ethernet IoT Starter Kit
frdm_k20d50m          mk20dx128vlh5  48Mhz     128Kb   16Kb   Freescale Kinetis FRDM-K20D50M
frdm_k22f             mk22fn512vlh12 120Mhz    512Kb   128Kb  Freescale Kinetis FRDM-K22F
frdm_k64f             mk64fn1m0vll12 120Mhz    1024Kb  256Kb  Freescale Kinetis FRDM-K64F
frdm_kl05z            mkl05z32vfm4   48Mhz     32Kb    4Kb    Freescale Kinetis FRDM-KL05Z
frdm_kl25z            mkl25z128vlk4  48Mhz     128Kb   16Kb   Freescale Kinetis FRDM-KL25Z
frdm_kl46z            mkl46z256vll4  48Mhz     256Kb   32Kb   Freescale Kinetis FRDM-KL46Z

Platform: nordicnrf51
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
wallBotBLE            nrf51822       16Mhz     128Kb   16Kb   JKSoft Wallbot BLE
nrf51_dk              nrf51822       32Mhz     256Kb   32Kb   Nordic nRF51-DK
nrf51_dongle          nrf51822       32Mhz     256Kb   32Kb   Nordic nRF51-Dongle
nrf51_mkit            nrf51822       16Mhz     128Kb   16Kb   Nordic nRF51822-mKIT
redBearLabBLENano     nrf51822       16Mhz     256Kb   16Kb   RedBearLab BLE Nano
redBearLab            nrf51822       16Mhz     256Kb   16Kb   RedBearLab nRF51822
seeedTinyBLE          nrf51822       16Mhz     256Kb   16Kb   Seeed Tiny BLE
hrm1017               nrf51822       16Mhz     256Kb   16Kb   Switch Science mbed HRM1017

Platform: nxplpc
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
blueboard_lpc11u24    lpc11u24       48Mhz     32Kb    8Kb    BlueBoard-LPC11U24
dipcortexm0           lpc11u24       50Mhz     32Kb    8Kb    DipCortex M0
lpc11u35              lpc11u35       48Mhz     64Kb    10Kb   EA LPC11U35 QuickStart Board
lpc4088_dm            lpc4088        120Mhz    512Kb   96Kb   EA LPC4088 Display Module
lpc4088               lpc4088        120Mhz    512Kb   96Kb   EA LPC4088 QuickStart Board
lpc1549               lpc1549        72Mhz     256Kb   36Kb   LPCXpresso1549
mbuino                lpc11u24       48Mhz     32Kb    8Kb    Outrageous Circuits mBuino
seeeduinoArchPro      lpc1768        96Mhz     512Kb   32Kb   Seeeduino-Arch-Pro
lpc11u35_501          lpc11u35       48Mhz     64Kb    10Kb   TG-LPC11U35-501
lpc1114fn28           lpc1114fn28    48Mhz     32Kb    4Kb    mbed LPC1114FN28
lpc11u24              lpc11u24       48Mhz     32Kb    8Kb    mbed LPC11U24
lpc1768               lpc1768        96Mhz     512Kb   32Kb   mbed LPC1768
ubloxc027             lpc1768        96Mhz     512Kb   32Kb   u-blox C027

Platform: ststm32
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
disco_f334c8          stm32f334c8t6  72Mhz     64Kb    16Kb   32F3348DISCOVERY
disco_f401vc          stm32f401vct6  84Mhz     256Kb   64Kb   32F401CDISCOVERY
disco_f429zi          stm32f429zit6  180Mhz    2048Kb  256Kb  32F429IDISCOVERY
nucleo_f030r8         stm32f030r8t6  48Mhz     64Kb    8Kb    ST Nucleo F030R8
nucleo_f070rb         stm32f070rbt6  48Mhz     128Kb   16Kb   ST Nucleo F070RB
nucleo_f072rb         stm32f072rbt6  48Mhz     128Kb   16Kb   ST Nucleo F072RB
nucleo_f091rc         stm32f091rct6  48Mhz     256Kb   32Kb   ST Nucleo F091RC
nucleo_f103rb         stm32f103rbt6  72Mhz     128Kb   20Kb   ST Nucleo F103RB
nucleo_f302r8         stm32f302r8t6  72Mhz     64Kb    16Kb   ST Nucleo F302R8
nucleo_f303re         stm32f303ret6  72Mhz     512Kb   64Kb   ST Nucleo F303RE
nucleo_f334r8         stm32f334r8t6  72Mhz     64Kb    16Kb   ST Nucleo F334R8
nucleo_f401re         stm32f401ret6  84Mhz     512Kb   96Kb   ST Nucleo F401RE
nucleo_f411re         stm32f411ret6  100Mhz    512Kb   128Kb  ST Nucleo F411RE
nucleo_l053r8         stm32l053r8t6  48Mhz     64Kb    8Kb    ST Nucleo L053R8
nucleo_l152re         stm32l152ret6  32Mhz     512Kb   80Kb   ST Nucleo L152RE
disco_f051r8          stm32f051r8t6  48Mhz     64Kb    8Kb    STM32F0DISCOVERY
disco_f303vc          stm32f303vct6  72Mhz     256Kb   48Kb   STM32F3DISCOVERY
disco_f407vg          stm32f407vgt6  168Mhz    1024Kb  128Kb  STM32F4DISCOVERY
disco_l152rb          stm32l152rbt6  32Mhz     128Kb   16Kb   STM32LDISCOVERY
disco_f100rb          stm32f100rbt6  24Mhz     128Kb   8Kb    STM32VLDISCOVERY

Platform: teensy
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
teensy20              atmega32u4     16Mhz     31Kb    2Kb    Teensy 2.0
teensy30              mk20dx128      48Mhz     128Kb   16Kb   Teensy 3.0
teensy31              mk20dx256      72Mhz     256Kb   64Kb   Teensy 3.1
teensy20pp            at90usb1286    16Mhz     127Kb   8Kb    Teensy++ 2.0

Platform: timsp430
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
lpmsp430fr5739        msp430fr5739   16Mhz     15Kb    1Kb    FraunchPad w/ msp430fr5739
lpmsp430f5529         msp430f5529    16Mhz     128Kb   1Kb    LaunchPad w/ msp430f5529 (16MHz)
lpmsp430f5529_25      msp430f5529    25Mhz     128Kb   1Kb    LaunchPad w/ msp430f5529 (25MHz)
lpmsp430fr5969        msp430fr5969   8Mhz      64Kb    1Kb    LaunchPad w/ msp430fr5969
lpmsp430g2231         msp430g2231    1Mhz      2Kb     128B   LaunchPad w/ msp430g2231 (1 MHz)
lpmsp430g2452         msp430g2452    16Mhz     8Kb     256B   LaunchPad w/ msp430g2452 (16MHz)
lpmsp430g2553         msp430g2553    16Mhz     16Kb    512B   LaunchPad w/ msp430g2553 (16MHz)
panStampNRG           cc430f5137     12Mhz     31Kb    4Kb    PanStamp NRG 1.1

Platform: titiva
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
lplm4f120h5qr         lplm4f120h5qr  80Mhz     256Kb   32Kb   LaunchPad (Stellaris) w/ lm4f120 (80MHz)
lptm4c1230c3pm        lptm4c1230c3pm 80Mhz     256Kb   32Kb   LaunchPad (Tiva C) w/ tm4c123 (80MHz)
lptm4c1294ncpdt       lptm4c1294ncpdt 120Mhz    1024Kb  256Kb  LaunchPad (Tiva C) w/ tm4c129 (120MHz)

That’s a LOT of different boards, including a large number of the ones I have. I was particularly interested in creating applications for the Freedom K64F board, which is supported. I typed “platformio install freescalekinetis”, and the script went out and found what version of tools it needed (gcc) and what support framework/libraries it needed, and installed them automatically (on Mac OSX/Linux, they end up hidden in the .platformio library in your home directory). You don’t need to go hunting around and find the right version, platformio takes care all of that (and can handle upgrades as new versions are created). In this way, platformio acts rather like a package manager such as apt-get on Linux.

To use platformio to build a new project, you create a directory, cd into it, and then run “platformio init –board=frdm_k64f”. This creates a src and lib directory, and a file called platformio.ini which describes which boards the project can support. It’s possible to create a single project which supports multiple boards (say, many different types of arduino) and build them all simultaneously, but in my case, I just used the one board. I then created this simple little program inside the src directory:

#include "mbed.h"

Serial pc(USBTX, USBRX);

Ticker timer;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);

int flip = 0 ;

int r=0, g=1, b=1 ;

void
attime()
{
    int t = led1 ;
    led1 = led2 ;
    led2 = led3 ;
    led3 = t ;
}

int
main()
{
        pc.printf("\nHello world.\n") ;
        led1 = r ;
        led2 = g ;
        led3 = b ;

        timer.attach(&attime, 1);
        
        for (;;) {

        }
        
        return 0 ;
}

This is a simple little program that prints “Hello world” back on the USB port, and then blinks the RGB LED in different colors. I didn’t really know much about the library support for these mbed based chips, but I’m old school. Snooping around in the .platformio directory, I found a bunch of header files that hinted at what is possible. I guessed on how this stuff worked, and coded the program up. You can then compile it with “platformio run”, or compile and upload it with “platformio run -t upload”. (There is a way to set it to automatically upload it if it compiles successfully too).

So, within one hour, I had this:


Awesome!

I’m looking forward to doing more experimentation with platformio, and now have it installed on both my Mac and Linux laptops. In addition to some of the odder platforms I have (like the FreeScale or STM32 boards) it also supports the Arduinos. I like the idea of being able to develop code for the Arduino without having to go through their IDE. I did a bit more experimentation with it last night, and got it to generate some display programs for the little OLED display that I wrote about earlier. Platformio also has a library manager which knows about a lot of the popular Arduino libraries, and can automatically download and update those. As I learn more, I’ll try to post more.

Thanks again to @ukscone! Best new thing I’ve discovered in weeks.