PIC18F Software Project Survival Guide

Now that I’m getting nearly through I feel confident about posting this series of posts about my work experience on PIC18F. Although my writing could seem a bit intimidating or cathedratical I would like to receive your feedback and your thoughts on the matter. I got through, but I don’t like to have universal solutions 🙂
So, at last you failed in defending your position. No use in all the documentation you provided, the articles from internet and blog posts where with no doubt, PIC was clearly depicted as the wrong choice.
But either your boss or your customer (at this point it makes not much difference) imposed a PIC18F on your project. And she also gave a reason you can hardly argue about – Microchip never sends a CPU the way of the dodo… so, twenty years from now we could continue to manufacture the same device with the same hardware avoiding the need for engineering maintenance.
Given that this device will be sold in billion units, that makes a lot of sense.
Their problem is solved, but yours are just looming at a horizon crowded with dark clouds.
Good news first, you can do it – PIC 18Fs (after some twiddling) have enough CPU power to fit most of the applications you can throw at them. I just completed a device which acts as a central hub of a real time network and provides information via a 128×64 pixels display.
Bad news – it won’t be easy, for anything more convoluted than a remote gate opener, due at most by yesterday (as most of the project requires nowadays) your life is going to be a little hell. I’ll try to describe if not the safest path in this hell, at least the one where you cannot get hurt too badly.
So, let’s start by architecture.

PIC18 architecture is described almost everywhere (checked on the back of your cereal box, recently?), but the first place you are going to look, the datasheet, will be mostly helpless. So I will try not to repeat anything and I will not go much into details, but I will try to give you a picture with the objective of showing the capabilities and the drawbacks of these gizmos.
First these are 8 bits CPUs rooted in the RISC field – simple instruction, simple task, low code density.
The memory follows the so called Harvard architecture – two distinct memories for data and for program instructions. Data memory is called Register File, while program memory is called… Program Memory. Data memory is a RAM, while program memory is a flash.
Program memory is linear (no banks, no pages), each word is 16 bits wide, but the memory can be accessed for reading (or writing) data one byte at time. Current PIC18s have program memory sizes up to 128k, but nothing in their design prevents them to address up to 16Mbytes (2^24).
You can erase and write the program memory from the PIC program itself (this is called self-programming), but there are some constraints – first memory is organized in pages, 1024 bytes each. In order to write the program memory you have first to erase it and this can be done only one page at time. Once the page has been erased you may write it altogether or just one byte at time.
The worst part is that when the program memory is erased or written the program memory bus is used and therefore the execution is stalled. This stall can last for several milliseconds.
Data memory can be accessed either linearly or through banks of 256 bytes each depending on the assembly instruction you use. Data memory for PIC18s is up to 4k, again there’s nothing in the design that prevents the CPU to address up to 64k or RAM. In the data memory there is a special section (Special Function Registers) where hardware registers can be accessed.
PIC18 architecture becomes quite funny on SFR since you can find the usual timer, interrupts and peripherals control registers along with CPU registers such as the status flags, the W register (a sort of accumulator). Further there are registers that basically implements specific addressing. For example PIC18 has no instruction for indirect addressing (i.e. read from a location pointed to by a register); if you want to indirect access a location you have to load the location into a SFR (say FSR0 for example) and then read from another SFR (e.g. INDF0). If you want a post-increment you read from POSTINC0.
That may sound elegant, but it is a nightmare for a C compiler, basically any function that accepts a pointer could thrash part of the CPU state, since most of the CPU state is memory mapped!
That’s also the reason why, conservatively, the C compiler pushes about 60 bytes of context into the stack on entering a generic interrupt handler.
There is a third memory in every PIC18F – the hardware return stack. This is a LIFO memory with 31 entries. Each entry is the return address stored every time that a CALL (or RCALL) assembly instruction is executed.
Still on the CPU side, PIC18F features two level of interrupts – the high priority level interrupt and the low priority interrupt, you can assign every interrupt on the MCU to one or the other of the levels.
Talking about the peripherals you will find almost everything – from low pin count device to 100 pins MCUs with parallel port interface, external memory and ethernet controller. Even in a 28 pins DIL package you found a number of digital I/Os, comparators, DA and AD converters, PWMs. Every pin is multiplexed on two or three different functions. I2C and SPI are available on each chip, while USB port is available only on a couple of sub-families.

Next time, I’ll talk about tools