Projects

Arduino PIC Programmer

Tim Blythman

Issue 8, February 2018

This article includes additional downloadable resources.
Please log in to access.

Log in

Program a PIC microcontroller with an Arduino? Yes! And not just because we can, but because it’s easy to build and program stuff with Arduino.

BUILD TIME: 1-1.5hrs
DIFFICULTY RATING: advanced

Many years ago, when computers had parallel printer ports, you could interface directly to the hardware, and a PIC programmer was not much more than a few passive components that pushed data straight onto the chip. With a setup like this, a PIC was the accessible microcontroller choice like Arduinos are today, and many circuit designs could be found on the early internet.

Nowadays, there are USB solutions for PIC programming like the PICkit 3, but if you want something a bit more bare-metal (and cheaper too), it’s a case of DIY. So in the spirit of the PIC programmers of old (say 10 to 15 years ago), I decided to build something myself, and along the way, I learned a lot about how the PIC programming protocol works at a low level. So far, the programmer works with the 12F675 of the PIC Pocket Remote Control and the ubiquitous 16F84A.

THE BROAD OVERVIEW

I wanted to design a simple-to-build PIC programmer for the 12F675 PIC, so that it would be easy for people to build the PIC Pocket Remote Control project, and what I’ve ended up creating is a breadboard (or protoboard –it’s simple enough to be built on a breadboard or protoboard) that, when combined with an Arduino board does the job of the “K150” type programmers, which can be found online these days. These appear to be clones of the programmers originally produced by a company called “Kitsrus”.

I got myself one of these with the idea of refreshing my knowledge of PIC microcontrollers, but quickly found driver issues related to Windows 10 and (apparently) counterfeit USB-Serial ICs.

In short, I was able to get it working on my 10-year-old laptop running Windows XP, but I wanted something a bit more future-proof. There are online guides to building your own version, but they usually start with “take a blank PIC 16F628 and the PIC programmer you already have”, (which sounds a bit like some recipes for building 3D printers). The program that is used with the K150 programmer is basic but works for uploading HEX code, so I set out to emulate the function of the programmer board, which includes a working USB-Serial link (included in our Arduino at no extra charge!), some extra components to get our signals in the right place, and of course, an Arduino sketch to make it do all the things a programmer should.

HOW IT WORKS

I found there were two sides to the final sketch that runs on the Arduino – the bit that talks to the host program on the PC, and the other bit that interfaces with the PIC itself to perform the programming. I was actually able to get the two halves working independently, first convincing the host program that a programmer is attached, then making sure I could talk to the PIC and understood the programming process. What followed was an interesting exercise in reverse engineering.

arduino host program

The host program “MicroPro” allows you to do such things as load a HEX file, program it onto the PIC, read the HEX file back out and set the configuration fuses. If you’re only familiar with programming Arduinos so far, this is a bit of a different process, but only so far as the Arduino IDE is actually doing all this in the background when you click “upload”.

The first thing I found with MicroPro is that it only supports COM ports up to number 9, so I had to renumber my COM ports in Device Manager to make sure that it could work. I found a document describing the software protocol that is used and also the schematic of the K150. I was pretty sure that the K150 clone I had was not the same as the schematic, but it was close enough that I was able to work it all out. Initially I soldered some header pins onto the serial communication pins to see if I could eavesdrop on the data to see how it matched the protocol.

arduino mega

The pins are wired up to an Arduino Mega, and a sketch (Mega_hex_transceiver_19200) is loaded that listens on the Mega’s Serial1 RX and Serial2 RX pins, allowing the command and response sequence to be captured. This is important as our Arduino programmer needs to be able to fool MicroPro into thinking a real programmer is connected. In any case, I found that the protocol spec had a few small deviations, but was mostly accurate.

SERIAL TRANSACTION MONITOR:

TXRX
x50-
x03x50
x04-
x00-
x00-
x40-
x06-
x00-
x50-
x02-
x00-
x01-
x01-
-x49
x14-
-x03
x04-
-x56

