NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » RGB LCD Screen

March 24, 2010
by Hexorg
Hexorg's Avatar

Hey everyone, I decided on a project to start. It will include several parts to it, but let's start with the first one. Project supposed to have 10x10 RGB image output, and image might be a subject to animation. So I have two ideas: 1) Using only one microcontroller, strobe each sub-pixel (R, G, or B) at a time. That way, I'll need 10 pins for row, 10 for column, and 3 for subpixel (23 total, which is possible with a nerdKit's ATmega168). 2) Have one ATMega168 controlling one column of pixels (10 rows, 3 Subpixels) That way I will need 10 ATmega's (I'm figgling with the usb programmer right now too) and one more to control everything through SPI.

Which method do you think is better, and maybe you have a better method to suggest? Once again I need to control 100 (10 rows X 10 columns) RGB LEDs, which is essentially 300 monochrome LEDs.

March 24, 2010
by bretm
bretm's Avatar

Save your pins! I would use shift registers. You want to drive more than one LED at a time, otherwise you won't get more than a 1% duty cycle on a single LED. So I would drive a whole row at a time.

Get a couple of 16-bit shift registers, also called serial-to-parallel converters. This lets you control 32 bits with just a few pins on the MCU. Wire all the R's of one COLUMN together, the G's together, and the B's together, and connect to the shift registers through 30 current-limiting resistors.

Wire all the cathodes for each ROW together to a third shift register, going through a MOSFET switch for each row to supply enough current. Or instead of a shift register you can use a 4-to-16 line decoder since you only need one row active at time.

Then the algorithm goes like this:

Turn off the previous row Shift in the RGB bits for the next row Turn on the next row Repeat

To avoid flicker you want to update at at least 50 frames per second, or 500 rows per second, or 15000 bit shifts per second, so this seems doable.

Additional logic needed if you want to do PWM to get more than 8 colors (including black), e.g. increment a 5-bit counter once per entire frame and only turn on a given LED if the brightness value (stored in an array) exceeds the counter value. You'll want to multiply the frame rate by 32 if you do this. This gives you 32768 colors. It requires about 480 thousand operations per second, which leaves only 30 clock cycles for each update. Still doable, but will use a lot of your CPU time.

March 24, 2010
by Hexorg
Hexorg's Avatar

ah! That makes life so much easier! I didn't know such thing as a shift register existed.

However, The data can be set either to +5V for HIGH, or to about +0.8V for LOW... How can I control row selection? LEDs' cathods are supposed to be connected to the ground, not to +0.8V

March 24, 2010
by bretm
bretm's Avatar

Where does 0.8V come in?

It doesn't really matter anyway. The LED can't tell the difference between 0.8V and 0.0V at one end. All that it sees is the voltage difference, 4.2V. If you used 4.2V high and 0.0V low it would be exactly the same.

And even the voltage doesn't really matter. What matters is the current. You will probably end up with one current-limiting resistor value for the red diodes, another for green, and another for blue. The voltage drop across blue LEDs is higher which means the drop across the resistor will be lower, which means a smaller resistance to result in an equivalent current.

Pay attention to the current requirements. If you use 20mA LEDs, a row of 30 of them will draw 600mA of current at full brightness. If they're 50mA, you'll need to supply 1.5 amps. That influences the power supply you choose, and the power rating of the MOSFET switches.

March 25, 2010
by Hexorg
Hexorg's Avatar

I think I get it... So the current doesn't always has to go from + to - of the battery. Voltage in electronics is just like pressure in pipes, and current wants to go from the level of high voltage to low voltage. Cool. I think that should help. Thanks.

I'm thinking to buy a couple of this shift registers, only concern - it's hard to find DIP packaging style. And then when my LEDs, ATmega, and ATmega programmer comes it, I'll start on the project :)

March 25, 2010
by bretm
bretm's Avatar

They're out there. 12-bit are easier to find, you'd just need 4 of them. Or five 8-bit ones, which seem really easy to find. But I'm seeing a few 16-bit ones at places like digikey.com and mouser.com.

But the problem seems to be low power dissipation ratings.

However, check out this guy, the TLC5941. It's DIP, it's 16 channels, and it has 12-bit PWM built in for brightness control. Custom-made for driving LEDs up to 80mA. Only one current-limiting resistor needed for all 16 channels. Huge power dissipation rating compared to plain old shift registers.

That's what you want. Just need two of those.

One thing I'm not sure about is the power dissapation requirements.

March 25, 2010
by bretm
bretm's Avatar

Sorry, meant to delete that last line once I found the power rating.

March 25, 2010
by Hexorg
Hexorg's Avatar

Yea, thanks alot! I saw that "guy" yesterday, but not yet sure I have enough knowledge to make it work with nerdkit. Well, I bought 2 of them, and 10 of 8bit serial-to-parallel (just in case)

March 25, 2010
by bretm
bretm's Avatar

This is a cool chip. I think I want to play with one, too. :-) But you're right, it's a bit complicated.

I was thinking you'd want to use SPI to drive it, but the information packets it wants are 6 or 12 bits each. That becomes a pain since SPI emits 8 bits at a time. Plus it looks like there's a weird requirement for one extra clock pulse after the PWM data is sent the first time following setting dot-correction data, but not second and subsequent times. So this will be a bit-banging application.

Easy pins are VCC, GND, and OUT0 through OUT15. Two will be unused, but I would still connect them up to single LEDs that you can use for diagnostic purposes. And that way you won't trigger the LED-open detection.

Mostly-obvious pins are TEST (connect to VCC), SOUT (connect from first chip to SIN of second chip).

It talks about "dot correction". This is for supplying less current to the decimal point or clock colon dots on 7-segment displays, which usually require less current than the digit segments. Since all of your LEDs are the same, you probably don't need dot correction. You may need it if you want to drive R, G, or B at a different current level than the others.

BLANK

Connect to an output pin, kept LOW usually. If XERR goes low you should set BLANK to HIGH to prevent damage. You'll also want to set it HIGH when you switch from one row to the next.

XERR

Connect to an input pin with a pull-up resistor. When you see this go LOW, you should blank the display.

IREF

Connect to ground through a resistor. Resistor value depends on desired maximum LED current. R = 39.06/I. For I=20mA, R=1953. For I=50mA, R=781.2.

XLAT

Connect to an output pin. Keep it LOW most of the time, but toggle it high after writing data out, to latch it into the chip's internal registers.

MODE

Connect it to an output pin. When you start up, you need to set it high to program the dot correction values. After that you'd just keep it LOW because you'll only need to program the PWM (grayscale) values.

If you don't need dot correction, just send 12 bytes of 0xFF at startup with MODE=1. Definitely do it that way for your first attempt and only deal with dot-correction once you have everything else working.

If you do need dot correction, it's probably because R or G or B need less current for equivalent brightness. (If white looks white, you don't need dot correction. If white looks a little green, you want to reduce the green outputs.) Let's say your output pins are connected like this:

