High Voltage Programmer

I’ve been experimenting with using non-standard pins on an ATtiny85. Using XTAL1 and XTAL2 is simple if you run off the internal oscillator at 8MHz/3.3v but I want to also use the RESET pin as D5/A0.

When you re-purpose the RESET pin, you lose the ability to program using an ISP, so we have to use a high voltage serial programmer (HVSP) which basically applies 12v to the RESET pin to set the fuses.

I redesigned the stripboard from here for use with perfboard and used a 2N2222 transistor as I have plenty of them, as well as a DC barrel jack for the 12v supply.

The hv_rescue.ino sketch which you load onto an Uno is as follows, I modified it slightly to compile nicely without needing the IDE:

// AVR High-voltage Serial Programmer
// Originally created by Paul Willoughby 03/20/2010
// http://www.rickety.us/2010/03/arduino-avr-high-voltage-serial-programmer/
// Inspired by Jeff Keyzer http://mightyohm.com
// Serial Programming routines from ATtiny25/45/85 datasheet

// Desired fuse configuration
#define  HFUSE  0xDF   // Defaults for ATtiny25/45/85
#define  LFUSE  0x62

//#define  HFUSE  0x5F   // reset as gpio5
//#define  LFUSE  0xE2   // 8mhz internal oscillator

// For Attiny13 use
// #define HFUSE 0xFF
// #define LFUSE 0x6A  

#define  RST     13    // Output to level shifter for !RESET from transistor to Pin 1
#define  CLKOUT  12    // Connect to Serial Clock Input (SCI) Pin 2
#define  DATAIN  11    // Connect to Serial Data Output (SDO) Pin 7
#define  INSTOUT 10    // Connect to Serial Instruction Input (SII) Pin 6
#define  DATAOUT  9    // Connect to Serial Data Input (SDI) Pin 5 
#define  VCC      8    // Connect to VCC Pin 8

int inByte = 0;         // incoming serial byte Computer
int inData = 0;         // incoming serial byte AVR

void establishContact() {
  while (Serial.available() <= 0) {
    Serial.println("Enter a character to continue");   // send an initial string
    delay(1000);
  }
}

int shiftOut2(uint8_t dataPin, uint8_t dataPin1, uint8_t clockPin, uint8_t bitOrder, byte val, byte val1)
{
	int i;
        int inBits = 0;
        //Wait until DATAIN goes high
        while (!digitalRead(DATAIN));
        
        //Start bit
        digitalWrite(DATAOUT, LOW);
        digitalWrite(INSTOUT, LOW);
        digitalWrite(clockPin, HIGH);
  	digitalWrite(clockPin, LOW);
        
	for (i = 0; i < 8; i++)  {
                
		if (bitOrder == LSBFIRST) {
			digitalWrite(dataPin, !!(val & (1 << i)));
                        digitalWrite(dataPin1, !!(val1 & (1 << i)));
                }
		else {
			digitalWrite(dataPin, !!(val & (1 << (7 - i))));
                        digitalWrite(dataPin1, !!(val1 & (1 << (7 - i))));
                }
                inBits <<=1;
                inBits |= digitalRead(DATAIN);
                digitalWrite(clockPin, HIGH);
		digitalWrite(clockPin, LOW);
                
	}

        
        //End bits
        digitalWrite(DATAOUT, LOW);
        digitalWrite(INSTOUT, LOW);
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
        
        return inBits;
}

void readFuses(){
     //Read lfuse
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x04, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x68);
    inData = shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x6C);
    Serial.print("lfuse reads as ");
    Serial.println(inData, HEX);
    
    //Read hfuse
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x04, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x7A);
    inData = shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x7E);
    Serial.print("hfuse reads as ");
    Serial.println(inData, HEX);
    
    //Read efuse
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x04, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x6A);
    inData = shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x6E);
    Serial.print("efuse reads as ");
    Serial.println(inData, HEX);
    Serial.println(); 
}

