Suppose I should post some code since I spent way too much time banging my head against it all.

If you look around for HSL/HSV to RGB code, you'll probably find nothing but floating point implementations. Modern micros such as an AVR seems to be plenty fast enough to pull this off in float, but as an obsessive optimizer I gotta have me some fixed point...
I messed around with HSL, I could not find a fixed point implementation so I tried converting a float implementation to fixed point myself, with no success. So I looked at HSV instead, which looked much simpler, and with some digging found some fixed point implementations, that were written for 32bit machines and did not work on an 8bit micro. The compiler on a 32bit architecture will happily promote everything to 32bit math at the slightest provocation, skirting overflow issues. This does not happen on an 8bit micro, you have to be very careful with your casts. I hid all that ugliness in the multiply macro.
Anyway, here's some code that should work properly on any architecture:
First, 8-bit. This is really raunchy and coarse, and does not cut it for the 10-bit ShiftBrites. But it should be as fast as can be, and may be good enough for something like an
LPD6803, which only do 5-bits per channel, or direct PWM.
// 8 bit integer HSV to RGB
static void HSVtoRGB8(
uint8_t& r,
uint8_t& g,
uint8_t& b,
uint8_t h,
uint8_t s,
uint8_t v
){
if(s==0){
r=g=b=v;
return;
}
uint8_t f = (h%43)*6;
// fixed point multiplication
#define mul8(a,b) ((((uint16_t)a)*((uint16_t)b))>>8)
uint8_t p = mul8(v,255-s);
uint8_t q = mul8(v,255-mul8(s,f));
uint8_t t = mul8(v,255-mul8(s,255-f));
switch(h/43){
case 0: r=v; g=t; b=p; break;
case 1: r=q; g=v; b=p; break;
case 2: r=p; g=v; b=t; break;
case 3: r=p; g=q; b=v; break;
case 4: r=t; g=p; b=v; break;
default: r=v; g=p; b=q; break;
}
}
And now the 16-bit version. This gives silky smooth fades with the ShiftBrites. (Remember to shift right by 6!) And should be fast as can be on an MSP430, being 16-bit plus the 32-bit multiplier, it was made for 16-bit fixed point! (However I have not confirmed gcc is actually utilizing the MPY...)
static void HSVtoRGB16(
uint16_t& r,
uint16_t& g,
uint16_t& b,
uint16_t h,
uint16_t s,
uint16_t v
){
if(s==0){
r=g=b=v;
return;
}
uint16_t f = (h%10923)*6;
// fixed point multiplication
#define mul16(a,b) ((((uint32_t)a)*((uint32_t)b))>>16)
uint16_t p = mul16(v,65535-s);
uint16_t q = mul16(v,65535-mul16(s,f));
uint16_t t = mul16(v,65535-mul16(s,65535-f));
switch(h/10923){
case 0: r=v; g=t; b=p; break;
case 1: r=q; g=v; b=p; break;
case 2: r=p; g=v; b=t; break;
case 3: r=p; g=q; b=v; break;
case 4: r=t; g=p; b=v; break;
default: r=v; g=p; b=q; break;
}
}
Have fun!