OUT   15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
COLOR  R  G  B  R  G  B  R  G  B  R  G  B  R  G  B  R

You need to send 6 bits per LED, representing a brightness from 0 to 63. Let's say you want R=50 (0b110010), G=45 (0b101101), B=63 (0b111111). The values to send would then be

110010 101101 111111   110010 101101 111111   110010 101101 111111   ...

If you're using SPI will want this broken up into 8-bit bytes, so this would become

11001010 11011111 11110010 10110111 11111100 10101101 11111111 00101011 ...

It's just a matter of figuring out the byte sequence once and hard-coding it into the application. It's a pain in the neck, but it's not going to change from run to run, but would change for different models of LED.

SIN

Connect this to an output pin. This is where you set the data bits.

Data bit pattern for dot-correct (done once after power-up) is explained above.

It's the same for grayscale control except that it's 12 bits (0 to 4095) per LED instead of only 6.

The first time after sending dot-correction data (MODE=1) and switching to grayscale data (MODE=0), you'll need to send 193 bits instead of 192 bits for some weird reason.

SCLK

Connect this to an output pin. This is where you will tell the chip that the next data bit is available.

GSCLK

This is the PWM oscillator. Connect it to an output pin, preferable one of the timer output compare pins so you can let the MCU handle wiggling this for you.

