/// fastMax - how many fast PWM steps to do in RISE and FALL states
/// 16 is a good compromise between silenced bed ("smooth" edges)
/// and not burning the switching MOSFET
staticconstuint8_tfastMax=16;
/// Scaler 16->256 for fast PWM
staticconstuint8_tfastShift=4;
/// Increment slow PWM counter by slowInc every ZERO or ONE state
/// This allows for fine-tuning the basic PWM switching frequency
/// A possible further optimization - use a 64 prescaler (instead of 8)
/// increment slowCounter by 1
/// but use less bits of soft PWM - something like soft_pwm_bed >> 2
/// that may further reduce the CPU cycles required by the bed heating automaton
/// Due to the nature of bed heating the reduced PID precision may not be a major issue, however doing 8x less ISR(timer0_ovf) may significantly improve the performance
pwm=soft_pwm_bed<<1;// expecting soft_pwm_bed to be 7bit!
if(pwm!=0){
state=States::ZERO;// do nothing, let it tick once again after the 30Hz period
}
break;
caseStates::ZERO:// end of state ZERO - we'll either stay in ZERO or change to RISE
// In any case update our cache of pwm value for the next whole cycle from soft_pwm_bed
slowCounter+=slowInc;// this does software timer_clk/256 or less (depends on slowInc)
if(slowCounter>pwm){
return;
}// otherwise moving towards RISE
state=States::ZERO_TO_RISE;// and finalize the change in a transitional state RISE0
break;
// even though it may look like the ZERO state may be glued together with the ZERO_TO_RISE, don't do it
// the timer must tick once more in order to get rid of occasional output pin toggles.
caseStates::ZERO_TO_RISE:// special state for handling transition between prescalers and switching inverted->non-inverted fast-PWM without toggling the output pin.
// It must be done in consequent steps, otherwise the pin will get flipped up and down during one PWM cycle.
// Also beware of the correct sequence of the following timer control registers initialization - it really matters!
state=States::RISE;// prepare for standard RISE cycles
fastCounter=fastMax-1;// we'll do 16-1 cycles of RISE
TCNT0=255;// force overflow on the next clock cycle
TCCR0B=(1<<CS00);// change prescaler to 1, i.e. 62.5kHz
TCCR0A&=~(1<<COM0B0);// Clear OC0B on Compare Match, set OC0B at BOTTOM (non-inverting mode)
break;
caseStates::RISE:
OCR0B=(fastMax-fastCounter)<<fastShift;
if(fastCounter){
--fastCounter;
}else{// end of RISE cycles, changing into state ONE
state=States::RISE_TO_ONE;
OCR0B=255;// full duty
TCNT0=254;// make the timer overflow in the next cycle
// @@TODO these constants are still subject to investigation
}
break;
caseStates::RISE_TO_ONE:
state=States::ONE;
OCR0B=255;// full duty
TCNT0=255;// make the timer overflow in the next cycle
TCCR0B=(1<<CS01);// change prescaler to 8, i.e. 7.8kHz
break;
caseStates::ONE:// state ONE - we'll either stay in ONE or change to FALL
OCR0B=255;
slowCounter+=slowInc;// this does software timer_clk/256 or less