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.

So, what do you think ?