PWM dithering TI's "ES PWM" - Page 1
Forum section: electronics / general

author: Buriedcode
author_rank: Super Contributor
timestamp: October 01, 2018, 08:25:47 pm
content: Hi,For a while now I've wanted to make a nice mood lamp. Either monochrome, or RGB, static brightness, orveryslow fades. Years ago I did some tests with LED's, and for most things I switched over to the addressable LED's (WS2128B, SK6812 etc..) because they are so cheap and easy to work with. However, for monochrome or very slow smooth fades, 8-bit just doesn't cut it.With the availability of multichannel PWM chips like the TLC5949, for one-off's it probably isn't worth rolling my own, but I'm curious if anyone has tried to improve single channel PWM control for lights with an MCU? By "improve" I mean >8-bits (gamma corrected 12-bit) and less flicker (<1ms off time). I've known about the so-called scrambled PWM (dithering) for years but never tried to implement it in an MCU using its hardware PWM module. Wondering if anyone has done this, or whether I should just try it myself, post results and code?I have noticed "flicker" even when the PWM period is under 2ms - mostly on the very low duty cycles where the off-time is the largest. There have been several threads about this, and there are a whole host of factors that go into how obvious so-called "flicker" is, I am not trying to start another one of those threads. Just asking about scrambled/dithered PWM and if anyone has used it. I'm not trying to re-invent the wheel here, there are plenty off-the-shelf solutions, as well as using fast (48MHz) clocked MUC's to speed up the PWM and/or increase resolution, both are valid solutions, but for curiosity, I wonder what other methods there are?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: October 01, 2018, 09:10:41 pm
content: It's pretty easy to do - all you need to do is change the lowest bit of the PWM every cycle.A simple way to do this is to have an accumulator for the sub-PWM fraction - add the fractional PWM value and if there is a carry, add one to the hardware PWM value.e.g. for 0.5 (128/256), you increase hardware PWM value every other cycle, for 0.25 (64/256) you increment every 4th cycle.i.e. with target PWM in phi,ploOn every PWM cycle :pacc=pacc+ploif(carry) PWM=phi +1 else PWM=phiIf you're not too pushed for cycles, you can also do binary code modulation instead of PWM, which gives you as many bits resolution you need, and is useful for larger numbers of channels.16 bits is probably unrealistic for 8 bit hardware, but you should be able to get the 12ish bits you need to do smooth gamma-corrected fades with minimal ripple.

author: ajb
author_rank: Super Contributor
timestamp: October 02, 2018, 02:51:15 am
content: Eh, these days it's pretty easy to find cheap tiny MCUs with two or three 4-channel 16-bit timers, and clock frequencies to high enough to give decent PWM frequencies at full resolution. Some of them even support dithering or other advanced features in hardware, or you can hook up dma and do whatever you want. How many channels are you after?

author: eliocor
author_rank: Unknown
timestamp: October 02, 2018, 03:29:41 am
content: You can use the PCA9685:https://www.nxp.com/products/analog/interfaces/ic-bus/ic-led-controllers/16-channel-12-bit-pwm-fm-plus-ic-bus-led-controller:PCA9685https://cdn-shop.adafruit.com/datasheets/PCA9685.pdfrather easy to use it.Some other links which can be of interest to you:https://jared.geek.nz/2013/feb/linear-led-pwmhttps://web.archive.org/web/20150718062227/https://home.comcast.net/~NikonD70/GeneralTopics/Exposure/Psychometric_Lightness_and_Gamma.htm

author: Buriedcode
author_rank: Super Contributor
timestamp: October 02, 2018, 05:19:11 pm
content: Thanks for the replies!As I said, there is no shortage of relatively cheap devices to do this - I had noticed the PCA96 series lin, but thought they were for slower PWM (servos). TI has many options.I'm actually only after 1 -3 channels, and I'm going to order a TLC5940 (stock 12-bit) and hopefully if I can source one a TLC5948 (with the newer "ES" PWM) for comparison. As I said, this is partly because I want a nice smooth fade for a single lamp (which could be the only light source in the room, which means flicker can be more noticable) and partly out of interest as to what "looks" good. On top of this I have some PIC12F1572's I got for this very task a couple of years ago - I'll try the ES/spread algorithm with one LED, and stock 12-bit on the other. The PIC is fast enough to do 12-bit PWM at ~2kHz, so I can play about with the master clock and compare which has more/less flicker.Mike, I was kind of hoping you'd chime in, after seeing your video on "driving LED matrix displays with an FPGA"which provided foods for thought(binary modulation for one). I'm not sure I follow your pseudo code. I was initially going to do something like the following:-Group 16 8-bit PWM periods to give effectively 12-bit PWM over a "super period". Using 8-bits is easier for data alignment whilst still keeping this relatively fast.-Use a 16-bit 16 entry lookup table that has bit patterns for incrementing each of the 16 PWM duty cycles.-Get PWM value (12-bit), divide by 16 (actually shift right 4 times) to get the base duty cycle value for each of the 16 PWM periods.-Get the remainder (just the lower 4-bits of our 12-bit value) and..-Use the above 4-bit value and the lookup table to get a 16-bit pattern, cycle through each duty cycle, and increment based on the lookup table pattern.This seems like a lot of work just to update a duty cycle value for PWM, but it'll actually be pretty quick, and given that a PWM "super period" will be 16x 8-bit periods, one can easily update faster than the whole PWM period. Even then because this is for slow fades I will not be drastically changing the brightness regularly so whilst the PWM clock should be quite fast, in terms of software, doesn't have to be fast at all. The only thing that may be slow is squaring for gamma correction - but most of the devices I use these days have at the very least a 8x8 hardware multiplier.It seems you're doing something quite similar but "on the fly", that is, adding 1 to each PWM period within the super-period, as and when it is required. Again using the upper 8-bits as the base PWM value, and the lower 4 to for the accumulator? Which seems way easier and spreads out the algorithm across the whole PWM period (much better for all interrupt driven implementation). Is this right?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: October 02, 2018, 05:49:43 pm
content: BCM isn't so useful if you only have a few channels, but it scales much better as channel count increases.One thing to consider if driving larger LEDs is how quickly they can turn on & off - if it's being driven by a buck or boost converter, then the conversion frequency can be a limiting factor, in particular the shotest turn-on time, more so if it's not synchronised to the PWM.PWM will generelly better here as BCM relies on being able to accurately do short pulses, whereas any turn-on delay with PWM just offsets the scaling slightly

