Jump to content
roadrunner84

Charlieplexing LEDs on the MSP430 Lauchpad

Recommended Posts

Hi all,

 

I am working on a project which uses 2 x (6 LEDs charlieplexed on 3 I/O lines). I chose for this setup instead of 12 LEDs on 4 I/O lines to up the dutycycle from 1/12th to 1/6th, hoping to increase the brightness. My timer ticks at 512Hz, so in 6/512 seconds all LEDs are cycled and the sequence starts over. The software is working fine, the LEDs are lit....

 

 

that is, when I turn off all the lights in the room I can berely discriminate lit from unlit. The LEDs shine so dim it's almost not noticable.

 

I chose red LEDs, because they need the least voltage of all (only 1.8V). For now, I do not use any series resistor.

 

I know the Lauchpad supplies 3.6 volts to the MSP430G2211, the datasheet is somewhat cryptic on that matter.

The datasheet says that at a load of 6mA per pin (the total load of 48mA) VoutHi >= Vcc - 0.3V and VoutLow <= Vdd + 0.3V.

Now I'm not sure what to make of that, but I think the MSP430 does not supply enough current for my application.

 

I have seen several charlieplexing projects, also on the MSP430. How come my LEDs barely shine at all? What should do the trick?

 

Thanks,

 

roadrunner.

Share this post


Link to post
Share on other sites

 

Someone else can probably help with the charlieplexing issue, just wanted to touch on the voltage issue.

 

The way it works is that the msp430 can provide up to 48ma of power per port, with a minimal voltage drop of 0.3v. The higher the current draw, the bigger the voltage drop. At 48ma per port, 6ma per pin, that means you will see 3.3v, not 3.6v, at that pin (or 0.3v, not 0.0v) And this is in single ended configurations, where the msp sinks or sources the current, not both, like you are doing. In your case, it might be affecting both ends, so instead of 3.3v, you are only seeing 3v, which really, shouldn't be a problem for red leds.

 

That said, plenty of people have had charlieplexed led projects, and with more leds without issues. Maybe a clock is wrong, your pwm has too short of a duty cycle because of it? Try posting your code so that others can help better.

Share this post


Link to post
Share on other sites

I used an osciloscope, and the dutycycle is indeed 1/6th as I expected.

I will not post my entire code, as it would just add a lot of noise, but I'll post the concerning parts.

 

I'm using IAR Embedded Workbench, so that's the intrinsics and compiler extensions you'll see here

void main(void)
{
WDTCTL = WDTPW | WDTHOLD;
DCOCTL = 0; // This is a fix for bug BCL12 as described in errata slaz061b
BCSCTL1 = CALBC1_1MHZ | DIVA_3; // Set ACLK to LFXT1 / 8 = 32kiHz / 8 = 4kiHz
DCOCTL = CALDCO_1MHZ; // Last step calibration loading
//BCSCTL2 = DIVS_3; // SMCLK = DCO / 8 = 1 MiHz / 8 = 128 kiHz
BCSCTL3; // TODO: set XCAP to correct setting, depend on XTAL
P2SEL = BIT6 | BIT7; // Use P2 pins for crystal
// Set TimerA to overflow at 2 / (ACLK / 4) = 2 / (4ki / 4) = 512 Hz
TACTL = TASSEL_1 | ID_2;
TACCTL0 = CCIE;
TACCR0 = 1;

/* MORE CODE HERE */

TACTL |= MC_1;
__low_power_mode_3();
__no_operation();
}

#define LED_CHARLIEPLEX_MAX 6
const uint8_t
LED_PLEX[LED_CHARLIEPLEX_MAX] =
{
LEDmA | LEDmB | LEDhA | LEDhB,
LEDmA | LEDmB | LEDhA | LEDhB,
LEDmA | LEDmC | LEDhA | LEDhC,
LEDmA | LEDmC | LEDhA | LEDhC,
LEDmC | LEDmB | LEDhC | LEDhB,
LEDmC | LEDmB | LEDhC | LEDhB
};
uint8_t
LED[LED_CHARLIEPLEX_MAX];

#pragma vector = TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
Display();
/* MORE CODE HERE */
}
void Display(void)
{
P1OUT &= ~(LEDmA | LEDmB | LEDmC | LEDhA | LEDhB | LEDhC); // Clear LED pins
P1DIR = LED_PLEX[D_state];
P1OUT = LED[D_state];
D_state++;
if (D_state >= LED_CHARLIEPLEX_MAX) D_state = 0;
}

Oh, and LEDmX and LEDhX are defines for pins all on port 1.

Share this post


Link to post
Share on other sites

