This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR5969: Efficient duty cycle calculation?

Part Number: MSP430FR5969

Calculating a duty cycle for PWM decoding requires the nasty division. 

DutyCycle = ((unsigned long)ON_Period*100/Period); 

This will defilitely work (as long as DutyCycle is USHORT anyways) but it takes around 500 cycles to resolve. After some googling there's hardly a shortage of integer division algorithms, texas presents 32/16 division assembler code in SLAA024 and the same long division algorithm is in many other places. That takes round about 230 cycles. There are also approximation divisions which seem fair bit more clever but I'm not sure how well they'd work with MSP430. 

Now since neither nominator nor denominator is constant we can't use most of the fast division methods. We *do* know that the result is between 1 and 99 which should be helpful. 

Short of reinventing the wheel, is there a fast algorithm to do this specific job someone has worked out to perfection a decade ago already?

  • Is Period a constant? i.e., do you know it ahead of time? If so you can create a lookup table.
  • I guess just doing something not-very-clever like multiplying the denominator by 16, 32, 48, 64 and 80 and doing comparisons plus followed by a looping decrement + compare if you get < result would give you reasonable performance..

    Accessing MPY directly lets you do 24/8 multiplication that results in a more manageable 32bit figures too.
  • I did point out the denominator is not constant. It's whatever the device supplying the PWM will use. We can define limits but that's about it. Practically something like 120Hz to 480Hz for example. Theoretically in screen refresh rate multiples but you can't know even that.
  • And I pointed out that constant means known ahead of time. You can just recalculate the lookup table based on the duty cycle, or have numerous look tables and use interpolation.

    Or have a lookup table of all the possible 100/period values.

  • How are you determining the on time? If you are using a timer, scale the timer value so that the result is the duty cycle directly. In other words, 100 ticks per period.

  • That's actually a pretty good idea. As I said in OP, I'm sure someone has worked out a good way to do this with no need to reinvent the wheel or use nasty math. PWM period should stay constant (but not known in advance) but never the less I can re-sample it something like once a second anyways. I already have 250ns high speed timer I use for performance metrics so measuring that PWM period is easy peasy. 

    Ideally that should be perhaps adjusted to 320 as my full current output is 320mA. But I guess for this a lookup table is the correct answer as the LED current response is not linear and I have a feeling without looking at the code that calculating the current value needs another division.. 

  • "All possible values" would be be the given range with perhaps 2Hz step to keep error within 1-2%.. Not very practical. You could try to minimize the lookup table to allow using 2x 4x values but still..
  • Well, nice idea in theory but you cannot arbitrarily set the timer tick. With 1MHz SMCLK I could have 64µs timer tick max. 100x that would be 6.4ms or 156.25Hz. The next step is divided by 56 which would be 5.6ms and 178.57Hz. That's just too coarse adjustment I'm afraid. SMCLK is used for other things as well so messing with it is not really an option, in fact it's set to 4MHz to allow 4MHz SPI operation.

    I guess I just need to go with my idea of using the 32x32 MPY to generate intermediate values for looping comparison.. Some assembly required! Heck, as long as dynamic backlight is not required I don't need to sample the PWM every frame anyways.

    ..

    Another way of attacking the problem would be to precalculate the lookup table once you've sampled the PWM frequency. One nasty divide-by-100 and then just keep adding the result to itself to generate the lookup table. Possibly go with two lookup tables so you can divide (shift) by 128 and then have another table with output current values in 128 steps. 

    ..

    Yet another idea would be to just do divisor*16 once after which you can do additions to generate the intermediate values (32, 48, 64, 80) for looping comparison approach. 

**Attention** This is a public forum