open collector

Stop, Blink and Drink

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 “the contest entry is due in 72 hours!” perspective.

Parts list

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

BB313 boards: Breakouts for easily attaching AVR ISP cables

ATtiny4313: Bigger tiny AVR for programming

ATtiny85: Smaller tiny AVR for programming

Assorted LEDs: Status indicators/Lighting

Logitech C920 Webcam: Takes all the pictures

Taking a picture

This small bash script invoking the gstreamer chain 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.

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

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"

RSYNC_PASSWORD="super_secret" rsync -avP frame.png rsync://rsync@storage.somewhere/frame-`date '+%s'`.png

sleep 60;
done

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:

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

Code doing the programming

(Various scripts and pieces of code used to drive the operation.)

This is the script that refreshes the display. 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.

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

Update the Teensy3 display with avrdude results
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/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:
    try:
        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
    else:
        failures_4313 += 1

   # Report statistics to the LCD screen
    report = "313:%s\n\n85:%s" % (counter_4313, counter_85)
    ser_port.write(report)
    try:
        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
    else:
        failures_85 += 1

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

At 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).

Teensyduino + Teensy 3.0 + SSD1306 SPI OLED Display
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*********************************************************************
* 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

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Display setup
  display.begin(SSD1306_SWITCHCAPVCC);
  display.clearDisplay();
  display.setTextColor(WHITE,BLACK);

}

void loop() {

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

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

  delay(500);
  display.setTextSize(1);
  display.setCursor(0,0);
}

And of course, hexified blink programs. These are for the ATtiny4313 and ATtiny85 respectively. They’re fairly generic, but the one for the 4313 is from the BB313 website.

1
2
3
4
5
6
:020000020000FC
:1000000000C000270FBD03E00EBD002707BB08BBE3
:10001000BE9A00270DBD0CBDC69A0DB51CB50D339B
:10002000E1F7C69800270DBD0CBD0DB51CB50D330D
:0C003000E1F7C69A00270DBD0CBDEFCF14
:00000001FF
1
2
3
4
:020000020000FC
:1000000000C0B99A19E31EBD112714E71DBD0FE703
:0800100000BF112714E018BB2A
:00000001FF