Start PIC development in Linux: blinking an LED

While programmers have always had to think creatively to get performance, or correctness, out of their platforms, I know am not alone in thinking that programming today has reached some sort of "peak abstractness" where any reflective or curious person could be overwhelmed by the number, and leakiness, of the abstractions that have accrued between our programming environments and the things we want to accomplish. In some sense, programming today feels no more tangible than a dream.
Luckily for us, it's never been easier to develop for microcontrollers. I think you'll find that it can be refreshing to revisit the roots of software, to commune directly with a processor and thus be either justly rewarded or punished on the basis of your software and your understanding of the microcontroller, rather than swatting at multiple lossy layers of abstractions like a cat trapped behind curtains.
This article will describe how to get started with PIC microcontrollers in Linux. We'll build the canonical introductory project: a blinking LED.

Materials

  1. breadboard
  2. grab bag of capacitors
  3. grab bag of resistors
  4. grab bag of LEDs
  5. solid core hook-up wire
  6. PICkit 2*
  7. PIC12F675
  8. 7805 voltage regulator
  9. 9V battery snap connector
You'll also need a 9V battery. You can get all of these parts at Jameco.
* There is also a PICkit 3, but some people have had difficulty making it work in Linux. Therefore I have not bothered to try it.
For more context, here's a photo of the completed breadboard, with the parts labeled (the PICkit 2 is not in the photo):

Assemble the breadboard

Here's a diagram for the circuit we're going to put together.
The gist of this circuit is that the 9V battery is regulated down to 5V by the 7805 chip, and this 5V is fed into the Vdd pin of the PIC. Pin 7, which we'll control in software from the PIC, is connected to an LED-resistor pair and then ground.
You may have some questions about this circuit.
Why use a voltage regulator? First of all, the PIC that we're using can be driven at a maximum of 5.5V. If you know something, but not enough about electronics, you might be tempted to replace this component with just a resistor, since a resistor will also cause a voltage drop. But the voltage regulator device is designed to give a certain voltage irrespective of input voltage (so long as it falls within, in this case, 7V-30V) and irrespective of current (up to about 1A).
Why the capacitors? Capacitors between a power supply and ground are meant to smooth out voltage ripple, which is the property of non-ideal voltage sources to slightly vary in delivered voltage depending on load or any other factor. A capacitor between supply and ground resists changes in the voltage difference between supply and ground by "filling in" from its store of charge. I'll admit that DC power supply design is a black art to me, and that voltage regulator-plus-capacitors is my belt-and-suspenders method to get a clean (no ripple) voltage source. Note: it's not important that you use the exact capacitance values that I put in the circuit diagram, it only has to be order-of-magnitude correct.
Why the resistor? An LED has little, or no, internal resistance. In the absence of resistance, a voltage source will happily supply all the current it is capable of supplying. This is bad for the LED (which will break down) and bad for the microprocessor which has to supply the current. So we put a resistor in series to limit the current.
Before we continue you should assemble the breadboard. If this is your first time putting together something on a breadboard, you will find this connection diagram useful:

Software