The next step was to create a sketch that fools MicroPro into thinking there is a programmer connected. Later on, this would be fleshed out with various functions that actually interact with a connected PIC. I even emulated the flash memory of the fictional PIC by storing data in the Arduino RAM. This was the “PICPGMdummy5” sketch, and it wasn’t quite complete, but it was close enough that I could start working towards a functioning version. The core of this sketch is a large ‘switch/case’ structure which detects which command MicroPro is sending and then jumps to a subroutine which may take extra parameters or return data before going back to wait for the next command.

Thus far, I hadn’t needed to build much hardware except for adding on the header pins to attach K150 to the Mega. Now I needed to build a circuit to interface the Arduino to the PIC. One thing that is very different about programming PICs is that they need a programming voltage of around 13V applied to one of their pins to correctly enter programming mode, so I needed a way of generating and switching a 13V supply with an Arduino. Because there is very little current needed at the programming voltage, I settled on using a voltage tripler circuit called a charge pump based on capacitors and diodes, and then switching the 13V with an opto-isolator. The other pins use normal 5V digital logic, so were simply connected to the Arduino pins via resistors. The PIC’s data pin changes from an input to an output during use, so I simply used two Arduino pins, one for the input function and one for the output function, with the resistors providing enough isolation to set and read the pins without constant changing the Arduino pins between inputs and outputs. If the PIC data pin is an input, it follows whatever is on the Arduino output pin, while if it is an output, it drives the input pin, and the resistor between the two output pins means that they are not trying to “fight” each other.

The voltage tripler needs a continuous stream of two out-of phase square waves to drive it, and I was able to generate this by using the PWM output on pins 9 and 10 on the Uno, with a little tweak to the code to create an out-of-phase signal instead of the normal in-phase signal that would be created. This is why this project may not work on other Arduinos, as the hardware timer is specifically attached to these two pins, but only on the UNO. This sort of circuit can be extended to more stages to create an even higher voltage, but with a decreasing current capacity. The tripler circuit makes up the left half of the circuit up to the third capacitor.

In an ideal scenario, the first capacitor is charged up to 5V via the first diode when D9 is low, then when D9 goes high, the first capacitor is lifted to 10V at its positive end, and so forth down the line, with each stage adding 5V. Extra stages can be added using two waveform pins, as long as they alternate. The actual result is 15V less whatever voltage is lost across the diodes and bled from the last capacitor from the circuit it is connected to. In practice, using Schottky diodes (because they have a lower forward voltage than silicon rectifier diodes), I was getting around 14V. I tried it with silicon rectifier diodes, and was only getting about 11V, which was not high enough according to the specs.

The output from the tripler is switched by an opto-isolator, where the output of the opto-isolator is also pulled to ground by a resistor to ensure there is no residual voltage when it is switched off. The 100kΩ and 10kΩ resistor form a voltage divider to monitor the tripler’s output via an analog pin on the Arduino, and are needed because they are measuring a voltage above 5V.

After the opto-isolator is the interface to the PIC itself, with some of the Arduino’s digital pins connecting to the PIC directly or via resistors. The ‘ICSP’ stands for In Circuit Serial Programming, and is used mostly because it is fairly standard to many of the programmers I have seen, although most applications will use an IC socket for out-of-circuit programming. To achieve this, I created a breakout board, which has an IC socket and a header for the ICSP signals. If I need to work with different PICs, it’s as simple as creating a breakout board with ICSP header that suits. A bonus is that the breakout board will work with any programmer that has an ICSP header, which most seem to do.

The programming protocol is well documented, and consists of 6-bit commands mixed with 16-bit data, with some commands sending and some receiving data. I tested this with the Manual_PIC_ProgrammerV2 sketch, which implements these commands and can be controlled via the serial monitor. For example, to read the program data of a 16F84A, the sequence “c04rc06” is entered, which performs command 4, which reads in the data that the command produces, then issues command 6 to increment the address to the next memory location. Repeating this sequence will slowly dump the program memory contents to the serial monitor. Using this, by manually entering various combinations of commands, I was able to determine the correct sequence of commands to read and write memory and also to write to the configuration fuses.

So far I’ve worked out the programming for 12F675 and 16F84A PICs, and the current version of the Arduino PIC programmer supports these. Some PICs use different commands for different functions, which is part of the difficulty in building a universal programmer.

