Hi all,
I'm hoping someone can help to shed some light on an issue I am having. This is my first time using an arduino, and generally in interfacing with hardware as a whole, but I've done my best to try to debug my application and determine the root of the problem.
My code is based off of the code provided in this article:
http://www.arduino.cc/playground/Learning/TLC5940
With some adjustments due to it being somewhat dated. You can download the documentation for the TLC5940 IC here: http://www.ti.com/lit/gpn/tlc5940
First, what I am attempting to do: I will be sending data via host computer every 20ms, with new brightness information for the LEDs. With a required 192 bits to set all 16 channels individually, plus a control byte, this is well within the means of the serial communication. I initially thought my problem might've been with latency or loss of data here, but have moved all the code to the arduino to ensure it's not due to the serial communication.
Given the code linked above, two internal timers are used to drive the TLC5940. The first one pulses pin 11 every 2.44uS, in order to manage roughly 4096 cycles in 10ms -- this is the PWM clock that actually drives the LEDs. At the end of every 4096 cycles, the IC requires a pulse on its BLANK input, which resets its internal timer and begins another iteration at the given clock speed. Instead of trying to keep a counter for the first timer (and then pulse BLANK when counter == 4095), the author of the above code opted instead to drive a second timer that pulses in roughly the same amount of time as it takes the first timer to reach 4096 cycles (2.44uS * 4096, so it tries to do so every 9994 microseconds). Hopefully I've both interpreted the code clearly, and done the same for the explanation.
As far as all of that goes -- on the surface, it works great. There's no flickering of the LEDs once I've set their brightness, and the blank signal pulses in time, preventing the output from stopping. However, I doubt the code was intended for 50 updates/second, as I'm looking to do.
My problem is thus:
While sending data to adjust the brightness of the LEDs every 20ms, I will occasionally get the LEDs flickering at a higher brightness than any of the values I'm setting them to. To clarify, I'll use the actual code I'm using to reproduce this:
for (uint16_t i = 0; i < 5000; i++) {
if (i%2) {
setGS(1);
}
else {
setGS(16);
}
delay(20);
}
setGS is the function used to actually write the value to the TLC5940's registers (I'll include the full test script at the bottom). I'm having the LEDs alternate between values of 1 and 16 every 20ms.. that is 1/4096th and 1/256th of the LEDs' actual potential brightnesses. Quite dim.
However, while watching this script run, for a fraction of a second the LEDs will occasionally light up what appears to be 100% brightness. There seems to be no reason nor rhyme to the rate at which this occurs. One run of the script can have it happen three times in 3 seconds, then another time 10 seconds later, whereas another run can have it not occur at all. I believe, though cannot be certain, that there are also occasional flickers at 0% brightness. Due to the nature of them, though, they are much harder for me to spot. Actually, I don't know why.. all I need to do is set both values to be up high, and see if it flickers low. Will test that now. .
.. okay. Aside from my eyes now seeing spots, I could discern no flicker at the lower end -- they only flicker up to 100%. Running them between 50/52% brightness, I could still see them flicker brighter. Running them at 95/97% or so brightness, I couldn't discern the flickering.
Some observations while trying to determine the cause:
-
It is not directly related to the fast speed. If I run it every 50ms, I still get flickering, but not as often -- at least, not as often in real time. Which is to be expected, however, as it's now running over twice as slow. 100ms, I can still get it to flicker. If I tried doing so at 1 second, I think it's possible that I could get the flickering to occur, but would take me some time to find out..
-
There's no software way for me to detect the flicker. I've tracked all of the variables right up until they're clocked into the IC, and they check out all the way through.
-
It only occurs when I alternate between different values. If I call the function to set the brightness to the same value every 20ms, even if the value is really low, I get zero flickering (and note that there's no code check to prevent an update to the same value). So, making it set the brightness to 1/4096 every 20ms, no flicker. Getting it to alternate between 1/4096 and 2/4096 every 20ms, flickering.
Reading over the documentation, I found this:
Grayscale data and dot correction data can be entered during a grayscale cycle. Although new grayscale data can be clocked in during a grayscale cycle, the XLAT signal should only latch the grayscale data at the end of the grayscale cycle. Latching in new grayscale data immediately overwrites the existing grayscale data.
I'm curious if this could be the cause. I say "I'm curious", because I can't sort out how to test this. The ideal solution would be to drop the timer for BLANK, and run a counter instead (or some sort of interrupt based on the first timer reaching a given value) -- but isn't keeping a counter too slow for the needed 2.44uS?