void setup()
{
  // Set up control lines for HV parallel programming
  pinMode(VCC, OUTPUT);
  pinMode(RST, OUTPUT);
  pinMode(DATAOUT, OUTPUT);
  pinMode(INSTOUT, OUTPUT);
  pinMode(CLKOUT, OUTPUT);
  pinMode(DATAIN, OUTPUT);  // configured as input when in programming mode
  
  // Initialize output pins as needed
  digitalWrite(RST, HIGH);  // Level shifter is inverting, this shuts off 12V
  
  // start serial port at 9600 bps:
  Serial.begin(9600);
  
  establishContact();  // send a byte to establish contact until receiver responds 
  
}

void loop()
{
  // if we get a valid byte, run:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    Serial.println(byte(inByte));
    Serial.println("Entering programming Mode\n");

    // Initialize pins to enter programming mode
    pinMode(DATAIN, OUTPUT);  //Temporary
    digitalWrite(DATAOUT, LOW);
    digitalWrite(INSTOUT, LOW);
    digitalWrite(DATAIN, LOW);
    digitalWrite(RST, HIGH);  // Level shifter is inverting, this shuts off 12V
    
    // Enter High-voltage Serial programming mode
    digitalWrite(VCC, HIGH);  // Apply VCC to start programming process
    delayMicroseconds(20);
    digitalWrite(RST, LOW);   //Turn on 12v
    delayMicroseconds(10);
    pinMode(DATAIN, INPUT);   //Release DATAIN
    delayMicroseconds(300);
    
    //Programming mode
    
    readFuses();
    
    //Write hfuse
    Serial.println("Writing hfuse");
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x40, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, HFUSE, 0x2C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x74);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x7C);
    
    //Write lfuse
    Serial.println("Writing lfuse\n");
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x40, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, LFUSE, 0x2C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x64);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x6C);

    readFuses();    
    
    Serial.println("Exiting programming Mode\n");
    digitalWrite(CLKOUT, LOW);
    digitalWrite(VCC, LOW);
    digitalWrite(RST, HIGH);   //Turn off 12v
  }
}

I then uploaded the following sketch to the ATtiny85 using make ispload, as you can see its using D5 to blink an LED:

const int led = 5;

void setup()
{
    pinMode(led, OUTPUT);
}

void loop()
{
    digitalWrite(led, HIGH);
    delay(1000);
    digitalWrite(led, LOW);
    delay(1000);
}

The Makefile is as follows, I used the latest IDE and the ATTinyCore as it supports more chips and I wanted to experiment with something other than the usual arduino-tiny or attiny-master with IDE 1.0.5:

ARDUINO_DIR = $(HOME)/arduino-1.8.5

ISP_PROG       = usbasp
AVRDUDE_OPTS   = -v
ALTERNATE_CORE = ATTinyCore
BOARD_TAG      = attinyx5
BOARD_SUB      = 85
F_CPU          = 8000000L
ISP_HIGH_FUSE  = 0x5F
ISP_LOW_FUSE   = 0xE2

include $(HOME)/Arduino-Makefile/Arduino.mk

The important bit is to then edit the hv_rescue.ino file to set the fuses:

#define  HFUSE  0x5F   // reset as gpio5
#define  LFUSE  0xE2   // 8mhz internal oscillator

Then upload that to the Uno, connect the HVSP board with the ATtiny85 mounted, and press a key to set the fuses. If you don’t edit the script it’ll just reset the fuses to their defaults of 0xDF and 0x62.

The order is important, as you can’t ISP the chip after you’ve set the fuse to disable RESET, so you can’t use make set_fuses for example, you have to use the HVSP to set the fuses, after ISP’ing the sketch. If you want to edit the sketch, you’ll have to reset the fuses, then ISP the sketch and set the fuses back again, so its not something you want to do often – maybe develop using a regular GPIO pin like D2, then when you’re ready switch to D5.

I made a PR to fix that – so you make ispload to upload the sketch, then make set_fuses to set the fuses, after which you need to reset them using the HVSP.

You can then blink six LED’s using an ATTiny85 (the RESET pin has lower power output) with just VCC and GND connected (no crystal etc.) using for example:

#include <avr/io.h>

void setup()
{
    // set d0-d5 as outputs
    DDRB = B11111111;
}

