1
\$\begingroup\$

I'm working on a DIY project at home which needs approximately 150 LEDs to be lit up at varying levels of brightness. I'd eventually also like to have these LEDs lit in certain patterns so they really need to be driven by a microcontroller (a controllable LED matrix if you will).

After some consideration, I've started dabbling with the Ardunio as it seems to be suitable for the task at hand and allows me to multiplex LEDs and so on.

I have both the Arduino Uno and the Arduino Mega 2560. For testing I used the Mega as it has 15 PWM channels so I can adjust the brightness of each LED etc without having to mess about with different valued resistors and hook enough LEDs to give me a good idea of what's going on.

I had a good proof of concept up and running with LED1 lit up for 1800 microseconds, then switched off and LED2 lit up... and so on for all 15 LEDs. None of the LEDs were actually lit at the same time but it gave the persistance of vision effect (all LEDs appear lit up at the same time) and didn't draw a huge amount of current. This is what I'm aiming for, on a larger scale of ~150 LEDs.

So, next I needed to scale this up. The next proof of concept came in the form of utilising the TLC5940 LED driver after reading some articles and blogs online.

I hooked up the TLC5940 to the smaller Arduino Uno, and connected 16 LEDs to the 16 output channels of the chip. I ran a test program (I think it faded/ran patterns along the LEDs and it worked fine).

I then began writing a loop which would again switch on the first LED, wait for a fraction of second, then switch it off and move to the next LED.

The code worked up to about 3 LEDs but as soon as it hit the 4th LED, flickering could be observed. By the time it was scaled up to all 16 LEDs, there was a clear visible pattern (like a mexican wave) running across the LEDs.

I tried changing the delay time, reducing it all the way down to 1 microsecond but this had little effect.

My code was something like this:

#include "Tlc5940.h"
int DELVAR = 1

void setup()
{
  Tlc.init(0); // initialise TLC5940 and set all channels off
}


void loop()
{
    Tlc.clear();
    Tlc.set(1, 4096);
    Tlc.update();
    delayMicroseconds(DELVAR);
    Tlc.set(1, 0);
    Tlc.update();

    Tlc.clear();
    Tlc.set(2, 4096);
    Tlc.update();
    delayMicroseconds(DELVAR);
    Tlc.set(2, 0);
    Tlc.update();

    Tlc.clear();
    Tlc.set(3, 4096);
    Tlc.update();
    delayMicroseconds(DELVAR);
    Tlc.set(3, 0);
    Tlc.update();   


    // ....and so on for all 16 channels .....   
    // (not optimal I know but at this point I'm still just getting my head around the logic)
}

Is there a limitation on the "speed" of the TLC5940 or the channels it's using from the Arduino?

How can I get around this so that all LEDs appear to be illuminated at the same time. Am I correct in thinking the duty cycle of the Arduino is 16MHz? and if so, shouldn't I theoretically be able to light up and switch off > 50,000 LEDs sequentially all in under one second?

Disclaimer - I have very basic electronic knowledge from when I was in school about 15 years ago so this is all a very steep learning curve for me!


NOTE: *For anyone wondering what it is I'm working on - it's a giant world map - the LEDs represent major urban or populated areas (cities etc) as viewed from space at nighttime. I'd eventually like these to be hooked up to realtime so that the LEDs lit up represent actual urban areas lit up at night at that particualr point in time - this is where the Arduino would be very useful.

It's a string art map based on one I did last year (below)

It's a string art map based on one I did last year (below)

Only a lot bigger - it'll be 8ft x 4ft - progress so far - holes for LEDs drilled are ready:

enter image description here

\$\endgroup\$
  • \$\begingroup\$ No, Arduino clock frequency is 16MHz, PWM frequency is only about 500 Hz, and duty cycle is a different concept altogether. \$\endgroup\$ – Dmitry Grigoryev Aug 26 '16 at 10:26
  • \$\begingroup\$ Thanks Dmitry. So is there any method I can employ to "speed up" the On/off frequency of these LEDs? \$\endgroup\$ – Huskie69 Aug 26 '16 at 10:29
  • \$\begingroup\$ Yes, you can speed things up by not using PWM. \$\endgroup\$ – Dmitry Grigoryev Aug 26 '16 at 10:31
  • \$\begingroup\$ Quick question then - could I use the I2C bus as an alternative - is that quicker? \$\endgroup\$ – Huskie69 Aug 26 '16 at 10:37
  • 1
    \$\begingroup\$ The Arduino's built in SPI peripheral is the quickest way to drive a TLC5940. The TLC6940 does not support SPI. Further, SPI is significantly faster than I2C. You already have all the parts to support 16 channel LED brightness control in a TLC5940, and it can be updated at about 5 times/millisecond. Buy 10 more and your project is done. \$\endgroup\$ – gbulmer Aug 26 '16 at 11:02
