I was playing around with ATmega88 and trying to control RGB LED light strip with it. I've quickly noticed that 8-bit PWM is not enough for light control: when PWM value is close to zero there are definetely visible steps in brightness as well as the lowest brightness (PWM value 1) is not enough dark.
I had to switch to more precise PWM, but in ATmega88 (and all cheap AVRs) there are only one 16-bit timer but I needed three PWM outputs at least. So I've scratched my head for some time and had came with solution.
I'm using 16-bit timer for timing.
So how it works

: firmware converts linear one-byte brightness values into integers (non-linear), sorts them, puts them into buffer for PWM processor. Then "Match A" interrupt saves the buffered values, turns all non-zero channels on and sets "Match B" interrupt to nearest (lowest) value. Then three (in general case, when all brightnesses are different and not zero) "Match B" interrupts occur one by one, on each one one of channels turns off and OCR1B value sets to next nearest value.
This description seems to be confusing, but this is how it works.
Yes, my algorithm have some limitations: due to not-hardware type of PWM and very long interrupts procedures values must differ more than 20 (in 0...8192 scale). Because of software-processing time lag. This is handled in not time-critical section: if integer value are too close to each other or to zero - they will be equalized or zeroed (and "equal" flags will be set). But it affects final RGB output only on very low brightness.
More detailed description of my algorithm:
1) First I have three one-byte (0...255) numbers: brightness values for RGB channels in some order, let's say "R (CH-1), G (CH-2), B (CH-3)".
2) I convert these one-byte (char) variables with table in flash memory (it is not loaded into RAM) into two-byte (integer) values. Conversion is not linear because of eye response. I choosed 13-bit value limit, this is good enough (8192 top value). Relation between values is in attachment "byte2pwm.png". This is not time-critical part and it runs in main program cycle.
3) Then I sort variables by value and set some flags if needed: "1 and 2 are equal" and "2 and 3 are equal" (this is for faster interrupt processing later).
4) Also I have to store order of channels to not mix them up. For example: R=125, G=0, B=230. Let's say after conversion values are: R=1048, G=0, B=6000. All of them are different, so no "equal" flags are set. After sorting values we have: LOW=0, MIDDLE=1048, HIGH=6000. Now we have to store order of sorted values. And this what it is: LOW=CH-2, MIDDLE=CH-1, HIGH=CH-3.
5) Now this is time critical part. I turn off interrupts and store values into global buffer for PWM processor: three integer values of brightness, three "order" chars and one char with "equal" flags. Then I turn interrupts on again. This is needed because interrupt can occur while not all of these values are stored into buffered variables, but interrupt will save all of them for internal processing while not all of them had been updated.
All these run in main program cycle.
Now, interrupt part.
Timer is set to "Clear on compare" with OCR1A=0x2000 (8192dec) as TOP value. OCR1B initially set to 0xFFFF. AVR core runs at 16 MHz and timer clock is clk/8=2 MHz.
I use two "Timer1 Compare Match" interrupts.
Match A occurs on PWM TOP value and this event turns on all PWM channels (if PWM value is not 0). Match B handles event of counting for next brightness level, switching according channel off and switching to another one OCR value.
What "Match A" handler does:
1) Stores all buffered on step 5 (above) variables into internal ones needed for PWM processing.
2) Checks one by one all brightness levels (from HIGH to LOW) and if they are not zero - set according "turn on" bit in mask and store it brightness level for "Match B" interrupt. Also it stores PWM stage according to last non-zero channel. While going from HIGH to LOW it overwrites previous values exept of mask.
3) Puts minimum found (but not zero) brightness value into OCR1B and switches PWM channels on by calculated mask.
What "Match B" handler does:
1) Resets channels "turn-off" mask.
For stage 1 (timer counted to LOW brightness):
2.1) Set bit for LOW channel in mask.
2.2.a) If "1 and 2 are equal" bit is set - set bit for MIDDLE channel in mask (so they can switch off together).
2.2.a.a) If "2 and 3 are equal" bit is set - set bit for HIGH channel in mask (so all channels can switch off together). Work is done, waiting for "Match A" interrupt.
2.2.a.b) "2 and 3 are equal" bit is not set - set OCR1B to HIGH value and switch to stage #3. Routine is finished.
2.2.b) "1 and 2 are equal" bit is not set - set OCR1B to MIDDLE value and switch to stage #2. Routine is finished.
For stage 2 (timer counted to MIDDLE brightness):
3.1) Set bit for MIDDLE channel in mask.
3.2.a) If "2 and 3 are equal" bit is set - set bit for HIGH channel in mask (so 2 and 3 can switch off together). Work is done, waiting for "Match A" interrupt.
3.2.b) "2 and 3 are equal" bit is not set - set OCR1B to HIGH value and switch to stage #3. Routine is finished.
For stage 3 (timer counted to HIGH brightness):
4) Set bit for HIGH channel in mask.
5) Apply mask to PWM output.
16-bit timer allows me to get more precise low-brightness values and lower minimum brightness (I use only 13 bits because time lag with software processing can't get me even more precise low-brightness steps and lower brightness).
13-bit PWM gets me more natural and soft colors and I can use wider range of them. For example, orange color on RGB strip with 8-bit PWM is pretty difficult task. You have RED on 255, you set GREEN to 1 and it is already yellow-like (also RED is often less bright than GREEN on these light strips). If you want to adjust brightness of this color - you are trapped (one channel is on maximum, other - on minimum).
I have implemented this algorithm, sticked it together with microphone, low-pass filter and yet another non-linear table conversions, and got an music RGB controller:


?? RGB 

?, 
? (10) (wide range brightness changing)


?? RGB 

?, 
? (
(different brightness orange color + white flash)
I don't know, if there are other similar algorithms. But what I got from my head gives me 13-bit 3-channel PWM out of cheap AVR MCU with very little limitations.