void loop()
{
    // set all high
    PORTB = B11111111;
    delay(500);

    // invert all
    PORTB ^= PORTB;
    delay(500);
}

There are other more complicated sketches around which can auto-detect the chip and prompt for the fuses to set, but they seem to require a button and a 12v DC-DC boost converter, as per the Rescue Shield

ATtiny85 And Shift Registers

I decided I wanted to play with shift registers, and the classic circuit for that is running a bunch more LED’s from a chip than the chip has pins, so I decided on an 8 pin ATtiny85 running 16 LED’s as a Larson scanner (Knight Rider or Cylon effect).

I started out on breadboard which was a terrible mistake as I ended up needing two breadboards to provide enough space to run 16 LED’s via resistors all with a shared GND. Should have gone straight to perfboard (I think veroboard would have the same problem as breadboard due to solid tracks instead of pads).

The shiftOut() function takes a bit of getting used to, especially when using two 74HC595 shift registers so need to output 16 bits instead of an 8-bit byte (and when it takes an hour of playing with code to realise one of the chip’s output pins it busted!) and for some reason when moving from breadboard to perfboard I had to change the code to use MSBFIRST instead of LSBFIRST or it would run the LED sequence on each chip instead of across the two…..?!

Anyway, here’s the circuit diagram:

And here’s the code, where you can see I visualised the effect in binary split over the two registers, which then gets latched, shifted out twice, then unlatched. All using 3 pins from the ATtiny85!

const int latchPin = 1; // st_cp=12
const int clockPin = 2; // sh_cp=11
const int dataPin = 0; // ds=14

void write2Registers(byte patternA, byte patternB)
{
    // set latch low so output doesnt change whilst sending in data
    digitalWrite(latchPin, LOW);

    // shift out the bits
    shiftOut(dataPin, clockPin, MSBFIRST, patternA);
    shiftOut(dataPin, clockPin, MSBFIRST, patternB);

    // set latch high to send output
    digitalWrite(latchPin, HIGH);

    // pause
    delay(100);
}

void setup()
{
    // configure pins
    pinMode(latchPin, OUTPUT);
    pinMode(dataPin, OUTPUT);
    pinMode(clockPin, OUTPUT);
}

void loop()
{
    write2Registers(B00000000,B00000001);
    write2Registers(B00000000,B00000011);
    write2Registers(B00000000,B00000111);
    write2Registers(B00000000,B00001110);
    write2Registers(B00000000,B00011100);
    write2Registers(B00000000,B00111000);
    write2Registers(B00000000,B01110000);
    write2Registers(B00000000,B11100000);
    write2Registers(B00000001,B11000000);
    write2Registers(B00000011,B10000000);
    write2Registers(B00000111,B00000000);
    write2Registers(B00001110,B00000000);
    write2Registers(B00011100,B00000000);
    write2Registers(B00111000,B00000000);
    write2Registers(B01110000,B00000000);
    write2Registers(B11100000,B00000000);
    write2Registers(B11000000,B00000000);
    write2Registers(B10000000,B00000000);
    write2Registers(B11000000,B00000000);
    write2Registers(B11100000,B00000000);
    write2Registers(B01110000,B00000000);
    write2Registers(B00111000,B00000000);
    write2Registers(B00011100,B00000000);
    write2Registers(B00001110,B00000000);
    write2Registers(B00000111,B00000000);
    write2Registers(B00000011,B10000000);
    write2Registers(B00000001,B11000000);
    write2Registers(B00000000,B11100000);
    write2Registers(B00000000,B01110000);
    write2Registers(B00000000,B00111000);
    write2Registers(B00000000,B00011100);
    write2Registers(B00000000,B00001110);
    write2Registers(B00000000,B00000111);
    write2Registers(B00000000,B00000011);
}

And a Makefile for use with the arduino-tiny core:

ISP_PROG     	   = usbasp
BOARD_TAG          = attiny85at8
ALTERNATE_CORE     = tiny
AVRDUDE_OPTS       = -v

include /usr/share/arduino/Arduino.mk

Also to help debugging I wrote a simplified code that would light a single LED:

