After I built my first Pinguino, I decided to do some experiments on using crystals of different frequencies. By default, Pinguino uses a 20 Mhz crystal, since most of the crystals I have run at 16 Mhz I decided to dig a little deeper to see whether I could make Pinguino bootloader run at frequencies other than 20 Mhz.
So I pulled the source code of the latest bootloader V2.12 from HackingLab. But soon I realized that this particular version was missing a few key files (such as configure.ac) in order to be built successfully. I guess that I could have created a Makefile myself for the build, but the process would likely be time consuming as each of the dependencies needed to be figured out one by one. So I reached out to one of Pinguino’s maintainers JP Mandon. After described what I was trying to achieve, he kindly referred me to the source files listed here. As it turned out, the Pinguino bootloader had been incorporated into a much larger project — PIC USB Framework (PUF).
While the bootloader from the PUF project has the same version number as the one I downloaded from the HackingLab website, the files are not all the same. But functionality-wise, these two versions seem to be identical.
After reviewing the code, it seemed that configure.c is where the PIC configuration registers are set. The version of the bootloader on HackingLab is slightly easier to work with as the configurations are set directly (the bootloader from the PUF project is essentially identical to the version on HackingLab except that the constants are re-factored into another header file).
code char __at 0x300000 conf1 = 0x24; code char __at 0x300001 conf2 = 0x0e; code char __at 0x300002 conf3 = 0x3f; code char __at 0x300003 conf4 = 0x1e; code char __at 0x300005 conf5 = 0x81; code char __at 0x300006 conf6 = 0x81; code char __at 0x300008 conf7 = 0x0f; code char __at 0x300009 conf8 = 0xc0; code char __at 0x30000A conf9 = 0x0f; code char __at 0x30000B conf10 = 0xa0; code char __at 0x30000C conf11 = 0x0f; code char __at 0x30000D conf12 = 0x40;
The configuration bits at 0x300000 set the crystal frequency used in conjunction with the USB bus speed. For detailed configuration settings, please refer to PIC18F2550’s datasheet. And the bit calculator I created a while ago can be quite handy at computing the configuration bits.
Microchip’s MPLab has a build-in config bits calculator tool and it can be used to generate the configuration settings needed for the program:
For the Pinguino bootloader, the default setting at 0x3000000 is 0x24, which translates to:
USBDIV = 1 (USB clock source comes from 96 MHz PLL / 2)
CPUDIV:CPUDIV0 = 0 (Primary oscillator used directly for system clock, no prescaler)
PLLDIV2:PLLDIV0 = 100 (Divide by 5, 20 MHz oscillator input)
According to the datasheet, the following crystal frequencies can also be used with USB by just changing PLLDIV2:PLLDIV0 without any other code adjustments:
101 (configuration bits = 0x25) — divide by 6 (24 Mhz oscillator input)
100 (configuration bits = 0x24) — divide by 5 (20 Mhz oscillator input)
011 (configuration bits = 0x23) — divide by 4 (16 Mhz oscillator input)
010 (configuration bits = 0x22) — divide by 3 (12 Mhz oscillator input)
001 (configuration bits = 0x21) — divide by 2 (8 Mhz oscillator input)
000 (configuration bits = 0x20) — no prescale (4Mhz oscillator input)
So for a 16 Mhz crystal, all we need to do is just change the configuration register at 0x300000 from 0x24 to 0x23 and recompile the bootloader.
To build the bootloader, extract the PUF tar ball and change the config.c under puf-1.1/bootloader/. If you want to compile the version of bootloader I used you can simply just remove the bootloader directory from puf-1.1, extract the bootloader into the PUF project directory and rename the directory to bootloader. This way, you will be able to use the same Makefile that comes with PUF to compile your bootloader code.
The PUF project comes with the code for Odyssey PIC programmer, which is compiled when the PUF project compiles. Since Odyssey is a very old project, the source file is no longer compatible with the latest gcc (e.g. 4.4.3). I created a patch that adds the necessary includes to compile Odyssey.
After recompiling and re-flashing the bootloader (I used the programmer I built a few weeks ago), everything worked!
I have only tested this change with a 16Mhz crystal, but other frequencies listed above should work as well.
Downloads: Bootloader (16MHz)