An Arduino-based programmer for the AT89C2051 chip

The Atmel AT89C2051 is a low cost microcontroller in a 20-pin DIL package.  It runs MCS-51 (commonly termed ‘8051’) code.  It works from 2.7V to 6V at anything from 0 Hz up to 24 MHz.  It has 2K bytes of Flash memory to hold the program and 128 bytes of RAM.  It has 15 I/O lines, a UART, an analogue comparator and two 16-bit timer/counters.

I came across the chip as it’s often used in cheap 7-segment clock kits such as this one from BangGood (only £2.71 at the time of writing).

I wanted to reprogram the chip so I could use the kit as a stopwatch/timer instead of a regular clock.  Of course I could have bought a programmer to do the job, but reading the chip’s data sheet it seemed straightforward to do the programming with an Arduino – and I thought it would be a fun project to do that.

The chip is programmed a byte at a time by setting up each byte on 8 of the chip’s I/O lines and then pulsing some of the other I/O lines to ‘burn’ the byte to flash memory and move on to the next byte to be programmed.  You can also read the existing program out of a chip (unless a read-protect bit has been set) and there are special ways of pulsing the I/O lines to erase the whole chip and so on.

The only tricky thing is that one pin has to be raised from the nominal operating voltage of five volts up to twelve volts during programming – the challenge was working out the easiest way to do this using an Arduino.

So I decided to use an Arduino Mega 2560 for this project.  A Uno doesn’t have quite enough I/O to do the job properly, and the Mega 2560’s double row of I/O pins makes routing the connections to the chip simple as the chip can sit directly over the double-row connector.

I decided to use a charge pump (voltage multiplier) running off the Arduino’s five volts to generate the programming voltage – that seemed cleaner than needing a separate twelve volt supply.  It just uses a few diodes and capacitors and relies on the Arduino pulsing some of its I/O lines to drive the voltage multiplier.  A couple of zener diodes clip the voltage down to exactly 5V or 12V and a couple of transistors, also switched by the Arduino, select between either of those voltages or 0V to drive the pin on the chip.

I designed a PCB using the free KiCad package.  Here’s a .pdf of the circuit diagram, and here is what KiCad produces as a picture of the design.  In the picture it looks like the chip to be programmed is soldered straight into the board, but of course in reality a ZIF socket is fitted in that position so that the chip(s) you are programming can be quickly swapped.

programmer3DThat picture wrongly shows the tracks on the top of the board – I design them that way for home production as the transfer process mirror-images the tracks so that they’re correct for the back of the board.  If you fancy making one of your own, it would be quite straightforward to  do it on strip board – like I say most of the pins of the chip just connect direct to the Arduino pins that the chip sits over.  If you want to etch your own PCB, here is a .pdf of the mask.

Here are a couple of snaps of the prototype board.  You can see I didn’t bother to crop back the board edges!


topbackAnd this is what it looks like when docked on top of the Arduino Mega 2560.

topDockedbackDockedSo that’s about it for the hardware.  I’ll make a separate post about the Arduino sketch that does the work of programming the chip, and the PC program that talks to the Arduino to send and receive hex files.

POV source code – part 3

If you’re trying to compile the source code with the Keil compiler, you’re probably getting error messages about ‘undefined identifier’ or similar.  This is because the standard Keil reg52.h header file doesn’t define all the necessary identifiers for the STC89C5x chips.

We need to define the special function register (sfr)

P4 = 0xE8;

so the code can access bits of the fourth GPIO port and then define the special bit (sbit)

INT2 = P4^3;

so that the code can react to the infra red photodiode that is connected to that pin.  It seems that the best way to include these extra hardware definitions is to edit and save the standard reg52.h file.  Here’s my modified version: reg52.h

Timer 2 interrupt

The bottom line of the display is handled in a slightly different way.  The idea is that the current rotation rate (measured inside the timer 1 interrupt) is used to calculate the settings for timer 2 so that the timer2 interrupt occurs 256 times per revolution.  Then from inside the timer2 interrupt code we just have to output the next set of 8 pixels to each of the ports that control the lower set of 8 LEDS on the arms.

