Stop, blink and roll*

 On 2013-05-13 and filed under: timelapse attiny buspirate contest bb313 buspirate3

A little bit of the cat got out of the bag some time ago:

6 seconds of AVR flashing

You’re looking at ~24 hours of continuous AVR flashing compressed down into 6 seconds.

While I won’t be releasing the connecting PCB just yet (i’m still beating down a few issues and refining the BOM), I thought it would be good to supply the scripts I used to do the actual time lapse since it was non-obvious from a “oh dear, the contest entry is due in <48 hours isn’t it..” point of view.

Parts and Materials

  • Teensy3: Attached to the system doing the programming

  • SSD1306: OLED display showing how many times the AVR has been programmed

  • Bus Pirate 3: Acting as an AVR programmer

  • Avrrrinator Rev B: Bus Pirate to 2x AVR ISP adapter (this is the super secret “prototype” I mentioned in the YouTube post)

  • BB313 boards: Breakouts for easily attaching AVR ISP cables

  • ATtiny4313: tiny AVR for programming

  • ATtiny85: tiny AVR for programming

  • Assorted LEDs: Status indicators/Lighting

  • Logitech C920 Webcam: Takes all the pictures

Taking a picture

The small bash script invoking the gstreamer toolchain (without reading the documentation this is pretty much magic) took on the duty of taking a picture every minute. It then copied everything out via rsync to another machine with tons of spare space.

This is not properly done since my start time edged uncomfortably close to when I had to stop, edit and ship (24 hours later).

Note that this constantly writes over the same file. It stops the local disk from being clogged up by continuous snapshots. It also does not check and do anything reasonable if the rsync transfer fails.. like move the file aside/retry.

In my case, losing a few minutes worth of snapshots wasn’t a big deal for 24 hours compressed down to 6 seconds. I actually deleted quite a few frames before rendering out to video to eliminate periods of darkness (they show up as jarring sub-millisecond transitions to darkness).


while true; do
gst-launch -e v4l2src ! video/x-raw-yuv,format=\(fourcc\)YUY2,width=1920,height=1080,framerate=5/1 \
! ffmpegcolorspace ! pngenc snapshot=true ! filesink location="frame.png"

# Yup, this is talking to an actual rsyncd daemon on a NAS
RSYNC_PASSWORD="super_secret" rsync -avP frame.png rsync:[email protected]/frame-`date '+%s'`.png

sleep 60;

Video out

After all the frames were assembled, I manually went in and pruned a bunch that were completely dark due to the lights being off. Compressing the video down a bunch to 6 seconds took a bit of playing around, mostly with the framerate:

mencoder 'mf://*.png' -mf fps=145:type=png -ovc lavc -lavcopts vcodec=mpeg4:mbd=2:trell -oac copy -o ~/Desktop/output-yt.avi

At this point, the video quality kind of sucked, but I had to ship it.

Here is the completed video:

Code doing the programming

This is the script that refreshes the display you see. It calls avrdude to flash the AVRs and records the return code.

If it is zero, then the success counter for the AVR is incremented.

From there counts are then written to the serial port where the Teensy 3 can handle persisting the display and refreshing it with new results.

#!/usr/bin/env python
# requires pyserial (pip install pyserial)
import subprocess
import serial

counter_4313 = 0
counter_85 = 0

failures_4313 = 0
failures_85 = 0

ser_port = serial.Serial(port='/dev/tty.usbmodem12341', baudrate=9600)

while True:
        ret_4313 = subprocess.check_call(['avrdude', '-v', '-p', 'attiny4313', '-c', 'buspirate', '-P',
        '/dev/tty.usbserial-AE01J4Q7', '-U', 'flash:w:blinky313.hex', '-x', 'reset=aux'])
    except subprocess.CalledProcessError:
        ret_4313 = 1

    if ret_4313 == 0:
        print "ATtiny4313"
        counter_4313 += 1
        failures_4313 += 1

   # Report statistics to the LCD screen
    report = "313:%s\n\n85:%s" % (counter_4313, counter_85)
        ret_85 = subprocess.check_call(['avrdude', '-v', '-p', 'attiny85', '-c', 'buspirate', '-P',
        '/dev/tty.usbserial-AE01J4Q7', '-U', 'flash:w:blinky45.hex', '-x', 'reset=cs'])
    except subprocess.CalledProcessError:
        ret_85 = 1

    if ret_85 == 0:
        print "ATtiny85"
        counter_85 += 1
        failures_85 += 1

   # We do this twice to make it look more live
    report = "313:%s\n\n85:%s" % (counter_4313, counter_85)

On the Teensy 3, the data is received and pumped out to the display. Not the greatest code, but decent enough to run for 24 hours without much of a hiccup.

Note that there are several small issues when using the SSD1306 library with the Teensy 3. I just stomped out the relevant sections after chasing down errors from the compiler (which were unrelated to SPI operation, and mostly due to i2c support).

* Flash Counter!
* Teensy 3.0 attached to a 128x64 SPI-driven OLED display
* Vendor: Adafruit
* IF YOU GET COMPILE ERRORS (you likely will!)
* Stomp out the compile errors in Adafruit_SSD1306.cpp line by line
* and everything should be OK (most of them are i2c related).
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_DC 11      // All pin numbers correspond to
#define OLED_CS 10  // the 'gray' labels on the welcome to
#define OLED_CLK 14     // Teensy 3 card
#define OLED_MOSI 12    // SSD1306 labels this as: "Data"
#define OLED_RESET 9


void setup() {
  pinMode(13, OUTPUT);

  // Display setup


void loop() {

  // Persist the display until we have something to display
  if( Serial.available() > 0 ) {
  display.println("AVR Program Count");
  while ( Serial.available() > 0 ) {
    digitalWrite(13, HIGH);
    char c =;

    if (c == '\n') {
    } else {
    digitalWrite(13, LOW);


And of course, blink programs. The ATtiny4313 and ATtiny85 each had their own. They’re pretty generic, (the one for the 4313 is from the BB313 website).

cheers (and drink, if thats your thing)