Monthly Archives: March 2012

Information radiator…

This afternoon I got my information radiator/team status board finished.

Here’s what the completed Arduino shield looks like:

On the front, we have four seven-segment LED digits, where the digits are 1” tall. I considered using a pre-built shield that displays digits but the ones I saw all used pretty tiny digits. I would have gone larger than this but I didn’t have the power to drive a bigger one from USB. The bigger ones also tend to use higher voltages which would have meant a separate power supply.

You will also notice the absence of any LED driver chip. The Arduino is perfectly capable of running the driver chip without any any separate hardware, and some of the Maxim chips are $10+ per item.

Across the top are the 4 transistors to drive the common cathode of each of the chips; they switch the cathode to ground to turn on the digits sequentially.

Finally, on the lower-left we have a header that is used to connect the LPD8806 LED strip to the board.

If you look closely you can see some small wires soldered on the surface of the board. They connect to the headers that hook into the Arduino

 

Here’s the bottom view. Sorry it isn’t better, but I inexplicably had my camera set to super-low resolution.

The seven-segment displays have 10 pins each; the 7 segments plus the decimal point, and then two common terminals. The 8 ones connected to the segments are all connected in parallel with the blue wire, and then connected with the dropping resistor (68 ohms) to the output pin of the microcontroller. This is the top part of the board.

The bottom section has the connections for the transistors; the collectors hook directly to the common terminals on the displays, the emitters hook to ground, and then the bases hook to the microcontroller pins through a 1K base resistor.

Finally, the header for the LPD8806 strip grabs +5V and ground from the headers, and then the data and clock lines from two more microcontroller pins.

That’s 12 pins for the display, 2 pins for the LPD8806, 2 pins for serial communication giving 16 pins used. Plus one more pin for timer interrupt debugging (more on that below). I think that leaves me 3 pins free.

All the wire is 30-gauge wire-wrap wire insulated with Kynar. It’s very thin and easy to work with but still hefty enough to carry the current we need to carry, and it’s color-coded.

Wire-wrapping can be used without soldering on square pins, but most of the components here have round pins. Soldering wire that is that thin is fairly challenging, so I use my old had wire-wrapping tool that I bought from Radio Shack in the mid-1980s (and still available for about 6 bucks) to wrap the wire around the pin/wire, and then solder it. It gives a very secure connection though it is a bit tedious; 48 connections just on the blue wire to hook the display segments together.

The LED multiplexing code worked correctly pretty much right when I wrote it. But I wasn’t sure whether it was fast enough. The easy way to figure this out is to allocate one pin (pin 4 for me) to output. At at the start of the interrupt handler, set it high. And at the end of the handler, set it back low.

Now you can hook your oscilloscope up to that pin, and it will look something like this:

       ____                         ____
      |    |                       |    |
______|    |_______________________|    |____

The high portion is the time spent in the interrupt, and you can see that it’s only spending about 20% of the time in the interrupt.

Driving the LPD8806 strip

The LPD8806 strip came from Adafruit. It uses a protocol that is SPI-like, and they provide a nice library to use it. The library has two modes – one that uses hardware SPI, and one that drives the pins directly (“bit-bang”). If I had really been planning ahead, I could have used the hardware mode, but those pins were already in use. That left the bit-bang version. So, I coded it up, added a call to update it when we switched digits, and uploaded the sketch.

It worked, but there was a slight glitch in the LEDs and on the scope whenever it updated. The write was taking long enough that it was missing the next interrupt. I dropped the number of active LEDs down, and when I got down to 4, the glitch went away. On the scope I could see that I *just barely* had enough time to do four.

I don’t really have to write out the color data for all the leds at once, but that’s the only way the library works, so I’m going to be hand-rolling some code. Use the library code as a base, I ended up with the following:

void WriteByteToStrip(byte value)

