Open per1234 opened 8 years ago
arduino is a 8bit mcu, if we try to use more than 8bit to store pwm levels, we have to do uint16_t arithmetic, that's like 2 times slower. http://www.avrfreaks.net/forum/multiply-divide-add-performance-various-data-types
the "timer frequency" is calculated as number of brightness levels * pwm frequency
, for example, 256 levels * 60hz = 15360hz
(60hz is an ideal pwm frequency to NOT cause visual flicker), on a 16Mhz mcu we have 16Mhz / 15.36Khz = 1041.66 cycles
to finish the task.
each channel takes 4 instructions, plus some overhead (around 10 instructions), if we're targeting 16 channels it's 16 * 4 + 10 = 74 instructions
to be executed every 1041.66 cycles, yields a cpu load of ~7.1%
.
and say, we now want 512 levels, 512 levels * 60hz = 30720hz
, around 16Mhz / 30.72Khz = 520.83 cycles
to complete each timer isr.
and the timer ISR now take 16 * 8 + 20 = 148 instructions
due to uint16_t arithmetic (512 can't be stored in a uint8_t), the cpu load is now 148 / 520.83 ~= 28.4%
.
even if we still do 256 levels but store the levels in a uint16_t, the isr load is bumped by a factor of 2.
so ~14%
cpu load.
well if we can make c++ automatically select optimal storage type for levels we may be able to achieve this without sacrificing performance, however I don't know how......
Thanks for the information! I was thinking of using preprocessor directive to switch the support for >256 PWM levels so the performance hit would only be incurred if the feature is needed. I do think 256 levels is sufficient for most applications. I've made some attempts at this but haven't been successful yet. It sounds like you're saying it is actually possible to accomplish this(at a cost) so that's good to know. I've managed to get around the issue by never fully turning the LEDs off but it was previously enough of a problem that I thought it worth considering adding this functionality.
i was thinking about something like
template<int levels> class levelsToType { public: typedef uint16_t levels_t; };
template< > class levelsToType<0> { }; // let it fail, we can't have 0 level...
template< > class levelsToType<1> { }; // let it fail, we can't have only 1 level...
template< > class levelsToType<2> { public: typedef uint8_t levels_t; };
template< > class levelsToType<3> { public: typedef uint8_t levels_t; };
...
template< > class levelsToType<254> { public: typedef uint8_t levels_t; };
template< > class levelsToType<255> { public: typedef uint8_t levels_t; };
and use levelsToType<pwm_levels>::levels_t _levels;
when defining the variable.
maybe something like this... http://ideone.com/lllWv9
for 256 levels we have to use uint16_t... because we do digitalWrite<PIN>((_current_level < _user_level) ? HIGH : LOW);
@Palatis I really appreciate you giving me this information! Now that I know this is possible and you have pointed me in the right direction I'm sure I can achieve my goal. This is a bit above my current programming skills so it will take me a little while to get there but it will also provide an opportunity to learn new things in the process.
this paradigm is called c++ template meta-programming.
this whole softpwm library wouldn't be possible without it.
When using this library with LEDs there is a large difference between PWM levels at low brightness so the option of more PWM levels than 256 would be useful.