Timer 2 has a 16-bit counter and an interrupt is generated when it counts up to FFFF.  To get 256 interrupts per turn, we count the number of ticks per turn from interrupt 1 and work out 3/4 of that value.  This is subtracted from FFFF to get the ‘start’ count.

Inside the timer 2 interrupt we count how many interrupts actually occur and use this to tweak the timer 2 start count slightly so that the 256 pulses eventually synchronize and stay in register with the infra red photodiode pulse.  If 256 or more pulses occurred in the last revolution the start value is tweaked slightly lower so that the interrupts during the next revolution happen slightly slower – and vice versa if 255 or fewer pulses occurred.

With the comments in the code that should enable you to modify the code for your own applications.  Be aware that the free version of the Keil compiler limits the compiled code size (to 2K, I think) so the full program here won’t produce a hex file.  But if you trim the program down to only work the clock on the upper row or only scroll a limited amount of text on the lower row, then you can get it to fit within 2K.

For an individual just writing code for fun, the Keil licence costs way too much: if you want to write larger programs you have to use one of the free alternatives to the Keil compiler – which are a little more tricky to set up and get working.

POV source code – part 1

These posts relate to the previous few concerning the Banggood kit: Cross LED Dot Matrix Display Circuit Board Rotating Electronic Kit

It uses an STC89C52RC microcontroller which is a (fairly) modern Chinese version in the 8051 family.

You can program it in assembler, but I chose to use the C language for this project.

The font

We’re going to be displaying text so we need some kind of font.  The kit provides 16 LEDs arranged vertically on each of the two arms, but I thought that if we use characters the full height of the arms then we wouldn’t be able to fit many of these large characters around the cylinder that the arms sweep out (unless the characters were ridiculously skinny for their height) so I decided to use an 8×8 font which would allow for two rows of characters.

For simplicity I wanted the characters defined in the font to include the spacing to the left and/or right of normal characters so most characters in the font are only 7 pixels wide – or even less for skinny characters such as i – and only a few characters like q and y have descenders, so the spacing between the two rows of characters is included in the font too.

The kit sensibly arranges the pins driving the LEDs so that the chip’s four 8-bit I/O ports, P0, P1, P2, P3 each drive either the top 8 LEDS or the bottom 8 LEDs on an arm:  one arm has P2 on the top and P0 on the bottom, the other arm has P1 at the top and P3 at the bottom (at least that’s the way mine turned out).  I chose to fit all blue LEDs to the P0/P2 arm and all red LEDs to the other one – obviously you can fit them in other ways – it might look pretty to get two extra colours – then you might have (say) yellow and green on the top row with red and blue on the bottom.

Anyway, each of the four ports has the least significant bit at the top, and then the bits going in order down to the most significant bit at the bottom.  If you wire up the motor with the red wire as positive, the board spins clockwise (viewed from above) so the LEDs scan the characters out in right-to-left order.  The wiring is such that the program has to write a ‘0’ to an I/O pin to illuminate the corresponding pin, or write a ‘1’ to switch it off.  It’s convenient to write 8-bit quantities in hexadecimal and in the C language we write 0xFF to indicate all 8 bits high or 0x00 for all eight bits low.

I searched on line and found this 8×8 font which I thought would be suitable:

toncFont The font is on this page and includes the data in C-friendly form

I had to manipulate the font data for right-to-left scan order with the least significant bit at the top and a zero-bit indicating ‘LED on’.  I wrote a C# program to do that.

Note that the font starts with the space character (ASCII 32) and is in ASCII order.  The last character (ASCII 127 [DEL]) renders a space too, but as that’s a duplicate you could tweak it to get a £ or € or some other symbol you might want to display.

Say our program wants to display the number 2  This is the ASCII character 50.  Our font doesn’t have characters defined for the first 32 ASCII values so we subtract 32 to get 18 and then multiply by 8 (eight bytes per character in the table) to get 144.  The data we need to display a 2 therefore starts 144 bytes into the font table and consists of the eight bytes:


So the program outputs those eight bytes in that order and (remembering that the arms scan out the characters from right to left) we get:


ISP programmer for the STC89C51 and STC89C52

I couldn’t find an ISP (programmer) for the STC89C52RC that worked with modern versions of Windows. I found several programmers that work with other chips in the STC range.

