maxint-rd / FastPwmPin

Arduino library to generate a fast PWM signal on an output pin at maximum frequency. Example included.
40 stars 14 forks source link

Attiny45 optimization #5

Closed shaddyx closed 3 years ago

shaddyx commented 3 years ago

just a simple operations swap saves ~ 800 bytes on attiny45 due to avoiding floating-point operations // Please note: I did not change this for other controllers

maxint-rd commented 3 years ago

Hello @shaddyx , Thank you for your contribution. In my latest update to fix a resolution issue, I obviously didn't look at memory usage and blindly followed the suggested floating point calculation. As soon as I can find some time I will test and integrate your changes and also apply them to the code specific to other processors.

shaddyx commented 3 years ago

just FYI, I just added the same commit here with the same changes for attiny13 as well

shaddyx commented 3 years ago

just realized that low values of OCR0A will cause a resolution issue as well, to fix this we could do the fixed point operations like long res = (OCR0A + 1) percentage 1000L / (100 - 1) / 1000; will test and re-create the pull request

maxint-rd commented 3 years ago

Hi @shaddyx , thank you for helping out. Unfortunately I have some other responsibilities taking priority, so I appreciate you spending the time to find the best suited fix. The resolution issue in previous versions occured due to integer divisions, causing PWM percentages like 60% to be rounded to 50%.

That percentage doesn't need to be exactly right down to the umpteenth decimal, one percentage point is probably fine. As long as we don't get these use roundings that were present previously. I thought this could be resolved by swapping some things around and can imagine that using long ints for intermediate calculations may suffice to provide the required resolution. I think your proposal to multiply by 1000 could work fine, so please go ahead.

When I find time, I will review the code, test it and make sure that both flash size and ram usage are all within normal bounds. I will test using ATtiny13A MCUs, so available resources are quite limited. When incorporating the float division I unfortunately didn't test for impact on flash size, so I consider that a lesson learned.

Thanks again!

maxint-rd commented 3 years ago

Hi @shaddyx , today I did some testing on an ATtiny44A. I tested using 16-bit Timer 1 on pin 5 and used a logic analyzer to verify the generated signal. Initially I saw that the floating point usage increased flash usage by 750 bytes.

Based on your suggestion I used this code to use integer calculations:

    unsigned long ulPercentage=(nPeriodPercentage>50?(100-nPeriodPercentage):nPeriodPercentage);
    unsigned long ulResult = ((OCR1A + 1) * ulPercentage * 10L ) / 1000L -1;
    OCR1B=ulResult;

I tested this code for resolution accuracy at 50%, 90%, 10%, 60% and 40% PWM at various frequencies. Note that I simplified the 1000/100 and that the -1 needs to be at the end, after the final division. After compiling the optimizer managed to use 38 bytes less flash than the previous (integer based) version, possibly at the expense of a slight temporary increase of stack usage during the calculation for the extra local variable. I also tested without additional local variables. Using a local variables apparently gives smaller code after optimization.

I still need to test on ATtiny13A and update the code for other MCU's, but thought you might be interested to read my findings.