SPI. You may have heard the acronym before. I pronounce it letter-by-letter: “S-P-I”. I think I had heard of it in the past before I learned how to program microcontrollers, but I had no idea what it was. Everyone at work was talking about how we use an “SPI flash chip” or an “SPI driver chip”. Well, eventually I did have to learn what it was, so I’ll try to explain it as easily as I can.

SPI stands for Serial Peripheral Interface. Let’s break it up into two parts:

Peripheral Interface

Peripheral interface means it’s a way to talk to peripherals using your microcontroller. It’s an interface for peripherals. You might have a temperature sensor chip that you need to receive readings from, or an accelerometer, or external memory storage such as a flash chip (like a computer’s BIOS chip, for example). Any of these could be considered to be peripherals. You could even consider your microcontroller to be the peripheral — more on that later.

Serial

Serial refers to the method that is used to communicate between your microcontroller and the peripheral. If you’re like me, you’ve heard of data transfer being “serial” or “parallel” — for example, older computers usually had two serial ports and a parallel port. It breaks down like this: when computer data is sent serially, you’re sending data over a single wire, a bit at a time. When computer data is sent in parallel, you’re sending multiple bits at once. For example, if you have eight wires, you could transmit a byte at a time by putting each of the eight bits in a byte onto a corresponding wire, a 1 being represented by a “high” (5V) value, and a 0 represented by a “low” (0V or ground) value. That would be parallel communication. If you put one of the bits onto a single wire, waited a short time, put the next bit onto the same wire, waited a short time, and so on, that would be considered serial communication.

SPI is a serial protocol because communication between your microcontroller and the peripheral happens over a single wire in each direction. There’s one wire for data transmission from your microcontroller to the peripheral, and there’s another wire for data transmission from the peripheral back to your microcontroller. You might be wondering: isn’t that parallel if there are two wires? Well, each wire is in a different direction so that doesn’t really count.

OK, so now we have that out of the way. Let’s dive into some more terminology.

There are two types of SPI devices: masters and slaves. On an SPI bus, there is one and only one master. It’s in control of all communication. There can be multiple slaves, but there should be at least one — otherwise the master doesn’t have anything to talk to.  The master decides which slave it wants to talk to. It can only talk to one slave at any time (except under certain circumstances when slaves are daisy-chained together — more on this later as well).

In most cases, your microcontroller will be the master, and the peripherals will be the slaves. You could, however, communicate between two microcontrollers with SPI by letting one be the master and one be the slave.

SPI uses these four wires:

  • CLK (clock)
  • MOSI (master out, slave in)
  • MISO (master in, slave out)
  • CS (chip select)

Actually, there is a separate chip select line for each slave you want to talk with. So if you have three slaves, you actually need a total of 6 wires — CLK, MOSI, MISO, and a CS wire for each slave.

MOSI and MISO are pretty straightforward. Data sent out of the master to the slave is transmitted over the MOSI line (master out, slave in). That makes sense because the data is going out of the master and into the slave. Likewise, data sent from the slave to the master will be transmitted over the MISO line (master in, slave out). Again, that makes sense because the data is going out of the slave and into the master.

The chip select line should make sense too, because that’s how each slave knows whether the master is talking to it or not. Basically, the master leaves all the chip select lines high when not talking to any slaves. When it decides it needs to talk to a slave, it brings that slave’s chip select line low, leaving all the other chip select lines high. That way, that particular slave knows the master is talking to it, so it knows that it should be the slave to respond. All other slaves will ignore any incoming data. Note: some slaves expect the opposite behavior: the CS line would normally be low, and only high when talking to the slave. You have to check the slave chip’s datasheet to see how it operates. The terminology here is that if a slave’s chip select line is asserted, it means that the master is talking to it.

That leaves us with the clock line. The clock line is probably the most important line of all the SPI lines. It is what handles the timing. The clock line alternates between high and low, and is controlled by the master. It is how the slave device determines when it is time to read the MOSI line to see what bit got sent to it by the master, and also how it knows when to change what it has written to the MISO line to send a bit back to the master. Since the master is in complete control of the clock, the slave needs to (pretty quickly) respond properly whenever the clock line changes. For this reason, slave devices will specify a maximum clock rate. The maximum clock rate is referring to how fast the master is allowed to flip the clock line between high and low. The master should not flip the clock line any faster than what the slave specifies as its maximum clock rate — otherwise, weird stuff will occur because the slave probably won’t be able to respond quickly enough.

Having a clock line might seem kind of weird. With other types of serial communication, there isn’t a separate wire for the clock. For instance, in a standard RS-232 PC serial port, there is not a clock wire. In that form of serial communication, both ends of the communication have to know ahead of time what the clock rate is. They stay in sync with each other because they both know how long the delay should be based on that predetermined clock rate, combined with a small delay between successive characters sent. On the other hand, as I already said, with SPI the master is in control of everything including the clock. The master decides how fast data is sent and received (as long as it is within the tolerable limits of both the slave and master). This whole setup is possible by having a separate wire just for the clock.

SPI communication is usually 8- or 16-bit, but it could be any number of bits. By that, I mean one complete message may be sent after 8 total bits have been sent and received to/from the master. It all depends on how the slave has implemented SPI. What this means is you really have to carefully study the slave device’s datasheet to determine how to configure the master to talk with it.

There is one other concept that might be confusing at first: the slave is always sending data back to the master at the same time the master is sending data to the slave. Every time the master sends a bit to a slave, a bit comes back in from the slave. If the slave needs to know what all the bits are before it can do something, what it sends back to the master might not mean anything until the master sends another set of bits, which will then give the slave device an opportunity to reply. You’ll see what I mean in this example:

Let’s do an example. Say you are a master device communicating with an SPI temperature and humidity sensor. How would you read the temperature and humidity data from the sensor? We need to know the communication protocol that the sensor uses, which will be defined in its datasheet. For now, I’ll make up a protocol.

Let’s say that the SPI temperature and humidity sensor accepts eight bits at a time (one byte):

  • 0x52 means “read the temperature”
  • 0x53 means “read the humidity”

So you will send a byte to the sensor to tell it which reading you would like to see–either 0x52 or 0x53. If you send it anything other than 0x52 or 0x53, you will get garbage back (or maybe all zeros). So let’s read the temperature by sending 0x52 to it.

So you send 0x52 over SPI to it. In binary, 0x52 is 01010010. So you will assert its chip select line. Next, one-by-one, you will set the MOSI line to:

0
1
0
1
0
0
1
0

(toggling the clock line as you go). Meanwhile, each time you send a bit to the sensor, it is responding with a bit. However, since the sensor does not know which command you are telling it until the entire byte has arrived, it will just reply with zeros for now. So you receive a reply of 0x00 (eight zeros) on the MISO line, and ignore it since it doesn’t mean anything. Finally, you will deassert its chip select line to let it know that you’re finished.

Now, the sensor knows which reading you wanted, but since the master is in control, the slave is not allowed to just send it to the master. Instead, the master has to initiate another transfer to allow the slave to send the reading back. So the master will send another byte, which can actually be anything (the slave will ignore the bits coming in over the MOSI line — all it knows is that it will send the temperature reading out over the MISO line). So you assert the chip select line, then send all zeros (or 0xAB or 0x15 or whatever else you want), and it replies with:

0
1
1
0
0
0
0
1

or 0x61, which is 97 in decimal. This corresponds to a temperature reading of 97 degrees Fahrenheit. Finally, deassert the chip select line. Now you can repeat the same process to read the humidity, or to read the temperature again. Get it? It’s really not that tough. Note that I made up the protocol in this case, and other chips may behave differently. This is just one example, and it’s very similar to how a GPIO expander chip I have used in the past works–you send it a command, then you send it a dummy byte to read back the results of the command.

I promised that I would talk more about two other concepts earlier: allowing your microcontroller to be the slave, and also daisy chaining. Here we go:

Your microcontroller could actually be a slave device. In that case, it would monitor the chip select line to see if a master is talking to it. Then, it would monitor the clock line, writing and reading bits from the MISO and MOSI lines as necessary based on how the clock line changed. You could easily use this type of thing to implement communication between two processors, although it might be a little overkill when you could do the same thing with a UART (a normal serial port).

Daisy chaining allows you to talk to multiple chips at once. An example would be if you have two of the same type of chip connected to each other like so (also keeping the clock and chip select lines connected to both chips at the same time):

In this picture, the MOSI line of the master is connected to the MOSI line of the first slave. This part is normal. But here’s where it gets weird: the MISO line of the first slave is connected to the MOSI line of the second slave! So data coming OUT of the first slave will go IN to the second slave. Finally, the MISO line of the second slave is hooked back into the master microcontroller. Essentially, any time you want to talk to the chips, you send data for each of the chips in sequence BEFORE deasserting the chip select line. So if you have two chips hooked up, you would send two bytes. On chips that support this, this will cause the first byte to go to the slave farthest away from the microcontroller, and the second byte will go to the slave that is connected directly to the microcontroller’s MOSI line. The first chip serves as a pass-through to the second chip, but it holds on to the last byte it receives. Finally, when you deassert the chip select line, each chip will actually interpret the byte it receives. You could do this with a countless number of slaves — it’s not just limited to two. Likewise, when you read from them, you will read multiple bytes. The first byte will be from the chip farthest away in the chain from the master, and the second byte will be in the next closest chip, and so on, until you’ve reached the chip that is closest to the master. That’s really all there is to daisy-chaining.

So with SPI, do you manage each of the four lines on your own? Do you manually control the MOSI, MISO, Chip Select, and Clock lines on your microcontroller, manually toggling the clock line using the GPIO peripheral built into your microcontroller? You absolutely can do it that way — it’s called bit banging. It basically means that you implement the four wire protocol all on your own. You handle the timing of the clock line, when you assert chip select, and also the timing of when you change what’s on the MOSI line and read what’s on the MISO line. However, you would be crazy to do it that way on most microcontrollers in most cases.

Most microcontrollers have at least one memory-mapped SPI peripheral built in. You configure it by telling it the clock rate, how many bits are transmitted per transmission, and other information such as whether the chip select line should be LOW when asserted or HIGH when asserted, and it handles everything for you! After setting it all up, you can simply write a byte to one of the peripheral’s registers, and it will send the data out perfectly, letting you make more efficient use of your CPU’s time instead of worrying about timing. Then, you can determine when the transfer is complete and read the data that the slave sent back. However, I’ve gone on long enough in this post. This post was simply an answer to the question “what in the world is SPI?” In my next post, I will actually show you how to use the SPI peripheral built into most microcontrollers so you don’t have to bit bang the protocol yourself.

The last time I talked about interrupts, I kind of described what interrupts are. I never really got into how to use them, though. In order to use an interrupt, you write an interrupt handler — a piece of code that the microcontroller jumps to when an interrupt occurs. How that interrupt handler is set up depends on which architecture you’re programming for. In any case, when writing it in a language like C, it’s basically a special function that may need some extra code at the beginning and/or end.

The trick with an interrupt handler is that when it’s done running, it needs to leave the processor in exactly the same state it was in before the interrupt occurred. Recall that a single C instruction may break down into multiple assembly instructions that will likely involve modifying values in the microcontroller’s registers. Let’s say we’re incrementing a variable stored in memory. It will turn into three raw instructions. Let’s assume the compiler decides to use register 2 to modify this variable:

  1. Load the variable from RAM into register 2.
  2. Add 1 to the value stored in register 2.
  3. Save register 2 to the variable in RAM.