2
\$\begingroup\$

Your post sounds a bit confused. It sounds like you are trying to simulate PWM by updating the TLC5940, which is not necessary.

A TLC5940 contains 16 PWM channels, each PWM channel drives the brightness of one LED. So you only update the TLC5940 when the brightness of a LED needs to be changed. The rest of the time, the TLC5940 will maintain the set brightness of each LED using its own PWM channels.

The time between each update needs to be visible to the human eye, so use delay() which is milliseconds, and never delayMicroseconds() which is only good for a few 10's of milliseconds.

The effect that you are seeing is likely because the whole of loop() is completing in a millisecond or so.

The code is likely updating the TLC5940 at less than one cycle of its PWM rate (I can't remember if there is logic in the TLC594 to force something more helpful, but I don't think so). So you might be seeing the visual equivalent of a 'beat' between the two frequencies (update vs PWM).

Tou could prove this hypothesis quickly by changing all of the
delayMicrosecond() to
delay(1000)

Please update your question if this doesn't fix it, or you have already tried this.

Your code does not need to control the visual brightness of the LEDs, the TLC5940 does that for you. When you set an LEDs brightness the TLC5940 will continuously use PWM to hold that brightness for that LED.

So for your project, you might be updating the entire scene once every few seconds, assuming each LED is driven by a single channel, and you use multiple TLC5940s with upto 16 LEDs on each.

I have not read all of the code in that library, but the Arduino's SPI hardware should be able to update a TLC5940 (192 bits) at about 4Mbits (or 8Mbits with the right settings).

So all 16 LEDs on one TLC5940 should be updated about 5 times per millisecond. Hence 160 LEDs would be 10 TLC5940s, and be updated every 2 milliseconds, which is way better than human vision response.

Every one of those LEDs is under brightness control by the TLC5940, so the code has nothing to do until one of the 'cities' needs to have it brightness changed.

Edit:
The key point is, your Arduino does nothing about PWM. The Arduino programs sends the TLC5940 values which are the brightness of each LED. That's it, nothing else to do.

The TLC5940 has 16 PWM channels, it does the LED brightness control using its PWM channels, all by itself, autonomously, without any further involvement of the Arduino.

The Arduino program only talks to the TLC5940 when one or more LEDs need to have their brightness changed.

I think it is inconceivable that you'd change the LEDs faster than 50/60 frames/second (TV refresh rate), which 10 TLC5940 would be easily capable of doing. In between each change of LED brightness, the TLC5940s will maintain those set brightnesses.

Edit2:
Maybe you intended to buy 74HC595 shift registers? They are much simpler devices. An LED would either be on or off. With those, the host microcontroller would be responsible for updating the 74HC595 to simulate PWM-like brightness control.

\$\endgroup\$
  • \$\begingroup\$ Sorry if it sounds confusing - the PoV effect in this instances to me implies that the LEDs all appear to be switched on at the same time - that's the effect I'm trying to achieve. I originally started with using just delay(some_small_number) but this lights up the LEDs very slowly. \$\endgroup\$ – Huskie69 Aug 26 '16 at 10:36
  • \$\begingroup\$ So this is purely a limitation with using PWM - I just can't do what I'm aiming for using the PWM channels of the Arduino? It's just too slow for my requirements? \$\endgroup\$ – Huskie69 Aug 26 '16 at 10:42
  • \$\begingroup\$ I think I have explained that your code tells the TLC5940 what brightness you want, then it does it for you, for all 16 LEDs. It has 16 PWM channels, one per LED. \$\endgroup\$ – gbulmer Aug 26 '16 at 10:43
  • \$\begingroup\$ Sorry - I've just seen your paragraph on the SPI hardware - this seems like it might be worth some further investigation \$\endgroup\$ – Huskie69 Aug 26 '16 at 10:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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