Get your own customer support community
 

Color Calibration / Dimming Curves (MaxM)

I have been working with the BlinkM MaxM for a couple of weeks and with the particular light chians I'm using, the color response is poor - the problem is that the PWM of the MaxM is scaled linearly and the LED output is logarithmic. So when I set the color to (128,128,128) the PWM is at 50% duty and my LED's consume half the measured power but are considerably more than 50% as bright as they would be at (255,255,255). This isn't the fault of the BlinkM hardware of course, but it does make for some odd fading behavior and some non intuitive response when one is trying to achieve a particular color. Also, I'm sure there are other LED's that have a more linear response, so please note that this is only what I am seeing - maybe nobody else is in the same boat.

So what can be done about this? Currently, in my arduino sketch I am transforming my rgb values using an inverse cube function to approximate (term used very liberally) a logarithmic curve. It's not perfect but it's considerably less expensive (CPU and code space) than actual logarithms. Here is the code (red only shown; the same is done for other values):

unsigned long rl = (unsigned long) r * (unsigned long) r
* (unsigned long) r / 65535 + 1;
r = (r == 0 ? 0 : rl);


So this transforms our color values into roughly equivalent "brightness" values -- if using HSB colors you could probably succeed in applying the same transform to only the "B" number and achieve the same thing. Internally the BlinkM is going to transform HSB back to RGB anyway.

The drawbacks with this approach are that at the "dim" end of the color ranges there are not enough steps for smooth dimming though the colors on the whole appear more accurate.

My question is, is there a better way to do this? Can I do anything between the MaxM outputs and the led light chain to achieve a linear to logarithmic transformation? Can the MaxM's internal PWM handling be converted to a higher resolution (4096 bit) and internally use a logarithmic (or other approximate) curve for dimming? Is this even a problem on other LEDs?

I have done a port of cyz_rgb firmware to the MaxM though I have not yet burned it to test. I'm trying to understand more about how the PWM is implemented and might be changed to work better before I begin testing with hardware.

I'm thinking we might not be able to get to 4096 steps of PWM without flickering unless we significantly bump the ATTINY44's clock using an external oscillator. I'm not this deep into the hardware yet --

Thanks for any ideas.
 
indifferent I’m thinking
Inappropriate?
1 person likes this idea

  • John Laur
    Inappropriate?
    I tested my port or cyz_rgb to the MaxM hardware yesterday and fixed a couple of outstanding bugs as well. Marcello Caprari was nice enough to add me as a committer, so the changes are now in SVN on google code.

    Unfortunately, I left my AVR programmer attached overnight and I think I damaged the internal logic on the reset pin of my MaxM hardware, so I am out of commission until I can get another MaxM or swap the mcu on the one I have.

    The cyz_rgb firmware performs PWM using an entirely software driven approach as has to be done on the ATTiny45. Looking at the MaxM design, it's evident that all the LED pins support hardware PWM and the official BlinkM firmware is probably using that (and getting some code size savings too). But only 1 of these pins supports 16 bit PWM, so we're still kind of stuck if we want to support smooth logarithmic (or approximately logarithmic) dimming curves which from what I understand will require at least 12 bit PWM to look right at low power levels.

    I have found an idea for a hybrid approach which can create (with some minor limitations)16 bit PWM output using the 8 bit hardware timer to call the nearest interrupt and the 16 bit timer to delay the pin switch, but the concept example is in assembly, and I'm still having trouble fully understanding it. It also may interfere with I2C; don't know yet --- If anyone has the ability to describe what's going on here in plainer terms (or C), I'd be interested in any help: http://stonestreem.com/interrupt-driv...
  • Inappropriate?
    Hi John,

    You are correct, the standard BlinkM firmware uses 3-channel software 8-bit PWM. The MaxM does its PWM in hardware, but it too is limited to 8-bit.

    I've been working on an update to the BlinkM firmware to make it 9-bit and include an 8-bit to 9-bit lookup table to produce slightly smoother fade curves. This would only work on the BlinkM though, not the MaxM, as the MaxM's ATtiny44 doesn't have the PLL that allows it to run at 16MHz instead of 8MHz.

    Thank you very much for the 16-bit PWM link. I'm going over it now and creating some software test fixtures as prep to see if it can be fit into the BlinkM firmware. Your input is greatly appreciated too. If you'd like some additional BlinkMs and/or MaxMs to experiment on, please contact me at blinkm @ thingm.com and I'll get you sorted.

    (What kind of AVR programmer do you use that can nuke an AVR chip?)
     
    happy I’m hopeful this will mean better blinkms
  • John Laur
    Inappropriate?
    Tod,

    I repaired the MaxM board I have with a new attiny44, so I am back in business for now, but thank you for the offer; I'll contact you via email about it.

    As far as progress goes, I have gotten 3 channel 16 bit PWM with logarithmic response working on the MaxM using some test code. After painfully going through the ASM, I've reimplemented the idea from the link above in C; it's not quite as efficient but it works OK; the 8 bit overflow ISR takes a maximum of 45 clock cycles, but in 99%+ cases executes in about 25 cycles. Due to an ATTINY44 hardware problem, It took me a while to figure out I had to use inverted PWM to get the LED's to the very very low duty cycle needed using the 8 bit timers, but after that it's all working great.

    My test code isn't integrated with cyz_rgb yet so I am unsure if the way I am using timers interferes with the operation of USI. Also, due to the size of my 512 byte lookup table, I don't know if I will be able to cram it all into 4k after integrating this design into cyz_rgb. I am about to try it out though! I havent worked very hard to reduce the code size yet, so I'm hopeful it will be OK.

    I use the "official" AVR ISP mkII. It was plugged in and running when I left for the evening and dead when I came back the next morning. I had heard somewhere not to leave that programmer attached when relying on the internal RESET pull-up, but it's obvious that a great number of things could have happened to cause this problem.
User_default_medium