Programming the PIC18F25K22 Oscillator with Swordfish

by Ralph S Bacon (aka Aresby), April 2012

Programming the oscillator on the PIC18F25K22 using Swordfish (and an Amicus18 board, optionally)

Getting Started

For an absolute beginner like me, it was a challenge setting up the clock on the PIC18F25K22 (possibly on an Amicus18 board) with the Swordfish compiler. Here are some pointers to get you going; I’ve written it for real newbies like me and with a level of detail that I would have liked to have read as I started out!

Swordfish's 18F25K22 device file does not set the primary oscillator for you; it is expected that you, the developer, will configure the chip to use either an external or internal oscillator. Without this, you can program the chip but the chip will not start running as no clock is pushing it along. It will just sit there, immobile, doing nothing. You’ve put the car in gear but haven’t started the engine.

Well, nearly. There is a fail-safe which I'll describe at the end of this article. For now, assume that if you don't set the clock then there won't be one running.

The Amicus board comes with a 16MHz crystal so you might think that the default would be to use it (which, with the chip's in-built 4-times clock multiplier ensures the chip runs at its top speed of 64MHz).

Well, yes, you could do this. One command at the start of your program (or permanently added to the 18F25K22 device file) would ensure this happens. The start of your program would then look like this:

   DEVICE = 18F25K22    'Automatically brings in device file 18F25K22.bas
   Clock = 64           '64MHz (top speed)
   CONFIG FOSC = HSMP   'tells PIC to use external high speed (crystal) oscillator, medium power

If all you want to do is get your 18F25K22 program running then this is the command to tell the chip to use the Amicus18's crystal. You don't need any other setting. If you want to know more, and why, keep reading.

When you come to implement the Amicus prototype on another circuit board, the crystal, together with the two small capacitors, add both an expense and a layer of complexity not required unless you really need an accurate clock, that’s less affected by ambient temperature, for example.

The chip's on-board oscillator has been factory configured for accuracy too so programming a small delay of half a second into your program will be just fine; a few micro-seconds either way probably aren't really going to matter that much. Even communicating serially with another device probably won't require this – but generally, anything that requires an accurate clock may be better off with an external, crystal controlled clock.

If you’ve decided you want to use alternative clock sources, or perhaps want to reduce the clock speed to save power, then we just need to tell the chip what source the clock should come from: the external crystal or the internal oscillator (there are some other options too but I'm not going to discuss them here).

Looking at the above code line, this is a known as a CONFIGuration setting. It tells the chip how to run (not what to run, that's up to your program code). In this case it tells the chip where to get its clock signal from – and possibly how fast to run that clock.

Bits & Bytes - the fundamentals

Before we discuss esoteric mnemonic codes like FOSC, let’s ensure we’re all singing from the same hymn sheet.

Feel free to skip this if I'm teaching my grandmother to suck eggs and you know how bytes and bits work together.

Your PIC is normally considered to work in block of memory called bytes. A byte can represent a single character of the alphabet, or a number up to 255. The 18F25K22 has about 32,000 bytes available for programs.

Each byte is made up of 8 bits (binary digits), numbered from zero to seven. So we might talk about “setting” bit 2 or “clearing” bit zero. A bit can only have the values 0 (cleared) or 1 (set).

When written down, the 8 bits in a byte are represented like this:

                  Bit No: 7 6 5 4 3 2 1 0

           Example value: 0 1 0 0 1 0 1 1

This means that the most significant (highest value) bit is bit 7 and the least significant is bit 0. What we’re not interested in is the value that all these bits make when put together as a byte – the value is inconsequential. The purpose of these bits when used to configure your PIC is that they can be set individually, not viewed as a byte-based number or character.

Getting the PIC clocked

Enough theory, let's start telling the PIC chip where to get its clock signal from, how fast to run it and a few other things.

FOSC

FOSC is the manufacturer's (Microchip) name that is short for Oscillator Settings and refers to the last four bits numbered 3 to 0 of the configuration register called CONFIG1H (short for Configuration Register 1 High). This is as snappy it gets in PIC world.

How do know that FOSC is considered part of the CONFIG1H special function register? Only by reading the Data Sheet and experience, I'm afraid.

A configuration register is simply a single byte with a predetermined value decided at compile time within the chip’s permanent memory that is used by the chip to know how to run. These registers have specific addresses determined by the manufacturer; you don’t have to know where they are located in the chip’s memory architecture as the compiler will deal with this for you.

You can tell that FOSC is a configuration register because it has CONFIG in front of it.

Collections of bits, and individual bits too, that make up the configuration register bytes are named like this so we can refer to them easily. There are several but you will only ever deal with a few. However, your compiler may not know about the individual bit settings of every special function register. Luckily it knows about FOSC as it is so important and so often used.

So these bits 3 through 0 are collectively known as FOSC and are written down as FOSC<3:0>. Thus when you see FOSC<3:0> you can understand that it is referring to a collection of individual bits, 3 through 0, in the configuration register called CONFIG1H, and that we call that collection of bits "FOSC".

Remember that when you refer to bit 1 you do actually look at the 2nd bit from the right not the first bit (which is bit zero). And in our special FOSC case, bits <3:0> refer to the bits 3,2,1,0 making up 4 bits in total.

Let’s move on to the internal oscillator.

To get the PIC chip to use its high speed internal oscillator instead of the external crystal we can change that line of code to read:

   DEVICE = 18F25K22      'Automatically brings in device file 18F25K22.bas
   Clock = 64             '64MHz
   CONFIG FOSC = INTIO7   'tells the chip to use its internal oscillator

Now the FOSC settings means: use the INTernal oscillator and leave pin 7 as an Input-Output pin.

As the clock setting has little to do with the Input-Output pin 7 (I’ll explain it at the end of this article) let’s just assume that we’ve now successfully told the chip to use the internal oscillator.

If you were to program the chip now, nothing would happen.

You’ve told the chip where to expect the clock signal to come from but not configured the actual oscillator itself. You may have just put the car in “Drive” but have yet to start the engine.

So you now need to specify another setting, this time a special function register, that tells the chip how to run the oscillator, at what speed and so on.

Compare this special function register to the previous configuration register. Special function registers are similar to configuration registers except they don't (necessarily) have a value pre-set at compile time - you, the developer, can set and adjust these as part of your program to further control how the chip behaves. You can even change them as you would any other variable, whilst the program is running.

OSCCON

   DEVICE = 18F25K22      'Automatically brings in device file 18F25K22.bas
   Clock = 64             ''64MHz
   CONFIG FOSC = INTIO7   'tells the chip to use its internal oscillator
   OSCCON = %01011110     ‘Tells the chip how fast to run (amongst other things), see below

The OSCCON register (aka Register 2-1 Oscillator Control Register) controls some aspects of the way the clock is configured. We’ve given it a binary setting here (denoted by the % prefix) and where we have set each bit specifically.

Let's look at each of the bit settings of this register:

                              0  1  0  1  1  1  1  0
          Bit 7 --------------^                    ^---- Bit 0

           Bit 6 ----------------^              ^-------- Bit 1

            Bit 5 ------------------^        ^------------ Bit 2 

             Bit 4 --------------------^  ^---------------- Bit 3

How do we know what the individual bit settings are? By referring to the Data Sheet and by reading on.

Bit 7 tells the chip how to process a SLEEP instruction. We’re not interested in that right now so we’ll set it to 0 in our examples (which means ‘Enter Sleep Mode’ when you process a SLEEP instruction). Just ignore it.

Bits 6-4 collectively tell the chip how fast to run the clock. I’m going to ignore all the very slow speeds which are for when you want to save power as much as possible (mainly); we'll concentrate on those speeds that make the chip run ‘normally’ at speeds of 1MHz to 16MHz.

The binary values we can use here for bits 6-4 are:

111 = 16MHz which is the default speed of the internal oscillator. It’s called HFINTOSC, short for High Frequency INTernal OSCillator).
110 = the main speed divided by 2 (8MHz)
101 = the main speed divided by 4 (4MHz)
100 = the main speed divided by 8 (2MHz)
001 = the main speed divided by 16 (1MHz)

To recap: we have now built up part of the OSCCON binary value, %0111 which means: process the SLEEP command normally, and run at 16MHz.

Let's deal with the remaining bits of this register.

Bit 3 tells the chip whether, on start-up, it should honour what we have configured in the FOSC setting (that’s FOSC<3:0> of the CONFIG1H register, remember) or, just ignore the FOSC setting and use the internal oscillator.

If you think that Bit 3 is just trying to confuse us I would have to sympathise. Having programmed the FOSC setting in our example to say “Use the INTernal oscillator” it’s just overkill to have to confirm that here. But it all adds to flexibility, of which there is a lot.

So Bit 3 will be set by us as 1 to mean “honour the FOSC setting”.

Bit 2 is for us to tell the chip whether the HFINTOSC (that we’re using, see bits 6-4) is stable or not. We’ll just set it to 1 to say “yes, it’s stable”. I'm not sure what the chip is expected to do if you tell it that the clock is not stable.

Finally, bits 1 to 0 collectively allow us to establish where the system clock is running from. Again. The available values here are:

1x = Internal oscillator block (the x means “don’t care what this value is”, it can be 0 or 1) 01 = Secondary oscillator SOSC (let’s not go there) 00 = The primary clock as specified by FOSC<3:0>

As we took such trouble to set the FOSC value the way we want it, we’ll use 00 as our setting.

So we now have our entire OSCCON register setting %01111100 as shown in our example.

You could program the chip now and it would run. But you may think that the chip is running more slowly than you thought it would and you would be right.

The maximum speed we can define here is 16MHz, as defined by bits 6-4 of the OSCCON.

So how come the chip can run at 64MHz? Is that only with an external clock? No, it’s not. Internally the chip has a four-times multiplier. So the chip can multiply the 16MHz clock signal by 4 and turn it into a 64MHz signal, thereby running the chip four times faster. Read on to find out how this is done.

OSCTUNE

How? We have to set another special function register, called OSCTUNE (aka Register 2-3 Oscillator Tuning Register). I hope you're liking these catchy mnemonics.

Thankfully we only have to set a single bit of this register to push the chip to maximum speed. Rather than define the complete set of bits as we did with the OSCCON we can refer to the individual bit we want to adjust like this:

   DEVICE = 18F25K22      'Automatically brings in device file 18F25K22.bas
   Clock = 64             '64MHz
   CONFIG FOSC = INTIO7   'tells the chip to use its internal oscillator
   OSCCON = %01011110     ‘Tells the chip how fast to run (amongst other things), see below
   OSCCTUNE.6  = 1        ‘Set the PLLEN bit 6 (turbo mode - see accompanying description).

This means set bit 6 ( i.e. set to binary value 1) that will ENable the Phase Locked Loop multiplier for the HFINTOSC oscillator source.

In other words, engage turbo mode. As shown above the bits can be programmed “on the fly”, whilst your program is running. So you can make the clock speed up or slow down as you require. You can test this out using the Blink1.bas simple LED flashing sample program and program the clock faster and slower and watch how it affects the LED flash rate.

Just so you know, several other bits in the OSCTUNE register allow you to tweak the clock frequency a tad either way (slower or faster) but we’re talking tiny amounts. Microchip say this is to allow the program to “self-tune” the clock when it discovers that it’s running too fast (or too slow), a good indication of which is when errors are received when communicating serially to other devices.

Needless to say we’ll leave this well alone for now and let it run at the factory calibrated speed.

Loose ends

To tidy up some loose ends, you may recall that we set the FOSC = INTIO7. We’ve covered the INT bit, but what about the IO7? There’s even a variant called INTIO67.

This means that pin 7 (and also pin 6 if using the INTIO67 option) of Port A should be configured as standard input/output pins instead of using these pins as part of the oscillator control.

As it happens, using INTIO7 allows you to measure the internal clock speed (divided by four) on pin 6 of PortA; useful when debugging or experimenting perhaps, but probably more useful to keep one or both of these pins as standard input/output pins.

Note that the clock is NOT output on either pin if you’re using an external clock source.

Fail safe clock

What happens if you forget to set (or mis-configure) the clock settings? Does your program really just sit there?

Well, not quite. As an absolute fail-safe mechanism, if no other clock is running then the PIC chip will run from the default, internal 32k clock. That's good then? Well, not really. If you have programmed the chip with the expectation that it's running at 64MHz but have not configured the clock correctly, it will default to the 32KHz clock - that's running 2,000 times slower than what you expected.

So a 1ms (milli-second) programmed delay (one thousandth of a second), for example, will actually take 2000ms, that's 2 seconds. Your program might as well be stopped - it will certainly appear to be 'hung'.

So if nothing seems to be happening (not even that LED lighting up that you programmed as the first thing) then check your clock settings!

Clock Speed (actual vs. what you tell the PIC)

Through this article we've had some code right at the top of your program like this:

   DEVICE = 18F25K22      'Automatically brings in device file 18F25K22.bas
   Clock = 64             '64MHz

The clock = 64 line tells the compiler the speed that the chip's running at so that the compiler can accurately calculate delays, loops and so on. So when you write DelayMS (1000) you want a delay of 1000 milli-seconds, or 1 second.

But that will only ever work if the chip is actually running at the speed that you told the compiler it was going to run at. Get it out of sync and your program will either crawl along (possibly making you think it has 'hung') or run much too fast. That's why it's a great idea to experiment with the Blink1.bas simple LED flash program - you can normally tell with just the second hand on your watch whether the 1-second flash is too fast or not.

Please take note - "includes" in your program

David has written a note (click here) about what you must do when using the internal oscillator and when you have "includes" in your program.

Basically, because the syntax of Swordfish requires you to have all "includes" at the top of your program before any executable code (such as OSCCON = %10101010) you will quickly discover that the initialisation code in any of the includes is running before your clock speed has been correctly set.

David shows you how to put the oscillator commands described in my article here into an "include" file so that your clock is initialised first, before any other code.

Final word

Finally, there are many, many more options available to configure the clock for this chip. Some of them are concerned with power saving (so the chip just tickles along until something happens at which point it can kick into high speed mode).

Some oscillator modes allow another source to supply the clock signal (not a crystal). Or you can use a resistor and capacitor network.

To really explore the options I can only recommend that you study the Data Sheet pages that deal with this topic; it's great bedtime reading for insomniacs.