3 channel 10+bit PWM

I am building a controller for RGB LED strip (12V 5m 5050 LED RGB strip with common anode). My current solution uses Arduino Uno with 3x IRFZ44N MOSFETs to power the strip. The solution is partially inspired from this site.

The problem is PWM resolution where 256 levels are not enough to have smooth "true color", especially for lower brightness, because eye's light perception is exponential. There is a way to adjust levels so that brightness would be linear but changes at low light intensity will still be "jumpy".

From what I've read it is possible to use Timer1 to produce 10bit PWM at two pins. Unfortunately I am missing the solution for the third pin.

I've read some articles about TLC5940 but found no good solution for as high current as I need.

Is there any relatively simple solution to have Arduino (or AVR) controlling 10bit (or better 12bit) PWM which I could use it as input to MOSFET transistor to use with 12V and current > 1A?

• Another possibility might be the PCA9685, or somethign similar. It gives you 16 channels of 12bit PWM, frequency up to 1.5kHz, via I2C. – uint128_t Jan 7 '16 at 22:45
• These threads may also be helpful. You can use MOFSETs alongside something like the TLC5940 or TLC59711 for high-current PWM switching. Forum Post and islou's Project Doc – Aaron Schultz Apr 23 '17 at 2:49

If you are flexible, use an Arduino Lenoardo, it has a high resolution timer that can drive 3 pins. 32U4, page 130, 10-bit High Speed Timer/Counter4 EDIT: it seems like analogWrite() doesn't support it

You can mimic 10/12 bit timers with an 8-Bit timer, by skipping cycles. I wouldn't know of a way to do this with the Arduino PWM library (analogWrite()), but if you are willing to handle timer interrupts, it becomes feasible.

• Arduino Leonardo is much more expensive comparing to Arduino Nano (on eBay) and also it is of a bigger size. There are smaller alternatives for a breakout board for ATmega32u4, but all I found are more expensive. Regarding mimicking, could you please send me a link to some article explaining it? Thanks. – Martin Ždila Feb 12 '15 at 7:54
• I'v found Leonardo Pro Micro and it is not that much expensive :-) – Martin Ždila Feb 13 '15 at 19:25

If all you're doing is multi-channel PWM + communications, you can probably bit-bang it using interrupts while the main loop does the comms.

Set up a Timer interrupt to happen at [PWM Freq. * Resolution], and inside of that, increment a ramp variable and compare it to each of the desired channels. If less, turn it on; else, turn it off. Don't forget to reset the ramp at your max value, if not using the full range allowed by the datatype.

Or, another way to do it, which might speed it up slightly for a lot of channels, is to have the main loop maintain an array of port values according to the commanded PWM value for each channel/pin. The interrupt then, simply steps through the array using the ramp variable as the index.

For example of how fast the interrupt needs to be, 50Hz PWM * 10-bit resolution = 50Hz * 1024 = 51200Hz. In that case, your timer interrupt needs to fire at 51.2kHz, and the code needs to finish in time for the next one, minus a small amount for the main loop to squeeze into.

• I'll try this solution in couple of days and will report here how does it work (+ rating). Thanks. – Martin Ždila Feb 12 '15 at 7:43
• Tried the solution, it works, but for 10bit I can only have PWM frequency max cca 150Hz which is too low for the ergonomic lighting of dark room I desire. – Martin Ždila Feb 13 '15 at 18:50
• 150 too low? Physiologically, you shouldn't be able to see anything more than 30 except for a strobe effect on things moving. What are you actually doing? – AaronD Feb 13 '15 at 20:58
• Aside from a different chip, I think the best solution to reduce the strobe effect is to keep the bit-banged timer interrupt, running as fast as you can get it, and add a lowpass in hardware. Look at the output filter of a class-D audio amp for inspiration. – AaronD Feb 13 '15 at 21:04
• Of course I don't see 150Hz, but it makes the eyes tired simmilar as neon lighting. Lowpass filter would destroy the linearity and the color RGB component matching would be harder to do to compute a color. Or I am not that experienced yet. – Martin Ždila Feb 14 '15 at 6:52

My solution uses Arduino Pro Micro and the linked code. Arduino API doesn't support other than 8-bit analogWrite for Pro Micro. Therefore I am manupulating the registers directly. The code controlls 3x 16bit PWM outputs. Relevant functions from the referred code are setup and applyRgb. The code also contains simple transformation to non-linear human eye light preception.

PS: I'll add README.md there soon.