Let’s do a concrete example using this process. Let’s say that the variable stored in memory contains the value 200. Without worrying about interrupts, here’s what happens:

  1. Load the variable from RAM (it contains the value 200) into register 2. Now register 2 contains “200”.
  2. Increment register 2. Now register 2 contains “201”.
  3. Save register 2 back to RAM. Now the variable in RAM contains “201”.

That’s all fine and dandy. Now let’s say an interrupt occurs between steps 2 and 3, and it doesn’t properly restore the state of the CPU:

  1. Load the variable from RAM. Now register 2 contains “200”.
  2. Increment register 2. Now register 2 contains “201”.
  3. INTERRUPT! The interrupt handler runs, and it did some stuff that used register 2. It didn’t save the original value of register 2, so now register 2 contains whatever the interrupt left it at — let’s assume it’s 1234.
  4. Save register 2 back to RAM. Now the variable in RAM contains “1234”.

In my first interrupt article, I had a very similar example, but you need to understand why this example is different. In the first article’s example, the main program was busy modifying a variable in memory the exact same way this one was modifying a variable in memory. However, the interrupt handler was also writing to that same variable in memory. Because of the possibility of the interrupt handler changing the variable while the main program was also busy changing it, I had to protect against that possibility by temporarily disabling interrupts whenever I was modifying the variable in the main program.

In this example, however, the interrupt routine didn’t care about the variable in memory. It was doing some arbitrary operation — anything. Whatever the ultimate goal of the interrupt routine, it had to change register 2 to get it done. Unfortunately, it didn’t restore register 2 to the value it originally had. After the interrupt routine, the main program went along happily, totally unaware that the register’s value had changed. In a real-world situation, this kind of a bug would likely screw up several different registers, unless the interrupt routine was very, very simple and didn’t need to use many registers to get its work done.

So could we protect the code by disabling interrupts here, just like in the last scenario? I guess so, but it wouldn’t make any sense to do it that way. In order to protect the code from this kind of a problem, you would need to have interrupts disabled during the entire program! Otherwise, any time you enabled interrupts, you would be at risk of your registers being totally corrupted. Needless to say, disabling interrupts during your entire program would not be a viable solution — what’s the point of having interrupts if they’re disabled the entire time?

So what’s the solution to this kind of a problem?

You have to make sure your interrupt handlers play nicely. The first thing an interrupt handler should do is save the values stored in any registers it knows it’s going to be using. Where does it save them? Generally, it will store them onto the stack. Likewise, the last thing an interrupt handler should do is restore any registers it saved when it first began. Also, it may have to execute a special instruction for returning from interrupts as its last instruction.

So rather than guarding against the interrupt everywhere else, you attack it at the source — the interrupt handler has to be nice enough to play along with the rest of your program.

It turns out that some microcontrollers are actually cool enough to save the registers for you. The Freescale 68HC11 is an example of a microcontroller that pushes all of its registers onto the stack before it jumps to the interrupt handler. That’s nice, but the 68HC11 doesn’t have many registers. On a more complex CPU, automatically saving all the registers just isn’t an option.

Some compilers will do all of this for you if you specify that a function is an interrupt handler. You might do this by adding __interrupt__ to its definition:

__interrupt__ void timer_intHandler(void);

It all depends on the compiler and the CPU architecture. You might even have to manually write the interrupt handler’s prologue and epilogue yourself with assembly.

I’m personally a big fan of the way the ARM Cortex-M3 works with interrupt handlers. Before I can get into it, though, I need to talk about ARM functions.

The Procedure Call Standard for the ARM Architecture states that any time you call a function, the first four registers (R0 through R3) are used to pass arguments to the function, and the function can also use them as scratch registers. So any time you call an ARM function, if something important is in R0 through R3, you need to save it before calling the function, because you’re not guaranteed that it will still be there when it finishes up (in fact, if the function returns something, the return value is stored in R0). You are guaranteed, however, that the other registers will still be intact after the function finishes up. Thus, if a function modifies pretty much any register other than R0-R3, it needs to save the value of it so it can restore it to its original state when finished. ARM C compilers automatically generate code that adheres to this procedure call standard. Sounds a lot like what an interrupt handler has to do, right?

The Cortex-M3 takes advantage of this fact. Before it jumps to an interrupt handler, it saves R0, R1, R2, and R3. Then it jumps to the interrupt handler. The C compiler follows the procedure call standard and makes sure it preserves the other registers it uses by generating code at the beginning of the function to push their values onto the stack (and matching code at the end of the function to pop the values off of the stack and back into the registers). Then, when the interrupt handler is finished, the processor restores R3, R2, R1, and R0. Since it works this way, a Cortex-M3 interrupt handler is nothing more than a normal C function! No special assembly or extra attribute needs to be added to the function. It just works out of the box.

As I said, though, on other architectures that don’t take advantage of rules like this, you will probably need to specify to the compiler that a function is an interrupt handler, and it will take care of all the saving registers mumbo jumbo for you.

There is one more thing I want to talk about. How do you tell the CPU what interrupt handler is for what interrupt? Let’s say your CPU has several interrupts — your timer has an interrupt, there’s an Ethernet controller interrupt, a USB interrupt, and several others. How does the microcontroller know that an interrupt handler belongs with a particular interrupt?

This is handled with what is called a vector table. A vector table is just an list of addresses to jump to. The first one might be the reset vector, which is where the microcontroller should jump to when it first starts. The next one could be for the timer, the next for the Ethernet, and so on. The microcontroller’s data sheet will specify which position in the list is for each interrupt. In high-level C terminology, you could say that a vector table is an array of function pointers pointing to the interrupt handlers.

So you create this vector table and put it in a place where the microcontroller expects it to be (often at the beginning of the program’s code), and then the microcontroller will know where to jump whenever an interrupt occurs. Your IDE may help you set up a vector table, and if it doesn’t, there will be sample code somewhere that will show you how to do it.

That’s enough for today. I’ve hopefully gone into more depth about what an interrupt handler is and why it has to be special (except on the Cortex-M3 and possibly others). I hope I didn’t go too crazy when talking about the Cortex-M3 (it’s a really nice architecture, I couldn’t resist!). I’m not sure exactly what my next article will be about, but I’m thinking I may start talking about some of these other crazy peripherals built into a microcontroller such as SPI.

I recently bought a chumby one from Woot. It’s an extremely hacker-friendly device with a 454 MHz Freescale i.MX233 ARM processor, 3.5 inch touchscreen, USB port, accelerometer, speaker, internal USB wi-fi module, and an internal microSD card. It boots from the microSD card, so it’s pretty much un-brickable as long as you keep a backup of the original SD card contents.

It’s an awesomely cool device out of the box, but all of the GUI stuff is based on Flash. Now that’s wonderful and all, but I’m just not much of a Flash guy. I really like working with Qt on embedded devices, so I got a cross compiler up and running, allowing me to design stuff on my desktop computer (running Ubuntu 10.04) and deploy it onto the chumby. I have learned during my time as a developer to document what I did when I do things like this! Two years later it’s hard to remember exactly what I did. I learned this the hard way and now I always document a procedure like this as I’m going through it. I figured while I’m documenting it, I might as well share it with the world. These instructions will walk you through creating a modern cross compiler toolchain for the i.MX233 (compatible with the chumby’s libc), using that toolchain to compile Qt/Embedded 4.7.2, and finally, creating apps on your build machine and running them on the chumby.

The basics

Start out with an Ubuntu 10.04 (“Lucid Lynx”) installation. This procedure will probably work in newer and older versions, but I’m assuming you’re using 10.04. I’m going ahead and using an amd64 install of Ubuntu, but it should work fine in an i386 install as well. Once you have that installed (however you want to do it — directly on the computer, Wubi, in a virtual machine, or whatever other crazy install method you can conjure up), we’re ready to begin.

First of all, we need to install some prerequisite packages for various purposes. In a terminal window, type:

sudo apt-get install build-essential bison flex texinfo automake libtool cvs libncurses5-dev subversion

crosstool-NG

After getting all this stuff downloaded and installed, we’re ready to start creating the cross compiler. Download crosstool-NG (I used version 1.10.0) and unpack it somewhere. crosstool-NG is absolutely amazing. It saves so much trouble while creating cross compilers. You just go through a menuconfig interface similar to the Linux kernel’s menuconfig interface, telling it exactly what you want. If you’re lucky, you just tell it to work and it grabs all the source code, patches it, and compiles it automatically, leaving you with a fully-functional cross compiler after a half-hour or so. In this case, I have verified that the configuration I’m going to give you will work. In other cases, you may have to do some trial and error because some versions of C libraries and binutils don’t work with some versions of gcc. Generally you want to use tools that came from the same time period, as this will give you a better chance of everything working together. Anyway, go into the crosstool-ng directory in a terminal, and type:

./configure --local
make

The –local option tells crosstool that we will be running it directly out of the directory we unpacked it to. Otherwise it would install itself into /usr/local or somewhere like that. I prefer it this way rather than putting it into /usr/local. This should create a script called ct-ng. We will be using this script to configure and create the toolchain.

So let’s start setting up the toolchain! I’d just give you the config file, but I’d rather walk you through setting up crosstool so you better understand how it works. Type:

./ct-ng menuconfig

After a few things finish setting up, you’ll be greeted with graphical interface in the terminal. You can move up and down with the arrow keys. The enter key will go to the selected item. Hit the Esc key twice to go back. Let’s go through the sections:

Paths and misc options

It turns out I’m going to break my own rules here. I’m going to choose newer compilers and binutils with an older glibc. It happens to work in this case, so no harm done. I’m using an older glibc because the glibc on the chumby’s root file system is version 2.8, so I’d like our version to match. If we use a newer version, some binaries will not be compatible with the older glibc, so we’d have to replace chumby’s glibc, and I’d rather not.

Highlight Use obsolete features and press the space bar to select it. This will allow us to choose an older glibc that is probably not compatible. (We’re actually going to use eglibc, which plays better with our setup than glibc)

Scroll down and you’ll notice that Prefix directory is set to “${HOME}/x-tools/${CT_TARGET}. This means it’ll create a folder called x-tools in your home directory which will store all cross toolchains you create. I left this alone, but if you’d like it elsewhere, go ahead and change it now.

Keep scrolling down until you find Number of parallel jobs. This one will save you some time if you have a dual- or quad-core processor. While creating the toolchain, this will allow some of the files to be compiled concurrently, making better use of your multiple-core CPU. For you techies out there, it’s letting you specify the -j option passed to the make commands that will run. I generally set this to the number of cores I have available. Since my 4-core Core i7 has hyperthreading, I normally choose 8. In a VMware virtual machine where I have given the VM two cores to work with, I’d choose 2. Different people have different opinions on what’s the best value here, but I’d say stick with the number of cores you have available and you’ll be fine. If you pick too high of a value your entire system will slow to a halt, and if you pick too low of a value, you’ll be under-utilizing your CPU.

Okay, sorry about that long explanation. Now we’re ready to move to the next section. Hit Esc twice to go back to the menu. Move down to Target options and hit enter.

