On Sat, 8 Feb 2003, Josh Koffman wrote: > Hi all. I've been playing around with software PWM controlling some > LEDs. Problem is, as the eye's response to brightness isn't linear, when > I simply control the LEDs brightness using an 8 bit value (with no > compensation) they don't appear to dim smoothly. So my thought was to > take the 8 bit value, use it as an index into a lookup table which would > give me a higher bit value (ie a 12 or 14 bit). > > Here is the problem (as I see it anyways). If I increase the bit > resolution of my PWM, the frequency will have to go down (as the PIC is > already running at full speed. yes, I could go to an SX chip...I know). > So, is there a resolution vs speed balance that anyone has reached that > gives optimal frequency and smoothness of the dimming? Also, how do you > choose the values for the lookup table? Most commercial theatrical > dimmers use a "modified S curve" which is essentially the integral of > the area under a sine wave (I think). I'm sure if I had Maple or > something (and knew how to use it) I could divide the area into 256 > sections and come up with the proper values for the lookup table. But > since I don't have access to this high powered math software, what are > my options? Plotting out by hand seems only an invitation for > frustration. > > Ideas welcome. Well, if you're using a software PWM then a really simple solution may be to just let the time base be logarithmic. For example, suppose you had a PWM with 8 levels. Normally, the time step is constant so that a pulse of 4 units, is on exactly twice as long as a pulse of 2 units. In terms of a time line: Start V V +---+---+---+---+---+---+---+---+---+---+---+ 0 1 2 3 4 5 6 7 0 1 2 3 At the 0's the PWM turns on and at the 1-7 steps it turns off. Now, suppose you made the time step like so: ++-+--+---+------+---------+--------------+---------------------++-+ 01 2 3 4 5 6 7 01 2 So now, a pulse 4 units wide takes more than twice the time of a pulse 2 units wide. The difficult part here will be to perform the non-linear time stepping. There are several ways to go about doing this, but they depend on the particulars of your system. Note that this really is the same thing that you're suggesting; I've only partioned the time differently. In your case, you're suggesting that the dynamic range of the PWM duty cycle be increased. In my case, I'm suggesting that the dynamic range is kept the same, but the time base adjusted. If you're using my software PWM (number of cycles = 7 + 2*Number PWM outputs or 23 for 8 outputs), then the first few iterations could be run back to back while the latter ones interrupt driven. You're still going to want the roll over rate to be large enough so that there's no perceivable flicker. Another possibility is to consider a Pulse-Modulation scheme based on phase accumulators. It gives you a non linear output that may be suitable. For example: phase_step = some number --- controls the output level phase_accumulator --- accumulates phase, i.e. an integrator The algorithm is simple: phase_accumulator = phase_accumulator + phase_step if phase_accumulator rolls over, then set the output. In PIC assembly, it'd look something like this: DECFSZ MainCounter,F goto update_pulses CLRF PWM_port update_pulses: MOVF phStep0,W ADDWF phAccum0,F RLF Rollovers,F MOVF phStep1,W ADDWF phAccum1,F RLF Rollovers,F ... MOVF phStep7,W ADDWF phAccum7,F RLF Rollovers,W ; the last shift goes into W IORWF PWM_port,W That's 28 cycles instead of 23, but look closely how it works. The rollover bit is simply the carry from the addition to the phase accumulator. If you wrote the rollover bit to an I/O pin, it would look almost like a square wave DDS. In other words, if phStep = 1, then the rollover rate would be 256 iterations and the frequency would be 512 iterations. If phStep = 2, then the rollover is 128 and the frequency is 256. It's twice as fast. If phStep is 3, then the rollover is in about 85 iterations (256/3) and the frequency is about 512/3 iterations. In general, the rollover rate is 256/N iterations and the frequency is 512/N. However, notice that the above code *does not* toggle the output at every rollover. Instead, it latches the rollover. In effect, the pulse outputs are just the first cycle of the DDS frequency. pwStep pulse width out ----------------------- 1 256/1 = 256 2 256/2 = 128 3 256/3 = 85 4 256/4 = 64 5 256/5 = 51 ... 128 256/128 = 2 129 256/129 = 1 ... 255 255/255 = 1 In other words, the output pulse is inversely proportional to the pwStep. Also note that there are way fewer than 256 steps. OTOH, it's computationally simple. You can also do a few tricks to sustain a constant output, (either on or off). Also, the IORWF can be changed to ANDWF to invert the polarity of the drive (and the outputs would all have to be set instead of cleared when the main counter rolls over). Scott -- http://www.piclist.com hint: The PICList is archived three different ways. See http://www.piclist.com/#archives for details.