void turnOnLed(int led)
{
    digitalWrite(latchPin, LOW);

    if (led >= 8)
    {
        shiftOut(dataPin, clockPin, MSBFIRST, 1<<(led-8));
        shiftOut(dataPin, clockPin, MSBFIRST, 0);
    }
    else
    {
        shiftOut(dataPin, clockPin, MSBFIRST, 0);
        shiftOut(dataPin, clockPin, MSBFIRST, 1<<led);

    }

    digitalWrite(latchPin, HIGH);
}

Which you can then call from setup() for instance, so it only gets run once:

for(int i=0; i<16; i++)
{
    turnOnLed(i);
    delay(120);
}

I also found that sometimes when first powered on, the circuit it would flash on some random LED’s, this is (mostly) solved by putting 10k pull down resistors between the latch pins and GND so that the registers don’t get rubbish data sent to them when the microcontroller is booting. I tried controlling the OE or SRCLR pins from the ATtiny85 but it didn’t fix the problem which is weird as SRCLR is supposed to reset the registers to all zeroes and OE is supposed to enable output!

Someone mentioned they got it working by adding a 110k resistor between OE and VCC to keep it high during boot, then pulling it low in setup().

I also varied the brightness by using PWM on the OE pin by calling analogWrite(4, random(255)); but the effect was a bit naff. You could vary the speed using a trimpot and analogRead(3) I guess, but I’m all out of potentiometers.

The pinouts are:

74HC595:

Q1  = 1		16 = VCC
Q1  = 2		15 = Q0
Q3  = 3		14 = DS (data)
Q4  = 4		13 = OE (output enable - tie to gnd)
Q5  = 5		12 = ST_CP (latch)
Q6  = 6		11 = SH_CP (clock)
Q7  = 7		10 = SRCLR (clear - tie to vcc)
GND = 8		9  = SO

ATtiny85:

RST   = 1		8 = VCC
A3/D3 = 2		7 = D2/A1
A2/D4 = 3		6 = D1
GND   = 4		5 = D0

RPi Soldering Scope

I’m thinking of making a soldering microscope from a Raspberry Pi (either a spare B+ I have or maybe a ZeroW). I had looked at Andonstar ADMSM201 or Lapsun 14MP HDMI 180x scopes, but they each have their limitations – crap software, tiny focal length requiring additional lenses, £200+ pricetags…..

So looking at it, I just have to buy a Pi camera module with a CS mount and a decent lens. Then I can either stream the display or plug into a HDMI monitor. Even without a Barlow lens I should get at least 20cm working area beneath the camera.

The only problem is how to mount it. I’m thinking of a threaded rod from a 3D printer attached to my wooden 3rd arm board and some sort of 3D printed bracket. I only really need up/down not left/right or forwards/backwards (I can just move whatever I’m soldering). I even thought of a laboratory retort stand.

I’m going to try without illumination initially, and potentially make something from a Neopixel ring that could be controlled by the Pi and potentially powered from the same USB supply.

BOM is currently:

I’ve made a pi camera to CS mount adaptor and I’ve also modified my Pi ZeroW case to include a screw-on CS mount adaptor and holes for a shutdown/reset button and wires for a Neopixel ring which I’ll probably use instead of a regular LED ring, or I may use a 12v PSU and some spare LED strip.

ArduinoOTA Solution for ESP8266

I’ve wasted about three days trying to get OTA upgrades to work on my ESP8266 boards. They take 1-2 OTA’s and then don’t even boot into the sketch. Tried my Gizwits WiFi Witty and ESP12F on a breakout board with an LDO as described in my earlier post. Then I tried my old NodeMCUv2 board and it worked fine, all of the time.

Turns out we need moar powah!

The HT7833 LDO on the white breakout boards from the earlier post, are supposed to be able to put out 500mA so I guess its not a current problem but a voltage one, when measuring what gets through to the ESP its just over 3.3v. I bypassed the LDO and fed a 3.7v LiPo to VCC and it works fine now!

Whilst playing around trying to get it to work I added the 4x 10k resistors and a 100nF capacitor across the ESP’s VCC/GND pins as well as a 470uF capacitor across the power rails feeding the LDO, as per here. Didn’t seem to make any difference.