figure 1
figure 2

THE BUILD

Parts Required:JaycarAltronics
3 x 1N5819 Schottky Diode ZR1020 Z0040
3 x 100uF Capacitor RE6140 R5124
1 x pack 100Ω Resistor RR0548 R7034
1 x pack 1kΩ Resistor RR0572 R7046
1 x pack 10kΩ Resistor RR0596 R7058
1 x pack 100kΩ Resistor RR0620 R7070
1 x pack 470Ω Resistor RR0564 R7042
1 x 4N25 opto-isolator ZD1928 Z1645
1 x 8 Pin Machine IC Socket PI6500 P0530
1 x 8 Pin Production IC Socket PI6452 P0550
schematic for build

You will also need standard prototyping hardware, such as breadboard and jumper cables.

It’s assumed that you have a 12F675 or 16F84A PIC to program for a project that is being built, or at least to experiment with. I found an 8-pin IC socket was handy for the case of needing to move the PIC from the programmer to the circuit it is used in. The machine-pin-type sockets are a better fit for breadboards, and I ended up using a machine-pin-type socket on the breadboard and production type socket attached to the PIC to protect the pins when it is moved to the test circuit. ››

BUILDING THE CIRCUIT

The actual construction is simple enough to be done on a breadboard, although I’ve also built a version on a protoboard to make it more permanent. If found it was easiest to build the circuit from left to right according to the diagram, testing the steps along the way. The tripler is the first module, consisting of the three left most resistors, capacitors and diodes. This part can be tested with this snippet of code (in the setup() part of an Arduino sketch):

  analogWrite(9,127);
  analogWrite(10,127);
  TCCR1A=0b10110000|(TCCR1A&0b00001111);

The remainder of the circuit is mostly built around the opto-isolator to switch the programming voltage on and off, and some resistors to feed the programming signals to the PIC. In the photo, there is both an ICSP header and an IC socket for a 12F675, which is why it looks like there may be too many wires.

inset

Apart from D9 and D10, the other pins can be reassigned if necessary, and of course reading the tripler voltage needs to be done by an analog input. At this stage, the Manual_PIC_ProgrammerV2 sketch can be used to test that the pins are being controlled correctly – for example, the ‘~’ command is used to toggle power on and off.

THE CODE

If you haven’t already done so, download and install the K150 MicroPro software. The final sketch code is a combination of the Manual_PIC_ProgrammerV2 and PICPGMdummy5 sketches, and is called “PICPGMFunctionalV7” (yes, there were a lot of versions of three different programs!), with some tweaks to round out some features. After setup sets up the pins, starts the charge pump and waits for it to get above 12V, the main loop waits for a command and then parses it with a large switch/case structure.

void loop() {
  int a;
  if(Serial.available()){
    a=Serial.read();  //if a command is received
    parsecommand(a);  //action it
  }
}
void parsecommand(int n){
  switch(n){
    case 0: break;
    case 1: Serial.write(‘Q’);break;
    case 2: do2command();break;  //echoes back next byte
    case 3: do3command();break;  //get Prog Variables
    case 4: do4command();break;  //V on
    case 5: do5command();break;  //V off
    case 6: do6command();break;  //cycle V
    case 7: do7command();break;  //program ROM
    case 8: do8command();break;  //program EEPROM
    case 9: do9command();break;  //program ID & Fuses
    case 10: do10command();break;  //write calibration/fuse
    case 11: do11command();break;  //read ROM
    case 12: do12command();break;  //read EEPROM
    case 13: do13command();break;  //read config
    case 14: do14command();break;  //erase chip? actual 14 appears to be missing, so all are off by one
    case 15: do15command();break;  //erase check?
    case 16: do16command();break;  //erase check EEPROM?
    case 20: do20command();break;  //out of socket detect, not implemented
    case ‘P’: Serial.write(‘P’);break;  //stay in programming mode...
  }
  return;
}

The individual commands are then customised to handle the particular functions. Command 12 is for reading the data (not program) EEPROM, and fortunately, the same 6-bit command performs a read on both 12F675 and 16F84A. The eepromsize variable is sent by MicroPro via an earlier command 3, and MicroPro knows this from the PIC which is selected.