Yeah, I could use transistors, alas it will inflate the size of my board :( I'm currently at 11x39mm single sided (to save height space) and wouldn't like to increase that size considerably.

Share this post


Link to post
Share on other sites

no sure if i mis-interpret this. u mention u want to set timerA to overflow so as to get to 512Hz interrupt. but my understanding is that if u set TACTL w/ MC_1, this would mean up count to CCR0, which u set it to 1.

 

now if this is the case, your interrupt will may be called a lot more frequently and it may not have enough cycles to execute what it intend to do.

 

i don't use energia enough, but i suppose also when u do __no_power_mode3() it will also enable general interrupt. I.e. _BIS_SR(GIE)?

 

 

 

 

// Set TimerA to overflow at 2 / (ACLK / 4) = 2 / (4ki / 4) = 512 Hz
TACTL = TASSEL_1 | ID_2;
TACCTL0 = CCIE;
TACCR0 = 1;
/* MORE CODE HERE */
TACTL |= MC_1

Share this post


Link to post
Share on other sites

Yes, I want TimerA to trigger an interrupt ever 1/512th of a second. I set the clock source for the timer to ACLK/4, and ACLK is LFXT1/8. So ACLK is 4096Hz, thus timerA is clocked at 1024Hz. By setting TACCR0=1 It will count 0,1,0,1,0,1,etc. and trigger once per round trip, so half the clock source frequency; 1024/2=512Hz. I think I set that all up correctly, did I not?

 

Oh, and yes, entering LPM3 via the __low_power_mode_3() intrinsic will indeed enable global interrupts (and disable all clocks but ACLK).

 

While only two timerA ticks are between the interrupts, this is still about 2000 cycles for MCLK (which is 1MHz), enough for my application (I hope).

Share this post


Link to post
Share on other sites

if your problem is with ghosting. u can try to turn off P1DIR bits 1st when u turn off P1OUT.

and when u turn on, do the P1OUT bits before flipping P1DIR bits.

 

for brightness, i had no clue, i do 1/8 cycles driving 7-segment red display modules and w/ 3.6V from launchpad, i usually have to insert dimmer cycles for indoor use. i do notice difference when using green modules, they are way less dimmer.

 

void Display(void)
{
P1DIR &= ~(LEDmA | LEDmB | LEDmC | LEDhA | LEDhB | LEDhC); // C
P1OUT &= ~(LEDmA | LEDmB | LEDmC | LEDhA | LEDhB | LEDhC); // Clear LED pins
P1OUT = LED[D_state];
P1DIR = LED_PLEX[D_state];
D_state++;
if (D_state >= LED_CHARLIEPLEX_MAX) D_state = 0;
}

Share this post


Link to post
Share on other sites

I do not have problems with ghosting, as you can see I usethis sequence:

  1. Set all High pins Low
  2. Set the correct pins to Out or HiZ
  3. Set correct pins from Low to High

In your example code you do

  1. Set all pins to HiZ
  2. Set all pins to latent Low
  3. Set correct pins to latent High
  4. Set pins from HiZ to High/Low

Both should work, as there is no conducting path between the first and the last step.

 

It is interesting that you have no problem with the brightness, even on 1/8 cycle. Could you look up what differences are between your code and mine? Do you use resistors in addition to your LED displays? How do you power your launhpad when using the LED displays? Are there any other passive or active components in your circuit?

Share this post


Link to post
Share on other sites

mine project is not full charlieplexing. it's like a hybrid of multiplex and charlieplex. i.e. 7 segment pins multiplex on 4 digit pins.

then i double up that w/ one common-cathode and one common-anode tied together where charlieplexing logic is used.

 

i direct drive the led modules and they are bright indoors.

 

 

i am not sure i understand what u describe. if some leds are unlit and some are lit. u should be able to tell precisely which ones are unlit.

if u can't discriminate between them, do they appears ALL to be lit, or NONE are lit?

 

that's why i read that as a ghost problem. depending on your P1REN setup and the order of flipping registers, some leds can be dimly lit unintentionally.

Share this post


Link to post
Share on other sites

P1REN is all low (ie: no weak pullup or pulldown in use).

When I say I cannot discriminate I mean that the lit LEDs are so dim, that I need to turn off all ambient light to see that they are lit. The unlit LEDs are unlit, as expected.

 

Do you mean that you use 7 segment driver lines and 4 common lines. Then use 4 common cathode and 4 common anode displays, so you can drive 8 segments from these 7+4 lines?

Share this post


Link to post
Share on other sites

Do you mean that you use 7 segment driver lines and 4 common lines. Then use 4 common cathode and 4 common anode displays, so you can drive 8 segments from these 7+4 lines?

 

yes, like so... (edit... actually 2x (4x7 displays))

 

IMAG0005.jpg

 

 

did u try altering the P1DIR=xx; P1OUT=xx; ordering in my previous note? it make a difference on my setup. (i.e. I got ghosting when the order is not right).

anyway, i think i do not have more input on your dimly lit led problem. may be there is some other factor in other parts of your code.

Share this post


Link to post
Share on other sites

Looking at your solutions, I found myself finding a "new" design:

Currently, I use 6 LEDs at 3 I/O lines, using traditional charlieplexing.

Wouldn't it be a solution to have 3 LEDs hooked up to Vcc, 3 to Vdd, and then hook them in pairs to the I/O lines?

This would save me one pin internal resistor. The drawback might be that the LEDs basically are always in a "conducting" form; two LEDs in series from Vcc to Vdd.

What will happen in these cases, if Vcc-Vdd is smaller than 2 times the LED operating voltage? (eg: with 2 red LEDs at 2*1.8V=3.6V, but using only 3V supply)

Share this post


Link to post
Share on other sites

Same thing that happens when you power a 3.3v led with a 3v battery. They just take less current, until the voltage is below the minimum needed to light them at all. Two red leds might still be on at 3.6v, or they might not be. Best bet is to give it a try with two spare leds to see. For the most part, it should work though. High to enable one led, low to enable the other, and tristate/input mode to disable both.

 

http://www.batsocks.co.uk/readme/p_tut_led16.htm

http://www.neufeld.newton.ks.us/electronics/?p=151

Share this post


Link to post
Share on other sites

Yes, the solution rom Batsocks is exactly what I was thinking about.

My only concern is (as my device will run on a coin cell, and must be very low power) that the LEDs - although not lit - will leak too much current to be acceptable.

Currently, when the LEDs are off, my current is 0.9 microampere. If each LED pair would leak, say, 2mA, that would 13-flod my standby current!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×