This should cycle 4096 times during the time you're updating the grayscale data for the next row. As it proceeds through all 4096 cycles, LEDs turn off in turn once the PWM counter exceeds the latched grayscale value for each output. Low grayscale values make them turn off quicker, which makes them look dimmer.

Let's say you want to update the display 50 times a second (0.02 seconds per frame) to avoid flicker. That means 0.002 seconds per row. Subtract some time for blanking and moving the to next row, etc., but basically GSCLK would need to run at 0.002/4096 seconds per tick, or 2.048MHz. The nerdkits clock with divide-by-8 prescaler would do handle this, almost. You're looking at 45 frames per second instead of 50. No big deal.

So the algorithm is:

1. Emit 192 bits for the dot-correction data (96 bits per chip). Set an
   output bit on SIN, toggle SCLK, repeat 192 times.
2. Bring XLAT high and then low to latch the data.
3. Emit 384 bits for LED brightness data (192 bits per chip).
4. Bring XLAT high and then low to latch the data.
5. Toggle SCLK one more time for some weird reason.
6. Un-blank the display.
7. Enable GSCLK output.
8. Repeat steps 3 and 4 for the next row of brightness data.
9. Wait for the previous row to finish up doing it's PWM thing (4096 
   ticks of GSCLK, or about 0.0022222 seconds). You can do other stuff
   while you're waiting.
10. Disable GSCLK and blank the display.
11. Go to step 8.

It looks like you'll be able to do 32768 MCU clock ticks per row (14745600 * 0.0022222). That leaves a budget of 85 clock ticks per bit. That seems plenty.

March 25, 2010
by Hexorg
Hexorg's Avatar

WOW! Thank you so much!

Well, i wasn't worrying too much about the software part, i have quite alot of experience in that. But where did you find out all the info about what pin does what?! It's not in the datasheet, it is?

March 25, 2010
by bretm
bretm's Avatar

Yup, it's all in the datasheet.

March 26, 2010
by Hexorg
Hexorg's Avatar

I've read both ATMega168, and TLC5941 datasheets, and I think to understand why to connect them the way you described. But it made me thinking - are the HDTVs so expencive, because there is a microchip that drives 1920x1080 = 2 073 600 x 3 = 6 220 800 pins at the same time? Because prograssive means all the pixels are displayed a whole image at a time, and not line by line.

March 26, 2010
by bretm
bretm's Avatar

No, progressive is line-by-line. Interlaced displays odd lines first, followed by even lines. Progressive displays each line in order. When objects are moving horizontally on screen, you can see jagged lines on the vertical edges because the adjacent interlaced rows are updated 1/2 a frame apart in time. Adjacent rows in a progressive display are updated very nearly at the same time because they're done immediately one after the other.

TVs are doing a lot more than copying pixels. They do things like frame rate upscaling by interpolating motion between frames, resolution compensation to display older TV signals at their best, contrast and brightness control in software, picture-in-picture, and all that other stuff.

April 13, 2010
by Hexorg
Hexorg's Avatar

I got all things I was waiting for, and I'm connecting led drivers right now. I have a question about GSCLK though - can I just

uint16_t i;
for (i=0; i<4096; i++)
{
    PORTB |= (1<<PB0);
    PORTB &= ~(1<<PB0);
}

?

April 13, 2010
by Hexorg
Hexorg's Avatar

sorry, i ment PB1

April 13, 2010
by Hexorg
Hexorg's Avatar

And one more question... I'm setting up an interrupt for XERR. I've connected XERR to INT0 (pin PD2) of the ATmega168. in the code

EICRA &= ~(1<<ISC01 | 1<<ISC00); // Interrupt INT0 on LOW    
sei(); // enable interrupts;

