I am interfacing my microcontroller (AVRmega32U4) to a 4x4 LED array. There are 2 control lines to operate columns (passed to a 2 to 4 demultiplexer) and 4 control lines to operate rows. I bring a column high and a row low to illuminate a specific LED. I pull either the column low or the row high to turn off an LED.

This design works fine for around up to 4 LEDs at once. However, when I try to light all 16 at once with this strategy, the LEDs are noticeably less brighter (they're on a 1/16 duty cycle after all!).

What are some ways to more effectively light larger numbers of LEDs in this array? Say, 10+?

I am considering writing a lot of code to handle the different situations, but that will consume more space on my microcontroller than I am comfortable with. I was considering adding another micro with 16 control lines to manage these LEDs, one at a time, but this seems like a lot of overhead to introduce.

enter image description here

  • \$\begingroup\$ Post a schematic. Words are great but a schematic helps immensely in figuring out what's going on. Because I don't see a schematic, I can't say if the following would work 100% - but trying using transistors to provide the actual power to the LEDs instead of a mux (which is what it seems is going on). \$\endgroup\$
    – Saad
    Commented May 29, 2012 at 15:37

4 Answers 4


I used valuable information from Telaclavo's answer to adjust mine. If you like his, don't forget to upvote him.

If your duty cycle is 1/16 then you would have to give each LED 16x its nominal current to get the same average brightness. This will decrease your LEDs' life. High brightness LEDs can be PWM controlled at their nominal current at 1/16 duty cycle and still be as bright as a common indicator LED.
The easiest solution is to keep that duty cycle fixed, so that you can also have the current fixed. Each column driver will have to drive 4 LEDs simultaneously, so that's 4 times nominal current.

The 7404 you have in your schematic is not suited for this. First TTL can source very little current: 0.4mA. But even sinking won't do, that's also only 16mA, most LEDs, also high brightness are specified for 20mA. You need a driver which can source that. In your 4 columns x 4 rows each of the 4 columns has to supply 4 LEDs with 20mA each, that's 80mA. There exist high side drivers, but you may have to work with discrete components (BJT or MOSFET). The current won't result in a high dissipation, since its average per high side transistor is only 1/4 of that: 20mA, and that's worst case, if all LEDs are on.

A BC807 is a good choice for this, and has an \$H_{FE}\$ of 100 minimum, so that a few mA of base current will drive it in saturation. You don't need the 7404 anymore to invert the active low output from the 74S139, since the BC807 is driven by a low voltage. The 74S139 (why not LS?) can sink the required current, also a 74HC139 will do.
While most microcontrollers are able to sink 20mA, this doesn't seem the case for the ATMega32U4. The datasheet doesn't give maximum current as a parameter (a lacune), but minimum and maximum output voltage are specified at 10mA. So for the low side you'll an extra driver. The 74LVC07A is specified for sinking currents to 32mA.

In quantities the 74HC139 + 74LVC07A + 4 \$\times\$ BC807 + 8 resistors cost less than 35 cent at Digikey.

  • \$\begingroup\$ Great answer! But do you think that since 7404's max output current can be 16 mA, connecting 4 LEDs to an output might be pushing it? \$\endgroup\$
    – Saad
    Commented May 29, 2012 at 16:03
  • \$\begingroup\$ I see your point about the TTL. What do you think about using transistors, as Saad suggested? Also, I'm not sure why you are mentioning 16 x 8, its a 4 x 4 array. \$\endgroup\$ Commented May 30, 2012 at 0:33
  • \$\begingroup\$ Forcing 80 mA through a 20 mA LED is not a good idea. It shortens its life. See last part of my answer. \$\endgroup\$
    – Telaclavo
    Commented May 30, 2012 at 15:29
  • \$\begingroup\$ @Telaclavo - Yes, I read it, I already fixed my answer. Thanks for the addition. Interesting. Yet I know several products which do this, with normal indicator LEDs. I have no data on failure rate or lifetime. \$\endgroup\$
    – stevenvh
    Commented May 30, 2012 at 15:38
  • \$\begingroup\$ I switched my design to use transistors, 4 on the columns and 4 on the rows, with the microcontroller connected to the base of each transistor. This helps, but I will be investigating some brighter LEDs to address the smaller duty cycle issue. Thanks for you help! \$\endgroup\$ Commented Jun 1, 2012 at 17:59

If one may want to have all LED's appear to be lit simultaneously, then the drivers for one dimension (often called "rows", regardless of the physical arrangement of LEDs) should be constructed so that when one row driver is energized, it will be able to light all columns simultaneously; in the other direction, columns will typically be designed to operate with one row at a time energized. In most cases, this will mean that row drivers have to be "beefier" than column drivers.

While there may on occasions be advantages to designing a display with row drivers that can only drive half the column drivers at once (e.g. because one wants to be able to flash bright messages in part of the display), in most cases achieving a particular level of apparent brightness with a particular number of rows will require a certain level of row current. If one could only drive half the columns at a time, lighting all the columns at a given brightness would require that they be driven with twice as much current to compensate.

BTW, one point not yet mentioned: if one is going to try for anything near maximum brightness when using multiplexed LEDs, one should design a circuit which will prevent a row from being energized for an excessive amount of time. At minimum, one should design things so that if the CPU stops the display will either shut down or cycle through the rows autonomously, and so that the display scanning cannot be restarted too frequently without blanking the display (either by having the counter tell the CPU when it wraps, as opposed to having the CPU reset the counter, or by having the "counter reset" signal disable the row drivers for a certain minimum time). Otherwise a CPU malfunction may destroy an LED panel.

  • 3
    \$\begingroup\$ Very good 3rd paragraph. \$\endgroup\$
    – Telaclavo
    Commented May 29, 2012 at 19:35

The ATmega32, with Vs=5 V, can source and sink +/-20 mA per pin, with a loss in voltage of about 0.7 V .. 0.8 V


and it can source and sink 4·(20 mA)=80 mA in total (per package), and even per port, with no problems.


Assuming you do not want to exceed the 20 mA rating per LED, this would be a different way of doing this:


U1 = ADG1636. It has two SPDT switches. Each switch connection can carry 238 mA (max), in any direction, at 25 ºC. That is well higher than 4·(20 mA)=80 mA. So, U1 acts as a high-current buffer. The IC costs $1.83 in 1 kpcs.

Rs = (5-2-0.7 V)/(20 mA)=115 \$\Omega\$, 1/4 W. You only need four of them.

In order to be safe to connect pairs of LEDs in anti-parallel, as shown, it must be \$V_{F}<|V_{Rmax}|\$, and that condition is usually satisfied.


1) Set B=0 (as shown in Fig). That will give you access to diodes D9 to D16. Diodes D1 to D8 will all be off.
2) Set A=0 (as shown in Fig). That will give you access to diodes D10, D12, D14 and D16.
3) Set C=A if you want D10 to be off. Set C=!A (! means negated) if you want D10 to be on.
4) Simultaneously with 3), do the same for {D,D12}, {E,D14}, {F,D16}.
5) Set A=1. That will give you access to diodes D9, D11, D13 and D15.
6) Repeat 3) and 4), but for {C,D9}, {D,D11}, {E,D13}, {F,D15}.
7) Set B=1. That will give you access to diodes D1 to D8.
8) Repeat 2) to 6), but for diodes D1 to D8.
9) Repeat 1) to 8), for each new whole cycle.