Target options

Highlight Target Architecture (alpha) and hit enter. Scroll down to arm and hit the space bar. We are telling crosstool-NG that we’re building a cross compiler that will target the ARM architecture, which is what the chumby uses.

chumby uses a Freescale i.MX233, which is an ARM926EJ-S. We need to tell crosstool which CPU we’re targeting, so scroll down to Emit assembly for CPU and hit enter. Type “arm926ej-s” (without the quotes) and hit enter.

Scroll down to Floating point and hit enter. Scroll down to software and hit the space bar. The i.MX233 does not have a hardware floating point unit, so we need to choose softfloat here (otherwise, the kernel emulates hardware floating point instructions, and it gets terrible performance).

We’re done here, so hit Esc twice, move down to Toolchain options, and hit enter.

Toolchain options

Our toolchain will be called “arm-chumby-linux-gnueabi”. The “chumby” part of this is called the vendor string, so we need to configure it as such. The vendor string makes no technical difference–it’s purely a cosmetic thing. Scroll down to Tuple’s vendor string, hit enter, backspace until you have erased “unknown”, type “chumby”, and press enter.

Exit this menu and go to the Operating System menu.

Operating System

Change Target OS to linux. You’ll notice that the kernel version is set at 2.6.37. It may not make a huge difference in some cases, but in this case, we need to pick a kernel version closer to the chumby’s kernel (2.6.28-chumby). Otherwise, the touchscreen library won’t work. We could probably get a tarball of the chumby’s kernel and be exact, but rather than bother with that, I set it at 2.6.27.57. Once you’ve made that change, exit this screen and go to Binary utilities.

Binary utilities

We’re not going to change anything here, but this is where you would change the version of binutils. Leave it at version 2.20.1.

Exit again and go to C compiler.

C compiler

Leave gcc at version 4.4.5. You need to scroll down under Additional supported languages to C++ and hit the space bar to make sure the toolchain is enabled for compiling C++. Now move down to C-library.

C-library

The C library is already set as eglibc, which is what we want. Change eglibc version to 2_8 (OBSOLETE). Normally this would be a bad idea to use an old version of eglibc combined with newer binutils and gcc, but we need version 2.8 in order to be compatible with the chumby’s provided glibc, and it works OK with the newer binutils and gcc. This is the sole reason we had to enable Use obsolete features when we were starting out. We also need to add an extra option here to fix a problem I encountered when I first tried to build this toolchain. Go to extra target CFLAGS and set it to “-U_FORTIFY_SOURCE”. Exit this screen and head over to Debug facilities.

Debug facilities

Go ahead and enable gdb (leaving it at version 6.8). We probably won’t use it, but it won’t hurt to have it. Leave this screen.

All done configuring

We don’t need to mess with anything else, so hit Esc twice and you will be asked if you want to save your new configuration. Hit enter, and you’re ready to build your toolchain!

Type:

./ct-ng build

crosstool-NG will update you on the status of your build as it keeps going on, but for now you can sit back and relax. If you’d like, skip ahead and start downloading some of the other stuff you will need to have as you progress further through these instructions. Depending on the speed of your computer, this compilation might take 15 minutes to an hour.

If all goes well, crosstool-NG will finish by saying “Finishing installation (may take a few seconds)…” followed by a shell prompt. At this point, your cross toolchain is complete! Assuming you left it to be installed at the default location, you can now compile programs for the chumby by using:
~/x-tools/arm-chumby-linux-gnueabi/bin/arm-chumby-linux-gnueabi-gcc

I made a quick test app:

chumbytest.c:

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("It works!\n");
}

compiled it:

~/x-tools/arm-chumby-linux-gnueabi/bin/arm-chumby-linux-gnueabi-gcc chumbytest.c -o chumbytest

and transferred it to the chumby with scp to make sure it worked before advancing any further (assuming ssh has been enabled on the chumby):

scp chumbytest root@MyChumbysName.local:/tmp

to run it on the chumby over ssh:

ssh root@MyChumbysName.local
/tmp/chumbytest
exit

As long as it worked as expected, you’re ready to start working on getting Qt compiled. Well, kind of.

tslib

We need to do one prerequisite in order to get the touchscreen working, and it’s a library called tslib. Download it and extract it.

Start out inside the tslib directory and type:

./autogen.sh

Let’s go ahead and add our cross compiler to our path:

export PATH=~/x-tools/arm-chumby-linux-gnueabi/bin:$PATH

Now we’re ready to configure tslib to be cross compiled, and we’re going to tell it to install itself into a temporary directory inside our current directory. There are two hacks we have to do here–the first is we define a variable ac_cv_func_malloc_0_nonnull to be yes to avoid a compile error, and we also add -U_FORTIFY_SOURCE to the CFLAGS to avoid other errors, the same way we had to during the compilation of eglibc. Here’s the complete command:

ac_cv_func_malloc_0_nonnull=yes ./configure --prefix=$PWD/tslib --host=arm-chumby-linux-gnueabi CFLAGS=-U_FORTIFY_SOURCE

Compile it:

make -j 2 (or 4 or 8 or whatever, depending on how many cores you have)

Install it:

make install

Now there should be a tslib subdirectory inside the tslib directory, containing the compiled library, plugins, and a config file in etc. We really need to put the tslib library and include files into the appropriate place in our cross compiler’s sysroot so we can use it when compiling. Type:

sudo cp -R tslib/lib/* ~/x-tools/arm-chumby-linux-gnueabi/arm-chumby-linux-gnueabi/sysroot/usr/lib

to copy all the libraries into the cross compiler. We should also copy the include files in there:

sudo cp tslib/include/tslib.h ~/x-tools/arm-chumby-linux-gnueabi/arm-chumby-linux-gnueabi/sysroot/usr/include

This will simply make it easier in the future when compiling, so we don’t have to specify where the libraries are located. Now, let’s get the touchscreen working on the chumby before we compile Qt. Transfer the compiled tslib subdirectory to the chumby’s storage:

tar -cf - tslib | ssh root@MyChumbysName.local tar -xf - -C /mnt/storage

Now we need to get a shell into the chumby, quit the chumby control panel, and set up a few environment variables so we can calibrate the touchscreen:

ssh root@MyChumbysName.local
/usr/chumby/scripts/stop_control_panel
export LD_LIBRARY_PATH=/mnt/storage/tslib/lib:$LD_LIBRARY_PATH
export TSLIB_TSDEVICE=/dev/input/by-id/soc-noserial-event-ts
export TSLIB_CALIBFILE=/mnt/storage/tslib/etc/pointercal
export TSLIB_CONFFILE=/mnt/storage/tslib/etc/ts.conf
export TSLIB_PLUGINDIR=/mnt/storage/tslib/lib/ts

Edit /mnt/storage/tslib/etc/ts.conf and uncomment the “module_raw input” line.

You’re now ready to calibrate the touchscreen! Type:

/mnt/storage/tslib/bin/ts_calibrate

If all goes well, you should see “TSLIB calibration utility” and “Touch crosshair to calibrate” appear on the screen. Touch the crosshair for each corner and then the center, and the app will exit (the screen will stay the same, though). Now you’re calibrated! Test it by typing:

/mnt/storage/tslib/bin/ts_test

You should be able to drag the crosshair around on the screen. Hit ctrl-C to exit.

OK, so your touchscreen setup is now complete. You know all of those export commands you just typed before calibrating? You may want to put them into a file somewhere so they can be sourced whenever you need to run them. Whenever you want to use the touchscreen, those environment variables need to be set that way. We are now finally ready to compile Qt.

Qt

Here we go! The exciting part has arrived. We are ready to compile Qt. First, you need to download the latest source code for Qt. Pick the LGPL version unless you have a commercial license. Note that these instructions are based on version 4.7.2. Once you’ve downloaded the tarball, extract it and enter its directory. We now need to set up a Qt spec for the chumby.

Spec

Inside the mkspecs directory is a list of other directories containing specs for many different architectures. There is also a directory called “qws”. We want to use a qws spec, because our Qt will be drawing directly to the frame buffer device without having to have a window server like X11 installed. Instead, Qt will be its own window server. In the qws directory, there is a spec called linux-arm-gnueabi-g++. This one is very similar to the toolchain we are using, so let’s go ahead and duplicate it:

cd mkspecs/qws
cp -R linux-arm-gnueabi-g++ linux-arm-chumby-gnueabi-g++

Now, you need to edit the qmake.conf file inside of our new linux-arm-chumby-gnueabi-g++ directory. You will see several references to tools prefixed with “arm-none-linux-gnueabi-“. You should replace this prefix with the prefix for your toolchain. In fact, I would put the full path to each of these tools. For example, change arm-none-linux-gnueabi-gcc to /home/yourname/x-tools/arm-chumby-linux-gnueabi-gcc, and so on. It may seem stupid because you could always add the directory to your path, but when we’re executing the cross compiler from inside of Qt Creator, it will be easier if the full path is already there. Once you’re done with this, save the file and we’re ready to go!

Compiling

Here is the complete command, along with descriptions of what every option does below it:

./configure -opensource -embedded arm -xplatform qws/linux-arm-chumby-gnueabi-g++ -no-feature-cursor -qt-mouse-tslib -nomake examples -nomake demos

-opensource: specify that we’re using the LGPL. If you have a commercial license you should change this.
-embedded arm: specify that we’re compiling Qt/Embedded for ARM.
-xplatform qws/linux-arm-chumby-gnueabi-g++: specify the make spec that will be used for compiling. This tells Qt where our cross compiler is, and info about the cross compiled system.
-no-feature-cursor: hides the cursor, since it doesn’t make much sense to have one with a touchscreen. If you want a cursor, you can remove this option.
-qt-mouse-tslib: tells Qt to use tslib for its mouse driver
-nomake examples: Tells Qt to skip the examples. I already know how to use Qt so I don’t need a bunch of examples compiled. If you want them, keep it there.
-nomake demos: Same as above.

There are other options you can use to turn off specific features. If you don’t envision ever using WebKit, you can turn it off (-no-webkit). Anyway, type the command above, and you’ll have to agree to the open source license. Once that’s done, it’ll take a few minutes to configure the build. When the configure is complete, type:

make -j 2 (or whatever number of cores you have available)

Once that’s done (and it’ll be a while, trust me on this one!) you can install the libraries by typing:

sudo make install

The reason you need sudo is that Qt defaults to installing in /usr/local/Trolltech. You can change this with the -prefix option on the configure script, but I don’t mind Qt residing there. Once that’s done, you should have a functional Qt. Send the Qt libraries over to the chumby:

cd /usr/local/Trolltech/QtEmbedded-4.7.2-arm/
tar -cf - lib | ssh root@MyChumbysName.local tar -xf - -C /mnt/storage

And now Qt should be on the chumby’s SD card, with its libraries stored in /mnt/storage/lib. We can’t test it until we make a quick Qt app, though, so let’s install the Qt SDK.

Qt SDK

The Qt SDK is a massive download, currently in beta, but it works just fine. We’re going to install it and use it to create a test app to make sure Qt works. First, download the SDK from the Qt download site. I downloaded the Qt SDK 1.1 Beta online installer for Linux 64-bit from here (since my development machine is 64-bit). Make it executable and run it:

chmod +x Qt_SDK_Lin64_online_v1_1_beta_en.run
./Qt_SDK_Lin64_online_v1_1_beta_en.run

At this point, you’ll need to wait for it to finish “Retrieving information from remote installation sources…”. Once that’s done, accept the defaults, allow it to install in ~/QtSDK or wherever else you want it, and eventually you’ll have to wait for it to finish downloading and installing the SDK. Once it’s done, go ahead and allow it to Launch Qt Creator, but uncheck Open Qt SDK ReadMe.

After a few moments, Qt Creator will pop up. We now need to add our cross toolchain so that Qt Creator knows about it.

Adding the cross toolchain

Click on Tools, and choose Options. On the left, click Qt4. You should see a list of available Qt versions. We are going to add a new one, so click the blue + on the right side of the window. Where it says <specify a name>, type “Chumby Qt”, and where it says <specify a qmake location>, click Browse… and navigate to your cross compiled Qt’s qmake binary (/usr/local/Trolltech/QtEmbedded-4.7.2-arm/bin/qmake). Below, it should say “Found Qt version 4.7.2, using mkspec qws/linux-arm-chumby-gnueabi-g++ (Desktop)”. It’s inaccurate in claiming that this is a desktop target, but it’s ok — it still works. Click OK to save your new Qt version.

Creating a test app

I didn’t want to turn this into a tutorial on how to use Qt, but I at least want to walk you through creating a basic app, cross compiling it, getting it onto the chumby, and running it. Click on File and choose New File or Project…. Leave Qt Gui Application highlighted and click Choose…. Name your project TestChumbyQt and save it wherever you’d like. When it asks you to set up targets, uncheck all the targets except for the Chumby Qt target we created earlier. Click Next and leave the QMainWindow class name alone (MainWindow is fine for this example). Accept all the default choices.

Now we are ready to create the test app. Expand the Forms folder on the left and open mainwindow.ui. Click on the background of the newly-created window. Next, on the right side, there should be a “geometry” property. Click the + to expand it. Change width to 200 and height to 150. This should shrink the window a bit. On the left, drag a push button onto the main window. You can resize it to make it easier to press if you’d like.

Compiling the test app

Ok, we’re ready to compile the app. Go to Build and choose Build Project “TestChumbyQt”. If it asks you to save, click Save All. You should see a progress bar on the left side and eventually it will turn green, meaning the compile succeeded.

We’re ready to go. I put my test app in ~/Documents, so your command may be slightly different from mine:

scp ~/Documents/TestChumbyQt-build-desktop/TestChumbyQt root@MyChumbysName.local:/mnt/storage

Environment variables

Now, we need to define a few environment variables in order for Qt to work. You will need to do all of the exports we did above when we were testing out tslib, so if you still have that shell open you can skip doing those again. I’m listing them again just in case, though, plus some extras you need to do regardless.

export LD_LIBRARY_PATH=/mnt/storage/tslib/lib:$LD_LIBRARY_PATH
export TSLIB_TSDEVICE=/dev/input/by-id/soc-noserial-event-ts
export TSLIB_CALIBFILE=/mnt/storage/tslib/etc/pointercal
export TSLIB_CONFFILE=/mnt/storage/tslib/etc/ts.conf
export TSLIB_PLUGINDIR=/mnt/storage/tslib/lib/ts

And the ones you need to do:

export QWS_DISPLAY="LinuxFb:mmWidth80:mmHeight52"
export QT_QWS_FONTDIR=/mnt/storage/lib/fonts
export QWS_MOUSE_PROTO=tslib

The QWS_DISPLAY variable tells Qt about the physical dimensions of the chumby’s screen in millimeters. I did a very crude measurement with a ruler. If you don’t specify it, all the text will appear tiny because we’re working on a small screen. QT_QWS_FONTDIR tells Qt where to look for its fonts. Because it thinks it’s stored in /usr/local/Trolltech, we need to specify this so it knows where it should actually look. Finally, QWS_MOUSE_PROTO tells Qt to use tslib rather than the generic Linux input system.

As I said earlier, you will want to make a file you can source that includes all of these environment variable definitions — they are necessary in order to start a Qt app. Notice I didn’t add /mnt/storage/lib (where we put the Qt libraries) to LD_LIBRARY_PATH — the reason I didn’t is because the chumby already has that directory in its pre-supplied LD_LIBRARY_PATH, so I didn’t want to put it in there twice.

Running the test app

We’re ready to go now. In an SSH session to the chumby, type:

/mnt/storage/TestChumbyQt -qws

(-qws tells TestChumbyQt to be a window server. If you run other apps while it’s running, you don’t want to pass -qws to them–only one app should be the window server.) You may see an error about being unable to open /etc/pointercal, but that’s okay–our environment variable tells it to look elsewhere anyway. If all goes well, your window should appear on the chumby’s screen. Try pressing the button and dragging the window around. Everything should work! You can quit the app by pressing control-C in the terminal, or tapping the X in the upper right corner of the window.

Congratulations, you now have Qt working on the chumby. There are ways to get a Qt app to run at bootup now rather than the flash-based GUI, but that’s beyond the scope of this document. All that’s important is now you know how to run Qt apps.

All done

Unfortunately, I just don’t have the bandwidth necessary to host any binaries or source code for this. However, I have (hopefully) provided you with all the info you’ll need to create the libraries yourself. I have not yet figured out how to make a Windows-based toolchain for this — I know how to create the ARM cross compiler for Windows, but I just don’t know how to get Qt to compile inside of Windows. If I ever discover how, I’ll make another post about it. So for now, you will need a Linux environment for your development.

I know some of what I did was a little crude — I should have specified the ultimate destination directory for tslib when I configured it with –prefix, and I also probably could have specified in the configure script some of the paths that I had to redefine with environment variables, but this works for now. There’s nothing special about /mnt/storage, by the way — I just picked it because it was easy to put stuff there. It might be better suited for a special directory in /usr or something along those lines.

If you run into any problems, feel free to leave a comment and I’ll try to figure out what’s wrong. Enjoy!

Wow! It has been a while. I finally decided to write another one of these. I promised a long time ago to write about timers. Well, almost 4 months later, here we go!

Timers are extremely useful peripherals often built into microcontrollers. Are you going to be doing anything that involves timing or delays in your microcontroller program? Are you going to:

  • Increment a variable every second?
  • Measure the length of time a button is pressed down?
  • Wait for 20 milliseconds?
  • Blink a light every half second?

If you are doing any of the above, or anything even remotely related, you are probably going to be using a timer. A lot of desktop frameworks have a similar kind of setup — Qt, for example, has the QTimer class which allows you to schedule something to happen in the future. .NET has a Timer class that does the same thing. And as you can guess, Mac OS X’s Foundation framework has the NSTimer class. These tend to use lower-level operating system routines, which in turn use hardware timers, and they will run a handler inside your event loop when they fire. You don’t have to know how to use the hardware timers though–the operating system handles it for you. Well, in a microcontroller, you will directly use a timer peripheral to do similar tasks.

Timers can generally be put into several different modes. Some microcontrollers have more complex and powerful timers than others. I’m only going to focus on basic timer concepts here. The first thing you need to know is that timers are usually memory-mapped peripherals built into the microcontroller. They have various configuration registers you can access. The most important register is the counter register. As you can guess, it counts. It holds the timer’s current value, and while the timer is running, it is constantly being incremented or decremented, based on what direction the timer counts. Some timers count up, some timers count down. Some even allow you to set which direction it counts. It doesn’t really matter what direction a timer counts, because you can do all the same things with it either way.

Anyway, so I said this counter register counts up or down, depending on the timer. Let’s pretend that it counts up, for the sake of explaining how this timer works. So the counter starts at zero, and then after a certain amount of time, it will be incremented to 1, and then 2, and so on. How often is it incremented? This is the key to how timers work! Generally the timer runs at a fraction of the system clock rate. So if your microcontroller is running at 100 MHz, the timer might run at 25 MHz. In many microcontrollers, this is configurable. You might be able to set the timer to also run at 100 MHz, or 50 MHz, or 12.5 MHz. Let’s assume that our microcontroller is running at 100 MHz and its timer runs at 25 MHz. This means that in one second, it will be incremented 25 million times. That’s a lot! Alternatively, we could say the counter will be incremented every 1/25,000,000 seconds, or every 40 nanoseconds.

My example here was a little crazy. It’s very doubtful that you need resolution that high. Generally timers, particularly fast ones such as the 25 MHz one we are using here as an example, also have a divider. The divider does exactly what it sounds like — it divides. It does it like this — it has a divider counter register which counts up every time the timer would count. After the divider counter gets high enough, the main timer counter register is finally incremented and the divider counter register is reset to zero. What this does in effect is makes the timer count slower. In this case, let’s say our divider is 25. This means that every 25 ticks of the 25 MHz timer clock, our final counter register is incremented, effectively making it into a 1 MHz clock instead of a 25 MHz clock. It’s just a nice way to slow down the counting. The value the divider will count up to is a value configurable in a register.

So let’s say we’ve configured the timer as follows: the CPU is at 100 MHz, the timer is at 25 MHz, and the timer’s divider is set to 25. Thus, the timer’s counter register is incremented at a rate of 1 MHz, or 1 million times per second. I like making my timers count at nice, even intervals like this because it makes it easier to do the math in your head to figure out how many counts it will take for a certain amount of time to pass. You can do it however you’d like, though!

The only other thing I really need to cover before we jump into the basics is: how to tell the timer to start counting. Timers generally have a configuration register of some kind, and one of the bits in it tells the timer to start counting. For this timer peripheral, let’s say if bit 0 of the timer config register is a 1, it is counting, and if it’s a zero, it’s not counting.

If the timer is configured this way, you now can do some very basic timing. Let’s say all your program does is turn on an LED for a second, then turn it off for a second, and repeat the process. So for our example, we have an LED connected to PORT A, pin 0. Here’s some sample code (keep in mind that TIMER_CONFIG, TIMER_DIVISOR, TIMER_DIVISOR_COUNTER, and TIMER_COUNTER are the registers for the timer):

// Set port A, pin 0 as an output.
DDRA |= 0x01;
// Turn it off.
PORTA &= ~0x01;

// Make sure the timer is turned off
TIMER_CONFIG &= ~0x01;

// Configure the timer to have a divisor of 25, and reset all the counters.
TIMER_DIVISOR = 25;
TIMER_DIVISOR_COUNTER = 0;
TIMER_COUNTER = 0;

// Start the timer (bit 0 of the timer flag register turns it on, in our example)
TIMER_CONFIG |= 0x01;

// Initialize this variable -- it will contain the time we last did something.
uint32_t lastTimeValue = TIMER_COUNTER;

// Do this forever...
while (1)
{
    // Look at the counter's value now.
    uint32_t nowTimeValue = TIMER_COUNTER;

    // Has it been 1 million ticks since the last time we toggled the LED?
    // (1 million ticks = 1 second)
    if ((nowTimeValue - lastTimeValue) >= 1000000)
    {
        // Toggle pin 0 of port A (^ is the XOR operator,
        // think about how it works!)
        PORTA ^= 0x01;

        // Update our "last time" variable to contain this time.
        lastTimeValue = nowTimeValue;
    }
}

Okay, did you follow along? This program will do nothing except toggle that LED on and off. It will toggle it every second. A couple of notes: the data type uint32_t is brought in by including the header file stdint.h. It’s just a portable way of specifying that it’s a 32-bit unsigned value. I could have used unsigned long instead, but I like using uint8_t, uint16_t and uint32_t (and their signed equivalents — int8_t, int16_t, and int32_t) because they make it obvious how big each variable is.

Also, the XOR operator (^) will toggle bits. Remember that PORTA ^= 0x01 is equivalent to: PORTA = PORTA ^ 0x01. This will turn bit 0 on if it’s off, and off if it’s on.

So this works and is fine and dandy, but it takes up the entire main loop of the program! Well, you can put other things to do in the main loop, but if you do it that way, you may not toggle the LED after exactly 1 second, especially depending on what other CPU-intensive things you’re doing in the main loop. This may not matter for something as simple as a blinking light, but for other tasks it could be very important. If you need more precise timing, you need to set the timer to use interrupts instead.

Most timers support a mode where it’s constantly checking the counter to see if it matches another value you specify, and once the counter matches it, it interrupts. This would be the mechanism you would use to do a precise timing. In this case, you have another register called the match value register. You would set your match value register to the value you want the counter to match — 1000000 in this case. What happens after this may depend on the timer. Some timers may have an option to automatically reset the counter back down to zero (or another specified value) after it reaches the match value. In other timers, you might have to adjust the match value instead. I’ll cover both methods so you see what I mean. Assume that the timers and GPIO have been configured as I had them before.

Program 1 (assuming the timer automatically resets the counter back to zero whenever a match occurs):

int main(void)
{
    // All the previous configuration stuff goes here,
    // setting up the GPIO and timer (but don't start the timer yet...)

    // Set the timer match value to 1000000, so it interrupts every 1 second.
    TIMER_MATCH = 1000000;

    // Start the timer
    TIMER_CONFIG |= 0x01;

    // Now our main loop literally does nothing!
    while (1)
    {
    }
}

// This is where the interrupt will jump to -- may need to specify
// to your compiler that it is an interrupt handler.

void TIMER_INT_HANDLER(void)
{
   PORTA ^= 0x01;
}

I may have to explain TIMER_INT_HANDLER to you. This is heavily microcontroller-dependent, but basically you need a way of specifying to the microcontroller what to do when an interrupt occurs. You do this by creating an interrupt handler, and then the address of it gets put into a table of addresses to jump to when a specific type of interrupt occurs (called a vector table). For now, just pretend that TIMER_INT_HANDLER has been properly set up as an interrupt handler for the timer peripheral. I’ll cover that later.

This is a lot simpler! You can put all kinds of other stuff in the main loop, and that interrupt will occur at almost precisely every second. It may vary just a little based on if you have disabled interrupts anywhere in your main loop for interrupt safety (as I mentioned in my last post on interrupts).

Now, here’s another code sample for if your microcontroller does not automatically reset your timer’s counter back to zero after a match occurs:

Program 2 (assuming the timer does *not* reset the counter back to zero when a match occurs):

int main(void)
{
    // All the previous configuration stuff goes here,
    // setting up the GPIO and timer (but don't start the timer yet...)

    // Set the timer match value to 1000000, so it interrupts every 1 second.
    TIMER_MATCH = 1000000;

    // Start the timer
    TIMER_CONFIG |= 0x01;

    // Now our main loop literally does nothing!
    while (1)
    {
    }
}

// This is where the interrupt will jump to -- may need to specify
// to your compiler that it is an interrupt handler.

void TIMER_INT_HANDLER(void)
{
    TIMER_MATCH += 1000000;
    PORTA ^= 0x01;
}

The difference is in TIMER_INT_HANDLER. I added 1,000,000 to the match value, so now it will match again 1,000,000 ticks (1 second) after the last match occurred. In this case, the counter register continues counting past 1,000,000, so by moving the match value up another 1,000,000, it will catch the counter when it gets to 2,000,000. Get it? It’s nothing really difficult, but the first option I showed earlier is easier if your timer peripheral automatically resets the counter back down to zero after a match. So if you have to do it this way, this is how you do it–otherwise, I’d recommend the first approach. You may be asking me: in this method, why didn’t you just set TIMER_COUNTER to zero instead of add 1,000,000 to TIMER_MATCH? Wouldn’t that have the same effect? You may think that it would, but it actually does not. Here’s why:

Between when the timer signals that a match occurred and we actually get to execute the interrupt handler, some time passes by. If the timer itself resets the counter back to zero, this is no problem, because it can reset the counter instantly as soon as the match happens. But if we try to do it ourselves manually, we will only reset it back to zero after so much time has already passed. In other words, the counter might actually be up to 1,000,002 or so before we tell it to go back to zero. In effect, this causes us to toggle the LED every 1 second PLUS however long on average it takes to get to that first instruction that resets the counter. By adding 1,000,000 to the TIMER_MATCH register instead, it guarantees that the next match will occur exactly 1 second after the last match occurred. This may not matter for something as simple as toggling an LED, but if you add up that extra delay over time in a very time-sensitive algorithm, it would cause inaccuracy.

Note that at one point we will overflow the 32-bit TIMER_MATCH register. When the match register gets up to 4294000000, the next time we add 1000000 to it, we will get 4295000000, which is larger than the maximum 32-bit integer (4294967295). That’s okay — it will wrap around and work correctly. The C standard guarantees that unsigned integers will wrap around correctly — e.g. if you add 1 to 0xFFFFFFFF, you will get 0. So in this case, when we add 1000000 to 4294000000, we will end up with a match value of 32704 (4295000000 % 4294967296), and all will be well with the world (the timer counter itself will also overflow correctly back up to 0, and match when it reaches 32704, exactly 1000000 higher than 4294000000 after wrapping).

These are the two simplest ways to use timers. Timers also have all kinds of other crazy features; I described the most common way they are used. I hope I didn’t make that too confusing. It was a lot to digest, but basically, here’s a summary:

  1. Timers are memory-mapped peripherals, and you know what their clock rate is based on what you read in the microcontroller’s data sheet and how you configure it.
  2. Timers have divisors, so you know exactly how long it takes between increments (or decrements) of the timer’s counter.
  3. You can use that information alone to do time-based stuff, but if you want maximum accuracy you should use an interrupt.
  4. To use an interrupt, you set a match value and the timer will interrupt whenever it reaches the match value.
  5. Some microcontrollers will allow you to automatically reset the counter whenever the match value is reached, which is handy for periodic tasks.
  6. If your microcontroller doesn’t automatically reset the counter after a match, you should update the match value instead of resetting the counter value on your own, or your interval between interrupts will be slightly longer than it should be.

Ok, that’s enough for today. I’ll talk more about interrupts and interrupt handlers next time. Have fun!

In my last post, I made the decision that the next post would be about interrupts. Well, here goes nothing…

Interrupts allow a program to be temporarily stopped while another section of code (an interrupt handler) is executed instead. When the interrupt handler finishes up, the program continues where it left off. You can turn interrupts on and off, usually (always?) with a single assembly instruction.

So I’ve described what an interrupt is, but what’s the point? Where are they used? Peripherals built into the microcontroller use interrupts to tell the program that something happened. Examples: there might be an interrupt to tell the program that the serial port just successfully finished sending out a character. Or there might be a timer set up to cause an interrupt to occur every millisecond (which you could use to cause something to occur after a specified number of milliseconds). As you could imagine, this can be extremely useful. Often, you hear about polling I/O versus interrupt-driven I/O. With polling, your program sits in a loop waiting for something to occur, wasting lots of cycles that could be used elsewhere. With an interrupt-driven architecture, your program can be doing other things, and when it’s ready it will receive an interrupt.

Interrupts are a tricky concept because you have to be extremely careful when you’re coding a program that might be interrupted. Let’s take, for example, the following C statement:

blah = blah + 5;

Assume that blah is a variable somewhere. Obviously, that line of code will take whatever is stored in blah, add 5 to it, and store the new value into blah. That one statement does not directly translate into a single assembly language statement — at least in common microcontroller architectures. In general it will translate into three instructions:

1) Load whatever is stored at the memory address of blah into a register
2) Add 5 to the register’s value
3) Store the contents of the register to the memory address of blah

OK–so what’s the big deal? The deal is that since the single line of C translates into 3 assembly instructions, it’s not an atomic operation. An interrupt could occur in between the first and second instruction, or between the second and third instruction. You’re not guaranteed that nothing else will occur while that line of code is executing. If you’re expecting an interrupt to come in and modify the value stored in blah, you may end up with unexpected results. Let’s say that your interrupt routine consists of one line of code:

blah = 0;

If the interrupt fires in between two of the instructions belonging to the line that adds 5 to blah, something weird might happen. Example:

1) Load whatever is stored at the memory address of blah into a register.
2) INTERRUPT! blah = 0 now.
3) Add 5 to the register’s value
4) Store the contents of the register to the memory address of blah

Do you see what happened? The interrupt was supposed to clear blah, but it didn’t actually end up getting cleared. The first instruction read the value of blah into a register, and then the interrupt cleared blah. But that didn’t change the register’s contents, so 5 was added to blah‘s old contents still residing in the register and then the register was re-stored into blah. It’s as if the interrupt never occurred. Ideally, after this code runs, blah should contain 0 (or maybe 5, if the 0 immediately has 5 added to it). Instead, in this particular case, it contains the old value of blah + 5.

This example scenario above is very similar to a real-world bug that I have personally seen in an actual product. The end result was that it caused a speedometer to occasionally show a speed twice as large (and extremely rarely, 3 times as large) as the actual speed.

This kind of subtle behavior is what makes programming with interrupts difficult to grasp when you’re just getting started. It can cause all kinds of crazy stuff to happen that is very difficult to debug.

So how would you solve this problem in a real program? Let’s say you really did want to make sure that blah was cleared by the interrupt. One way to do this is to temporarily disable the interrupt from occurring while you’re modifying blah. Usually the easiest way to do this is to disable all interrupts, do the operation, and then enable all interrupts again:

__disable_irq();
blah = blah + 5;
__enable_irq();

Pretend that __disable_irq() and __enable_irq() are macros that end up resolving to assembly statements for enabling or disabling interrupts. This will guarantee that when blah is cleared, it will not happen in the middle of adding 5 to it. If the interrupt is supposed to happen while interrupts are disabled, it will occur as soon as interrupts are enabled again.

Think about what I said there — the interrupt may not occur exactly when it’s supposed to. If this is a time-sensitive interrupt, it could be bad to delay it from happening. So if you do this, you should minimize the amount of code you have wrapped in a disable/enable interrupts combination, so if an interrupt does get held off, it doesn’t get held off very long.

I think that’s enough about interrupts for today. This should be a decent introduction to interrupts and why they have the potential to cause all kinds of problems. But they are really useful, and it’s vital to understand them if you’re going to be writing software for a microcontroller. Remember how I talked about an interrupt that could occur every millisecond? I’m going to go into how to do that kind of thing in my next post. We’ll be moving back into peripherals built into microcontrollers: in this case, timers.

In my last post in the series about microcontroller programming for normal programmers, I talked a little bit about general purpose I/O. I’d like to expand on this topic today by talking about inputs, outputs, pull-ups, and pull-downs. As a summary, a GPIO pin on a microcontroller can be set up to be an input or an output, and if it is set as an input, there are various options you can set for how the input works. This is the first step toward getting the microcontroller to actually do something. I’ll go into more detail now.

When I was talking about a hypothetical “light-emitting diode” peripheral last time, I was basically describing the output functionality of a GPIO port. If you set a GPIO pin as an output, you can control whether its output is a 1 or 0. What does this 1 or 0 mean? Well, a microcontroller generally operates at a voltage, such as 5 volts or 3.3 volts. I’ve been playing with various incarnations of the ARM Cortex-M3, and they have all been 3.3V, while older microcontrollers like the Freescale 68HC11 run at 5V. I’ve also seen some new Cortex-M3s that operate at 5V, but let’s just assume for today that we’re working at 3.3V. Generally, this means your GPIO pins also operate at that same voltage. Basically, a 1 is represented by 3.3V (VCC), and a 0 is represented by 0V, or ground (GND). Since the LED was connected to one of the microcontroller’s pins, we could turn it on or off by setting the GPIO pin’s output value to 0 or 1.

If you understand everything I just wrote, congratulations. You understand outputs.

Inputs are different. You have something else hooked up to your GPIO pin, but you’re not controlling it. Instead, you’re determining whether it’s currently “showing” a 1 or 0 value to you. What kind of use would this have? Well, the easiest example is probably a push button. If you want to determine whether a push button is “pushed” or “released”, you could hook it up to a GPIO pin so that you can read whether you’re seeing a 1 or 0. However, because of how electricity works, it’s going to get slightly complicated, so bear with me.

If you’re not familiar with how buttons work, here’s a quick explanation. Buttons have two terminals on them. When the button is pushed, the terminals are connected together internally, creating a “closed circuit”, allowing electricity to flow through them. If the button is not being pushed, the terminals are not connected together, so electricity is not allowed to flow between them. Got it? Good!

When you wire a button to a microcontroller’s GPIO pin, you hook one of the button’s terminals to the pin, and you hook the other terminal to either ground or VCC (3.3V in our case). But you’re not done yet! Let’s assume we wired the button to GND (0V). See the picture above. So when the button is pushed, the circuit will close, and thus, it will be as if the microcontroller pin was connected directly to ground. If you read the port pin at this time, you will get a 0. However, if the button is not pressed, the circuit does not close. In that case, as far as the microcontroller pin is concerned, it’s not connected to anything else in the circuit. It’s floating. This means the value you read from the pin will be unpredictable.

So…we need a way to make it so the pin thinks it has 3.3V connected when the button is not pressed. That way, it would read a 1 if the button is released, and a 0 if it’s pressed. How can we do that? Well, we need to hook it to VCC as well. So we leave the existing connection to the button in place, but also add another connection so the port pin is always connected to VCC. See the picture below.

Let’s think about what this will do. When the button is released, the port pin is connected directly to VCC, reading a 1. But if it’s set up this way and you press the button, the port pin will still be directly connected to VCC, but closing the button’s circuit will also directly connect it to GND at the same time. In other words, you will have VCC and GND directly connected together with no resistance in between (the button itself doesn’t count as resistance — it’s just like a wire). This is commonly referred to as a short circuit, and it will cause things to get hot very quickly. You will probably burn up the circuit board and the microcontroller, creating some magic smoke in the process.

Now what? How can we safely stay hooked to both VCC and GND simultaneously? We need a resistor. Instead of connecting the GPIO pin directly to VCC, put a resistor between the pin and VCC. See below.

When the button is released, the pin will no longer be directly connected to VCC, but it will be connected to VCC through a resistor, which is perfectly OK, and will still cause the voltage on the pin to be 3.3V, or 1. When the button is pressed, the pin will be connected to VCC through the resistor, and also directly to GND through the button. If you think about it, this also means VCC will be connected to GND through a resistor. Since there’s a resistor in between, you won’t get any smoke. It’s no longer a short circuit. Now let’s look at it from the point of view of the port pin–it’s still simultaneously connected to GND and VCC. Since it’s connected to VCC through a resistor, and directly to GND, GND will “win”. VCC is trying to pull the port pin’s value up to a 1, but with the resistor in between, it’s a very weak connection compared to the pin’s connection to GND, so GND keeps the port pin pulled down to 0.

I know this may be kind of confusing, especially if you have no experience with electricity. I hope the pictures make sense. I didn’t understand this concept at first, but it’s pretty important. You need to understand it so that you can understand pull-up and pull-down resistors.

Basically, here’s the purpose of pull-up and pull-down resistors. When nothing is hooked up to a pin, a pull-up or pull-down resistor will give that pin a default value. If you have a pull-up resistor enabled, the default value will be a 1. If you have a pull-down resistor enabled, the default value will be a 0. In our example, we started out with the microcontroller only hooked to the button, which gave the input a value of 0 when the button was pressed. We then added a connection to VCC through a resistor to give the input pin a value of 1 when the button was not pressed. It turns out that what we added is called a pull-up resistor, and most microcontrollers nowadays have them built in. You just have to enable them.

So instead of having to add a resistor outside of the chip, we actually can get away with hooking the button directly to the pin as we did in the first picture, which I am showing again below.

Until we enable the internal pull-up resistor on that pin, we’ll run into the same problem I mentioned at first–when the button is not pressed, the value we read will be unpredictable, because the pin is not hooked to anything in the circuit. So if we enable the pull-up resistor, the full circuit will look just like the third picture above where we added the resistor. It’s just that the resistor connected to VCC is inside the chip, so we don’t have to bother adding it to our circuit board–we just have to tell the microcontroller to turn it on. Nice, huh?

Pull-down resistors work the same way, but they connect the pin through a resistor to ground, rather than VCC. Many microcontrollers also have pull-down resistors built in.

I’ve talked enough about the hardware side for one day, so now let’s get to the part we programmers enjoy–the software. Usually, you have a memory-mapped GPIO peripheral. Let’s assume we have a hypothetical PORTA peripheral mapped in memory to address 0x100.

PORTA is made up of four 8-bit registers:

DATAA
DDRA
PULLUPA
PULLDNA

DATAA is at 0x100, DDRA is at 0x101, PULLUPA is at 0x102, and PULLDNA is at 0x103.

I’m actually going to explain the DDR register first. DDRA stands for data direction register A. It describes whether each pin on PORTA is an output or an input pin. An input is represented by a bit being zero, and an output is represented by a bit being 1. So if DDRA was set to 0x03, then port A pins 0 and 1 are outputs, and the rest of its pins are inputs. It’s as simple as that.

If you set a pin as an output, you can change its output value by changing the appropriate bit in the DATAA register. For instance:

DATAA |= 0x01;

will set port A, pin 0 to the value “1” or “high” or “3.3V” or however you’d like to think of it.

DATAA &= ~0x02;

will set port A, pin 1 to the value “0” or “low” or “ground”.

If you read my last post about memory-mapped peripherals, this should all make sense.

On the other hand, if you set a pin as an input, you have a few more options. You can turn on the pin’s pull-up or pull-down resistor (but certainly not both at the same time–that would make no sense). You don’t have to turn on either resistor if you don’t want to. It only makes sense to enable pull-ups or pull-downs on pins set to input–the value will be ignored for outputs.

PULLUPA |= 0x04;

will turn on the pull-up resistor on port A, pin 2.

PULLDNA |= 0x08;

will turn on the pull-down resistor on port A, pin 3.

Finally, to read the input value on an input pin, you read the DATAA register. If you only care about a specific pin, you can ignore the rest of the bits using bitwise operations in C. For instance:

if (DATAA & 0x04)

The above line will be true if port A, pin 2 has an input value of 1 (in our example, that would mean the button connected to it is not being pressed)

if ((DATAA & 0x04) == 0)

The above line will be true if port A, pin 2 has an input value of 0, meaning the button is pressed.

If you try to read the input value of an output pin, it will just tell you the last value you set it to output.

Whew! You made it! That’s really all you need to know about GPIO for now. The way I described the software interface to these GPIO pins is generally exactly how it works in a real microcontroller. The registers might have slightly different names, and their organization in the memory map may be different, but that’s essentially how it goes. I did skip some more advanced stuff, but for now the other stuff is not important.

Congratulations–you’ve made your way through understanding the first built-in peripheral in a microcontroller. My next article will be an introduction to interrupts–a very important concept in microcontroller programming. The reason they are important is that they tell you that an operation has completed, or something is ready. Interrupts also took me quite a while to fully understand, but they are another important concept. If you’ve ever used signal handlers in your regular desktop programs, it’s the same kind of concept. Your program stops and another portion of code executes instead, and then your program picks up where it left off as soon as the other portion of code is done. Anyway, I won’t go into any more detail about them until my next article. See you then!

Note: I have written a post containing updated compatibility information you may want to read here. The remainder of this post below is still very important, but I’d like to make sure everyone has the most up-to-date information about compatibility between the different DLLs and parallel port cards out there. If you’re looking for my patched io.dll for Willem programmer compatibility, see below.

Last year I bought a Willem EPROM programmer board from Sivava. It’s basically a cool little board with various sockets for plugging in EPROM/EEPROM/Flash/etc chips for reading/erasing/writing. Apparently it can even program some AVR microcontrollers. I have the PCB50 version of the board.

Here’s the deal. It has a USB port, but it’s only for supplying power. All communication goes through the parallel port. As everybody should know at this point, the parallel port is on the way out. No, scratch that. The parallel port is long gone. I had to use a really old HP Pavilion with a Celeron running Windows 98 to do anything with it. The programmer worked great, and I was able to fix a computer’s BIOS chip that I had messed up while trying to hack its BIOS.

Let’s fast forward to over a year later (a.k.a. now). I have a homebuilt PC with an Intel DX58SO motherboard and a Core i7 CPU, running Windows 7 Ultimate edition, 64-bit. The DX58SO literally has no legacy peripherals, other than a single PCI slot. It has no PS/2 ports, no parallel port, no serial ports, and no standard IDE ports. It does have a variety of types of PCI Express slots, though.

I recently bought a sweet PCI Express 1x card with four serial ports and a parallel port from Newegg. (Note: Newegg’s product specs lie about this card — the parallel port does not support EPP or ECP mode, according to a sticker on the box, even though Newegg says it does). I remembered that I had my programmer and decided I totally needed to get it working in Windows 7.

Easier said than done.

It’s difficult enough to get low-level legacy stuff working in Windows 7, but when you’re using the 64-bit edition, a lot of older stuff breaks even more. Also let’s remember that add-on parallel ports do not get mapped to the standard I/O addresses for parallel ports (0x378 and 0x278), but instead some other random address (mine is at 0x3000). I tried running the software that came with the board, but it just gives me errors and actually won’t let me exit without forcing it to quit from the task manager.

Let’s go on a Google adventure. Google lesson #1: sometimes when you’re looking for info about Windows 7 64-bit, you can find very useful stuff when you search for Vista 64-bit (or XP 64-bit) instead. My first search was willem vista 64-bit.

The second result was a digg posting titled Willem Eprom for Vista and 64bit XP (digg post is no longer available; link removed). The linked page is a forum posting at a forum called onecamonly.com. The post is by the admin of the site, and he mentions to install software called TVicPort and then a modified io.dll file. The first comment on the digg posting was by a user named rabitguy, who said he had a Willem board working on Windows 7 64-bit with tvicport and iodllwrapper.

So I kept seeing this io.dll and iodllwrapper stuff. What exactly is it? Let’s Google for “io.dll”.

The first result is to a homepage for io.dll. Basically, it explains that it’s a library allowing direct port access from several different Windows versions. Awesome! Except it doesn’t mention Windows Vista or Windows 7, or anything 64-bit at all. Crap. Well, I looked in the installation directory for the Willem software that came with my Sivava programmer board, and sure enough, in C:\Program Files (x86)\EPROM50, there’s an evil file named io.dll. So that’s why it doesn’t work.

So anyway, I searched for iodllwrapper, deciding to follow the advice of rabitguy. The first result is to a forum posting on an Amiga message board. I did a search on that page for “Willem” and found a posting by Toni Wilen who wrote a 64-bit-compatible io.dll wrapper which depends on TVicPort and uploaded it as an attachment to the forum, called iodllwrapper.zip. He even included the source code. Aha! So I think I get it. He wrote a DLL that provides all the functions that io.dll would provide, except rather than implementing the raw functionality himself, he forwards the relevant function calls to TVicPort, which handles all the low level stuff (in a manner that works on 64-bit operating systems!). Actually it’s a pretty genius idea. So I downloaded his DLL and tried it out, replacing the stock io.dll file that came with the Willem software with his new wrapper.

I crossed my fingers and opened the programmer software. Awesome! I no longer got a bunch of weird errors when the program opened! I’m pretty sure Toni’s DLL would have worked great, but there’s a problem in my case. I don’t have a built-in parallel port, so my parallel port is at a non-standard I/O address (0x3000). The Willem software only lets you choose from a list of three standard I/O addresses where built-in parallel ports would appear.

Ugh! So I was stuck again. At this point I was about to throw in the towel. But first, I thought about it and came to the conclusion that I can’t be the only one with this problem. So I searched for io.dll willem address.

The first result this time was Ben Ryves’ Remapped IO.DLL. So someone else had the exact same problem! Ben also wrote an IO.DLL wrapper (and he included his source code, too!). His solution is to add an additional file called io.ini into the same directory as io.dll. You put the I/O address of your parallel port into that file (so my io.ini file would contain one line — 0x3000), and set the Willem software to use LPT1. The wrapper DLL looks for any I/O reads/writes in the LPT1 range and remaps them to actually occur at the address specified in the io.ini file. This is exactly what I needed!

It uses another DLL called inpout32.dll to do the dirty work. Actually, Ben’s site very nicely describes everything his DLL does, so I won’t go into any more detail about it.

Well, it turns out that his DLL didn’t work for me, either. It seems that it’s just not compatible with 64-bit Windows 7, at least in my experience. I just could not get it to work. The Willem software would not detect the connected board. I looked at the homepage for inpout32, and apparently there is a 64-bit version, so maybe if I had fiddled long enough I could have gotten inpoutx64 to work, but at this point I actually had an idea of my own, after looking at the source code that Ben included for his DLL.

I knew from everything I had read that Toni’s 64-bit-compatible io.dll wrapper using TVicPort did work. All it was missing was the remapping. So I took Ben’s code and modified it to use TVicPort rather than inpout32.dll. (Alternatively I could have added the remapping to Toni’s code.) I only changed a few lines. I just changed the calls to inpout32.dll for reading/writing to use the corresponding TVicPort functions instead, and also added initialization and deinitialization code for TVicPort.

So I compiled it with Visual C++ Express Edition 2008…ran the “Test Hardware” function on the Willem software…and success! It found the hardware! I was stoked, so I grabbed a BIOS chip from an old motherboard I’m not using anymore (Asus A7V133). It’s a SyncMOS F29C51002T. I chose that model in the software, set up the DIP switches correctly, and stuck the chip in the cool ZIF socket on the programmer board. I then read the BIOS from the chip. I looked at the read buffer and it looked good! I saw stuff about an Award BIOS, so it sure looked like it was working. I happened to have a good copy of the same BIOS file from when I had messed with that same chip on the older computer, so naturally I did a diff against them to make sure that the file was read correctly.

It didn’t read correctly. It differed by just a few bytes. It was mostly OK, but mostly is not good enough when you’re reading to/writing from chips that contain computer code and/or data. At this point I decided to sleep on it and think about it the next day. That approach really works well in all aspects of life in my experience. When I had trouble learning to play a piano piece I would sleep on it and the next day it was like my brain had somehow prepared itself ahead of time, and I would play the part I had been struggling with perfectly.

The next day I noticed that the TVicPort driver actually has an option for two I/O port access “modes.” The default mode is hard mode, which is slower, but provides more reliable access to an I/O port if it’s already been opened by a different driver. Soft mode is faster, but has trouble if a port is already open by another driver. On a whim I decided to try out soft mode. I read the chip again, and this time it worked perfectly. I then erased it, wrote the file back, and compared it. Perfect. I did this several times just to make sure I wasn’t getting lucky, and it worked every time.

So either I got really unlucky on my first try with hard mode, or using soft mode fixed it. I don’t know which one is the case, but regardless, I now have my programmer working in Windows 7 64-bit. And this is the end of our Google adventure.

Google can do a lot of great things if you’re willing to sit down and search. And search. And search. I didn’t actually find all this stuff that easily. I tried many different searches, wording things slightly differently. I ended up only showing you guys the search queries I tried that gave me interesting results.

So…thank you to everyone I mentioned in my post. I’ve never met you or even corresponded with you, but you all helped me get this working. Thank you rabitguy, admin at onecamonly, Toni, and Ben. With all of your info I got it working.

So naturally, here’s my io.dll wrapper, based on Ben’s wrapper, along with the source code for it.
Remember, I’m not responsible for any damage done by this software–it’s been tested lightly and seems to work for me, but your mileage may vary!
Download 64-bit remapped IO.DLL wrapper and source code (new version 1.1 which fixes a bug–thanks Paco!)
You will also need to download TVicPort from here.

Install TVicPort, then restart your computer (mine didn’t work until I restarted, and it does ask you to restart). Replace the io.dll file in the Willem software directory (C:\Program Files (x86)\EPROM50 on my computer) with this patched version. Open up the io.ini file, replace the address there with your parallel port’s I/O address (make sure you keep the “0x” before the address or it won’t work), and put it in the same directory you just copied the DLL file to. Set the Willem software to use LPT1 (0x378). If everything is working correctly, you should be able to go to the Help menu and choose Test hardware, and it will say “Hardware present” in the status bar at the bottom.

If you need to compile the modified io.dll for yourself or make modifications, grab TVicPort.h and TVicPort.lib from the TVicPort installation (C:\TVicPortPersonal\Examples\MSVC) and put them in the project directory. After doing that it should compile.

Hope this helps anyone out there, and thanks again to everyone whose information and source code helped me out!

A quick note: To find your parallel port’s I/O address, go into the Device Manager and open up your parallel port. It’s in the Resources tab:

The I/O range that is 8 bytes long (in my case, 3000-3007) is the important one. So prefix the start address with 0x (so in my case, I ended up with 0x3000) and that’s the value you should put in the io.ini file.

Version History:

  • 1.1 – Fixed a bug where I was calling functions from DllMain that I should not have been calling, causing the DLL to not work for at least one person – August 15, 2011. [Download]
  • 1.0 – Initial release – October 9, 2010. [Download]

I couldn’t resist jumping into my “microcontroller programming for high level programmers” series as soon as possible, so I’d like to go into a bit more detail about where I left off in my last post–memory-mapped peripherals.

Like I said in my last post, I missed out on memory-mapped peripherals during my CS education (which is not too surprising). My mental model for how memory addresses work was missing a chunk of knowledge. I thought that every memory address was a storage location–either RAM (readable and writable) or ROM (only readable). It turns out that memory addresses in computers can also be used for other stuff, like telling an external chip or a built-in peripheral to do something.

A memory-mapped peripheral works exactly how I just described. The peripheral reserves a portion of the address space on the computer. You write to (or read from) somewhere inside that address range, and the peripheral does something in response. Let me give you a simple example:

Let’s pretend that a microcontroller has an “LED” peripheral. By LED I mean a light-emitting diode–a little green or red or whatever other color light. Get used to the acronym “LED” because it’s very common. An example of an LED is the power light on your computer. Anyway, back to the pretend world. Imagine that the physical microcontroller chip has eight pins you can hook up to LEDs to light up, and your program can control them. The “LED” peripheral is mapped to memory location 0x1234, and it’s one byte long. Each of the eight bits in the byte controls one of the LEDs. If a bit is one, its corresponding LED will be turned on, and if the bit is zero, its corresponding LED will turn off.

In a C program, you would then turn the LEDs on and off by changing the value at address 0x1234. I’m going to assume you understand pointers. I’m creating a pointer so that I can manipulate the LED peripheral. Remember that uint8_t is usually typedef’d as unsigned char–an 8-bit integer that has no sign bit, so you can mess with all eight bits without worrying about side effects. Here’s some sample code:

#include <stdint.h>

/* Get a pointer to the LED peripheral */
/* Note that you cannot do this in Linux in a user program */
/* because each user program has its own virtual address space */
/* and other sections of memory are protected from direct access */

