Go Down

Topic: RGB led: can I put only 1 resistor at ground? (Read 14135 times) previous topic - next topic

oric_dan

Cool, something new to look at, :-). A couple of quick comments while mulling things over.

1. did you also include the time it took to think about what you needed to do [ie, "design
   time"], plus to do background research [eg, to find Timer references], in your 15-minutes?

2. one problem - you can't have 15-msec delays in your main loop, that'll kill the efficiency
   of your overall program.

The whole point of the exercise is to get multiplexing to work in the context of a "real" program that does something productive, and not just a "demo", as mentioned previously. But, new inputs are always good!
   

ph77

#31
Nov 24, 2014, 06:55 pm Last Edit: Nov 24, 2014, 06:58 pm by PetriH
Thanks!

1. I didn't take time, but I estimate about 15 minutes planning, 15 minutes implementation.

2. The main loop is just a demo showing that generating the PWM signals don't block the CPU and that the PWM update frequency is independent of the main program. I.e. adding new stuff to the main program does not make the LEDs flicker, a concern that was raised earlier in this thread.

btw. how would you define a "real program"? I think this technique is pretty general and can be used by any program that can yield one timer interrupt for the LED update routine.

ph77

#32
Nov 24, 2014, 07:22 pm Last Edit: Nov 24, 2014, 07:23 pm by PetriH
To further elaborate: the point of the sketch I did is that you can rip out the entire main loop and replace it with the "real program". The main program can change the values in the color array at will. The interrupt routine is the real beef and takes care of generating the multiplexed PWM signals based on the R,G,B values stored in the array.

You can adjust the update frequency by adjusting the timer period here:
Code: [Select]
Timer1.initialize(50);
Larger values use less CPU time.

oric_dan

ok, will take me a bit of time to figure out the code.

A real program would be something more than a simple demo, but where the multiplexing scheme might be inserted for monitoring ongoing processes. Eg, something that uses libraries, which tend to be cycle hogs. An example might be reading multiple A/D channels, buffering and formatting the data using sprintf() statements into a nice ASCII string format, and then writing to an SD card.

ph77

ok, will take me a bit of time to figure out the code.
Ok, I will happily answer any questions.

A real program would be something more than a simple demo, but where the multiplexing scheme might be inserted for monitoring ongoing processes. Eg, something that uses libraries, which tend to be cycle hogs. An example might be reading multiple A/D channels, buffering and formatting the data using sprintf() statements into a nice ASCII string format, and then writing to an SD card.
Sounds doable. I'll leave the details for you to fill out :)

Here's the code with "demo parts" ripped out if you want to try plugging in the stuff you mentioned above.

Code: [Select]
#include <TimerOne.h>

volatile uint8_t color[3]; // R,G,B led intensities in range [0,255]
volatile uint8_t phase = 0; // phase of the PWM signal, counts from 0 to 255
volatile uint8_t led = 0; // which led to update, counts from 0 to 2

// The interrupt routine that updates the states of leds.
void interruptRoutine()
{
 // turn all leds off
 PORTD &= B11100011;

 // sample pwm and turn on one led
 if(phase < color[led])
 PORTD |= 1<<(led+2);

 led = (led + 1) & 3;
 phase++;
}

void setup()
{
 pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 pinMode(4, OUTPUT);

 // attach interrupt routine
 Timer1.initialize(50);   // PWM update period here, make it larger if your program needs more CPU time
 Timer1.attachInterrupt(interruptRoutine);
}

void loop()
{
  // <insert your code here, write the intensities of LEDs to color array >
}

oric_dan

#35
Nov 24, 2014, 08:36 pm Last Edit: Nov 24, 2014, 08:38 pm by oric_dan
I'm not familiar with the TimerOne library. To get this straight,

1. you didn't actually write a multiplexing routine [from scratch] in 15-minutes, you found someone else's library that generates s.w. PWM using timer interrupts? LOL, good one.

2. initialize(50) means it's actually generating a timer interrupt every 50-usec, or 20,000 times per sec?

I imagine that's not overly loading down the AVR chip, but it's still a lot of interrupts. Luckily, your interrupt routine code is fairly short. I think one might need to do a fair amount of testing to determine whether all those interrupts might impact other processing in a "real" program. OTOH, you probably don't really need 8-bit PWM for Led intensities, so the interrupts could probably be slowed down by quite a bit. Does this sound right? I'm just trying to analyze what's going on here.


ph77

1. I feel you are trying to downplay my contribution :) TimerOne library is only used to attach the interrupt routine. I could have setup the interrupt myself, but why reimplement the wheel? The details of the multiplexed PWM generation is in the interrupt routine I posted. I.e. TimerOne library is not used to generate the PWM signal, because it can not generate a multiplexed PWM signal.

2. I already mentioned that you can change the timer interrupt frequency. 50 is just a value I threw in. You can use a higher value to slow down the update frequency if it matters in your application.

The number of steps needed depends on the application. It's easy to change. For example, change "phase++" to "phase = (phase + 1) & 63" and use color intensities in range 0-63 for 6 bits.

I suggest you wire this up, shouldn't take more than a few minutes and play around with the code.

oric_dan

Sorry, like I said, I am unfamiliar with TimerOne, so just trying to figure out what is going on here. You said to ask questions [:-)]. Ok, now I see you're doing all the pwm'ing inside the interrupt routine, but I think you need the very high interrupt rate to get good 8-bit PWM.

Quote
For example, change "phase++" to "phase = (phase + 1) & 63" and use color intensities in range 0-63 for 6 bits.
I think you could use phase+=4; and initialize(200) to get the same effect, although it may still be adequate [ie, no flickering] at even slower interrupt rates.

ph77

And to answer your question: yes, if you lower the number of PWM bits, lets say from 8 bits to 4 bits, so that phase counts from 0-15 instead of 0-255, the PWM loops x16 times faster. In this case you could increase the interrupt period by a factor of 16 without affecting the update frequency.

Also I believe that you can increase 50 in any case (even with 8 bits), I just didn't test with other values.

ph77

I think you could use phase+=4; and initialize(200) to get the same effect, although it may still be adequate [ie, no flickering] at even slower interrupt rates.
Yes, that would work too, same effect.

ph77

Tested with "phase += 2" (7 bits resolution) and "Timer.initialize(175)" and seems to work well.

Less than 6 bits is probably not sufficient for slow smooth fades (depends what you want really).

Also if we are talking about optimizations, I would try to squeeze every cycle out of the interrupt routine. Writing it in assembly and getting rid of TimerOne library and its interrupt call overhead would help.

oric_dan


ph77

All in all, pretty darn good solution.
Thank you!

I have to give you credit for criticizing the CPU usage. I admit the high interrupt rate can be a problem for CPU heavy programs.

oric_dan

Well, the idea is to try and look at these things from every which angle, isn't it. That's why this thread didn't die after 2 replys, :-). These are good problems to solve.

Also, I just thought to compute the actual update rate. With initialize(50) --> 20,000 interrupts/sec, for the original 8-bit PWM, that's 20000/256= 78 Hz. Divided by 3 Leds gives 26 Hz updates, which would probably result in quite perceivable flicker. OTOH, dropping to 5- or 6-bit PWM and using initialize(100) rather than initialize(200) would lessen the interrupt overhead and should still keep the PWM frequency up at 50 Hz or more, and which would be fine.

Pelleplutt

. The other guys who were also pushing its merits just disappeared in a puff of smoke.

I'm still here reading what you are writing.
Thanks Petri

Pelle

Go Up