[TUT] [C] Demystifying the TLC5940

Go To Last Post
24 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Demystifying the TLC5940

A free book by Matt Pandina

About four months ago I started writing a tutorial, which ended up getting so large that it turned into a book. In the process of writing the book, I taught myself how to use LaTeX, and then gEDA to make the schematics.

Demystifying the TLC5940 explains how to turn the datasheet and application notes for the TLC5940, a 16 channel LED driver with dot correction and grayscale PWM control, into an unencumbered C library for use with an AVR microcontroller. This library uses the CLKO pin of the AVR to drive the GSCLK line of the TLC5940, which allows grayscale values to be updated at 3906.25 Hz with a CLK_IO of 16 MHz, and 4882.8125 Hz with a CLK_IO of 20 MHz.

The first project in the book guides you through creating a reference implementation based on the official TLC5940 programming flowchart. The subsequent projects build upon this implementation, first refactoring it to be ISR-based, then optimizing it to use hardware SPI, then adding features, and finally turning it into a fully functional library, which can be reused for multiple projects.

The sample code was written for the AVR-GCC compiler and tested with an ATmega328P, but it should be easily modified to work with other compilers and/or microcontrollers.

Also available is a zip file with the complete source code for every project in the book, along with schematics and Makefiles.

Here is a photo of the persistence of vision toy I created using the library:

I used three TLC5940 chips, and four 10-segment LED bargraphs.

Even if you have no interest in learning about the TLC5940, you may still find this book useful, as I tried to cover the general process of turning a datasheet into code, along with pitfalls I encountered along the way.

I am very eager for feedback, so let me know what you guys think!

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Matt that's very good of you. I have downloaded both files and will try to find some time in the future to play with the creatures. I have used the TLC5941 so I understand the need for the tutorial. :)

Fortunately the firmware for that project was written by someone else, it can be rather painful.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This was perfect timing for me... I've started a project that will have several TLC's and I have a very basic understanding of them (well, and electronics in general!). From my first skim of your book, you have done an awesome job of lifting some of the fog for me. Thank you VERY much for your efforts!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John, I haven't tried any of the other TLC chips in the family, so I would love to hear feedback on how the library ends up working for you.

jas0420, you're welcome! I'm glad I can help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Heya Artcfox.
jas0420 pointed me at your site and I have to give you my thanks! I've been working on a project with the TLCs for over a year now and seeing the way you created your code was really helpful. My project is now slowly being moved to a PIC32, it started on a pic24 (am I allowed to say the "P" word here;) ) and was mostly based around the Arduino library I ported my self. But it looks like your way of updating the data is a lot more efficient so I'm changing my code to use the method you describe.

Only thing i'm a little confused about is this licensing thing. I generally don't bother with licenses or anything, i'm not really a programmer or anything so it doesn't bother me what my code gets used for. I'm not going to put big disclaimers or licence blocks at the top of my code. but now that I've "borrowed" from your method is it fair if I still share my code without a license? On one hand, I did use your code and manual as a template, but it's pretty much completely re-written for pic32, if someone was to do the same thing from scratch following your "tutorial" they'd no doubt come up with something similar. It's not like there are that many ways you can control the TLC, right? But then if someone translates a book into another language, it's still the same book... So I'm not sure how you feel about that.

You can see my project on my website www.vespine.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I've been working on a project with the TLCs for over a year ..... it started on a pic24
Would have been finished 11 months ago on an AVR. :)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
Would have been finished 11 months ago on an AVR. :)

Don't doubt it, if I had ANY idea what I was doing ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

vespine wrote:
js wrote:
Would have been finished 11 months ago on an AVR. :)

Don't doubt it, if I had ANY idea what I was doing ;)

:lol: Which, in hindsight, could spawn a discussion about when to say to the boss "I cannot do this project. Get someone who knows what they are doing." I know it might hurt the ego and reputation, but if it saves the company $$s ... is it the right thing to do?

Cheers,

Ross

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

vespine, I'm glad to see that you've been able to adapt my code to a PIC microcontroller.