With that, each diode will be on with a duty cycle of 1/4 (which is good, taking into account that you have 16 diodes). And yes, you can mix PWM with this idea, if you want to gradually control the brightness.

As I said, this solution does not exceed the 20 mA rating per LED, so the maximum brightness that you will see will be 1/4 of the maximum brightness that each LED can produce. If you want more brightness, use LEDs that produce more mcd/mA. This will keep intact their long life.

Thanks to the high current capability of U1, the amount of light that each LED will produce will not depend on the total number of LEDs that are on.

And, you still need only six GPIO lines from your MCU. With just one external IC, instead of decoder + buffers or transistors. This is more expensive, but more compact (if that is critical), and with a slightly easier wiring (six lines, instead of eight, go to the LED matrix). This is more of a curious and academical answer, in my opinion.

Added for Federico Russo: what you say was already addressed in my paragraph "As I said, this solution[...]". Forcing 80 mA through a 20 mA LED, even for 1/4 of the time, is not a good idea. Its life will be shortened. And not due to excessive dissipation (which is the same), but due to electromigration (wich is proportional to the current). See this reference from Cree. Excerpt:

Repetitive pulsing

The second type of over-current condition, high-current repetitive pulsing, may or may not result in an early catastrophic failure of the LED. Repetitive high-current pulsing may result in a shortened life expectancy for the LED compared to the usual expected lifetime, on the order of tens or hundreds of thousands of hours. A particular device subjected to repeated transients at an amplitude some percentage above the data-sheet limits but below the threshold required for single-pulse failure will still eventually fail. The failure mechanism will most likely be due to electromigration as enough metal ions are eventually shifted away from their original lattice positions.

If you want same life and same light for less current, use LEDs that produce more mcd at 20 mA.

  • \$\begingroup\$ Er, shouldn't that 0.7V for the resistor calculation be 2V (or whatever the LED's voltage)? Or is that the voltage drop due to the internal resistance? In that case, shouldn't the 2V be added to that? \$\endgroup\$
    – stevenvh
    Commented May 30, 2012 at 12:51
  • \$\begingroup\$ This is an alternative to the PNP transistors, one for each column, I proposed. Only more expensive: 4 BC807s are 10 cent together. \$\endgroup\$
    – stevenvh
    Commented May 30, 2012 at 12:56
  • \$\begingroup\$ @stevenh Sure, I forgot the 2 V of the LED. // This is an alternative to everything else. It has nothing to do with PNPs, neither in device types nor in structure. // Right, this will be more expensive, even adding the cost of a 2-to-4 decoder that you need, to keep using 6 GPIO lines, but it is more compact, and the wiring is slightly easier (only 6 wires, instead of 8, go to the LED matrix). // And, it is a curious solution. Different. \$\endgroup\$
    – Telaclavo
    Commented May 30, 2012 at 14:26
  • \$\begingroup\$ It's an original way to save two pins, but I don't think it's good. The LEDs have only 5mA average, not 20mA. To get the same brightness as 20mA you need 4x the current in a 1:4 multiplex. The microcontroller can't supply that, so you'll need a ULN2804. \$\endgroup\$ Commented May 30, 2012 at 14:34
  • \$\begingroup\$ @FedericoRusso See text above. Not enough space, here. \$\endgroup\$
    – Telaclavo
    Commented May 30, 2012 at 15:04

For lighting large numbers of LEDs a driver IC such as TLC 5940 is a great choice.

It only requires 7 pins from a MCU for 16 LEDs, and the drivers can be wired in series for up to 100s of LEDs.




Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.