volatile uint8_t *LED = (volatile uint8_t *)0x1234;

/* Turn all LEDs off */
*LED = 0;

/* Wait for 1 second -- just pretend this is already implemented */
wait_milliseconds(1000);

/* Turn every other LED on -- 0x55 == 01010101 in binary */
*LED = 0x55;

wait_milliseconds(1000);

/* Turn on the LED associated with bit 7 -- 0x80 == 10000000 binary */
*LED |= 0x80;

wait_milliseconds(1000);

/* Turn off the LED associated with bit 0 -- 0x01 == 00000001 binary */
*LED &= ~0x01;

Ok–I hope that wasn’t too much to start out with, but I’ll try to explain in detail what I did.

First, I created a pointer that points to the LED peripheral’s address (0x1234). I said earlier that the peripheral is one byte long. That’s why I picked a uint8_t as the type — because a uint8_t is 8 bits, or 1 byte, in size.

You may have noticed that I defined the pointer as volatile. Why did I do that? I’ll tell you as soon as I finish explaining the rest of the code. It will be easier to describe what it does as soon as you understand exactly what the code does.

After that, I write a zero to the LED peripheral. Remember that since the variable “LED” is a pointer, I have to use the * operator to tell it to write to the address to which LED is pointing. Since every bit of a zero byte is zero, this turns off all the LEDs (if any were on already). Next, I call an imaginary function to wait for 1000 milliseconds, or in other words, one second.