On a related note, the pinout of those white boards is insane. Turns out the VCC pin on the white board is where you should feed the supply into the LDO. It’s connected to VIN (middle pin). But bizarrely VCC on the ESP is not fed from there, its fed from a via from the LDO’s VOUT (right pin) and it seems CH_PD is fed from that via the leftmost 10k resistor on the breakout. So don’t power other components or connect other ESP pins to VCC as it’ll be running 8v or whatever you’re inputting!

I removed the LDO and had to replace the middle 000 resistor (solder blob) so that the breakout VCC goes to the ESP VCC.

So essentially if you want to use the LDO (I’d advise against it) you have to remove the 000 resistor and feed the LDO up to 8v via the breakout’s VCC pin, then run a jumper wire from VOUT on the LDO to the ESP’s VCC pin. I used the leftmost via as seen from the top, near VCC/GPIO13 pins rather than running a wire over and under the breakout.

If you don’t want to use the LDO, leave the breakout as it was and feed 3.7v into the VCC pin.

Update: I found that you can power the breakout from an external ~3.5v power source (with short wires) as long as you add:

  • 470uF capacitor on power rail
  • 0.1uF capacitor on power rail near to the VCC/GND pins
  • 10k pullup on RST pin
  • 10k pullup on GPIO0
  • 10k pullup on GPIO2
  • No pulldown on GPIO15 it already has one
  • No pullup on CH_PD it already has one

You can just about manage OTA’s this way but more than one sensor or LED and the thing falls over again! Nodemcu’s just seem much more robust.

I’ve received my free Amazon Echo – wow I need to get another when they’re £80 again! They are amazing! I’ve been using the fauxmoESP library to control the LED on an ESP8266, sooooo easy.

Here’s my sketch, including OTA code. Note to generate an MD5SUM to use as your OTA password, you need to call echo -n "otapassphrase" | md5sum to ensure you don’t get a newline! Then pass espota.py the plaintext string.

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include "fauxmoESP.h"

// init vars
const int RED = 15;
const int GREEN = 12;
const int BLUE = 13;

// constructor
fauxmoESP fauxmo;

void callback(uint8_t device_id, const char * device_name, bool state)
{
    Serial.print("Device ");
    Serial.print(device_name);
    Serial.print(" state: ");
    if (state)
    {
        Serial.println("ON");
        analogWrite(RED, random(0,1023));
        analogWrite(GREEN, random(0,1023));
        analogWrite(BLUE, random(0,1023));
    }
    else
    {
        Serial.println("OFF");
        analogWrite(RED, 0);
        analogWrite(GREEN, 0);
        analogWrite(BLUE, 0);
    }
}

void setup()
{
    // configure led
    pinMode(RED, OUTPUT);
    pinMode(GREEN, OUTPUT);
    pinMode(BLUE, OUTPUT);
    analogWrite(RED, 512);
    analogWrite(GREEN, 0);
    analogWrite(BLUE, 0);

    // debug
    Serial.begin(115200);
    Serial.setDebugOutput(false);
    Serial.println("After connection, ask Alexa to 'turn pixel on' or 'off'");

    // wifi
    WiFi.mode(WIFI_STA);
    WiFi.begin("myssid", "mypassword");
    WiFi.config(IPAddress(192, 168, 1, 2), IPAddress(192, 168, 1, 1), 
         IPAddress(255, 255, 255, 0), IPAddress(8,8,8,8));

    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }

    // ota
    ArduinoOTA.setPasswordHash("b7e82cbfc5bf5f1a44d8e5e526e2f1fe");
    ArduinoOTA.begin();

    // fauxmo
    fauxmo.addDevice("pixel");
    fauxmo.onMessage(callback);
}

void loop()
{
    fauxmo.handle();
    ArduinoOTA.handle();
}

I’ve improved my ESP Makefile to handle OTA and debugging etc (mind the word-wrapping on the fqbn line)