To program a PIC we need several pieces of software. We'll start with pk2cmd, which is a C program supplied by Microchip that interfaces between your computer and the PIC programmer (in our case, the PICkit 2) over USB.
To build pk2cmd you'll need the libusb headers. For example in Ubuntu or Debian do sudo apt-get install libusb-dev. Then:
git clone https://github.com/edmund-huber/pk2cmd make && sudo make install
Now plug in your PICkit 2, and connect the PICkit 2 to the development board that came with it. The development board should have come with a PIC already seated in the socket. Mine came with a PIC16F690:
$ pk2cmd -P Auto-Detect: Found part PIC16F690. Operation Succeeded
This shows that in principle the PICkit 2 is working. Don't worry that we're using the wrong microprocessor yet.
Next, we'll need the tools to compile PIC assembly files to binary. You can install the gputils suite on Ubuntu or Debian with sudo apt-get install gputils. gputils includes an assembler, a disassembler, and other stuff.
So now we'll try to compile a program for the PIC12F675 and upload it. Download blink_led.asm. For reference, here is the program listing:
processor 12F675 org 0 ; This shorthand assigns COUNT1=0x20, COUNT2=0x21, etc. cblock 0x20 COUNT1 COUNT2 COUNT3 endc ; See "Section 27. Device Configuration Bits" of the "PICmicroâ„¢ Mid-Range MCU ; Family Reference Manual" ; (http://ww1.microchip.com/downloads/en/DeviceDoc/33023a.pdf). ; _INTRC_OSC_NOCLKOUT: we want to use the internal oscillator to drive the PIC, ; so that we don't need to connect a crystal, see "Section 2. Oscillator". ; _WDT_OFF: disable the watchdog timer, which if enabled would reset the PIC ; every 18ms, see "Section 26. Watchdog Timer and Sleep Mode". ; ; _PWRTE_ON: enable the power-up timer, which instructs the MPU to wait about ; 72ms to give time for Vdd to reach a stable voltage, see "9.3.3 POWER-UP TIMER ; (PWRT)". ; ; _MCLRE_OFF: if "Master Clear" is enabled, pin 4/GP3 is the reset pin, so ; you'd need to supply Vdd on that pin. By disabling this, GP3 becomes available ; for I/O. #include __config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF ; The PIC assembler will warn every time you try to use a register that isn't ; in Bank 0. The warning is annoying and unnecessary. errorlevel -302 ; See "3.1 GPIO and the TRISIO Registers" in the PIC12F629/675 data sheet. The ; following turns GP0 into an output pin: ; Select Bank 0 of memory by clearing the Register Bank Select bit (RP0) of ; the STATUS register. See "FIGURE 2-2: DATA MEMORY MAP OF THE PIC12F629/675". bcf STATUS, RP0 ; Set byte at address GPIO in Bank 0 to 0, so that digital pin outputs will be ; a known value (0, low). clrf GPIO ; This turns the comparator off, see "FIGURE 6-2: COMPARATOR I/O OPERATING ; MODES". This lets pins GP{0,1,2} act as digital I/O pins. movlw b'111' movwf CMCON ; Select Bank 1. bsf STATUS, RP0 ; Disable analog circuitry on pins AN{0,1,2,3}. bcf ANSEL, ANS0 bcf ANSEL, ANS1 bcf ANSEL, ANS2 bcf ANSEL, ANS3 ; Finally: this turns all pins which can act as digital outputs, into digital ; outputs. clrf TRISIO ; (Done!) ; Back to Bank 0 so that we have access to GPIO. bcf STATUS, RP0 loop ; Generated cycle-accurate delay code using ; http://www.golovchenko.org/cgi-bin/delay . Since the code was generated using ; the assumption that the clock is exactly 4MHZ, this won't create a delay of ; exactly one second, since the internal oscillator is not tuned that well. ;999997 cycles movlw 0x08 movwf COUNT1 movlw 0x2F movwf COUNT2 movlw 0x03 movwf COUNT3 Delay_0 decfsz COUNT1, f goto $+2 decfsz COUNT2, f goto $+2 decfsz COUNT3, f goto Delay_0 ;3 cycles goto $+1 nop movlw 63 movwf COUNT1 ; Toggle the LED every second. movlw b'00000001' xorwf GPIO, 1 ; Repeat this forever. goto loop end
Compile that file to blink_led.hex:
$ gpasm blink_led.asm -o blink_led.hex
Now we have a binary. The next step is to program the PIC with this new binary. So, we need to get the (in my case) PIC16F690 out of its socket and put in the PIC12F675. Sometimes the manufacturer really jams the microprocessor in the programmer socket. You can use a small slotted screwdriver to lever the chip out from under the top and bottom ends. Take care to put the PIC12F675 in with the little tab on the package matching the tab cutout on the programmer socket. The PICkit 2 can remain connected to your PC during all this.
With your PIC12F675 seated in the socket, let's program it:
$ pk2cmd -PPIC12F675 -M -F blink_led.hex PICkit 2 Program Report 5-7-2015, 19:56:04 Device Type: PIC12F675 Program Succeeded. Operation Succeeded
Now, simply take the PIC out and put it in the breadboard as illustrated earlier. Connect the 9V and you should see a blinking LED.