As far as licensing goes... I've tried to make it as painless for myself and everyone else by going with the Simplified BSD License, which is very easy to read and understand. If you redistribute my code, or a modified version of my code, the license requires you to retain the copyright and license terms. The usual way to do so would be to include (below your Copyright and/or license):

Portions Copyright 2010 Matthew T. Pandina. All rights reserved.

followed by the terms of the Simplified BSD License.

This respects my copyright, and allows anyone to trace the lineage of a particular piece of code, and it gives them clear instructions for how they may redistribute the code themselves.

A real-world example of a piece of code that has multiple contributors and various compatible licenses can be found in the OpenLDAP Copyright here: http://www.openldap.org/software/release/copyright.html

If you are not redistributing any of my code (modified or unmodified), obviously you don't have to include the copyright and license, but it would be a nice gesture if you mentioned that you derived your code by following the procedures described in my book, so anyone can find and read the latest copy of the book themselves.

I'd rather not turn this thread into a boring discussion of copyrights and licenses. What is really exciting to me is the stuff in the code, and what it enables people to build and achieve. If you still have questions regarding the copyright or license, feel free to email me. My email is listed on the front cover of the book.

Good luck on your project! :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

valusoft wrote:
Get someone who knows what they are doing." I know it might hurt the ego and reputation, but if it saves the company $$s ... is it the right thing to do?

Cheers,

Ross


Fortunately I can't sack myself, otherwise I probably would have done it long ago ;) this is just a hobby project i'm doing on my own, no professional involvement so all good.

So thanks Artcfox for explaining it, seeing that example really helped. I suppose I should put something of a license together if I'm going to be sharing code.

One technical question, probably a bit curly, the TLC can run GSCLK up to 30MHz, but generating an interrupt every 4096 cpu clocks in that case gives a an interrupt at 7KHz, that's crazy!

I'm using the 80MHz pic, practically and this is the TOP end, i want 800Hz-1000Hz, i am multiplexing 8 ways so it's pretty extreme already, this means 800 interrupts a second, which is a LOT and this still means a top GSCLK of only 3MHz?! How could I have a reasonable GSCLK say around 20MHz or so, but a frame rate of say 800Hz? Something isn't adding up. Any thoughts?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

vespine wrote:
valusoft wrote:
Get someone who knows what they are doing." I know it might hurt the ego and reputation, but if it saves the company $$s ... is it the right thing to do?

Cheers,

Ross


Fortunately I can't sack myself, otherwise I probably would have done it long ago ;) this is just a hobby project i'm doing on my own, no professional involvement so all good.
Apologies. I got the wrong end of the stick.

And ... I "enjoyed" reading your eBay scam story. By the way, there is a unit of VicPol that deals with such crimes. The guys out in the 'burbs are very uneducated ... even about its existence. You will have heard of the "Leap" database ... well there is one entry in there that records an assault using a computer keyboard which was classified as a "computer crime" instead of common assault. What hope is there ...

Cheers,

Ross

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

vespine wrote:
So thanks Artcfox for explaining it, seeing that example really helped. I suppose I should put something of a license together if I'm going to be sharing code.

:)

vespine wrote:

One technical question, probably a bit curly, the TLC can run GSCLK up to 30MHz, but generating an interrupt every 4096 cpu clocks in that case gives a an interrupt at 7KHz, that's crazy!

I'm using the 80MHz pic, practically and this is the TOP end, i want 800Hz-1000Hz, i am multiplexing 8 ways so it's pretty extreme already, this means 800 interrupts a second, which is a LOT and this still means a top GSCLK of only 3MHz?! How could I have a reasonable GSCLK say around 20MHz or so, but a frame rate of say 800Hz? Something isn't adding up. Any thoughts?

I think you are confusing things. The interrupt that fires every 4096 clock cycles allows you to change the outputs if you so desire. It does so by using the hardware SPI to drive the SCLK pin of the TLC5940. The way the library works is it uses the actual frequency that the microcontroller is running at to drive GSCLK, completely independent of how often you choose to update the values.