ARDUINO_PATH = $(HOME)/arduino-1.8.3
SKETCHBOOK   = $(HOME)/arduino16
ESPTOOL		 = $(SKETCHBOOK)/hardware/esp8266com/esp8266/tools/esptool/esptool
ESPOTA		 = $(SKETCHBOOK)/hardware/esp8266com/esp8266/tools/espota.py
SKETCH 		 = $(notdir $(CURDIR)).ino
TARGET_DIR   = $(CURDIR)/build-esp8266
MONITOR_PORT = /dev/ttyUSB0
OTA_IP		 = 192.168.1.2
OTA_PASSWD	 = otapassphrase
#DEBUG		 = ,Debug=Serial,DebugLevel=all_____
DEBUG		 = 

all:
	@ mkdir -p $(TARGET_DIR)

	$(ARDUINO_PATH)/arduino-builder -compile -logger=machine \
	-hardware "$(ARDUINO_PATH)/hardware" \
	-hardware "$(SKETCHBOOK)/hardware" \
	-tools "$(ARDUINO_PATH)/tools-builder" \
	-tools "$(ARDUINO_PATH)/hardware/tools/avr" \
	-built-in-libraries "$(ARDUINO_PATH)/libraries" \
	-libraries "$(SKETCHBOOK)/libraries" \
	-fqbn=esp8266com:esp8266:generic:CpuFrequency=80,CrystalFreq=26,FlashFreq=40,
        FlashMode=dio,UploadSpeed=115200,FlashSize=4M3M,ResetMethod=nodemcu$(DEBUG) \
	-ide-version=10803 \
	-build-path "$(TARGET_DIR)" \
	-warnings=none \
	-prefs=build.warn_data_percentage=75 \
	-verbose "$(SKETCH)"

flash:
	$(ESPTOOL) -v -cd nodemcu -cb 115200 -cp $(MONITOR_PORT) -ca 0x00000 -cf $(TARGET_DIR)/$(SKETCH).bin

ota:
	$(ESPOTA) -i $(OTA_IP) -I 192.168.1.3 -a $(OTA_PASSWD) -f $(TARGET_DIR)/$(SKETCH).bin

clean:
	rm -rf $(TARGET_DIR)

monitor:
	screen $(MONITOR_PORT) 115200

Once you’ve discovered your device using the Alexa app (or go to echo.amazon.com then “Smart Home” > Devices > Discover) you just say “Alexa, turn pixel on”.

Soldering board with helping hands

Inspired by this Reddit post, I decided I’d have a go at making a soldering board with helping hands.

The bill of materials is over £10, but I’ve bought more than I need, so probably under a fiver for the build:

Note that my local PoundLand was selling stuff for 90p for a few months, but its back to £1 now 🙁

I used some M3x25 hex bolts and nuts to attach the crocodile clips to the hoses, but you could use whatever you have, some people even use zip ties.

My hoses seem to have a 12.1mm connector, some people have 1/2″ or 12.5mm diameter, contrary to the 1/4″ claims on ebay.

I also added some heatshrink over the teeth on the crocodile clips, so they don’t short/scratch my circuits.

The hardest part was cutting the wood – it was pretty rough and not straight or the right size, so first I tried cutting it with a hacksaw which worked well but took ages. The I tried a jigsaw which was faster but awkward, I ended up using a full saw and my Dremel to bevel the corners with some 150 grit sandpaper to smooth the surfaces.

I tested the heatproof silicone mat by warming the iron to 350c and melting some solder, then flicking it onto the mat. It worked a treat and didn’t even stick, even though its only rated for 150c I think.

To stop it moving and scratching my desk, I added some anti-skid felt feet, although you could probably add another mat and then you could turn it over when its dirty.

I drilled the holes after putting the heatproof mat on which was a mistake as it tore up the mat. I can see the drilled holes through the material so when the replacement mat arrives I will cut corresponding holes in the mat. The 12mm drillbit was just the right size, I’ll put some epoxy in and the arms will never move.

Here is the finished article holding a circuit:

And here it is holding the weight of my cellphone, which is acting as an inspection camera and lamp:

Update: I’ve replaced the nut and bolt holding the crocodile clips on with a banana plug. I made the hole in the orange tip slightly larger and pushed the banana plug through then filled the inside of the tip with hot glue (well not totally, the blue hose has to fit!) so now I can slip on whatever connect I fancy as long as it has a banana plug connector!