From 2ea34d21e755c942d5e38a9ac1f8e3aaa7724271 Mon Sep 17 00:00:00 2001 From: PavelSindler <pavel@prusa3d.cz> Date: Mon, 28 Jan 2019 14:20:31 +0100 Subject: [PATCH] Revert "Revert "Mk3 bed fast pwm"" --- Firmware/temperature.cpp | 37 +++++++++++--- Firmware/temperature.h | 4 +- Firmware/timer02.c | 103 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 Firmware/timer02.c diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index eb29b810..ddffcfac 100644 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -45,6 +45,12 @@ #include "Configuration_prusa.h" +extern "C" { +extern void timer02_init(void); +extern void timer02_set_pwm0(uint8_t pwm0); +} + + //=========================================================================== //=============================public variables============================ //=========================================================================== @@ -257,6 +263,7 @@ static void temp_runaway_stop(bool isPreheat, bool isBed); if (extruder<0) { soft_pwm_bed = (MAX_BED_POWER)/2; + timer02_set_pwm0(soft_pwm_bed << 1); bias = d = (MAX_BED_POWER)/2; } else @@ -293,7 +300,10 @@ static void temp_runaway_stop(bool isPreheat, bool isBed); if(millis() - t2 > 5000) { heating=false; if (extruder<0) + { soft_pwm_bed = (bias - d) >> 1; + timer02_set_pwm0(soft_pwm_bed << 1); + } else soft_pwm[extruder] = (bias - d) >> 1; t1=millis(); @@ -347,7 +357,10 @@ static void temp_runaway_stop(bool isPreheat, bool isBed); } } if (extruder<0) + { soft_pwm_bed = (bias + d) >> 1; + timer02_set_pwm0(soft_pwm_bed << 1); + } else soft_pwm[extruder] = (bias + d) >> 1; pid_cycle++; @@ -781,9 +794,11 @@ void manage_heater() if(current_temperature_bed < BED_MAXTEMP) { soft_pwm_bed = (int)pid_output >> 1; + timer02_set_pwm0(soft_pwm_bed << 1); } else { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); } #elif !defined(BED_LIMIT_SWITCHING) @@ -793,15 +808,18 @@ void manage_heater() if(current_temperature_bed >= target_temperature_bed) { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); } else { soft_pwm_bed = MAX_BED_POWER>>1; + timer02_set_pwm0(soft_pwm_bed << 1); } } else { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); WRITE(HEATER_BED_PIN,LOW); } #else //#ifdef BED_LIMIT_SWITCHING @@ -811,15 +829,18 @@ void manage_heater() if(current_temperature_bed > target_temperature_bed + BED_HYSTERESIS) { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); } else if(current_temperature_bed <= target_temperature_bed - BED_HYSTERESIS) { soft_pwm_bed = MAX_BED_POWER>>1; + timer02_set_pwm0(soft_pwm_bed << 1); } } else { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); WRITE(HEATER_BED_PIN,LOW); } #endif @@ -996,7 +1017,6 @@ static void updateTemperaturesFromRawValues() CRITICAL_SECTION_END; } - void tp_init() { #if MB(RUMBA) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1)) @@ -1063,10 +1083,12 @@ void tp_init() adc_init(); + timer02_init(); + // Use timer0 for temperature measurement // Interleave temperature interrupt with millies interrupt - OCR0B = 128; - TIMSK0 |= (1<<OCIE0B); + OCR2B = 128; + TIMSK2 |= (1<<OCIE2B); // Wait for temperature measurement to settle delay(250); @@ -1374,6 +1396,7 @@ void disable_heater() #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 target_temperature_bed=0; soft_pwm_bed=0; + timer02_set_pwm0(soft_pwm_bed << 1); #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 WRITE(HEATER_BED_PIN,LOW); #endif @@ -1538,8 +1561,8 @@ void adc_ready(void) //callback from adc when sampling finished } // extern "C" -// Timer 0 is shared with millies -ISR(TIMER0_COMPB_vect) // @ 1kHz ~ 1ms +// Timer2 (originaly timer0) is shared with millies +ISR(TIMER2_COMPB_vect) { static bool _lock = false; if (_lock) return; @@ -1606,7 +1629,7 @@ ISR(TIMER0_COMPB_vect) // @ 1kHz ~ 1ms #endif #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 soft_pwm_b = soft_pwm_bed; - if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0); + //if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0); #endif #ifdef FAN_SOFT_PWM soft_pwm_fan = fanSpeedSoftPwm / 2; @@ -1740,7 +1763,7 @@ ISR(TIMER0_COMPB_vect) // @ 1kHz ~ 1ms state_timer_heater_b = MIN_STATE_TIME; } state_heater_b = 1; - WRITE(HEATER_BED_PIN, 1); + //WRITE(HEATER_BED_PIN, 1); } } else { // turn OFF heather only if the minimum time is up diff --git a/Firmware/temperature.h b/Firmware/temperature.h index 9697f440..e94629d1 100644 --- a/Firmware/temperature.h +++ b/Firmware/temperature.h @@ -27,8 +27,8 @@ #include "stepper.h" #endif -#define ENABLE_TEMPERATURE_INTERRUPT() TIMSK0 |= (1<<OCIE0B) -#define DISABLE_TEMPERATURE_INTERRUPT() TIMSK0 &= ~(1<<OCIE0B) +#define ENABLE_TEMPERATURE_INTERRUPT() TIMSK2 |= (1<<OCIE2B) +#define DISABLE_TEMPERATURE_INTERRUPT() TIMSK2 &= ~(1<<OCIE2B) // public functions void tp_init(); //initialize the heating diff --git a/Firmware/timer02.c b/Firmware/timer02.c new file mode 100644 index 00000000..8db3cac7 --- /dev/null +++ b/Firmware/timer02.c @@ -0,0 +1,103 @@ +//timer02.c +// use atmega timer2 as main system timer instead of timer0 +// timer0 is used for fast pwm (OC0B output) +// original OVF handler is disabled +#include <avr/io.h> +#include <avr/interrupt.h> +#include <Arduino.h> + + +uint8_t timer02_pwm0 = 0; + +void timer02_set_pwm0(uint8_t pwm0) +{ + if (timer02_pwm0 == pwm0) return; + if (pwm0) + { + TCCR0A |= (2 << COM0B0); + OCR0B = pwm0 - 1; + } + else + { + TCCR0A &= ~(2 << COM0B0); + OCR0B = 0; + } +} + +void timer02_init(void) +{ + //save sreg + uint8_t _sreg = SREG; + //disable interrupts for sure + cli(); + //mask timer0 interrupts - disable all + TIMSK0 &= ~(1<<TOIE0); + TIMSK0 &= ~(1<<OCIE0A); + TIMSK0 &= ~(1<<OCIE0B); + //setup timer0 + TCCR0A = 0x00; //COM_A-B=00, WGM_0-1=00 + TCCR0B = (1 << CS00); //WGM_2=0, CS_0-2=011 + //switch timer0 to fast pwm mode + TCCR0A |= (3 << WGM00); //WGM_0-1=11 + //set OCR0B register to zero + OCR0B = 0; + //disable OCR0B output (will be enabled in timer02_set_pwm0) + TCCR0A &= ~(2 << COM0B0); + //setup timer2 + TCCR2A = 0x00; //COM_A-B=00, WGM_0-1=00 + TCCR2B = (3 << CS20); //WGM_2=0, CS_0-2=011 + //mask timer2 interrupts - enable OVF, disable others + TIMSK2 |= (1<<TOIE2); + TIMSK2 &= ~(1<<OCIE2A); + TIMSK2 &= ~(1<<OCIE2B); + //set timer2 OCR registers (OCRB interrupt generated 0.5ms after OVF interrupt) + OCR2A = 0; + OCR2B = 128; + //restore sreg (enable interrupts) + SREG = _sreg; +} + + +//following code is OVF handler for timer 2 +//it is copy-paste from wiring.c and modified for timer2 +//variables timer0_overflow_count and timer0_millis are declared in wiring.c + + + +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) + +// the whole number of milliseconds per timer0 overflow +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) + +// the fractional number of milliseconds per timer0 overflow. we shift right +// by three to fit these numbers into a byte. (for the clock speeds we care +// about - 8 and 16 MHz - this doesn't lose precision.) +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + +extern volatile unsigned long timer0_overflow_count; +extern volatile unsigned long timer0_millis; +unsigned char timer0_fract = 0; + +ISR(TIMER2_OVF_vect) +{ + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) + { + f -= FRACT_MAX; + m += 1; + } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; +} +