I have not had the (mis)fortune of using a PIC, so I can't comment on any of its specific hardware capabilities, but I can offer you some general pointers.

If the PIC is running at 80 MHz, then you wouldn't be able to drive the GSCLK line directly off that clock, since the TLC5940 only allows a maximum of 30 MHz. If the PIC allows you to divide the clock by 4 and output that on a pin, you should be able to use that to drive the GSCLK at 20 MHz. If you do that, make sure you set your interrupt to fire every 16384 clock cycles, since you divided the clock by 4.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
If the PIC allows you to divide the clock by 4
All the PICs I have worked with (and Motorola chips) divide the clock by 4 anyway. So the real clock is only 20MHz.

edit and of course running anything at a few MHz for more than a few centimetres becomes very interesting. I have run the SPI bus for the TLC5941 at < 1MHz up to about 2m (daisy chained boards) and that was a bit "hair falling" (or was it raising? :? ). So running it at 30MHz could become a short wave radio transmitter or just a lot of unrelated random pulses.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so you're saying you don't HAVE to shift in the data during the 4096 GSCLK pulses? Right, because that's not the impression I had from your document. Maybe I didn't read it right but it sounded like the data had to be there before then next BLANK pulse, but that's only if you want to XLAT it at that time, right? That's fine if that's the case.

As for John's comment.. Yes well obviously that's the problem with not having a background in electronics, you learn this stuff as you go :) In fact, i am almost definitely suffering from what you're talking about. I've been constantly plagued with random flickering and artifacts when I touch the signal cables, when our wireless phone goes off and often for no obvious reason at all... So I'm pretty sure what you're talking about is playing a factor.

Apart from shortening my signal cables as much as possible, which I should be able to do substantially, are there other "tricks of the trade" which you can suggest? short of printing my own PCBs.. How about shielded audio cable? or something like that? At the moment i'm just using standard ribbon cable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

vespine wrote:
so you're saying you don't HAVE to shift in the data during the 4096 GSCLK pulses? Right, because that's not the impression I had from your document. Maybe I didn't read it right but it sounded like the data had to be there before then next BLANK pulse, but that's only if you want to XLAT it at that time, right? That's fine if that's the case.

Read the code in Appendix A, the answer is right there. You don't have to shift in new data every 4096 clock cycles. If you don't shift in new data, the ISR will still be called and BLANK will unconditionally be pulsed to reset the counter and refresh the previously shifted in data. When you finally decide to shift in new data, by changing gsData[] and calling TLC5940_SetGSUpdateFlag(), the new data will be (conditionally) shifted in during the next call to the ISR.

Note that the ISR does not shift in or even look at gsData until gsUpdateFlag is true, so you can take as much time as you want writing to that array when you decide to update it. Once you call TLC5940_SetGSUpdateFlag(), during the next call to the ISR it will see that gsUpdateFlag is true, and then it must shift in all of the new data in under 4096 clock cycles.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
are there other "tricks of the trade" which you can suggest?
The first thing I would do is to SLOW DOWN the clock as much as you can, maybe 100 or 200KHz.

Depending on how many chips you have wired up in series the data will be delayed in respect to the clock as it has to go though each chip. The faster the clock the more chance you have that the clock will arrive before the data or that the data set up time is too short.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lol, ok i think we're not understanding each other, sorry, I'll do more reading.. Yes I understand i have as much time to write to the ARRAY, i don't care about that, that bit is sorted. What i care about is shifting the data to the TLCs.

Do i HAVE to shift the data in ONE period of 4096 GSCLK cycles between 2 blank pulses, (which you say yes in your last sentence) or can I shift in the data over a few of those? I don't see anything in the datasheet which says you can't do this:

start shifting in data, blank pulse 4096GSCLK,
still shifting in data, blank pulse 4096GSCLK,
still shifting in data, blank pulse 4096GSCLK,
Finished shifting in data blank on xlat blank off 4096GSCLK,

Does that make sense? Blank does reset GSCLK, but the GS register is only updated from the shift register when you pulse XLAT. So what stops you taking more then one lot of 4096 GSCLK to update the input shift register which has an independent clock?

