How to Program a PIC microcontroller using a Raspberry Pi or Orange Pi Plus 2

I use PIC microcontrollers for many of the projects I work on, including the PedalPC. I like using them because:

  • they have a wide variety of useful peripherals, like 12-bit differential ADCs and on-board Full Speed USB 2.0,
  • they're inexpensive (about 1/3 to 1/2 the cost of comparable AVR microcontrollers when you're purchasing them in low quantities like I do), and
  • almost all chips with 40 pins or less are available in an easy-to-use DIP form factor.

Compiling programs for PIC microcontrollers is easy on a low-resource single board computer like a Raspberry Pi using open-source program languages like Great Cow Basic or JAL. (I will describe how to do this in another post).

The challenge is how to get the compiled programs onto the chip. The usual technique is to use a dedicated external device (called a programmer) that attaches both to your computer and to the chip and transfers the compiled program into the memory of the microcontroller.

These programmers can be somewhat expensive (usually at least $30) and are another piece of specialized hardware you have to keep around.

However, with the right software and a few resistors, you can transfer your programs directly to your PIC using the GPIO pins of a single-board computer (SBC) like a Raspberry Pi or Orange Pi.

In this tutorial, I will explain how to:

  1. install the software needed to program the PIC,
  2. connect the PIC to the GPIO pins on your single-board computer,
  3. create the configuration file required by the program,
  4. install a driver if your computer is unsupported,
  5. and check your system to make sure it's working properly.

The in-circuit serial programming (ICSP) software we'll be using in this tutorial is an excellent utility called Pickle written by Darron Broad. It works with many single-board computers running Linux, and requires only a few resistors to successfully program most PICS at 3.3V. (Programming a 5V PIC in-circuit will require an inexpensive 4-channel 5V-to-3.3V logic level converter, which are widely available on eBay and other sites.)

This method works only with PIC microcontrollers that can be programmed using the low-voltage programming (LVP) method, which includes most common PICs in use today. (Darron has a list of supported PIC microcontrollers on his site as well as a large table of PICs that have been tested.) It will not work with older chips that require the high-voltage programming (HVP) method. For those chips, you'll need a programmer, not just a few resistors or level converter.

Installing the Software

Use the following commands to install the Pickle ICSP program onto your SBC:

cd /tmp
tar zxf pickle-4.0f.tar.gz 
cd pickle/
sudo make install

This compiles and installs the Pickle utilities in /usr/local/bin on your SBC.

Choose Your Programming Pins

You'll need 3 (or 4) GPIO pins to connect to VPP, PGC, and PGD (and PGM, if your PIC requires it--most chips nowadays don't.) These pins can't currently be in use by your kernel. You can see the GPIO pins being used by:

ls /sys/class/gpio | grep gpio{0,1,2,3,4,5,6,7,8,9,_}

If no pins are listed, then you can choose any of the available GPIO pins on your board. If you need to use a pin already in use, you can make it available this way:

sudo echo <pin number> | /sys/class/gpio/unexport

Here's a list of the Raspberry Pi's GPIO pins:

Raspberry Pi 2 and 3 GPIO pins
header pin function header pin function
01 3V3 02 5V
03 GPIO0/GPIO2 04 5V
07 GPIO4 08 GPIO14/TX
09 GND 10 GPIO15/RX
11 GPIO17 12 GPIO18
13 GPIO21/GPIO27 14 GND
15 GPIO22 16 GPIO23
17 3V3 18 GPIO24
19 GPIO10 20 GND
21 GPIO9 22 GPIO25
23 GPIO11 24 GPIO8
25 GND 26 GPIO7
29 GPIO5 30 GND
31 GPIO6 32 GPIO12
33 GPIO13 34 GND
35 GPIO19 36 GPIO16
37 GPIO26 38 GPIO20
39 GND 40 GPIO21

Raspberry Pi 2 and 3 GPIO pins

For the Raspberry Pi 2 or 3, I recommend using GPIO_9, GPIO_10, and GPIO_11.

Here's a list of the pins on the Orange Pi+ 2:

Orange Pi Plus 2 40-pin header
pin function sysfs GPIO number pin function sysfs GPIO number
1 3.3V 2 VCC-5V
7 PA6 (SIM_PWREN/PWM1/PA_EINT6) gpio_6 8 PA13 (SPI1_CS/UART3_TX/PA_EINT13) gpio_13
9 GND 10 PA14 (SPI1_CLK/UART3_RX/PA_EINT14) gpio_14
13 PA0 (UART2_TX/JTAG_MS0/PA_EINT0) gpio_0 14 GND
15 PA3 (UART2_CTS/JTAG_DI0/PA_EINT3) gpio_3 16 PC4 (NAND_CE0) gpio_68
17 3.3V 18 PC7 (NAND_RB1) gpio_71
25 GND 26 PA21 (PCM0_DIN/SIM_VPPPP/PA_EINT21) gpio_21
29 PA7 (SIM_CLK/PA_EINT7) gpio_7 30 GND
31 PA8 (SIM_DATA/PA_EINT8) gpio_8 32 PG8 (UART1_RTS/PG_EINT8) gpio_200
33 PA9 (SIM_RST/PA_EINT9) gpio_9 34 GND
35 PA10 (SIM_DET/PA_EINT10) gpio_10 36 PG9 (UART1_CTS/PG_EINT9) gpio_201
37 PA20 (PCM0_DOUT/SIM_VPPEN/PA_EINT20) NA 38 PG6 (UART1_TX/PG_EINT6) gpio_198
39 GND 40 PG7 (UART1_RX/PG_EINT7) gpio_199

For this board, I recommend using gpio_13, gpio_14, and gpio_110.

(A sidenote: It took me a while to figure out how the pins are numbered on the Orange Pi boards.

The GPIO pins are identifed by a letter corresponding to a bank location and a two-digit number associated with its position in that bank. For instance, pin "PD14", which is in the 12th position on the header, is the 14th pin in bank "D".

This letter-and-number system must be converted to a pure number that Linux's sysfs understands. The formula to do this is:

GPIO number = (position of letter in alphabet - 1) x 32 + pin number

For this pin, since "D" is the fourth letter of the alphabet :

GPIO number = (4 - 1) x 32 + 14 = 110

Therefore, header pin #12 is gpio_110.

I used this formula to calculate the pin numbers listed in the table. The table is taken from the linux-sunxi wiki) for the Orange Pi Plus 2 board. Other Orange Pi boards may have diffferent configurations. See their corresponding page on the linux-sunxi wiki.)

Note that not all of the I/0 pins available on the header will be available for use as general-purpose I/0 pins. I determined the ones which are available by reading the script.bin configuration file in the boot folder:

sudo bin2fex /boot/script.bin | grep gpio_

This works only for the legacy (3.x) kernels. You can determine which Linux kernel you are using via.

user@orangepiplus:~$ sudo uname -a
[sudo] password for user: 
Linux orangepiplus 3.4.112-sun8i #14 SMP PREEMPT Tue Jul 5 16:28:14 CEST 2016 armv7l GNU/Linux

The version number is listed after the words 'Linux' and your hostname. In this case, it's 3.4.112. If it's less than 4, you are using a 'Legacy' kernel. If it's > 4, then you're using a 'vanilla' kernel. These newer kernels have a different configuration system known as a 'device tree'. Follow these instructions to view your settings.)

Creating the Configuration File

Pickle requires a configuration file to know which pins to use to program your PIC and what procedure it should follow when programming the chip. The file is named '.pickle' and stored in your home directory.

A sample file is created when you install the software. You can either edit the existing file or create a new one.

You can run this command to create 's the file you need for a Raspberry Pi 2 or Raspberry Pi 3:

cat > .pickle <<EOF
# set PGM = -1 if not used, otherwise use the correct pin number below

In this configuration, GPIO pins 9, 10, and 11 of the Raspberry Pi will be connected to the VPP, PGC, and PGD pins on the microcontroller. PGM won't be used.

Here's the command to run to create the configuration file for an Orange Pi+ 2:

cat > .pickle <<EOF
# Linux bit-banging GPIO
# original Orange Pi or Mini
# Orange Pi Zero
# Orange Pi Plus or Orange Pi Plus 2
# I/O bit rules.
#       These rules determine the polarity of the control lines and whether
#       data input requires data output pulled high.
# 0x0001 PGD_OUT_FLIP
# 0x0002 PGC_OUT_FLIP
# 0x0004 VPP_OUT_FLIP
# 0x0008 PGD_IN_FLIP
# 0x0010 PGD_IN_PULLUP
# 0x0020 PGM_OUT_FLIP
# 0x0040 VPP_OUT_CLOCK
#       These rules are for GPIOs on program exit.
# 0x0100 PGD_RELEASE
# 0x0200 PGC_RELEASE
# 0x0400 PGM_RELEASE
# 0x0800 VPP_RELEASE
# 0x1000 VPP_RUN
#       This rule enables shift with irq lock for GPIO BIT-BANG.
# 0x2000 BB_LOCK
#       This rule re-enables the ALT0 function when an R-PI GPIO is released.
# 0x4000 ALT_RELEASE
# We want VPP in 'run' mode and PGC & PGD released for use by UART3
#PGD - pin #8 (PA13/UART3_TX -> sysfs 13)
# Note: PGD can also be UART_RX on many PICs
#PGC - pin #10 (PA14/UART3_RX -> sysfs 14)
# Note: PGC can also be UART_TX on many PICs
#VPP - pin #12 (PD14 -> sysfs 110)
#PGM - not used