Then, I write 0x55 to the LED peripheral, turning on the LEDs associated with bits 0, 2, 4, and 6. Of course, I wait a second here too.

For the last few operations, I turn on the LED associated with bit 7 (without affecting the other LEDs), wait another second, and then turn off the LED associated with bit 0 (again without affecting the other LEDs). If you haven’t seen the bitwise operations |, &, and ~ used much in C, you should definitely learn them before venturing onward. They will be used endlessly to manipulate individual bits in memory-mapped peripherals. Sometimes you want to turn on a single bit at an address while leaving all the rest of the bits unchanged. The | operator is perfect for this. Likewise, the & operator (combined with ~ for a bitwise NOT) works great to turn off a single bit without affecting the other bits. Study those two lines in my example code carefully until you understand exactly what they are doing.

If you were to run a program like this on a real microcontroller that had a real “LED” peripheral, you would physically see the LEDs changing each time the corresponding code wrote to the LED memory-mapped peripheral.

Back to the volatile keyword for a minute. Declaring a pointer as volatile forces the C compiler to always access the memory address a pointer points to, no matter what, with no optimizations allowed. You’ll notice that I write several different values to the LED peripheral in this program. A good compiler might notice that I first write 0 to it, then write 0x55, then turn on bit 7 (effectively writing 0xD5) and then turn off bit 0 (effectively writing 0xD4). It might think “hey, why should I do all these intermediate operations? I know that it will effectively end up with the value 0xD4, so why not just write that in directly?” For normal variables in a program, this could very well be a great idea to make your program run faster, because it would save unnecessary arithmetic operations from needing to be performed. For memory-mapped peripherals, it’s not such a great idea, because those intermediate values being written to the peripheral actually have a meaning. The volatile keyword simply makes sure the compiler does not make any optimization decisions like that. Whenever you’re accessing a memory-mapped peripheral, a pointer to it should be defined as volatile.