I did find one that worked on Windows XP, and with some hacking got it to work with Windows 7; however I had no luck with Windows 10. In any case, it was a Chinese program, and as I don’t read that language, I just had to remember which controls to use.

I also found one that worked under Linux, from the command line.  Using that source code as a guide I figured out how to write my own Windows version.

Image1It’s pretty basic but all you really need.  You select the COM port and the hex file you want to upload.  Connect up to your chip with a 5-volt serial port such as an FTDI (or you can use an Arduino UNO or similar that has a 5V FTDI built-in).

Here’s the video showing how to use the Arduino UNO as a programmer.  Here it’s being used to program a Banggood POV kit which uses an STC89C52RC chip – but you could obviously adapt the Arduino sketch and/or make a wiring harness to work with any STC89 board:


Here’s the Arduino sketch when you’re using the UNO as a programmer as shown in the video: Arduino sketch

Edit: the programmer program is now at V0.4 which fixes a few bugs and lets you switch the microcontroller to high speed (6T per machine cycle) or normal speed (12T per machine cycle).

Further Edit (August 2017): the programmer program is now at V0.5, and supports some different STC-chip bootloader firmware versions that previous versions did not.

If you’re not using the Arduino (which powers up the STC chip by itself when it detects activity on the serial port) then press the button to start the upload and then apply power to the target chip.  There’s a progress bar indicator – it takes maybe ten seconds to program the chip.

I’ve tried it on Windows 10 and Windows 7.  I’ve no reason to suspect that it won’t work with other versions of Windows.

Beware the fake Prolific serial chips that come in some USB-serial adapters and some cheap STC89C5x development boards.  I have one of those boards. I found an old version of the driver that let me get the Prolific chip operating as a loop back device – it even worked under Windows 10.  But it’s flaky and doesn’t work for programming the chip.  I found the only way I could get the programmer to work reliably was to cut the tracks leading from the STC chip’s serial port to the Prolific chip and connect an FTDI interface to the STC chip instead.

You may also need to fit a pull-up resistor to the STC’s TxD pin – only try that if you think you’ve connected everything up properly but it’s still not working – something like 10K or 100K should do the trick.  It depends on how much pull-up effect is already present on the RxD line of your serial interface and on the amount of stray capacitance present on your boards and cables.

Here is the link to download the install zip file for the programmer

Update: Ewald Burger (see comments below) encountered problems with the installation that he eventually traced to his AVAST virus scanner.  If you encounter problems with the installation you may want to try temporarily disabling your virus scanner while installing.

Here’s the source code – unzip it to your ‘projects’ folder. It was done using the free version of Visual Studio 2015 source code

Fast, small, and simple Arduino SPI RAM chip routines.

The 8-pin chip, 23LC1024, is a good candidate for adding extra RAM to simple Arduinos such as the Uno, Nano, Mini.  It provides 128K of RAM (the ATmega328 chip that these Arduinos use only has 2K of internal RAM).

The chip works at 5V (anything from 2.5V to 5.5V) and uses SPI so it only uses 4 pins of the Arduino to talk to it.  You can buy the chips on eBay for less than £5 each.

I wanted some fast simple routines to copy any arbitrary number of bytes between ‘normal’ RAM and the SPI RAM.  I didn’t want to link in any huge libraries so I wrote these small routines that hit the 328 chip’s SPI registers direct.

There are only three functions:

spiRam::start(); // sets up the SPI interface – call once from your setup() routine

spiRam::writeSpi(*ptr, address, length); // copies to SPI RAM

spiRam::readSpi(*ptr, address, length); // copies from SPI RAM

*ptr is an unsigned byte (uint8_t) pointer – but you can cast any other data type address to that easily – see example.

address is an unsigned long (uint32_t) as addresses in the SPI RAM range from 0 to 131071 (2^17 – 1).

length is an unsigned int (uint16_t) – but will never be bigger than 2048 as the 328 chip only has 2K of RAM.

Standard connections (you can use a different pin than D10 for the chip select – but there’s not much point unless you want to use more than one RAM chip to give more than 128K RAM – see notes in the .h file).

Chip pin Arduino pin
1 D10
2 D12
3 5V
4 Gnd
5 D11
6 D13
7 5V
8 5V