Here, we're using gpio_13 for PGD, gpio_14 for PGC, and gpio_110 for VPP. I chose these particular pins because some PICs (like the 16f1788 I'm currently using) have an alternate mapping of their serial Tx and Rx pins over the PGC and PGD pins, respectively. This allows me to use the same lines to both program the chip and send and receive data. This frees up two extra pins on both the board and the chip.

This is how it looks when wired to my Orange Pi Plus 2 board:

PIC ICSP wiring for an Orange Pi Plus 2

The leads in the photo above above are wired as follows:

  1. VDD
  2. PGD
  3. PGC
  4. VPP
  5. GND

Install Bit-Bang Driver (for non-supported boards only)

Pickle supports all Raspberry Pi boards, and support was added for most Orange Pi boards since version 4.0f. If your board is not supported, you will need to install Darron Broad's Linux bit-bang driver. First, install Mercurial if it isn't installed on your Pi already:

sudo apt-get install mercurial

Next, clone his repository and run the install script:

hg clone
cd gpio-bb
sudo make install

It should now show up in your list of installed modules:

lsmod | grep gpio_bb

As installed, you'll need to be root to use the bit-bang driver (and therefore program your chip). To change that, create a group for users of the driver and add yourself to the group:

sudo addgroup gpiobb
sudo chgrp gpiobb /dev/gpio-bb
sudo adduser your_username gpiobb

Update the modprobe configuration file so it will load each time you reboot your machine by adding this to /etc/modprobe.d/modprobe.conf (you may need to create the file if it doesn't exist):

install gpio-bb modprobe --ignore-install gpio-bb && modprobe gpio-bb && mknod /dev/gpio-bb c 180 0 && chmod 666 /dev/gpio-bb && chgrp gpiobb /dev/gpio-bb

Finally, add the following to your /etc/modules file:


Checking Your Configuration

Once everything is installed, wire your chip to the GPIO pins on your board using the pins you selected in your .pickle file. (Darron recommends putting a ~470 ohm resistor in series in each of the programming and Vpp lines to prevent damage in case you make a mistake.) Be sure to wire the ground line, too, as well as the 3.3V line if you device is not self-powered.

If your device is self-powered by 5V at the time you're programming it, you'll need to use a 4-channel 3.3V-to-5V level converter between your device and your SBC, because most SBC GPIO pins are 3.3V.

Once this is done, run the following command if you're using a 16F series chip:

p14 lvp id

If you're using a 18F chip, run:

p18 lvp id

You should get something back like:

[0000] [PROGRAM]  4000 WORDS (0200 ROWS OF 0020 WORDS)
[8000] [USERID0]  3FFF .
[8001] [USERID1]  3FFF .
[8002] [USERID2]  3FFF .
[8003] [USERID3]  3FFF .
[8004] [RESERVED] 3FFF
[8005] [REVISION] 2041 REV:041
[8006] [DEVICEID] 302A DEV:302A PIC16F1789
[8007] [CONFIG1]  39E4
[8008] [CONFIG2]  3FFF
[8009] [CALIB1]   314D
[800A] [CALIB2]   1D49
[800B] [CALIB3]   3FFD
[800C] [CALIB4]   3A87
[800D] [CALIB5]   3FFF
[800E] [CALIB6]   3887
[800F] [CALIB7]   3988
[8010] [CALIB8]   3B86
[8011] [CALIB9]   3FCF
[8012] [CALIB10]  3FD4
[8013] [CALIB11]  3FD7
[F000] [DATA]     0100 BYTES

If you get:

pic14_read_config_memory: information: device not detected.

either it's wired wrong on your have something wrong in your configuration file. Connect an LED and resistor in series between VPP and ground, then run the following command:

ptest VPP 5

The LED should blink. Repeat for PGC and PGC as well.

If an LED blinks in each situation but one, then you either are using the wrong GPIO pin or that pin isn't configured correctly.

If none of the LEDs blink, check your configuration settings, make sure your board has power, and you have permissions set correctly.

written by
Jim Gregory (contact)
2016-10-18 updated


RSS feed