should I loop ISR(INT0_vect) until PD2 is HIGH, or will the interrupt loop itself as long as PD2 is LOW?

April 13, 2010
by bretm
bretm's Avatar

I don't think you'll have enough time to generate GSCLK manually like that. You need to be loading the next row of data while the timer is handling GSCLK for you.

ISC00 and ISC01 are set to 0 by default, so you don't need the EICRA &= ... statement. But you need to do EIMSK |= 1<<INT0 to enable the INT0 interrupt.

I don't think you would want to set it up this way, however. It seems to me like you would want to take an action once when XERR goes low, and then take a separate action when XERR returns to high. In that case you want EICRA |= 1<<ISC00 and no looping.

And the XERR stuff is something I would deal with after I got the basic display working. Maybe for now just manually check for low XERR once in a while and have it shut off the display and then do a tight loop to intentionally hang the MCU. Perhaps turn on a diagnostic LED first. Then I'd go back and finish XERR handling once the more complicated and more interesting display stuff is worked out.

April 13, 2010
by Hexorg
Hexorg's Avatar

ok. I just thought to get error handling first, not to break the IC. What about next row uploading clock?

Is there something in ATmega that would output SCLK while I change pin's states? Or should I manually do

    PORTB = (PORTB & ~(1<<PB4)) | (dataBit & 1);
    PORTB |= (1<<PB5); // Clock High
    PORTB &= ~(1<<PB5); //Clock Low
April 13, 2010
by Hexorg
Hexorg's Avatar

Would I do the timer like in Crystal Real Time Clock tutorial? Except with a smaller prescale? And on timer interrupt just HIGH, and LOW the GSCLK pin?

April 13, 2010
by bretm
bretm's Avatar

Interrupts aren't going to be fast enough. GSCLK will be about 2MHz. That's only about seven MCU clock ticks per GSCLK tick, and it takes more than that just to save and restore the registers at the start and end of the interrupt routine.

Instead you're going to have to let the timer hardware handle the GSCLK output generation without any babysitting from the software except for starting and stopping the clock, and a much slower interrupt to count the ticks so you know when it's done clocking in the data.

You'll need to use CTC mode (Clear Timer on Compare) in order to get a fast enough clock. You'll also need to configure the timer to toggle the output on each compare match. If you use Timer/Counter0, no prescaler (divide-by-1), and set OCR0A to 3, the frequency will be 14.7456Mhz / 8, which is 1.8432MHz, which should let you do 45 frames per second. Something like this:

TCCR0A = _BV(COM0A0)  // toggle OC0A on compare match
       | _BV(WGM01);  // CTC mode
OCRA = 3;             // toggle every 4 ticks (total period of 8 ticks)
TCCR0B = _BV(CS00);   // no prescaling

And remember to sei() and configure the OC0A pin for output at some point.

Now, how to count the ticks so you can stop when you've generated 4096 ticks? I think this will be the trickest part of the whole thing. For this, you should be able to feed the Timer0 clock output (pin PD6) back into the T1 pin (Timer/Counter1 External Counter Input) which is PD5. Timer1 is a 16-bit timer and you can program it to generate an interrupt after 4090-something ticks. You might have to look at the assembly code generated by the compiler for the interrupt routine to get the exact count you need, or just try every number starting with 4090 and adding 1 each time until the darn thing works.

The reason it's not 4096 is because by the time your interrupt code runs, Timer0 will have already generated one or more additional ticks and it will be too late. You have to catch it slightly early to stop Timer0 (by setting TCCR0B to zero) at the right time. You might need one or more NOPs. And then you'll need to clear TCNT0 manually before restarting it because it might be left with a non-zero value.

TCCR1B = _BV(WGM12) // CTC mode
       | _BV(CS10) | _BV(CS11) | _BV(CS12); // external clock on T1 rising edge
OCR1A = 4093; // or so
TIMSK1 = _BV(OCIE1A); // enable interrupt on compare match A