Anyway, if i'm still not making sense, don't worry:) I don't want to hijack this thread completely with my incoherent ranting.

The problem I have John is that I really need to be shifting about 1.5Mbits/s, ideally 2Mbits/s, so 100 or 200 KHz just ain't gonna cut it.

So in your opinion is the only answer "same circuit board" ? If that's the avenue I have to start investigating, then so be it... I'm not giving up on this project now...

Isn't that your area of expertise? What do you charge per hour for circuit board design? And i'm only half kidding :lol:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

vespine, take a look at the programming flow chart, specifically the "Grayscale Data input cycle Combined with Grayscale PWM cycle" section.

Quote:
Data input must be complete before GSCLK_Counter reaches 4096.
Use the following equations to verify that the data input cycle will be
completed before the PWM cycle is completed.

Also, you can look at the timing diagrams in the datasheet, but those are a bit complicated (which is why I was so happy to have found the programming flow chart).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AHA! That's what I was not seeing!

Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Andee,

Good to see you're still fiddling with this and making good use of the pic24 I soldered for you!

If you want to send high speed signals down a flat cable, you probably want to use differential drivers and receivers like the ones used for RS485 - MAX485 comes to mind. These are good to 10mbit/s from my rapidly fading memory.

as for a choice of processir, you'd want to use one that can do DMA via the SPI port. This will offload the job of shifting data from memory to the SPI port onto the DMA hardware thus less load on the cpu. I'm not sure the PIC32 has such a feature but the higher end Luminary Cortex M3 processors do and a few other ARM variants.

Having an interrupt of 7kHz is not that crazy - depends on what the isr has to do within that time period.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, i've tried this code on a atmega8.

I've attached the TCL5940 the same way like he did write in his book:
SIN MOSI (PB3)
XLAT OC1A (PB1)
SCLK SCK (PB5)
GSCLK PB0
BLANK SS (PB2)
VPRG PD7
DCPRG PD4

The mega8 is running with 16mhz from an XTAL.

I've changed the init-routine from timer0 to timer1 because the mega8 has no TIMER0_COMPA_vect ISR, but a TIMER1_COMPA_vect.
This is the piece of code i have changed:

...
ISR(TIMER1_COMPA_vect) {
...

init() {
...
	TCCR1A = (1 << WGM11); 	// CTC with OCR1A as TOP
	TCCR1B = ((1 << CS12) | (1 << CS10)); 	// clk_io/1024 (From prescaler)
	OCR1A = 3; 	// Generate an interrupt every 4096 clock cycles
	TIMSK |= (1 << OCIE1A);
...
}

I know 16mhz instead of 20mhz makes the PWM run a bit slower, but i should see something on the leds...
However, none of the 16 LEDs is working...

Can anyone of you help me?[/code]

my site, currently only in German:
http://krumeltee.wordpress.com/

I²C devices on AVR32/Linux: max127 ADC, PCF8574, LM75

I²C devices on AVR: max127 ADC, PCF8574, ADS7841 ADC, max520 DAC

I²C devices for every PC via RAM modules

...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please start a thread in the main forum, this is the tutorial forum. (someone with mod rights here may move this?)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

On Page 26 inside the TLC5940_Init() function, it says

setOutput(GSCLK_DDR, GSCLK_PIN);

Should this be

setOutput(GSCLK_PORT, GSCLK_PIN);

instead?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No. GSCLK_DDR is correct. The DDR [Data Direction Register] register is used to configure the port as input or output. The PORT register is used to set its value when configured as an output via the DDR [or control the internal pull-up when set as an input]

There is an error a little further along where it reads

setLow(GSCLK_DDR, GSCLK_PIN);

it should read

setLow(GSCLK_PORT, GSCLK_PIN);

Which perhaps is the line you meant?

However since the code is designed to use the CLKO pin, the GSCLK pin is inaccessible as a GPIO, and thus any manipulation of its PORT or DDR values will have no meaning.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.