Budding electronics hobbyists and `software' guys who aren't too intimidated by the prospect of taking up the soldering iron once in a while would love to hack on the Microchip family of controllers - cheap, electrically robust, feature rich and with an incredibly easy to learn (and use) instruction set, they are ideal for doing a whole lot of cool things. In this article, I review the use of a few Linux tools using which you can get started with programming any one of the dozens of PIC's out there in the market. And yes, you won't have to spend lots of money on hardware and software - the hardware is simple, do-it-yourself stuff, and the software is freely available - thanks to the effort of a lot of great developers.

What is a Microcontroller?

I suppose I won't hear too many people asking this question. But then, just in case ...

A microcontroller is a sort of `single chip computer'. If you wish to design a computer system using the classical microprocessor, you need to get a lot of extra components (RAM/ROM, I/O ports, timers/counters, glue logic) and wire them up together - which isn't a very simple thing to do (and is expensive also). A microcontroller integrates all these essential components into a single package. You will need very little extra components (other than the power supply) to get your program running. The controller as such is not `cutting edge' technology - it's what you can do with it which is really interesting. Here is a picture of my tiny 8 pin PIC running an LED blinking program - note the absolute lack of extra components. The blue and black wires provide +5V and Ground - then there is the LED, which is placed in series with a resistor.

You are looking at the PIC12F675 in action. This is an inexpensive device which packs a lot of punch in a really small footprint. Before we discuss this device, a few things about the Microchip family.

Microchip brings out a lot of microcontrollers - many of them targetted at specific applications. These are available as either one time programmable, EPROM or flash memory based packages. The hobbyist should go for the flash version, because it is easy to reprogram the part. For many years, the `de facto' entry level PIC was the 16F84. Now, it seems the 16F628 is ready to take on the mantle (I haven't used this part, but hope to do so soon). If you wish to do ADC stuff, and don't want too many I/O pins, the tiny 12F675 might be ideal for your need.

Getting Started

Choosing a PIC to get started depends on many things - cost of the part, the components which you wish to be included in the part, the platform on which you will be developing applications (which, as far as we are concerned, is definitely Linux), the tools available for development on that platform and availability of programmer hardware (do-it-yourself would be great).