While you're waiting for the Timer1 interrupt to happen, you're sending all the data for the next row while GSCLK is causing the LED driver to do it's magic blinkenlights thing on the current row.

April 13, 2010
by bretm
bretm's Avatar

Regarding your previous question, that's almost right. If you do

PORTB = (PORTB & ~(1<<PB4)) | (dataBit & 1);

it will clear PB4, and then the data bit will be OR'd with bit 0 of PORTB, which is PB0. Not what you want. You need to shift the data bit into the PB4 position:

PORTB = (PORTB & ~(1<<PB4)) | ((dataBit & 1) << PB4);
April 13, 2010
by bretm
bretm's Avatar

Depending on how the chip actually works, you might not need to stop GSCLK after exactly 4096 ticks. Extra ticks might be harmless. It may be the XLAT latch signal that controls it all.

April 14, 2010
by Hexorg
Hexorg's Avatar

To actually start the timer, I Need to change TIMSKn bits, right? It seems like I have the clock starting before I need it to. Here's the code:

TCCR0A |= (1<<WGM01) | (1<<COM0A0);
TCCR0B |= (1<<CS00);
OCR0A = 3;
//Clock starts here
TCCR1B = (1<<WGM12) | (1<<CS10) | (1<<CS11) | (1<<CS12);
OCR1A = 4039;

while (1) // main loop
{
    for (i=0; i<sizeof(imageRow); i++)
    {
        dataOut(pgm_read_byte(&(imageRow[i])), 1); // Output Image (PWM DATA)
    }
    BLANK(1); // Clear Screen
    XLAT();   // Save the data
    BLANK(0); // Turn Screen on

    sei(); // enable interrupts;
    TIMSK1 = (1<<OCIE1A); // IT SHOULD START HERE
    TIMSK0 |= (1<<OCIE0A);
}
April 14, 2010
by bretm
bretm's Avatar

TIMSK is only for enabling interrupts, so you don't need TIMSK0. The timers start when you set the clock source for them, which happens when you set TCCR0B or TCCR1B. You can set TCCR1B right away because that just tells it to get the clock source from Timer0, which you're not starting yet.

I would do TIMSK1 and sei() before the loop. You're controlling the interrupts manually by starting and stopping the timers so you don't have to worry about them happening early.

To start GSCLK, just set TCCR0B to _BV(CS00). To stop it, set TCCR0B to zero. This will stop both timers because Timer0 feeds Timer1.

April 14, 2010
by Hexorg
Hexorg's Avatar

IT WERKS!!!!

lol yes, wErks...

April 14, 2010
by bretm
bretm's Avatar

Wow! With 12-bit grayscale and everything? That's 69 billion colors.

April 14, 2010
by Hexorg
Hexorg's Avatar

well, i'm fiddling with it right now... My original data (image) is 8 bit per pixel, so I'm just shifting it to the left by 4, turning 0b11111111 into 0b111111110000

But it looks like I chose the wrong current limiting resistor (too much current), because there is barely any difference between 0x33 and 0xff

April 14, 2010
by Hexorg
Hexorg's Avatar

but there is definately a difference between 0x00, 0x01, and 0xff

April 14, 2010
by bretm
bretm's Avatar

Interesting. Are you just lighting up one row for now, or do you have the row-selection stuff hooked up, too? Because each row is only going to be lit up 10% of the time, so you'll want them bright to compensate for that.

April 14, 2010
by Hexorg
Hexorg's Avatar

yep! Changing the resistor did the trick :D

April 14, 2010
by Hexorg
Hexorg's Avatar

Yea, only one row, i'm still waiting for 4-to-16 decoder. But that's just calibrating - it can be a long process, but not hard. I still need to figure out though why TLC has XERR on LOW... I had to override it by connecting according pit on ATmega to +5 rail.

April 14, 2010
by Hexorg
Hexorg's Avatar

On the RGB LED documentation, i found that red is 7000mcd, green is 8000mcd, and blue is 9000mcd, so I adjusted dot-correction accordingly: // Red - 63 B8(111111), listed 7000mcd // Green - 55 B8(110111), listed 8000mcd // Blue - 49 B8(110001), listed 9000mcd

