This is probably not what you think it is. It is not an application that controls ICD2, PicKit2 or any form of custom LPT PIC programmer for a PC (you can use MPLAB X for that). What lpicp does is provide a user space application and kernel driver to perform the functionality of a PIC programmer on embedded systems running Linux. After deploying these modules onto such a system (and assuming the hardware is layed out properly), you can run something like:
lpicp -x write -d /dev/icsp0 -f my-pic-program.hex
and have your embedded system program a Microchip PIC microcontroller via an ICSP bus.
Implementing the ICSP protocol and bus
Microchip has devised a simple 4 wire bus to allow for programming the PIC devices. In reality, the majority of the physical protocol is over 2 wires – pgc (clock) and pgd (data). The bus master (the programmer) clocks out 4 command bits followed by 16 data bits. The commands are specified in the flash programming spec for each device but they can be divided into three main groups:
- Execute instruction
To implement a high level operation like reading a device requires a mixture of commands, spanning across all the three groups; simplisticly you’d have to execute instructions to prepare the PIC, write the address pointer and read data. You really must read the flash programming spec to understand the specifics, but the jist is the same for all high level operations (erase/read/write).
Since no hardware controller exists for operating the bus transactions, we are required to bit bang it. The hardware protocol itself is very simple (although very inconsistent across operations and devices). I had the option of implementing the bus protocol entirely in userspace and using the platform independent GPIO infrastructure but this does not achieve the desired bus timing (despite the fact that the PICs are very lax in their timing, especially in maximum values, I still wanted the bus to look as clean as possible).
To do this, I offloaded all bus transactions to a platform driver (mc_icsp) using callbacks to the platform (which toggles the GPIOs). All timing is configured when registering the platform driver and user space interacts with it via /dev using 4 ioctls:
- transmit: send 4 bit command and write 16 bits of data
- receive: send 4 bit command and read 16 bits of data
- send command only: send only the 4 bit command with a configurable waveform
- send data only: send only 16 bits of data
The user space application, lpicp, takes care of receiving the command from the user, parsing Intel HEX records and performing the higher levels ICSP protocol. This is very device specific so there is framework in place to allow for adding devices without ugly ifs() and #ifdefs.
The application is built using cmake, which outputs liblpicp.a and an lpicp executable. The executable adds a command line layer, but you can just as well link to liblpicp.a to integrate PIC programming into your application. The lpicp executable can be run with the following arguments:
- -x, –exec: r, read | w, write | e, erase | devid
- -d, –dev: ICSP device name (e.g. /dev/icsp0)
- -f, –file: Path to Intel HEX file
- -o, –offset: Read from offset, Write to offset
- -s, –size: Size for operation, in bytes
- -v, –verbose: Verbose operation
The application uses libGIS‘s ihex.c module to parse the Intel HEX record file outputted by PIC compilers. The files contain data records to be written to program, configuration and eeprom memory. The application knows where to burn each record according to its address.
Getting the source
This project is really in its infancy and will probably only ever serve as reference. I was contracted to implement this for PIC18F452 and PIC18F4520 and this is what works. Browse the README @ github to understand the limitations of the current version and build instructions.
You can get the lpicp code @ the lpicp github repo and the driver can be found here.