Recently, I came across the need to utilize an external clock source for my ATMega microcontroller. I was initially under the impression that it would be a relatively daunting task after reading about the mounds of bricked AVRs which had fallen into the unforgiving grip of incorrectly set fuse bytes. I didn’t find any tutorials geared specifically towards addressing this subject, suitable for beginners. Fortunately my experience wasn’t bad at all, and the main reason for that (I suspect) is that I did a lot of research and asked even more questions to understand exactly what I was doing, and what I may be up against. My goal for this tutorial is to teach anyone who wants to learn exactly what each and every aspect of setting up an external clock source is, leaving no stones unturned.
In brief, I needed to set up an external clock source because of the limitations of the internal one; the limitations being speed and accuracy. I needed more speed to support V-USB (expect a tutorial on that in the future) which requires a faster clock than the internal one, and for those who don’t know, the USB protocol itself is infamous for its timing accuracy requirements. This tutorial will be based on the ATMega8, but for the most part the information here will be applicable to any other ATMega you have. If you don’t have the ATMega8, then I’ll teach you how to read the relevant parts of the datasheet so you can easily figure out what you have to do on your own. If you know your stuff, feel free to skip sections you find irrelevant – in which case I also apologize for crowding this tutorial with basic information.
Let us first take a little while to understand the basic concepts and ideas associated with setting up an external clock source. I highly recommend opening up the datasheet for the ATMega8 (or your microcontroller) for the duration of this tutorial, and briefly skimming the chapter on System Clock and Clock Options (page 25). Click here for the ATMega8′s datasheet.
What is a clock?
A clock is simply a device that keeps track of time, it kind of gives you a beat to move to. The clock on your wall counts in increments of seconds, for example. A metronome for your instrument might give you a beat every half or full second. The amount of times a clock ticks/cycles per second is called its frequency, measured in Hertz (Hz or cycles/second). Similarly, your ATMega has a clock inside too, and its speed directly relates to how many instructions it can carry out per second (on every tick/cycle of the clock). The default clock speed that comes shipped with most AVRs is 1 MHz (1 million cycles per second) because they have internal clocks which keep time. The internal ATMega8 clock can be set up to a maximum frequency of 8 MHz, and beyond that you need an external source or else you would be over clocking your AVR – which could lead to unpredictable problems.
How can we set a clock speed?
We have two options: use the internal one, or use an external source. If you are writing code that does basic stuff, and you don’t require precision timing, the internal clock should suffice. In any other case, particularly for communication (i.e. using the UART for example, or in my case, USB), timing is critical. In that case, we need an alternate method, so we use things like crystals, resonators, oscillators, and clocks. They are all suitable to produce the beat we are looking for, at the frequency we are looking for, but the most common amongst hobbyists are crystals and resonator (you’ll see how they are pretty much the same). We will be using a crystal for this tutorial, and it looks like this:
To use the crystal we will also require two ceramic 22 pF capacitors (so have those handy). A resonator, on the other hand, has the capacitors and crystal built into one package, thus making it a little more compact. That’s pretty much the only difference, but there may be subtle differences in setting fuse bits if you are using a resonator – just something to look out for in the datasheet. Oscillators require an external power source to operate, and usually have four pins. External clocks, something a lot people don’t have (but wish they did), can also be used by pumping in a square wave at the desired frequency.
Clocks sources usually need a little bit of time to warm up and start giving us a reliable signal when the microcontroller is turned on. This is called the start-up time. To play it safe, we will be using the maximum start-up time to give the clock as much time as it needs to get up to speed (no pun intended). Actually, the max start-up time is only a few milliseconds anyway!
What are fuse bytes?
This is the one concept which I noticed catches a lot of beginners off guard (myself included), and is the source of a lot of confusion and mishaps. Typically, there are only two fuse bytes: a high one, and a low one. As you should hopefully know, one byte contains 8 bits. So we have 16 bits to set to on or off. Each of those bits, depending on whether they are on or off, impacts the critical operations of the microcontroller. The mistake most people make is messing around with bits they did not intend to change, or giving bits they intended to change the wrong value. This is particularly easy because a bit set to 0 means it is programmed, and a bit set to 1 means it is unprogrammed – kind of counter intuitive, especially for those who wear binary wrist watches *whistles innocently*. But more on that later.
Going back to fuse bits, basically we modify a few bits in the high byte and the low byte to tell the microcontroller that the next time you start up, expect an external crystal giving you a frequency of x MHz, and you have to give it y amount of time to start up before you start running the code inside of you. That’s pretty much it; look over the section called Memory Programming on page 215 just to get a general idea of what comprises a fuse byte. As you may notice, each bit in each of the two bytes has a specific name (i.e. RSTDISBL, CKSEL, SUT1, etc.). This makes it easier to refer to them, and harder to make mistakes because the name of the bit alone gives you a good idea about what its purpose likely is. For example, RSTDISBL stands for reset disable (you do not want to program this guy, unless you pretty much never want to reprogram your precious microcontroller again), CKSEL for clock select, SUT for start-up time, etc. Finally, it’s important to note that the default values for each fuse byte are also listed in the datasheet.
Let’s Do It!
So what do we know so far? Well, we now know that we have to set some bits to indicate we are using an external crystal, one greater than a certain frequency, and requiring a certain start-up time. Let’s go through the datasheet, and bring our ideas together. Scroll over to the chapter titled System Clock and Clock Options on page 25 (or whichever page it is for your microcontroller’s datasheet). So we have 7 bits to change in order to get everything working the way we want: CKOPT, CKSEL3..0 (that means CKSEL3, CKSEL2, CKSEL1, CKSEL0), and SUT1..0. We will address each bit below, with the associated tables to refer to from the datasheet. For convenience I have also added the tables and figures to the post, but they are all copied directly from the datasheet.
But first, let’s take a quick peek at Figure 10:
As you can see, the clock multiplexer is given an input from one of the many clock sources. We will be using the Crystal Oscillator. That input goes directly to all the critical parts of the microcontroller, from the CPU and EEPROM, to RAM and your GPIO pins. The clock really is at the heart of everything, giving the entire system a beat to operate at. Pretty cool huh?
Choosing the values for the fuse bits
Just to make sure we are on the same page, CKSEL3..0 means all the CKSEL bits from CKSEL0 to CKSEL3. CKSEL stands for clock select, and tells our microcontroller what kind of a clock we are using, and what its frequency is. Let’s look at Table 2:
From this, we see that CKSEL3..0 has to be somewhere between 1111 and 1010. So the four bits (CKSEL0, CKSEL1, CKSEL2, CKSEL3) are somewhere in that range. How do we know what they are exactly? That depends on our crystal’s frequency, Table 2 is just telling us that if we use an external crystal, the four bits will be somewhere in that range. Right, moving forward.
Table 4 gives us some more detail about CKSEL3..1 (note, not CKSEL0 just yet), and tells us what our options for CKOPT are. We will program CKOPT (set it to zero) because a programmed CKOPT is needed when we are dealing with higher frequency ranges, need a full swing signal, or we are driving a second buffer with the same output from the clock. We meet the first criteria (16 MHz is > 1 MHz), so we will set CKOPT to 0. As a result, CKSEL3..1 can be any of 101, 110, or 111, it doesn’t matter. We’ll go with setting the three CKSEL bits to 111 just for kicks.
Good, let’s move on to the final three bits we have to work on: CKSEL0, SUT1, and SUT0.
As you may notice, Table 5 is the last piece of the puzzle. It tells us exactly what CKSEL0 and SUT1..0 have to be! So let’s see, we decided that we want the maximum start-up time earlier. In this table, that would correspond to a Start-up Time of 16K CK and an Additional Delay of 65ms. Thus, CKSEL0, SUT0, and SUT1 would all be unprogrammed (set to 1).
We’re done! To summarize our bit settings, we have:
- CKSEL0 = 1
- CKSEL1 = 1
- CKSEL2 = 1
- CKSEL3 = 1
- SUT1 = 1
- SUT2 = 1
- CKOPT = 0
Setting the fuse bytes
We know exactly which bits we need to change in the fuse bytes, so let’s look at how the fuse bytes are organized. Head over to the chapter called Memory Programming on page 215. As I said, there are two fuse bytes, the high fuse byte, and the low. The bits we need to set are scattered inside these two bytes, so we need to find which one is where, and change it without changing any of the other ones. Take note of the default values in the fourth columns of the following two tables.
Table 87 shows the bits inside the high fuse byte. The only one we want to change is CKOPT (bit 4) to 0. So the high fuse byte should be 11001001 in binary, or C9 in hexadecimal.
Similarly, Table 88 is the table for the low fuse byte. We have 6 bits to change in here, and in the end, our low fuse byte should be 11111111 in binary, or FF in hexadecimal.
We’re almost at the final step!
Setting Up the Hardware
Finally, you are at the point at which you are ready to burn the fuse bits into your microcontroller. But you want to make sure you have the crystal connected to your AVR too, so follow the schematic below:
C1 and C2 are 22 pF ceramic capacitors. Have this setup as close together as possible, don’t have wires running around the breadboard to reach the crystal and ground. You could use the following setup to try out the impact of the crystal along with the following code (skip this little bit if you don’t want to try out a simple example):
So if you want, give the above minimalistic setup and code a go, and you should see the LED blink every 200 milliseconds (note that you should not connect the crystal just yet if you are going through the example, so simply don’t connect the green and orange wires for now). I ignored the pull-up on the reset pin, decoupling capacitors, etc. just to keep it simple, but you should have that stuff (if you don’t, this setup should still work if you did everything else right). Also, make sure you have the correct pins for your AVR model. One mistake in the diagram is the resistor value; sorry, I forgot to change it. Let me know if you need help choosing the correct resistor, but I am sure you can handle that
Now we will run the commands in avrdude to burn the fuse bits. Of course, if you don’t use avrdude, use whatever tool you are comfortable with because the bytes will be the same.
avrdude -c usbasp -p m8 -U lfuse:w:0b11111111:m -U hfuse:w:0b11001001:m
Notice that we are using the actual binary values because the bits being changed are very clear. However, it is recommended to use hex values, like this:
avrdude -c usbasp -p m8 -U lfuse:w:0xff:m -U hfuse:w:0xC9:m
Just to make it clear, you wouldn’t be using -c usbasp and/or -p m8 if you are not using the USBasp programmer and/or the ATMega8.
If you followed the above example, go ahead and connect the wires to the XTAL1 and XTAL2 pins on your AVR (the green and orange ones in the diagram). If you did everything right and used the exact code as the one pasted above, you will now notice the LED is not flashing. Well, that’s because the F_CPU value in your code is wrong. Well, it isn’t wrong, but your F_CPU value of 1000000 now means 1/16th of a real second is actually one second to the AVR. So your delay is no longer 200 milliseconds, but 1/16th of 200 milliseconds. The delay results in a “frame rate” of 80 flashes per second! That’s too fast for the human eye to comfortably process.
So to fix this, we have to tell the AVR that because we changed the clock speed to 16 MHz, one second actually is now made up 16 million cycles, not 1 million. All we have to do is change F_CPU to 16000000UL, and we’re done! Your LED should blink ever 200 milliseconds, just like it was before.
That was fun! I hope you learned something today, and I would like to sincerely apologize to anyone who found this tutorial filled with too much basic information. One last note: if you would like to return your fuse bit settings to the way they were from the factory, just run the same process again but use the default bit values found in Table 87 and 88 instead of the ones we came up with.
I would love to read your comments and answer your questions as well, so drop me a line below. Keep it cool everyone