void do12command(){   //read EEPROM from chip
 unsigned int d;
 for(unsigned int i=0;i<eepromsize;i++){
  sendcmd(5);   //init read from data mem
  d=readdata();   //read
  Serial.write(d&0xFF);  //only send 8 bits
  sendcmd(6);  //increment
 }
}

Once the hardware is built, upload the “PICPGMFunctionalV7” sketch to the UNO and connect the MicroPro app to the programmer by choosing the correct COM port. Select a PIC type appropriate to what is being used, and then you can test the response of the programmer without a PIC connected – the memory locations will be read as zeros. If the MicroPro app can at least complete these operations without complaining about a problem with the programmer, then it is time to connect a PIC and test that a HEX file can be uploaded and read back.

From time to time I found that MicroPro complained about the programmer being disconnected, but allowing it to perform a reset seems to do the trick. If the programmer doesn’t seem to be responding at all, check that the charge pump is reaching 12V, as the program waits during setup for this to occur – it should normally take less than a second. If you’ve been waiting to build the PIC Pocket Remote Control, it should be as simple selecting the 12F675 under chip selector, use the file menu to open the HEX file, and then click program to upload the HEX to the chip.

WHERE TO NEXT?

I would like to update the Arduino code to support the 16F88 and 16F628 PICs, the former because it is an updated pin-compatible version of the 16F84A, and the latter because it is used in the K150 clones, meaning that I can make my own version, perhaps using an Arduino type USB-Serial converter module and a similar set of components to the Arduino PIC programmer. There are even design files for the PICkit 2 programmer available online, so if I can configure the programmer to work with the 18F series PIC that’s used in the PICkit 2, then I can work towards building my own version of these.

As I’m working on compatibility with further PICs, I have built a protoshield version, which can sit directly on top of the Uno, making for a quite compact programmer. It even has separate 8-pin and 18-pin sockets for different types of PIC. A further refinement will be the addition of an ICSP breakout board with a ZIF socket (as seen on the K150 board I bought) to make it easier to program multiple chips.

One of the features of the PICkit series of programmers is a “programmer-on-the-go” mode, which can allow the target PIC to be programmed without being connected to a PC. Given that the Arduino has more flash memory than many of the smaller PICs, it should be possible to add this feature, or even add a display and SD card slot to allow selection, loading and programming of different files in the field. In this case, the MicroPro program becomes unnecessary.

Another feature of the PICkit 2 is the ability to control ICSP power and behave as a logic analyser, allowing testing of the target PIC without removing it from the programmer. Although MicroPro does not have the means or commands to control power, a simple switch on the protoshield version should be enough to switch between programming and testing mode.

HOW TO CONSTRUCT A BREAKOUT BOARD WITH AN ICSP HEADER

Because I’ve been working with PICs for a while, I already had a breakout board that I had built – something similar to this could also be done on a breadboard, as it’s not much more than a bunch of connections to suit the PIC that’s being used. In this case, because there is space, I’ve built breakouts for the 12F675 and 16F84A on the same board, with the 12F675 breakout being the small eight-pin socket. Note how one pin is marked on the six-pin header – this is always the VPP pin. Also, note the fact that it’s a six-pin header when it only needs to be five-stem from the layout that Microchip uses on its PICkit programmers.

The important information we need to build the breakout is found in the PIC datasheet; in this case, the IC pinout diagram above can also be found in the 12F675 programming specification. Apart from making sure we know where pin 1 is (if we align the notch on the IC socket with the notch on the diagram, we should be fine), we also need to work out which pins on the PIC correspond to which pins on the ICSP header.

For VPP, VDD and VSS this is easy enough. VPP has other functions, but we can easily find that VPP is one of those functions. For PGD and PGC, it is not so obvious, but in this case, the pins who have ICSP in the name are the ones we need. So ICSPDAT is equivalent to PGD, and ICSPCLK is equivalent to PGC.

From there, it’s a simple case of running connections from the ICSP header to the respective pins. I’ve also added an LED and resistor to GP2 so that I can leave the PIC in circuit for testing.

As long as you have the datasheet for a specific PIC, you should be able to create an equivalent ICSP breakout board to suit it.