I will finish off this first real post of the series with a reality check. In my experience, there’s not really such thing as an “LED” peripheral. Instead, what you end up using is a “GPIO” peripheral. GPIO stands for General Purpose Input/Output. A microcontroller might have several “ports” — port A, B, C and D, for example, each eight bits. The physical chip would have pins corresponding to each port. Port A pin 0, port A pin 1, and so on. There would also be corresponding memory-mapped peripherals for each port. So if you had LEDs hooked up to port A pins 0 through 7, you could then do exactly what I showed in my “LED” example, except you would write to the GPIO port A peripheral, which would be memory mapped similar to how I described before.

It’s a little more complicated than that because I only really described the “output” capabilities of GPIO ports. You can also configure GPIO pins as inputs, so they read data from an external source and your program can see whether they are “high” or “low”. I hope that makes sense, and I’ll go into more detail about GPIO in the future. The memory space of a GPIO peripheral is more than just a byte wide. There are other sections of its memory space for configuring things like whether a pin is input or output, and also pull-up/pull-down resistors for inputs. In general, you will see these various sections of the memory-mapped address space referred to as the peripheral’s “registers.”

Anyway, that’s all for this first post. If you happen upon this post and have any questions, feel free to ask in the comments and I will try my best to answer them.

When I went to college, I majored in computer science. I took classes about algorithms, data structures, software engineering, design patterns, systems analysis and design (now that is a BORING topic!), web development, databases, operating systems, and even assembly language and computer architecture. To be honest, I actually thought those last two classes I listed were some of the more interesting topics my education covered (and they were both electives, not really part of the core CS curriculum). Maybe that’s a sign I should have done more in the computer engineering side of things. I don’t know for sure.