Here’s the sketch: Unzip it inside your Arduino folder. You want to end up with the SpiRam23LC1024 folder in your Arduino folder with the SpiRam23LC1024.ino and the two other files inside.  Then it should compile and upload okay.  To use it with your own code just move the .h and .cpp files inside your folder where your .ino file is and add the line

#include “spiRam.h”

up at the top of your sketch.

Because the routines are interrupt driven your code could be doing something else while the transfers are taking place – but be careful if you’re not sure – it’s easy to start destroying or changing contents before they’ve finished being transferred if you’re careless. The routines are very fast anyhow (9 milliseconds to transfer 1024 bytes in either direction), so as standard there is a ‘busy wait loop’ until the transfers are complete so you don’t need to worry about checking from inside your code.


Untangle, Planarity.

I’ve been writing some code (in Java) to solve this fun puzzle.  I’ve played the puzzle for many years – it’s part of the excellent and free Simon Tatham’s Portable Puzzle Collection which has been available on many platforms for ages and has recently been ported to Android too.  Untangle was inspired by Planarity, written by John Tantalo.

My first effort modelled the puzzle as a physical system.  The links between points are elastic bands, where the attractive force is proportional to the cube of their length.  The points have an electric charge which produces a repulsive force between all points in line with Coulomb’s inverse square law.  The whole thing is submerged in a viscous fluid so that things don’t move too fast.


It solves many puzzles just using those rules but sometimes, especially with puzzles with a large number of vertices, it gets stuck in ‘a knot’ or takes too long to stabilize.  Also, if it happens to ‘choose’ an outer face with a large number of vertices, then some inner vertices can be pushed out by the repulsive force so that they cross the ‘perimeter line’.

I’m now working on a faster and guaranteed-to-work algorithm – though it may not be as interesting to watch in action.  Stay tuned for an update…

ATmega328P-PU 12MHz bootloader

It took me an embarrassingly long time to get a 328 with a 12MHz crystal working so that it would allow a normal (serial / FTDI) upload from the Arduino IDE.

There are a few older guides around but I didn’t find one that used the newer optiboot bootloader.

If you don’t want to compile the bootloader yourself, you can download the compiled optiboot_at328mega_12.hex file from this link (right-click and and Save (link) as…) just copy it to your optiboot folder before editing your “boards.txt” file as described below.

If you want to compile the hex file yourself here’s how:

Edit the Makefile in your optiboot folder. On my (Windows 7 64bit) machine using Arduino 1.0.5-r2 this folder was C:\Program Files (x86)\Arduino\hardware\arduino\bootloaders\optiboot

Add this section. I put it in after the existing atmega328 sections and before the Sanguino section  (note that the -W1, … shouldn’t be on a separate line – it’s a continuation of the LDSECTIONS line, but this blogging software seems to want to wrap it onto a new line):

atmega328_12: TARGET = atmega328
atmega328_12: MCU_TARGET = atmega328p
atmega328_12: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
atmega328_12: AVR_FREQ = 12000000L
atmega328_12: LDSECTIONS  = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
atmega328_12: $(PROGRAM)_atmega328_12.hex
atmega328_12: $(PROGRAM)_atmega328_12.lst

atmega328_12_isp: atmega328
atmega328_12_isp: TARGET = atmega328
atmega328_12_isp: MCU_TARGET = atmega328p
# 512 byte boot, SPIEN
atmega328_12_isp: HFUSE = DE
# Low power xtal (12MHz) 16KCK/14CK+65ms
atmega328_12_isp: LFUSE = FF
# 2.7V brownout
atmega328_12_isp: EFUSE = 05
atmega328_12_isp: isp

This is just a copy of the atmega328. section with:

  • the name changed from atmega328. to atmega328_12.
  • the f_cpu parameter changed from 16000000L to 12000000L
  • the two (PROGRAM) lines changed so that the .hex and .lst filenames also have the “_12” addition
  • the comment about the 16MHz crystal frequency changed to 12MHz

Run a command shell as administrator and navigate to the optiboot folder.  Enter the following command to compile the new 12MHz optiboot bootloader:

omake atmega328_12