{

  for (uint8_t bit=0x80; bit; bit >>= 1)

  {

    if (value & bit)

    {

      digitalWrite(DataPin, HIGH);

    }

    else

    {

      digitalWrite(DataPin, LOW);

    }

    digitalWrite(ClockPin, HIGH);

    digitalWrite(ClockPin, LOW);

  } 
}

The if-then sets the data pin to high or low, and then toggles the clock pin. This uses the digitalWrite() support in the Arduino, which is very convenient but does a *lot* of work:

  1. It has to map the number of the pin to one of the ports on the Arduino
  2. It has to create a bit mask for the appropriate bit in that mask
  3. It either OR’s the bit mask with the port to set the bit, or ANDs the complement of the bit mask with the port to clear the bit.

Take a look at wiring_digital.c to see what work it does.

If you know what pin is going to be used, this can be done much more efficiently; you can figure out what port your are using and precompute the masks to set or clear the bit, and then just update the bit with a single operation.

The code to call WriteByteToStrip() is very simple as well:

void UpdateLedStrip(int currentItem)

{

  static int ledToUpdate = 0;

  int dimAmount = (ledToUpdate == currentItem) ? 1 : 3;

  DumboItem* pDumboItem = &dumboData.m_items[ledToUpdate];

 
  WriteByteToStrip((pDumboItem->m_green >> dimAmount) | 0x80);

  WriteByteToStrip((pDumboItem->m_red >> dimAmount) | 0x80);

  WriteByteToStrip((pDumboItem->m_blue >> dimAmount) | 0x80);

 
  ledToUpdate++;

 
  if (ledToUpdate == dumboData.m_itemCount)

  {

    WriteByteToStrip(0);

    ledToUpdate = 0;

  }

This writes one one led’s worth of data (3 bytes) each interrupt, so if there are 10 leds, they will get updated at 100Hz, which is more than quickly enough. A look at the scope shows that there is plenty of time left in the interrupt handler. I can also see the terminal byte being written; some of the updates take just a little bit longer.

 

Here’s an action picture. It’s set up with 8 values, and there is a separate LED for each of those values. It will increment through the values every second or so, making the current LED brighter and showing the associated value on the LED display.


Arduino pin current reality check

If you look at the documentation for the Arduino, you will find a section that says that the Arduino can source or sink a maximum of 40 mA on any of the digital pins. This is, at best, very misleading.

I’m working on a multiplexed 7-segment display, which requires me to use 7 pins to drive the display, and then 4 pins to switch between displays. The 7 digits will go high based on what digit they want to display, and then one of the 4 “digit select” pins will be driven to turn that digit on. Each digit will only be on 1/4 of the time, but they will switch fast enough for you not to notice.

To limit the current through each segment to 20mA, there are dropping resistors for each of the 7 segments, and I need to figure out how big they should be.

Let’s see, the Arduino runs at 5V, and my display drops 3.7 volts and I want 20mA across it, so if I plug it into an LED calculator, I get 68 ohms as my value. If I had all 8 digits on at 20mA, that would put 160mA through the digit select pin, which is way above the 40mA max that Arduino (and Atmel) say I can use, so I’ll be using a transistor to switch those low.

I wire it one digit, write some code, and it all works… (the preceding has been edited for time and content).

And then I pull out my multimeter to check how much current I’m putting through the segments. Hmm. 10.5mA, quite a bit less than what I’m expecting to see. Let’s think about it a bit (this part took me far longer than I’d like to admit).

First off, the transistor collector voltage is about 0.11 volts. Adding that to the expected 3.7 volt drop of the display should give us 3.8 volts, which is pretty close to what we measure.

So, go back to the calculator, and we’ll find that we’d expect about 18mA with a 3.8 volt drop and 68 ohms. Still not what I’d expect. Hmm.

I put my voltmeter on the digital pin driving the resistor, and measure 4.5 volts. Back to the calculator, play with the numbers, and 4.5 volts and 10.6 ohms does give us 68 ohms.

So, when is 5 volts not 5 volts, but 4.5 volts?

This is one of those areas when digital electronics stops being digital and becomes analog. To understand a bit about what’s going on, we need to go behind the scenes.

Inside the datasheet

Here’s the datasheet for the ATMega328 that powers the Arduino Uno.

If we look at section 28.1, that’s where we find the 40mA rating and the 200mA maximum rating mentioned on the Arduino site. But that’s only part of the story.

What we really want to do is head over to section 29.4.8, “Pin Driver Strength”. We’ll start with figure 29-160, which shows the relationship between the output voltage and the current on a pin when we are sinking (sending current to ground). There are different curves for different temps (-40C, 25C, and 85C) if you want the details, but if we stick with the 25C one, we see values like this:

Current Voltage
5mA 0.12V
10mA 0.24V
15mA 0.35V
20mA 0.47V

Figure 29-162 gives the curves when you are sourcing current:

Current Voltage
5mA 4.8V
10mA 4.7V
15mA 4.6V
20mA 4.5V

As curves go, these are pretty much straight lines. You’ll also notice that the source and sink is roughly symmetrical, much different from the TTL chips I used to use, which were good at sinking current and poor at sourcing it (16mA sink, only 2mA source).

Anyway, when I look at the graph and find the expected voltage drop at 11 mA, and find that it’s a little over 4.7 V. Which is about 0.2V more than I’m actually getting.

My best guess is that I’m seeing a little extra droop because I’m putting out 70mA total for all the digits.

If I want to hit a higher current, I can put the new values back into the calculator, and I’ll find that it suggests 36 ohms for 20mA. Though that is going to sag a lot more than the 10mA I’m getting, which will reduce the voltage, and therefore reduce the current, not giving me the full 20mA. My guess is that I’d be looking at around 30 ohms to get the full 20mA, but I’m tired of doing all these measurements, and I’ll leave it as an exercise for the reader.


Introduction to Arduino timer interrupts

I’ve been working on a project that involves driving a 4-digit 7-segment LED display. I could do it with a separate chip, but I want to do it with the Arduino. Each digit has a line to each segment, and a separate common connector. To drive all 7 segments would take 7 x 4 = 28 digital output lines, which is more than the Arduino has available.

The classical solution for this problem is multiplexing. We connect the 7 segment lines for all of the digits together, and then connect them to the Arduino output pin through a dropping resister. Which leads to a bit of an issue – if we turn on the segments to show a “3”, it will show on all of the digits.

So… We connect each common line to an output line of the arduino, and then work our ways through the digits. If we do it fast enough, all of the digits appear to be lit. The one downside – other than the extra complexity of the code – is that since each digit is only on for 1/4 of the time, it will only be 1/4 as bright. We work around this by increasing the amount of current we send through the LEDs. *Generally*, if you only light up an led for 1/4 of the time, you can use 4 times the current, but a) you should check the datasheet for the led you’re using to be sure, and b) you should only exceed the normal current when you’re sure everything is working, because if your code stops running with one digit on too bright, you will quickly fry the display.