I’m not saying I didn’t enjoy my CS education, because I did! It was awesome, and I always looked forward to taking my CS classes. I was a math minor as well, and as you can probably guess, I enjoyed taking math classes. I actually took more math classes than I needed (such as operations research) just because they were fun. I guess my point is that I’m not dissing on my CS education; I’m only trying to point out that I had multiple interests in college.

After graduating college, I ended up working at a place that does a lot of work with microcontrollers. I’ve also written some “ordinary” desktop or web-app software, but I’ve found myself really enjoying the work with microcontrollers. As a person with a bachelor’s degree in computer science, I didn’t have any trouble picking up on the concepts. After all, computer science is not a “here’s how to program a generic desktop application in Visual Studio” type of education. You can apply what you learn to many different fields. But in order to fully understand the concepts, you have to do examples, at least in my opinion. And the examples I did in college were C/C++ console applications running on Linux, Java console and GUI applications, shell scripts, and websites in various flavors such as Java servlets, JSP, ASP.NET, PHP, and Ruby on Rails. All of this stuff is pretty high-level–even C apps running on Linux are high-level compared to bare metal code. So in doing this, I understood the general computer science ideas that the curriculum was actually teaching, but I didn’t really have any kind of concrete experience with directly programming to a microcontroller. Even in the assembly class, we ran programs on floppy disks inside of DOS, so that wasn’t bare metal either.

So as you might expect, when I first started at the place where I work, I knew literally nothing about how to use microcontrollers. I had no idea how microcontrollers actually did anything. I remembered from my assembly language class that x86 machines use a software interrupt instruction to talk to a PC’s BIOS, but that was about it. I heard my coworkers throw around terms like “SPI”, “I2C”, “UART”, “GPIO”, “PWM”, “DMA”, “CAN”, “Timers”, “Watchdog”, and all that kind of stuff, but had no idea what they meant.

Luckily, I have become familiar with this stuff (thanks to reading datasheets and my awesome coworkers, of course!), and once you get down to it, it’s really not complicated. It turns out I didn’t understand what goes on inside computers at one specific level. My computer architecture class was at too low of a level (transistors, gates, adders, ALU, etc.), and my assembly language class was at too high of a level (this is what registers are, this is what instructions are, here’s an example of how you multiply two numbers in the x86 instruction set, now go make your own DOS program that uses DOS and/or BIOS interrupt routines to do something cool), if that makes any sense at all.

I think it’s important to understand both of those levels, but there’s a level in between as well. I think I’ll call it “memory-mapped peripherals.” It turns out that microcontrollers have a bunch of special extra devices built in to assist you. They might do stuff like communicate with another chip that’s connected to it or display a message on an LCD display. Ok, so memory-mapped I/O is not really a “level”, but it points out a concept that somehow slipped through the cracks of my education.

So anyway, I’ve decided I’m going to write a series of posts about how to do microcontroller programming from the perspective of someone who has experience with “normal” application programming. I’ll try to teach all the stuff that datasheets just assume you know. I’m sure there are people out there with this same kind of issue. I know I was one of them! If you’re interested in this, stay tuned, and I will start doing more posts! Below is a list of posts in this series I have already written, and I’ll keep it up to date as I add more.

Posts in the series:

I was so excited about fixing that Polaroid DVD recorder on Thursday (see my last post) that I remembered I had an RCA DVD recorder also sitting around that had quit working. Quite a while ago, we had a power outage. When the power came back on, my RCA DRC8052NB DVD recorder wouldn’t turn on. The LCD on the front panel turned on, and the message “HELLO” scrolled across it. I couldn’t get it to stop without unplugging the power.

The normal behavior when you first plug it in is for the “HELLO” message to scroll across for a few seconds. Then it’ll say something like “NO DISC”. Finally, it’ll shut itself back down and display the time, waiting for you to power it back up. Then, when you press the power button to turn it on, the “HELLO” message will come back for a few seconds, and finally it will turn on and display the current channel number or “NO DISC” or whatever else, depending on the mode you left it in when it was last turned off.

Anyway, so “HELLO” kept scrolling indefinitely. I figured it was a similar problem to what I saw on the Polaroid DVD recorder. The difference was that in the Polaroid DVD recorder, nothing displayed on the front panel. At first thought, I figured it might have something to do with the power board. But because the LCD was displaying a message, that made me a bit skeptical because you’d think a program on the main DVD board would be displaying that message, which would mean the main DVD board would be getting a good 3.3V power input.

I went ahead and checked it out with my multimeter. This power supply board is a bit different because it needs some sort of signal to tell it to turn on. I tried powering it up with its cable that goes to the “motherboard” (I don’t know the technical term for it, so I’ll call it the motherboard from now on) disconnected, but nothing happened. So I had to leave the motherboard plugged into the supply while measuring the output voltages. Anyway, the 3.3V output was only 2.8V, and several of the other voltages were pretty far out of range too. Some of the 5V outputs were only 4.5V, and the 40V output was only 35V. Sounds like a power supply problem again…I guess the “HELLO” message doesn’t necessarily mean the output from the power supply is good.

My suspicion was confirmed when I found some other postings online about this exact same model. In fact, this question on FixYa has several answers all pointing to a single capacitor that was probably causing the problem. Another post on FixYa also seemed to point toward capacitors.

None of the capacitors on the power supply board looked weird. In the Polaroid DVD recorder I fixed earlier, two of the capacitors were bulging. In this one, nothing looked weird to me. But an answer to that first FixYa question I linked to above also pointed out that the capacitor looked OK but was still bad.

Based on the first FixYa question, I went ahead and desoldered the 1000uF, 6.3V capacitor (C22). Multiple answers in that question implied that particular capacitor was the source of the problem. Interestingly enough, the footprint on the board for that capacitor is a lot larger than the actual capacitor soldered in. It makes me think that perhaps the board was originally designed for a cap with higher ratings.

Luckily, when I fixed the Polaroid DVD recorder, I ordered two of each capacitor I replaced, even though I only needed one. As you’ll remember, one of those capacitors was a 1000uF, 16V capacitor. It perfectly fit the footprint on the RCA DVD recorder’s power board. Since it was the same capacitance with a higher max voltage, I was good to go.

I soldered it in, put the power board back into place and reconnected all of the wires going into it. I plugged the DVD recorder back into AC power. The “HELLO” message came on, and I crossed my fingers. A couple of seconds later, the “NO DISC” message appeared, and shortly thereafter, the display read “12:00 AM”. Awesome!

I pressed the power button to turn the DVD recorder back on. Then I measured some of the power board’s outputs. The 3.3V output now was correctly at 3.3V. The 40V output was still pretty low (36V) but it was higher than it was. I didn’t bother to check the 5V outputs because it was a tight fit and I didn’t want to short anything like I did in the Polaroid one!

Anyway, thanks to roybro123 and neveo1999 on FixYa. Their answers helped revive my DRC8052 DVD recorder.

Before I realized that I already had a 1000uF capacitor sitting around here, I ordered all new capacitors on DigiKey for the DVD recorder. Oh well–it’ll be nice to have the spare parts laying around in case another one goes bad.

In conclusion, cheap capacitors suck. Companies are saving a few pennies by using cheap capacitors instead of high-quality ones. Or maybe they’re not allowing for proper ventilation and the capacitors are getting stressed from too much heat. Something along those lines. It’s a little disturbing to me that these products came from two different manufacturers and they both had bad caps as the problem. The problem was widespread enough that other people saw it too. Whatever happened to quality control? I actually bought both of these DVD recorders on Woot.com for a really good deal, refurbished. I think I now know why the manufacturers were getting rid of them for so cheap. But anyway, Woot is an awesome website you should check out some time. 10 PM pacific time every night–a new deal!

Now that I’ve done some electronics repair blogs, I think I’ll go back into my area of expertise–computer stuff. I’m an electronics newbie. My soldering technique is terrible and I really don’t have a clue what I’m doing. I probably have no business working on power supply boards. I work for a company that makes electronics, but I don’t do any of the electronics stuff–I write software. But having coworkers around to answer my questions about the hardware stuff helps, so I guess that’s why I feel comfortable working on this stuff without worrying about getting lethally shocked.

Anyway, I don’t know what my next blog will be about, but I’ll think of something soon! Until next time, goodbye!