PIC programs are almost always coded in assembly language (there are C compiler implementations, and specialized languages like `Jal'). The PIC instruction set is not friendly towards high level languages which depend a lot on stack manipulations and different kinds of addressing modes. I suppose nobody would write a GCC backend for it! But the good thing is that PIC assembly is easy to learn - only 35 instructions, most of which are well designed. There is an excellent package, called GNU PIC Utilities which includes an assembler, GPASM using which you can convert your PIC assembly language program to Intel Hex file format. The assembler supports almost all the PIC's in the market.

After converting your program to Hex code, you will have to `program' it into the PIC. You will need programming hardware as well as software. Again, the good news is that there are plenty of simple, parallel port based do-it-yourself circuits available on the web - most of which are based on David Tait's classical parallel port programmer. The circuit can be built in an hour on a prototype board and works without any trouble. It can be adapted to work with, say, the PIC12F675.

Once the hardware is built, you start searching for programming software - again, you will be happy to see that there is a project which brings out a package using which you can program almost any PIC on Linux. It is available for download from here.

So you see that using Linux as your development platform does not in any way restrict you in your choice of the PIC part which you wish to use. For the rest of this article, I shall demonstrate how I went about programming the PIC12F675 on Linux.

The PIC12F675

This `tiny' PIC can run at a speed of 20MHz and is packed with:

and many other goodies!

My first step was to adapt the David Tait parallel port programmer (which seems to have been designed with parts like 16F84 in mind) to work with the tiny PIC. The PC sends hex files over to the PIC through two lines - RB6 and RB7 in the case of PIC16F84. RB6 is the serial programming clock and RB7 is data. The corresponding pins on the 12F675 are GP1 and GP0 (pins 6 and 7 of the 8 pin package).

The next step was to test whether the circuit works fine by using the pplin program available from the PP06 Project home page. I first wrote a simple assembly language program, `a.s':

	list p=12f675
main:
	movlw 0x0
	end
Using the gpasm program, this file was assembled to Intel hex format. The hex file was next transferred to the program memory of the microcontroller by running pplin:
pplin -device=12F675 -hw=3 -xt -notest a.hex

The body of the assembly language program is simple to understand. The first statement is an `assembler directive' which tells gpasm that code is to be generated for the PIC12F675. The label `main' is not really significant - I use it as a convention. The statement `movlw 0x0' stores the `literal' (ie, constant) value 0x0 to the W register (accumulator) of the PIC. The last statement `end', tells the assembler that our source file is complete at that point.

The pplin program accepts a lot of command line arguments. The -hw=3 option tells it that we are using the David Tait parallel port programmer whose schematic is given here; pplin can be used with many other types of hardware programmers. The -device=12F675 option identifies the device which we have placed on the programming circuit. The -xt option sets some `configuration bits' in the PIC which basically lets it run with a 4MHz crystal connected to its OSC1 and OSC2 pins (you should be having the Microchip datasheets near at hand - it's impossible to work without them). I don't have a clear idea as to what -notest does, but once I power on my home made programming board and place the PIC in it, pplin refuses to work properly without the -notest option.

This assembly language program doesn't do anything useful - we can't really verify whether it is running or not. So, my next step was to write and run the great `LED Blinker'.

Blinking LED's

Here is a small program which when executed on the PIC12F675 with an external 4MHz clock will blink an LED connected to the GP0 pin.


; An LED Blinker
; Around 10 times per second

	list p=12f675
	include "p12f675.inc"

small_delay_tmp	equ	0x20
long_delay_tmp	equ	0x21

	goto main

small_delay:
	movlw 0xff
	movwf small_delay_tmp
small_delay_L1:
	decfsz small_delay_tmp, F
	goto small_delay_L1
	return

; ----------------------------
; W contains count on entry.
; Store it in a temp variable.
; Keep on decrementing and
; calling small_delay
; ----------------------------
	
long_delay:
	movwf long_delay_tmp
long_delay_L1:
	call small_delay
	decfsz long_delay_tmp, F
	goto long_delay_L1
	return

; ----------------------------
; Here comes the main LED blinker
; ----------------------------

main:

	bcf STATUS, RP0
	clrf GPIO
	movlw 0x7
	movwf CMCON ; disable comparator
	bsf STATUS, RP0
	movlw 0x0
	movwf TRISIO ; All pins outputs
	bcf STATUS, RP0

infinite:
	bcf GPIO, GP0
	movlw 0x82
	call long_delay
	bsf GPIO, GP0
	movlw 0x82
	call long_delay
	goto infinite
	
	end

Let's have a quick walk through the code. The 12F675 has 64 bytes of data memory (SRAM) which are accessed by addresses in the range 0x20 to 0x5f. The machine code of the program is stored in 1K locations of flash memory. Let's first look at the function small_delay. A count 0xff is loaded into memory location 0x20 (movwf copies a value in the W register to a memory location). The instruction decfsz long_delay_tmp, F finds out the value of (long_delay_tmp - 1) and stores it in long_delay_tmp itself. If the result is zero, the next instruction is skipped (PIC instructions are rather poetic to read - decrement f and skip if zero). Note that the first `f' identifies the fact that long_delay_tmp (ie, 0x20) will be interpreted as a memory location (and not a constant). The `F' which comes as the second operand indicates the fact that the result of subtracting 1 will be stored in long_delay_tmp itself. Had that been a `W', the result would be stored in the accumulator. Each instruction takes 4 clock cycles (as our clock is 4MHz, time for each instruction is 1micro second) - except the goto (which takes 2*4 clock cycles) and the decfsz which takes 2*4 clock cycles if the next instruction is skipped and 4 clock cycles if the next instruction is not skipped. The `call' and `return' instructions also consume 2*4 clock cycles. Using these values, it is easy to compute the amount of time one invocation of small_delay would consume.

Let's now look at the main program. All the PIC12F675 (except the +5V and Gnd pins) are multifunction. The GPO, GP1 and GP2 pins act as the two inputs and the output of an analog comparator module. These pins can also act as digital I/O pins. In our program, we do not need the comparator functionality, so we turn it off by writing a particular bit pattern to the Comparator Control Register, CMCON. Now, you can decide whether you want the I/O pins to act as inputs or outps. If a particular bit of the TRISIO register is 0, then a corresponding I/O pin will act as an output pin, and if it is 1, as input. The TRISIO register can be accessed only after performing a `bank switch' (which is what the bsf STATUS, RP0 does. The instructions bsf and bcf turn on/off one bit of an eight bit register/memory location. The register/memory location is the first operand and the bit number is the second operand).

The remaining part of `main' is a simple infinite loop which turns off GPO, executes a delay loop, turns it on, again executing a delay loop. An LED connected to pin 7 (GP0) should start blinking.

The `Running Circuit'

The only thing remaining is to build a circuit and test run the program. This can be done in 5 minutes. The 12F675 does not need anything more sophisticated than a crystal to get started (even that can be avoided by using the internal oscillator). Here is the circuit:

Changing the configuration word

Internal to the PIC, there is a special `configuration word' the values of individual bits of which control stuff like whether code protection should be enabled or disabled, whether the watchdog timer should be enabled, whether the MCLR pin should be externally tied to Vcc or not etc. There are two ways in which this configuration word can be programmed. One, by giving options to pplin. The -rc0 option, for examples, enables the internal RC oscillator and frees up pins GP5 and GP4 for other uses. Another way is to specify, in the assembly language program itself, via an assembly language directive which all bits should be set/cleared. For example, if I place the following line in the beginning of the my source file (after I have included the standard header file p12f675.inc which is part of the gputils distribution):


	__CONFIG _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_OFF &_PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT

I disable lots of stuff like code protection, watchdog timer etc and enable the internal RC oscillator. With a little bit of help from the Microchip datasheet, you should now be able to write an LED blinking program which works without an external oscillator! (the internal timer should be calibrated, details are found in the manual)

Using the internal Analog Comparator

The tiny PIC has an analog comparator as well as an ADC for doing mixed analog-digital design. The comparator is fairly easy to use - its two inputs are pin numbers 7 and 6 and output can be connected to pin number 5 under software control.

The comparator can be configured to work in different modes. In mode3, the positive input of the comparator is taken from an internal programmable voltage reference. The negative input is taken from the GP1/CIN- pin. The mode is set by writing to the CMCON register. In this mode, the comparators output is available on the GP2/COUT pin. It is high if Vin+ is greater than Vin- and low otherwise. Here is a small program which demonstrates use of the comparator (It should be written on to the PIC by running pplin -device=12F675 -hw=3 -notest filename.hex):



; Use of comparator
; Use of __CONFIG directive

	list p=12f675

	include "p12f675.inc"
	__CONFIG _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_OFF & _PWRTE_OFF & _WDT_OFF & _XT_OSC

main:

	bcf STATUS, RP0
	clrf GPIO
	; vin+ from vref module
	; GP1 analog input
	; COUT on GP2
	; Mode 3
	movlw 0x3
	movwf CMCON 
	bsf STATUS, RP0
	movlw 0x2 ; GP1 input; All else outputs
	movwf TRISIO 
	movwf ANSEL ; GP1 analog input, all else digital
	movlw 0xaf
	movwf VRCON ; Low range, Vref = 15/24 * Vdd
	bcf STATUS, RP0

infinite:
	goto infinite
	end

First, we program the comparator in mode 3. Next, we define GP1 as an input pin and all others output by writing to TRISIO. The ANSEL register also should be written to to indicate the fact that only GP1 is being used as an analog input. A bit pattern is stored into VRCON which makes the voltage reference equal to (15/24)*Vdd (remember, the voltage reference is programmable).

We build the test circuit and execute the program, with the wiper of a potentiometer connected to GP1/CIN- (pin number 6 of the 12F675) and an led on GP2/COUT (pin number 5). We note that if the voltage on CIN- goes above 5*15/24, which is the reference voltage, the LED goes off.

Conclusion

I hope the article provides sufficient information to get started with the PIC on Linux. There are tons of tutorials/projects on the web centred around the PIC. Hope you have fun hacking Linux, and of course, the PIC.