Sunday, January 4, 2009

Common pitfall: setting up registers while using bootloaders

I've recently been in trouble understanding how the 16F88's internal clock is working. Starting from a supposed i2c speed problem, I dive into internal clock's internals, with Joep, my guide... Here's what I learned.

First of all, I like using internal clock, because it requires less parts, provides still nice performances and consume less energy, which is good when working on embedded systems. Maybe the major drawback is you can't reach a decent 115 200 bds for your serial communication.

Anyway, I used to setup my 16f88 to run at 8 MHz. Yeah, just say:

pragma target CLOCK 8_000_000
pragma target OSC INTOSC_NOCLKOUT

and that's it, you'll run at 8 MHz... Will you ? Well, all my 16f88 always run @ 8MHz using this configuration. But Joep, the Grand Master of the Hidden Clock, said: "no you don't, because the holy datasheet says, by default (on power), this configuration will setup a clock running @ 31.25 KHz". Errr... 31.25 KHz, how can this be possible ? I'm sure it runs @ 8MHz. And why 31.25 KHz ? "Because IRCF bits are read as 0 when powered, see OSCCON register", said Joep the Grand Master.

So I looked at OSCCON register:



Yes, now I can see OSCON_IRCF bits selects the appropriate internal clock speed. IRCF = 0b_000 by default, and not 0b_111, which is the correct setting for an 8MHz clock.

Still, I'm sure it's running @ 8MHz. It's like my 16f88 decided to set IRCF to 0b_111, despite what datasheet can say... How can this be possible ?

Bootloaders... Yes, bootloaders can be sometime quite surprising. Because when using them, what you specify in your code about registers might not be what's programmed ! I use Tiny bootloader, a very nice and small one. And I use the internal clock version for 16f88, running @ 8MHz. And Tiny bootloader code correctly setup the internal clock. So the "default" value becomes what Tiny has set:
IRCF = 0b_111 that is, it runs @ 8MHz. Of course, you can still select the speed you want, by playing with IRCF, but the apparent default value is not what the datasheet says... Confusing :)

So, to be accurate, the appropriate way to specify an internal clock running @ 8MHz for a 16f88 is:

pragma target CLOCK 8_000_000
pragma target OSC INTOSC_NOCLKOUT
OSCCON_IRCF = 0b_111


Another pitfall I usually fall into is CCP1MUX. With this register, you can specify which pin, RB0 or RB3, will produce PWM for instance. Every time I set it to RB3, it just doesn't work. Why ? Because Tiny bootloader has set it to RB0. And this time, it cannot be changed, because Tiny bootloader (as any bootloader for PIC ?) cannot re-program such as register !

If using a bootloader, remember, the actual program being originally uploaded to your PIC is not your program, it's the bootloader itself. So remember its proper configuration might conflict with your own, or at least confuse you...

Solution ? Don't use bootloader, or be careful !



1 comment:

  1. Nice post. I too faced the same problem, but I was not using a boot loader It was 16f767, didn't test again, but I couldn't get the int clock working at 8Mhz, with an ext Xtal it works fine.

    ReplyDelete