April 14, 2010
by bretm
bretm's Avatar

Do you have all 16 outputs hooked up to an LED? If not, XERR goes low to tell you you have a broken LED somewhere.

April 14, 2010
by Hexorg
Hexorg's Avatar

yea, i do, i've read and understood datasheet... XERR goes low either when one of the LEDs is broken, or when it overheats. I have an LED in all 16 (32) outputs. (16th LED is one of the LEDs that comes with the NerdKit. Could it be that they require different powers, and TLC treats it as broken?

April 14, 2010
by Hexorg
Hexorg's Avatar

well i think i found out why my XERR is always LOW. This is from datasheet:

The open-drain output XERR is used to report both of the TLC5941 error flags, TEF and LOD. During normal operating conditions, the internal transistor connected to the XERR pin is turned off. The voltage on XERR is pulled up to VCC through an external pullup resistor. If TEF or LOD is detected, the internal transistor is turned on, and XERR is pulled to GND. Because XERR is an open-drain output, multiple ICs can be ORed together and pulled up to VCC with a single pullup resistor. This reduces the number of signals needed to report a system error...

So I guess I'll need to get an external pull-up resistor.

April 15, 2010
by Hexorg
Hexorg's Avatar

One more thing... Right now I have tow TLCs connected just like an example in the datasheet (SOUT of TLC1 is in SIN of TLC2, and ATmega outputs 382 bits of PWM data on one single pin).

Can't I put TLCs' SINs to separate pins of ATmega? Wouldn't it pretty much write 2 bits of informations per one SCLK rising edge, and, therefore incresing data transfer speed?

April 15, 2010
by bretm
bretm's Avatar

Yup. They just show it that way to show that you can drive multiple chips without increasing the pin count. But if you have the pins to spare there should be no reason you can't do it.

The only thing you'd theoretically have to worry about is "fanout" but with two chips you're nowhere near having that problem.

April 26, 2010
by gnkarn
gnkarn's Avatar

