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.
This is the EEPROM programmer I built to connect the chip to my desktop computer. It interfaces through the RS232 serial port. All it is are three 5V zener diodes ($1) and three 4.7K ohm resistors ($1). The rest is some 22 AWG hookup wire and a breadboard ($5). And here’s my programmer.
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 (Updated to PICkit 4), 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.
SIMPLE EPROM PROGRAMMER A simple EPROM programmer is described here. It connects to a PC's parallel port and can program EPROMs from 2716 to 27512. The design can be expanded to program even larger EPROMs. DOS based software is available to program EPROMS from various data file formats. EPROM Programmer Design This programmer is shown in. 93Cx6 Programmer is a software designed for writing/reading Serial Microwire BUS EEPROM. The interface is actually a DB25 jack, an 8 pin socket and a capacitor. The application was tested on Intel.
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 compatible 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.
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.
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.
The pins are wired up to an Arduino compatible 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 based 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.
TX | RX |
---|---|
x50 | - |
x03 | x50 |
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 based PIC programmer supports these. Some PICs use different commands for different functions, which is part of the difficulty in building a universal programmer.
Parts Required: | Jaycar | Altronics |
---|---|---|
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 |
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. ››
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. I 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):
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.
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.
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.
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.
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.
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 based 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.
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.
2003-04-18
Here is a simple serial (I2C) EEPROM programmer for the PC parallel port. I built it to program 24XX devices, but it can, in principle at least, talk to any I2C device with a suitable adapter or fly-lead, it implements a complete I2C bus interface.
The original prototype and control software was developed against a 24LC16B device, but has since been extended and tested against the 24LCX range with X in { 08, 16, 21, 32, 64, 128, 256 }. It should work fine with other 24X I2C EEPROM devices, perhaps with slight changes to the addressing logic and sizing for larger devices like the 24LC512 (and 24LC1024 when it becomes available). Adding an extra device is generally just a matter of adding an extra struct near the top of 24xx.c and recompiling.
One exception might be the power supply. The 24LC16B and other similar chips pull just a little more than 3 mA when writing to power the internal programming voltage generator (less when reading, and virtually nothing in standby). The programmer is port powered but the parallel port outputs are specified to source only 3.5 mA. That is cutting it a bit fine, but in practice it has worked perfectly on several different PC parallel ports.
Power is sourced from the C0 bit, on some weird parallel ports this may be open collector rather than being capable of sourcing current. If yours is one of them, or you suffer other power problems, you can try pulling power from D2-D7 and C2-C3 with extra diodes, they are all pulled up by the software. If all else fails, supply an external 5 V supply. The diodes will protect the port if external power is supplied, especially if you intend to use the programmer as a generic I2C interface.
Note the switch/jumper in the diagram that allows selection of the state of the /WP signal on most devices. This was added after support for the 24LC21A was requested by Miika Ahdesmäki. The 24LC21A's /VCLK signal has the opposite sense to the usual /WP, as do several others designed for plug-n-play data service. The driver was also modified to pre-clock it as per the requirements in its datasheet to get it into the bi-directional operation mode.
A bi-directional parallel port is not required as the SDA and SCL lines are read through the Error and Paper-Out status bits (S3 and S4). The C1 bit drives a power indicating red LED (or a 'don't remove chip' warning if you prefer). The D0 and D1 lines drive the pull-down of SDA and SCL, they have a yellow and green LED to display their states. (The state of the pull-down drive, not SDA and SCL themselves! You may wish to add two more transistors to drive the LEDs from the bus state instead, making them more useful.)
You can download my Linux user space programmer drivers. They call ioperm() to establish access to the I/O space for the parallel port so they must be run as root, or setuid root. Currently the I/O base is hardcoded for the 1st parallel port at 0x378. The code is interactive, entering '?' at the prompt will give you a list of options:
Commands: q Quit ? This usage message d Dump EEPROM, as hex D <start> <len> Dump EEPROM, as hex f <value> Erase EEPROM, filling with value r <filename> Dump EEPROM into raw binary file w <filename> Program EEPROM from raw binary file t <type> Set EEPROM device type (as 24C<type>) p <delay> Set delay between I2C transitions (for slower devices)
It is fairly primitive right now, it only supports raw binary input and output files, but I intend to add support all the common hex-file formats. It already has the option to dump the data pretty-printed in hex for manual inspection, and can fill the device with a specified byte to clear it or test it for bit failures near its end of life.
It would not be very challenging to make this code portable to Win32 console, just replace the inb/outb() and ioperm() calls. All else should port directly. This is true for all remotely POSIX systems, as long as they have some facility to allow user space programs to invoke I/O instructions.
10 comments.