Generally, you need the the refresh rate of the display to be greater than 100 Hz or the display will flicker. I’d aim for something like 250Hz.

The code that we would write looks pretty much like this:

void loop()
{
    for (int digit = 0; digit < 4; digit++)
    {
        /// turn all digits off
        /// set the values for the current digit to the 7 segments
        /// turn on the current digit
        /// delay a bit of time (say, 3 milliseconds)
    }
}

That will work fine if that is all that we want to do, but it has some disadvantages:

  1. If I need to do other things (such as read from the serial port), any code I write has to fit in the loop where the “delay” section goes. This will make the code more complex.
  2. If my code spends a variable amount of time, the digits will update at a variable rate, and they could flicker if things get too slow.

What I really need is a way to separate the functions – a way for the display to update at a constant rate and not get in the way of everything else that I want to do.

This is a perfect place to use a timer interrupt.

An interrupt is something that interrupts the code that is running to perform another task. Timer interrupts happen periodically, and are perfectly suited to running tasks repeatedly at a set interval. A timer is just a configurable counter that counts the whole time the microcontroller is running.  We make use of it by enabling a timer interrupt, which can be configured to generate an interrupt in the following conditions:

  1. When the counter overflows. Timer 0 and timer 2 are 8-bit timers, which means they overflow after the timer counts to 255. Timer 1 is a 16-bit timer, and it overflows after the timer counts to 65535.
  2. When the timer equals a specific value. This works only on the 8-bit timers, and each of them have two values that can generate the interrupt (named “A” and “B”).