Did somebody tried to use Alex leone Library for the 5940? I`m interested on making his library to work with mega168, but still having an error when compiling. as you have been using the TLC I think you may have researched it or may be interested on doing , if this is the case I will be more than happy on hearing your thoughts about it on trying to make this work.

source file are in : http://code.google.com/p/tlc5940arduino/downloads/detail?name=Tlc5940Mux.zip&can=2&q=

regards Gustavo

April 26, 2010
by Hexorg
Hexorg's Avatar

Gustavo, I never heard of this library before, after downloading it first thing that I saw was that It was made for Adruino (which, I think, is something like another NerdKit). AOn Adruino's website I found a strange link called "Adruino Language Reference". This might be very close child of C language, but because it's a different language - that might be a reason behind bad compilations. I haven't tried to compile it, and don't know what kind of errors it shows, but I'm pretty sure you'd have to rename those .h files into .c files to begin with.

April 26, 2010
by gnkarn
gnkarn's Avatar

Yes, I went through the arduino desing and it is not hard to understand, programs are not difficult to translate if have the arduino libraries , they do have some macros to make coding easier to read, and the function of the arduino kit pins are standardized and the code takes this into account ( so is less flexible than the bare 168 of course), anyway ACleone has codded his library almost in a "non arduino" mode so it compiles with very minor modifications.

this is the line where I´m having trouble

/* Enables the output of XLAT pulses /

#define enable_XLAT_pulses() TCCR1A = _BV(COM1A1) | _BV(COM1B1);

/* Disables the output of XLAT pulses /

#define disable_XLAT_pulses() TCCR1A = _BV(COM1B1);

// static void TlcMux_init(uint16_t initialValue = 0 );// >>>>LINE WITH ERROR!!

COMPILER ERROR : ../Tlc5940Mux.h:33: error: expected ';', ',' or ')' before '=' token

IF I REMOVE THAT LINE COMPILATION works normal...

April 26, 2010
by Hexorg
Hexorg's Avatar

oh! I think C doesn't support default function parameters. In the given example with "uint16_t initialValue = 0" it means that you can call TlcMux_init(); and that would be equal of calling TlcMux_init(0); in C, however you must call TlcMux_init(0); so just modify that line to

static void TlcMux_init(uint16_t initialValue);

and in the code make sure all TlcMux_init(); are replaced with TlcMux_init(0);

April 26, 2010
by gnkarn
gnkarn's Avatar

ok, should I define initialValue=0 in other place and then call : TlcMux_init( initialValue); ?

April 26, 2010
by Hexorg
Hexorg's Avatar

well,

static void TlcMux_init(uint16_t initialValue);

means that variable initialValue can be "seen" only by the function TlcMux_init. So all you have to do is make sure that whenever TlcMux_init() is called from other functions it is called as

TlcMux_init(0);

and NOT as

TlcMux_init();
April 26, 2010
by gnkarn
gnkarn's Avatar

thanks, it compiles ok now. now I´m simulating the code to understand how it works ..

April 26, 2010
by Hexorg
Hexorg's Avatar

let us know what did you find out :)

The way i made my code - was direct pin status changing with PORTn |= bla bla bla

April 28, 2010
by Hexorg
Hexorg's Avatar

I'm stuck a bit in the code... is there any way to forse SPI clock tick? I've tried

PORTB |= (1<<PB5);
PORTB &= ~(1<<PB5);

but it diesn't seem to work.

April 29, 2010
by bretm
bretm's Avatar

If PB5 is configured as an output pin, it probably means you have to disable SPI so that it relinquishes control of the pin.

Why do you need to do this? Is it because of the 5941's weird requirement of one extra clock tick after switching from dot-correction to gray-scale data?

April 29, 2010
by Hexorg
Hexorg's Avatar

Well turns out I don't have to make that one extra click for 5941s requirement (works just as great), I was thinking to make a simple 8 to 12 bits conversion by clicking SPI clock 4 times... but nevermind that, I already wrote a program for linux that'd convert bmp file to 12-bit per channel data :)

May 01, 2010
by Hexorg
Hexorg's Avatar

ok, everything seems to work good right now :D dynamic upload works great :D Still one trouble though, I cant seem to figure it out - the brightness of LED increases from 0x000 to 0x010 to 0x020... 0x200 at about 0x200 the brightness seems to be maximum and there is no difference between 0x200 and 0xFF0. I figured there is something fishy going on with PWM. However setting OCR1A from 4090, to 1000 actually made it better! The maximum recognizible value grew up to about 0x420

May 01, 2010
by Hexorg
Hexorg's Avatar

played with it a little more, OCR1A = 3000, seems to bring maximum recognisible value to grow up to 0xcc... 3200, 3500, 3700 didn't seems to have much effect.

May 02, 2010
by Hexorg
Hexorg's Avatar

hm... This is all quite wierd... I've modified my program to support not only dinamic upload, but also a dinamic OCR1A change. it seems quite odd - if OCR1A is in range of 1504 to 3780 - the quality of the image is quite good and doesn't change (as far as PWM goes), if I hit 1503, or 3781 - that's where it seems to "cancel" PWM effect.

How fast can that 16-bit timer work? for speed I did:

TCCR0A |= (1<<WGM01) | (1<<COM0A0);
OCR0A = 0; // Burst width = 67 ns

TCCR1B = (1<<WGM12) | (1<<CS10) | (1<<CS11) | (1<<CS12);
OCR1A = 3700;
May 12, 2010
by gnkarn
gnkarn's Avatar

ACLEONE code works perfect. Im using TLC5940Mux version of the library. I have tested with no Multiplexing, now I will connect the TLC to have the channels multiplexed, but I will need P channel mosfets, and only have N channel at hand..., will have to buy a couple..

Post a Reply

Please log in to post a reply.

Did you know that negative numbers are represented in two's complement notation in binary? Learn more...