A PIC12 programmer from an Arduino

In order to program the microcontrollers for interval bars, I needed a programmer. This is a device which connects to the chip and to a computer, and which allows one to transfer a program from the computer to the chip. You can buy them for $40 or so but I decided to make my own - since I already have an Arduino to act as a low level computer interface, I could make it very cheaply. The only complicated bit is the 13V power supply - I used this little boost converter circuit.

The Arduino program is fairly straightforward - it just reads a hex file over the serial serial line, checks the checksums and converts it to the sequence of signals according to the PIC12's programming specifications. It has facilities for reading back the microcontroller's contents and passing them back to the computer as well, and also a way of calibrating the clock rate. I added this not because I accidentally overwrote the OSCCAL and backup OSCCAL values (well, I did, but I had already read them at that point so I knew what they were) but because I wanted to know what the effect of the OSCCAL value was and if the factory programmed one was optimal.

I discovered that it wasn't quite the best (the preprogrammed value of 0x24 gave a within-spec clock speed of 996.5KHz but 0x26 gave a clock speed of 1002.0KHz). I also discovered that (with the one part I tested) the low bit of the OSCCAL was ignored and the top 7 bits interpreted as a signed quantity between -64 and 63 gave an extremely linear relationship to frequencies between 587.1KHz and 1230.1KHz with a resolution of about 5KHz. I also discovered that the frequency stability was very good - a standard deviation of only about 30Hz.

Here's the schematic for the programmer:

To build the programmer, edit the second line of build_programmer.bat to point to your Arduino installation (if it's somewhere other than C:\Program Files\Arduino) and run it. To upload it to the Arduino you'll need WinAVR, modify upload.bat to point to your WinAVR installation and run it. We can't use the avrdude from the Arduino installation here because it won't toggle the line to reset (that's normally done by the Arduino software).

To use the programmer, connect to it with a serial monitor (like the one in the Arduino IDE). There are several one-character commands:

  • W - Write program from Arduino to PIC.
  • O - Write program from Arduino to PIC, including OSCCAL value (necessary if write failed, or if we want to use a different OSCCAL value).
  • P - Write program from Arduino to PIC, including OSCCAL value and backup OSCCAL value - only use if the backup OSCCAL value got screwed up somehow.
  • R - Read program from PIC to Arduino.
  • U - Upload program from PC to Arduino (follow this with the contents of your hex file).
  • L - Download program from Arduino to PC.
  • T - Start timing mode.
  • Q - Stop timing mode.
  • A - Perform automatic calibration.
  • B - Output a nybble to port B (for debugging purposes.)

The returned status codes are as follows:

  • K - Success.
  • EF - Error: config fuses didn't verify.
  • EV - Error: Program, OSCCAL, user IDs or backup OSCCAL didn't verify.
  • ER - Address in hex file out of range.
  • EU - Unknown record type in hex file.
  • EZ - Non-zero byte count in end-of-file marker in hex file.
  • EC - Hex file checksum failure.
  • EH - Incorrect hex digit.
  • E: - colon expected but not received.

In automatic calibration mode, the Arduino also sends calibration information as three numbers per line: OSCCAL value (3 digits), frequency in Hz (7 digits) and standard deviation of frequency in Hz (5 digits).

Don't overdo it with the automatic calibration - it reprograms the PIC with each possible OSCCAL value so you'll wear out the flash if you do it too much.

10 Responses to “A PIC12 programmer from an Arduino”

  1. Peter says:


    I wonder what PIC12F did You program using arduino? I'm looking for solution which will allow me to program PIC12F683.


    • Andrew says:

      Hi Peter,

      I used PIC12F508s, though I'm sure the same circuit and program could be adapted quite easily - just take a look at the programming datasheet for the chip you're using and see what the differences are in how it's programmed.


  2. Andrew says:

    Any particular reason you chose to use both BC337s and a 2N3904? Unless you're doing something sneaky their specs look pretty much identical to me.

    • Andrew says:

      I'm not doing anything sneaky. I put the circuit together from smaller circuits that I found elsewhere on the internet, and those were the parts those circuits used. I happened to have them anyway, so I didn't look at the specs or investigate whether other transistors would work, but it'll probably work with all three the same.

  3. Martin says:

    Can't get the code to compile, maybe someone still reads this and is able to help! :)

    The following is happening and all the solutions and hacks found by Google don't work:
    root@vm:~/reenigne/intervals/programmer# avr-gcc -g -Wall -O3 -mmcu=atmega328p -o programmer.elf programmer.o programmer_c.o --save-temp
    programmer.o: In function `__vector_10':
    (.text+0x38): relocation truncated to fit: R_AVR_13_PCREL against symbol `sendTimerData' defined in .text section in programmer_c.o
    collect2: ld returned 1 exit status

    • Andrew says:

      Try changing the "rcall" instruction on line 37 on programmer.s to a "call" instruction. It looks like with more recent versions of the avr-gcc toolchain, things are bigger and/or in different places so the rcall instruction no longer reaches.

      • Martin says:

        First of all: Thank you very much for your almost instant answer!
        And believe it or not, it worked! :P Thought I tried this before, even tried on different architectures, different Windows and Ubuntu versions...

        Now I only have to figure out why avrdude from this ancient WinAVR refuses to talk to my arduino but it works with the Arduino IDE.
        And last but not least try to burn my PIC12F1572, but might have to change the programmer code a bit - we will see.

    • Martin says:

      I know have some pretty strange setup, involving a 4x2/1 multiplexer and an old ATX power supply as the 12V source, but still there seems to be something wrong with it.
      Reading from the PIC and downloading the output to the PC seems to work, but as soon as I try to write a uploaded code I get two alternating errors (so hard to debug): EF and EV.
      Would be great if you'd have some suggestions! :)

      • Andrew says:

        It's been a while since I played with this stuff, but perhaps there are some differences between the programming protocols between PIC12F1572 and the PIC12F508 that I targeted. You may need need to check the programming manuals for the two chips and adjust programmer_c.c accordingly. You might also want to check that the voltage from your ATX PSU is high enough for the microcontroller to recognize it as the programming voltage (I think it was 13V for the PIC12F508 I was using but I'm not sure what the tolerances are).

        • Martin says:

          Thanks again! Just realized that V_IHH (V_PP) needs to be between 8.0-9.0 volts, so I focused on adapting your code for LVP (and interally clocked) on my chip.
          Already spent some hours and tried to strip down your code and add what I thought is needed to deal with the PIC12F1572 - but without success so far.
          My main problem is, that I don't even know if the device entered programming mode after my signals, so debugging is nearly impossible.
          Maybe I got there into a project that is too big for a beginner like me. :P

Leave a Reply