Getting the proper interval

The clock on the arduino runs at 16 MHz, or 16,000,000 counts per second (note that running the AVR at 16 MHz requires an external crystal, as on the arduino board. AVR processes can run without a crystal, but they are limited to 8 MHz).  I want my update to happen at 1000 Hz (4 * 250Hz per digit). That means we need to have a timer that divides the clock rate by 16,000.

We could do this by using the timer overflow function of timer1. It overflows when it his 65,536, and I need it to do it every 16,000 counts, and I can get this to happen by setting the clock value to (65536-16000 = 49536). 16,000 counts later it will overflow, and then I can reset the counter to that value in the interrupt handler. 

In this case, I want to save timer 1 in case I need it for something else, so I’ll be using timer 2. But timer 2 is only an 8-bit timer, and I need to count to 16,000. What I need is a way to slow down the count…

Enter the prescaler…

The prescaler is a programmable divider that sits between the clock and the timer. For timer2 (it is different for different timers), it can be set to the following values, which give us the following counts to get 1,000 Hz:

Divisor Resulting rate Count to get 1000 Hz
1 16,000,000 Hz 16,000
8 2,000,000 Hz 2,000
32 1,000,000 Hz 1,000
64 250,000 Hz 250
128 125,000 Hz 125
256 31,250 Hz 31
1024 3906 Hz 39

We should pick the smallest divisor that lets us get a count that is less than 255, so we’ll use a divisor of 64.

For timer 2, we can use either method of generating the interrupt. We can set the counter to 6, so it overflows and generates an interrupt 250 counts later, or we can set “compare A” to 250, so it will generate an interrupt when the count gets to 250. Either will work.

Configuring the timer registers

To figure this out, you need to refer to table 17-9 in the datasheet for the Atmel ATMega328, the microcontroller used in the arduino. When we see that, we can figure out that we need to set the TCCR2B register to 0x04.

TCCR2B=0x04;

We will need to configuration the timer so that it will generate an interrupt when it overflows. A look at section 17.11.6 shows that we do this by setting bit 0 (value=1) in the TIMSK2 register.

TIMSK2=0x01;

And then finally, we need to set the initial count of the timer to 6 (though 250 is close enough to 256 that is really wouldn’t matter if we didn’t do this.

 

Here’s our initial sketch:

#include <pins_arduino.h>

void setup()
{
  Serial.begin(9600); 
 
  initTimer2();
}

void initTimer2()
{
  noInterrupts();
 
  ASSR=0x00;
  TCCR2A=0x00;
  TCCR2B=0x04;
  TCNT2=0x06;
  OCR2A=0x20;
  OCR2B=0x00;
  TIMSK2=0x01; 

  interrupts();
}

int count = 0;

ISR(TIMER2_OVF_vect)
{
  TCNT2=0x06;
 
  count++;
 
  if (count % 1000 == 0)
  {
    Serial.println("a");
    count = 0;
  }
}

void loop()
{
}

If this was working correctly, every second it will send an “a” out the serial port. We can check this by choosing Tools->Serial Monitor from the Arduino IDE. And it did.

So, now we can develop the rest of the timer code, and use the main() loop to handle the rest of the functions.