Ingredients and Goal
Presumably you already have a pickit2, some board you can use to program PICs (I have a handy 28 pin demo board) and a computer. You need three additional things: a text editor for writing C, a compiler for turning it into a hex executable and a utility to copy the compiled program onto the device, via the pickit2.
Once you’re finished you’ll be able to write, compile, burn and run C programs on PICs via your pickit2 like this:
$ edit main.c
(write C program in external editor)
$ xc8 main.c --outdir=build --chip=16F886
$ pk2cmd -Fbuild/main.hex -PPIC16F886 -T
Text Editor
Any plain text or code editor will suffice for writing basic embedded C applications. I like TextWrangler, so much so I am writing this article in it, but any code editor will do. If it has syntax highlighting for C, all the better.
Compiler
After a long period of PIC compiler fragmentation, Microchip has released the XC8 compiler as the canonical C compiler for PIC, and there’s a free version.
After the download is complete, open the installer and follow through the installation process. If you’re using a non-bash shell you’ll have to add Applications/microchip/xc8/v1.30/bin
to your PATH.
Now you not only have the xc8
compiler available, you also have a whole bunch of documentation and device-specific header files in /Applications/microchip/xc8
.
docs/
contains PDF documentation of the compiler and C used (MPLAB_XC8_C_Compiler_User_Guide.pdf
), as well as a bunch of HTML documents detailing the config options available to each different chip.
include/
contains header files for each chip, as well as various libraries.
xc.h
is the top-level file you include in your application. It automatically figures out which PIC you’re targeting and includes other relevant headers. plib/
contains a bunch of PIC18 peripheral libraries. There are various other header files which reward study scattered around in here too.
Barebones C program
This is the smallest meaningful PIC C program:
#include <xc.h>
#include <stdbool.h>
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config DEBUG = OFF
#pragma config FOSC = INTRC_NOCLKOUT
#pragma config FCMEN = OFF
#pragma config MCLRE = OFF
#pragma config WDTE = OFF
#pragma config CP = OFF
#pragma config LVP = OFF
#pragma config PWRTE = OFF
void init(void) {
// 4MHz clock
OSCCON = 0b01100000;
TRISA = 0;
TRISB = 0;
TRISC = 0;
}
void main(void) {
init();
PORTA = 0b111111;
PORTB = 0b11111111;
PORTC = 0b11111111;
while (true)
NOP();
}
The #include
directives include xc.h
, which automatically includes the header file for the chip as mentioned above, and stdbool.h
, which defines true
and false
as 1 and 0, respectively.
The #pragma config
directives set chip-specific config options as defined in the chip’s datasheet and in the HTML file for the device. In this case we are turning all the interesting features off and telling the device to use the internal oscillator without exposing the signal on a pin.
void init(void)
is a function which sets up the PIC by setting the internal clock to run at 4MHz, and setting all of the available digital IO pins to outputs. 0bXXXXXXXX
is a binary literal, e.g. 0b0
is zero, 0b1
is one, 0b10
is two, etc.
void main(void)
is the function which is called when the PIC is turned on. It calls init()
to set up the device, then raises all of the available outputs. If you have a different device you may have to change the PORT references or lengths of the numbers here. The PIC16F886 just happens to have three ports, one of which has only six pins. Refer to your datasheet or CHIP.h file.
Finally we enter an endless loop of NOP()
s (no-operation), which prevents the PIC from shutting down. If we didn’t do this the LEDs would be lit for a small fraction of a second and we would be left wondering why our program didn’t work.
Write this out as main.c
somewhere and compile it as so, replacing 16F886 with the part number you’re using:
$ xc8 main.c --outdir=build --chip=16F886
You should now have a build/
folder containing a bunch of files, including main.hex
.
Burning a program to the device
For this you will need the free pk2cmd
utility offered by microchip for command-line control of the pickit2 device over USB.
I defer to Curuxa’s installation instructions. If compiling from source (you will probably have to) replace make linux
with make mac105
.
I use the following homebrew formula to install pk2cmd. Use with brew edit pk2cmd
, paste this code in, save, then brew install pk2cmd
.
require "formula"
class Pk2cmd < Formula
homepage "http://microchip.com/pickit2"
url "http://ww1.microchip.com/downloads/en/DeviceDoc/pk2cmdv1.20LinuxMacSource.tar.gz"
sha1 "19e90a665caef6d993820ce6c7ace5416b656f47"
version "1.20"
depends_on "libusb"
def install
system "make mac105"
bin.install "pk2cmd", "PK2DeviceFile.dat", "PK2V023200.hex", "usbhotplug.txt"
doc.install "ReadmeForPK2CMDLinux2-6.txt"
end
test do
system "pk2cmd"
end
end
At some point I might try getting this merged into homebrew core.
pk2cmd
is rather a weird command-line application. Every command you run demands the -P
option, which specifies the device you’re using, e.g. -PPIC16F886
. Basic commands:
pk2cmd -Fbuild/main.hex -M -PPIC16F886
burns your program to the device by writing the contents of themain.hex
F
ile to the PICsM
emorypk2cmd -A5.0 -T -PPIC16F886
powers theT
arget boardA
t 5Vpk2cmd -PPIC16F886
turns off power to the target board
Next Steps
Now you should have some pretty LEDs lit up as well as a minimal edit/compile/deploy workflow. The next steps depend on your personal interest, project and skill level.
I uploaded the source code for this project to github: barnabywalters/barebones-xc8. It has a few little command line tools you might find interesting or useful.
If like me you don’t know C, work through c.learncodethehardway.org/book. Not all of it will be relevant to embedded C (case in point: lack of filesystem) but it’s solid stuff nonetheless.
You’ll probably need to read through the datasheet for your device to get a feel for what it’s capable of and how to use it. If you’re using a PIC18 device, check out the plib
for ready-built peripheral libraries. Otherwise, look through your datasheet, chip header file and chip HTML file.
Again, using PICs seems a little masochistic in a world where Arduino is so widely available. Perhaps you should consider whether or not it’s really a good idea to use them for your project. Either way, the option is now available to you.