Now edit your boards.txt file.  On my machine this was located at C:\Program Files (x86)\Arduino\hardware\arduino  Add this new section at the end – again this is just a copy of the ‘uno’ section with the few obvious edits for frequency and bootloader file.

############################################################## 12MHz crystal

Now launch Arduino, select “ATmega328 12MHz crystal” as your board and “Burn Bootloader” from the Tools menu.

That’s it, and you should be up and running with the normal hardware serial port working correctly with the ‘Serial’ commands and serial uploading from the Arduino IDE also working correctly.  I’ve seen comments that not all of the timing functions (microsecond delays etc.) work accurately when using a 12MHz crystal and the standard Arduino libraries.  I’ve not investigated that yet; and so far I’ve not tried using software serial with a 12MHz crystal – that also may require some tweaking…



Controlling the Raspberry Pi camera from C

I wanted to be able to stop and start the camera driven by events instead of just calling raspivid to record for a preset time.

My code is really just a simple wrapper around raspivid using the SIGUSR1 option to stop the video under program control rather than after a preset time.

The example main() function starts the video, sleeps for five seconds and then stops it.  For demo purposes I included the options for black and white inverted video.  To record with the normal raspivid defaults you just call startVideo with an empty options string:

startVideo(“filename.h264”, “”);

Obviously you can put any of the normal raspivid options in the string – but you should avoid -t, -n, -o, and -s as the code fills those in for you.  If you want to enable preview/monitoring then make the obvious change to remove the -n (no preview) option.

Save code as, say, video.c and compile with gcc -o video video.c

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static pid_t pid = 0;

void startVideo(char *filename, char *options) {
    if ((pid = fork()) == 0) {
        char **cmd;

        // count tokens in options string
        int count = 0;
        char *copy;
        copy = strdup(options);
        if (strtok(copy, " \t") != NULL) {
            count = 1;
            while (strtok(NULL, " \t") != NULL)

        cmd = malloc((count + 8) * sizeof(char **));

        // if any tokens in options, 
        // copy them to cmd starting at positon[1]
        if (count) {
            int i;
            copy = strdup(options);
            cmd[1] = strtok(copy, " \t");
            for (i = 2; i <= count; i++)
                cmd[i] = strtok(NULL, " \t");

        // add default options
        cmd[0] = "raspivid"; // executable name
        cmd[count + 1] = "-n"; // no preview
        cmd[count + 2] = "-t"; // default time (overridden by -s)
                               // but needed for clean exit
        cmd[count + 3] = "10"; // 10 millisecond (minimum) time for -t
        cmd[count + 4] = "-s"; // enable USR1 signal to stop recording
        cmd[count + 5] = "-o"; // output file specifer
        cmd[count + 6] = filename;
        cmd[count + 7] = (char *)0; // terminator
        execv("/usr/bin/raspivid", cmd);

void stopVideo(void) {
    if (pid) {
        kill(pid, 10); // seems to stop with two signals separated
                       // by 1 second if started with -t 10 parameter
        kill(pid, 10);

int main(int argc, char **argv) {
    printf("Recording video for 5 secs...");
    // example options give an upside-down black and white video
    startVideo("temp.h264", "-cfx 128:128 -rot 180"); 
    printf("\nVideo stopped - exiting in 2 secs.\n");
    return 0;

Flash Rubik Cube Simulator

Snapshot of Flash Rubik Cube Simulator

Above is a snapshot image.  Here’s the real thing.

It works for any size of cube from 2 x 2 x 2 up to 11 x 11 x 11.  Actually, 11 is an arbitrary limit – the same code would work for any size of cube.  Use the little + and – buttons up in the top left hand corner to select the size of the cube.

Turning a face or slicing a layer is pretty intuitive – just click somewhere on the cube, hold down the mouse button and drag.

Turning the whole cube around is the same but you have to double-click, hold the mouse button down on the second click and then drag.

There’s a bug in the turning of the whole cube which causes the orientation to jump occasionally.  I think I can fix it by using quaternions to do the whole-cube rotation, but with the demise of Flash I’m thinking this would be a good project to migrate to HTML5 – and then I could patch in the quaternion stuff at the same time.

You can also use the keyboard to turn layers (there’s a sort of agreed way of doing this among speed-cubers, and the simulation mostly uses the agreed keys),