At home lately I’ve been trying to learn about electronics and simple analog circuits towards understanding microcontrollers from the bottom up rather than from the top down. In the past, I’ve relied on the kindness of others and/or good books or websites to handle all the component work and stuck to microcontroller programming in C. In C, microcontroller programming is just a bunch of bit operations, shifting, loops, polling, etc. But every time things failed to work like you think they would in “normal” programming (microprocessors) it invariably came down to the hardware, or the interface between the micro controller and the hardware---not the C language implementation or the code itself.
So in working from the electrons up, I’m finally to the point where I’m programming again now that I have a working knowledge of how resistors, capacitors, diodes, transistors, inductors and voltage regulators come into play. But the programming is in assembly, and my only previous assembly experience is on PowerPC architecture (some experience) and 680x0 architecture (a fair amount of experience a long long time ago.)
There are basically two ubiquitous chip families in simple 8 bit microcontroller programming. There are a lot more, but these two are far and away the most popular and often-used. They’re the PIC processors from Microchip and the AVR family from Atmel. The PIC’s seem the most popular overseas and the AVR’s seem most popular in the United states, though the AVR’s are (rightfully) starting to overtake PIC’s.
PIC is an abomination.
Here is a list of things I’ve come to loathe:
1. Program space is organized into 14-bit (yes, that’s FOURTEEN BIT) words.
2. There’s only one register, called W, and it only supports a tiny set of addressing modes.
3. Accessing data is done via the “file registers” which is just a fancy way of describing more 14-bit words in program space.
4. There are no conditional branches, you test condition codes as bit operations with the condition code register and there are only “skip the next instruction” kinds of branching.
I have to stop here and offer an example of how fucked up this is. You have to test the OPPOSITE case you want, with a operand that conditionally SKIPS the next instruction.
; I want to see if bit 4 is set in my file register
BTFSC SomeFileRegister, 4 ; so I test to see if the bit ISN’T set “Bit Test File and Skip if Clear”
; continue normal execution
[ elsewhere in the code ]
; the condition was met
Two instructions to do a conditional branch, and you have to test the INVERSE CASE.
What the hell were they thinking?
5. The same thing applies for loop counters, where you do the test at the decrement or increment instruction and SKIP the next statement (which is always a GOTO for conditional branches).
6. It’s an 8-bit architecture, so the working values are all 8 bit, but stored in 14 bit file registers (program memory.) That’s 6 bits wasted when storing data.
7. Storing a string in program space requires building a table of return-literal-value instructions, and then jumping the program counter to the appropriate line by adding to the PC file register. WTF??
8. There’s no stack register. You get 8 nested CALL instructions or INTERRUPTS and you’re out of space.
AVR, fortunately, is a much more sane set of machine instructions, and the C compilers available for the PIC chips handle all this madness for you. Soon I’ll be comfortable enough with the architecture to let the C compiler take care of it for me. Until then I have to boggle at the decision decisions!