author: Buriedcode
author_rank: Super Contributor
timestamp: October 04, 2018, 03:56:36 pm
content: As you could probably tell from my post I was grossly over thinking things.The simple way - as mike alluded to - is to spread the remainder bits across all the PWM periods, one at a time. So if we want 12-bit PWM, using 16 blocks of 8-bit PWM, the upper 8-bits are the base value, and the 4-bit remainder determines which periods have an extra bit in their duty.Eg: 12-bit PWM value - 589. base value = 589/16 = 36. Remainder = 589 & 0x0F = 13. The first 13 PWM periods will have an extra 1 in their duty cycle eg: 37 instead of 36.This is nice and simple but it has onevery minordrawback. For very low duty cycles where the base value is 0 (in this case, duty < 16), we can still have long periods with no output. Obviously a duty value of '1' has the longest off-time. But 2,3,4,5 etc.. will reduce this off time by one PWM period each. Whilst it's probably over kill just for the case of duty values 2-12, I used a table that adds the extra duty cycle bits in a specific order to reduce the maximum off-time. So the second is added for the 9th period, then 5th, then 13th etc.This extra step requires a 16-bit 16 entry look up table and setup every time the PWM is changed, and I'm not sure if its really worth it just for the special case of duty values 2-10 (out of 12-bit PWM!). Without this it just requires a few lines of code in the PWM period interrupt that uses a counter and checks whether or not to increment the duty for that PWM period.I'll have to compare the two but I can't see it making a noticeable difference. Even with a high speed clock (32MHz for the PIC) a very low duty of <16 is going to be very dim, and will still probably have some kind of flicker for high resolution (12-16 bit) regardless of any clever tricks. It's also unlikely that such a low duty cycle will be used in a lamp, but I thought I might as well add to the thread.

author: xani
author_rank: Frequent Contributor
timestamp: October 11, 2018, 01:49:54 pm
content: Two ideas:Just slap a fat RC filter on itUse another PWM (or DAC if micro has it) to regulate the current source for LEDs. That would effectively add a "brightness" setting to the LED so you could go way lower with brightness overall without getiing problems with low duty cycle

author: Buriedcode
author_rank: Super Contributor
timestamp: October 11, 2018, 05:53:20 pm
content: Quote from: xani on October 11, 2018, 01:49:54 pmThe second one is often used by these multichannel drivers, usually 3-4 bit resolution used for dot correction. Its very handy. But I wouldn't really put a filter on the output as that cancels out the benefits of PWM for brightness control. There are many ways to do this. Yet another is to just use the 8-bit PWM gating a faster 4-bit PWM. Given that the 4-bit PWM will be 16 times faster you're just double modulating, and since many micro's have multiple PWM timers these days, it costs nothing. But for 3-channel, that requires 6 PWM channels - many micro's have that but most do not.I managed to get a very crude test set up. As expected, with extremely low PWM values there isn't much of a difference between 12-bit PWM @ 2kHz and "scrambled" (I still haven't seen a decent name for it yet) using 16 groups of 8-bit, because the off-time will be the same for both types. That is with duty of 1 or 2 (out of 4095), violently shaking the breadboard with the LED lit I can still see the on/off periods - not when turning my head though, which is important. But at > 12 the "scrambled" LED just appears static, whilst at the same brightness as the stock PWM.This is using a PIC12F1572, two PWM channels, running at 8MHz - it can run up to 32MHz from the internal osc so one could just increase the frequency, but it was just used for testing. Plus if people wanted to use say, an Arduino pro micro, or 3.3V Arduino running at 8MHz then this can give them 12-bit PWM without any noticeable flicker. I think this kind of modulations is pretty much required for 16-bit PWM, which at 32MHz clock would run at ~488Hz. Using the above method it would be 16 times faster @ 7.8kHz.So yeah, not the best test, but for an extra few lines of code in an interrupt its actually pretty good. Next test would be low duty values, with a brighter (3W) LED as the only light-source in a dark room - that is when flicker is most noticeable/annoying.