From 4abc3aa2f061d60f5f69611bba3a507282cff753 Mon Sep 17 00:00:00 2001 From: Nico Tonnhofer Date: Tue, 14 Mar 2017 18:22:56 +0100 Subject: [PATCH] heater: software pwm with delta sigma algorithm @triffid points me to the delta sigma algorithm. This is pretty nice for slow updating routines. Others than normal PWM, this scale better for slow frequencies. This algorithm is a mix of https://www.mikrocontroller.net/topic/293454#3128867 and https://github.com/Smoothieware/Smoothieware/blob/29e80/src/libs/Pwm.cpp#L55 --- clock.c | 2 + config/board.3drag.h | 9 +++-- config/board.cnc-shield-v3.h | 5 ++- config/board.gen6.h | 5 ++- config/board.gen7-arm.h | 15 ++++---- config/board.gen7-v1.1-v1.3.h | 8 ++-- config/board.gen7-v1.4.h | 7 ++-- config/board.melzi.h | 9 +++-- config/board.nanoheart-v1.0.h | 7 ++-- config/board.pcbscriber.h | 3 +- config/board.ramps-v1.2.h | 9 +++-- config/board.ramps-v1.3.h | 9 +++-- config/board.rumba.h | 9 +++-- config/board.sanguinololu-v1.1.h | 7 ++-- config/board.sanguinololu-v1.2.h | 7 ++-- config/board.sanguish.h | 7 ++-- config/board.sinaptec-at328-02.h | 9 +++-- config/board.teensy++-v2.0.h | 9 +++-- config/board.teensy-v2.0.h | 9 +++-- config/board.tronxy.h | 9 +++-- heater-avr.c | 30 ++++++++++----- heater-lpc.c | 24 ++++++++---- heater.c | 55 +++++++++++++++++++++++++++ heater.h | 13 +++++++ simulator/heater_sim.c | 3 ++ testcases/board.regtest-no-endstops.h | 2 +- testcases/config.h.Profiling | 4 +- 27 files changed, 197 insertions(+), 88 deletions(-) diff --git a/clock.c b/clock.c index 0af23fe..7d8f487 100644 --- a/clock.c +++ b/clock.c @@ -147,6 +147,8 @@ static void clock_10ms(void) { temp_sensor_tick(); + soft_pwm_tick(); + ifclock(clock_flag_250ms) { clock_250ms(); } diff --git a/config/board.3drag.h b/config/board.3drag.h index 3b6d7d2..075618f 100644 --- a/config/board.3drag.h +++ b/config/board.3drag.h @@ -226,7 +226,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO14, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -237,9 +238,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO14, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO10, 0, 1, 100) -DEFINE_HEATER(bed, DIO9, 0, 1, 100) -DEFINE_HEATER(fan, DIO8, 0, 1, 100) +DEFINE_HEATER(extruder, DIO10, 0, 2, 100) +DEFINE_HEATER(bed, DIO9, 0, 2, 100) +DEFINE_HEATER(fan, DIO8, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.cnc-shield-v3.h b/config/board.cnc-shield-v3.h index 5b5fb18..3341d05 100644 --- a/config/board.cnc-shield-v3.h +++ b/config/board.cnc-shield-v3.h @@ -226,7 +226,8 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, AIO3, THERMISTOR_EXTRUDER) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -237,7 +238,7 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, AIO3, THERMISTOR_EXTRUDER) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, AIO2, 0, 1, 100) +DEFINE_HEATER(extruder, AIO2, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder //DEFINE_HEATERS_END diff --git a/config/board.gen6.h b/config/board.gen6.h index 883bae9..c5d6c6d 100644 --- a/config/board.gen6.h +++ b/config/board.gen6.h @@ -221,7 +221,8 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, AIO5, THERMISTOR_EXTRUDER) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -232,7 +233,7 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, AIO5, THERMISTOR_EXTRUDER) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO6, 0, 1, 100) +DEFINE_HEATER(extruder, DIO6, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder //DEFINE_HEATERS_END diff --git a/config/board.gen7-arm.h b/config/board.gen7-arm.h index afee8dc..7742eee 100644 --- a/config/board.gen7-arm.h +++ b/config/board.gen7-arm.h @@ -225,14 +225,13 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, PIO1_0,THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - frequency in Hertz (Hz) on ARM based controllers to set PWM frequency of - this pin's output. Frequency isn't always accurate, Teacup - will choose the closest possible one. FAST_PWM is ignored - on such controllers. Valid range is 2 to 200'000 Hz. - 1 on AVR based controllers for using Pulse Width Modulation (PWM) - on a pin supporting it. PWM frequency can be influenced only - somewhat and only globally with FAST_PWM. - 0 for using a PWM-able pin in on/off mode. + >=2 in Hertz (Hz) on ARM based controllers to set PWM frequency of + this pin's output. Frequency isn't always accurate, Teacup + will choose the closest possible one. FAST_PWM is ignored + on such controllers. Valid range is 2 to 200'000 Hz. + It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM at 100Hz. + 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict with slow switches, like solid state relays. A too high frequency can diff --git a/config/board.gen7-v1.1-v1.3.h b/config/board.gen7-v1.1-v1.3.h index e4e0b62..c43ee32 100644 --- a/config/board.gen7-v1.1-v1.3.h +++ b/config/board.gen7-v1.1-v1.3.h @@ -230,9 +230,11 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO2, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. + Using PWM usually gives smoother temperature control but can conflict with slow switches, like solid state relays. PWM frequency can be influenced globally with FAST_PWM, see below. @@ -241,8 +243,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO2, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO4, 0, 1, 100) -DEFINE_HEATER(bed, DIO3, 0, 1, 100) +DEFINE_HEATER(extruder, DIO4, 0, 2, 100) +DEFINE_HEATER(bed, DIO3, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.gen7-v1.4.h b/config/board.gen7-v1.4.h index a6574ff..9dad7f0 100644 --- a/config/board.gen7-v1.4.h +++ b/config/board.gen7-v1.4.h @@ -231,7 +231,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO0, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -242,8 +243,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO0, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO4, 0, 1, 100) -DEFINE_HEATER(bed, DIO3, 0, 1, 100) +DEFINE_HEATER(extruder, DIO4, 0, 2, 100) +DEFINE_HEATER(bed, DIO3, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.melzi.h b/config/board.melzi.h index e8c4738..5c9211b 100644 --- a/config/board.melzi.h +++ b/config/board.melzi.h @@ -230,7 +230,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -241,9 +242,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO13, 0, 1, 100) -DEFINE_HEATER(bed, DIO12, 0, 1, 100) -DEFINE_HEATER(fan, DIO4, 0, 0, 100) +DEFINE_HEATER(extruder, DIO13, 0, 2, 100) +DEFINE_HEATER(bed, DIO12, 0, 2, 100) +DEFINE_HEATER(fan, DIO4, 0, 1, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.nanoheart-v1.0.h b/config/board.nanoheart-v1.0.h index d98fb98..7cded1b 100644 --- a/config/board.nanoheart-v1.0.h +++ b/config/board.nanoheart-v1.0.h @@ -228,7 +228,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO7, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -239,8 +240,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO7, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO11, 0, 1, 100) -DEFINE_HEATER(bed, DIO3, 0, 1, 100) +DEFINE_HEATER(extruder, DIO11, 0, 2, 100) +DEFINE_HEATER(bed, DIO3, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.pcbscriber.h b/config/board.pcbscriber.h index 4ef416a..c37a095 100644 --- a/config/board.pcbscriber.h +++ b/config/board.pcbscriber.h @@ -247,7 +247,8 @@ for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict diff --git a/config/board.ramps-v1.2.h b/config/board.ramps-v1.2.h index a31c59e..ddb0fbc 100644 --- a/config/board.ramps-v1.2.h +++ b/config/board.ramps-v1.2.h @@ -227,7 +227,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO1, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -238,9 +239,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO1, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO10, 0, 1, 100) -DEFINE_HEATER(bed, DIO8, 0, 1, 100) -DEFINE_HEATER(fan, DIO9, 0, 1, 100) +DEFINE_HEATER(extruder, DIO10, 0, 2, 100) +DEFINE_HEATER(bed, DIO8, 0, 2, 100) +DEFINE_HEATER(fan, DIO9, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.ramps-v1.3.h b/config/board.ramps-v1.3.h index fafd2a0..d751d00 100644 --- a/config/board.ramps-v1.3.h +++ b/config/board.ramps-v1.3.h @@ -232,7 +232,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO14, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -243,9 +244,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO14, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO10, 0, 1, 100) -DEFINE_HEATER(bed, DIO8, 0, 1, 100) -DEFINE_HEATER(fan, DIO9, 0, 1, 100) +DEFINE_HEATER(extruder, DIO10, 0, 2, 100) +DEFINE_HEATER(bed, DIO8, 0, 2, 100) +DEFINE_HEATER(fan, DIO9, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.rumba.h b/config/board.rumba.h index ede906b..d215e46 100644 --- a/config/board.rumba.h +++ b/config/board.rumba.h @@ -230,7 +230,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO11, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -241,9 +242,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO11, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO2, 0, 1, 100) -DEFINE_HEATER(bed, DIO9, 0, 1, 100) -DEFINE_HEATER(fan, DIO8, 0, 1, 100) +DEFINE_HEATER(extruder, DIO2, 0, 2, 100) +DEFINE_HEATER(bed, DIO9, 0, 2, 100) +DEFINE_HEATER(fan, DIO8, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.sanguinololu-v1.1.h b/config/board.sanguinololu-v1.1.h index 22c2a93..cec1949 100644 --- a/config/board.sanguinololu-v1.1.h +++ b/config/board.sanguinololu-v1.1.h @@ -228,7 +228,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -239,8 +240,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO13, 0, 1, 100) -DEFINE_HEATER(bed, DIO14, 0, 1, 100) +DEFINE_HEATER(extruder, DIO13, 0, 2, 100) +DEFINE_HEATER(bed, DIO14, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.sanguinololu-v1.2.h b/config/board.sanguinololu-v1.2.h index d069182..af4e546 100644 --- a/config/board.sanguinololu-v1.2.h +++ b/config/board.sanguinololu-v1.2.h @@ -228,7 +228,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -239,8 +240,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO12, 0, 1, 100) -DEFINE_HEATER(bed, DIO13, 0, 1, 100) +DEFINE_HEATER(extruder, DIO12, 0, 2, 100) +DEFINE_HEATER(bed, DIO13, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.sanguish.h b/config/board.sanguish.h index bd59c50..ec90822 100644 --- a/config/board.sanguish.h +++ b/config/board.sanguish.h @@ -228,7 +228,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO0, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -239,8 +240,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO0, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO3, 0, 1, 100) -DEFINE_HEATER(bed, DIO4, 0, 1, 100) +DEFINE_HEATER(extruder, DIO3, 0, 2, 100) +DEFINE_HEATER(bed, DIO4, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.sinaptec-at328-02.h b/config/board.sinaptec-at328-02.h index 7879aec..8772d79 100644 --- a/config/board.sinaptec-at328-02.h +++ b/config/board.sinaptec-at328-02.h @@ -229,7 +229,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -240,9 +241,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO3, 0, 1, 100) -DEFINE_HEATER(bed, DIO6, 0, 1, 100) -DEFINE_HEATER(fan, DIO5, 0, 1, 100) +DEFINE_HEATER(extruder, DIO3, 0, 2, 100) +DEFINE_HEATER(bed, DIO6, 0, 2, 100) +DEFINE_HEATER(fan, DIO5, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.teensy++-v2.0.h b/config/board.teensy++-v2.0.h index 513fb27..94e7d72 100644 --- a/config/board.teensy++-v2.0.h +++ b/config/board.teensy++-v2.0.h @@ -226,7 +226,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -237,9 +238,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO15, 0, 1, 100) -DEFINE_HEATER(bed, DIO14, 0, 1, 100) -DEFINE_HEATER(fan, DIO16, 0, 0, 100) +DEFINE_HEATER(extruder, DIO15, 0, 2, 100) +DEFINE_HEATER(bed, DIO14, 0, 2, 100) +DEFINE_HEATER(fan, DIO16, 0, 1, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.teensy-v2.0.h b/config/board.teensy-v2.0.h index 20ce6d0..772a6bc 100644 --- a/config/board.teensy-v2.0.h +++ b/config/board.teensy-v2.0.h @@ -226,7 +226,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO0, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -237,9 +238,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO0, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO10, 0, 1, 100) -DEFINE_HEATER(bed, DIO9, 0, 1, 100) -DEFINE_HEATER(fan, DIO8, 0, 0, 100) +DEFINE_HEATER(extruder, DIO10, 0, 2, 100) +DEFINE_HEATER(bed, DIO9, 0, 2, 100) +DEFINE_HEATER(fan, DIO8, 0, 1, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/config/board.tronxy.h b/config/board.tronxy.h index dd52954..8409f49 100644 --- a/config/board.tronxy.h +++ b/config/board.tronxy.h @@ -228,7 +228,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) for this pin, e.g. for a MOSFET with a driver. Set 'pwm' to ... - 1 for using PWM on a PWM-able pin and on/off on other pins. + 2 for using PWM on a PWM-able pin. It will force to 1 on none-PWM-able pins. + 1 for using software emulated PWM. 0 for using on/off on a PWM-able pin, too. Using PWM usually gives smoother temperature control but can conflict @@ -239,9 +240,9 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO6, THERMISTOR_BED) //DEFINE_HEATERS_START // name pin invert pwm max_pwm -DEFINE_HEATER(extruder, DIO13, 0, 1, 100) -DEFINE_HEATER(bed, DIO12, 0, 1, 100) -DEFINE_HEATER(fan, DIO4, 0, 1, 100) +DEFINE_HEATER(extruder, DIO13, 0, 2, 100) +DEFINE_HEATER(bed, DIO12, 0, 2, 100) +DEFINE_HEATER(fan, DIO4, 0, 2, 100) #define HEATER_EXTRUDER HEATER_extruder #define HEATER_BED HEATER_bed diff --git a/heater-avr.c b/heater-avr.c index 7d5dac2..309195c 100644 --- a/heater-avr.c +++ b/heater-avr.c @@ -15,12 +15,14 @@ /// \struct heater_definition_t /// \brief simply holds pinout data- port, pin, pwm channel if used +#define U8_HEATER_PWM uint8_t * + typedef struct { volatile uint8_t *heater_port; ///< pointer to port. DDR is inferred from this pointer too uint8_t heater_pin; ///< heater pin, not masked. eg for PB3 enter '3' here, or PB3_PIN or similar /// Wether the heater pin signal needs to be inverted. uint8_t invert; - volatile uint8_t *heater_pwm; ///< pointer to 8-bit PWM register, eg OCR0A (8-bit) or ORC3L (low byte, 16-bit) + volatile U8_HEATER_PWM heater_pwm; ///< pointer to 8-bit PWM register, eg OCR0A (8-bit) or ORC3L (low byte, 16-bit) uint16_t max_value; } heater_definition_t; @@ -30,8 +32,8 @@ typedef struct { &(pin ## _WPORT), \ pin ## _PIN, \ invert ? 1 : 0, \ - pwm ? (pin ## _PWM) : NULL, \ - ((max_value * 64 + 12) / 25) \ + (pwm >= HARDWARE_PWM) ? ((pin ## _PWM) ? (pin ## _PWM) : (U8_HEATER_PWM)SOFTWARE_PWM) : (U8_HEATER_PWM)pwm, \ + ((max_value * 64 + 12) / 25), \ }, static const heater_definition_t heaters[NUM_HEATERS] = { @@ -39,6 +41,14 @@ static const heater_definition_t heaters[NUM_HEATERS] = }; #undef DEFINE_HEATER_ACTUAL +// We test any heater if we need software-pwm +#define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, ...) \ + | (((pwm >= HARDWARE_PWM) ? ((pin ## _PWM) ? HARDWARE_PWM : SOFTWARE_PWM) : pwm) == SOFTWARE_PWM) +static const uint8_t software_pwm_needed = 0 + #include "config_wrapper.h" +; +#undef DEFINE_HEATER_ACTUAL + /// \brief initialise heater subsystem /// Set directions, initialise PWM timers, read PID factors from eeprom, etc @@ -126,7 +136,7 @@ void heater_init() { // setup pins for (i = 0; i < NUM_HEATERS; i++) { - if (heaters[i].heater_pwm) { + if (heaters[i].heater_pwm >= (U8_HEATER_PWM)HARDWARE_PWM) { *heaters[i].heater_pwm = heaters[i].invert ? 255 : 0; // this is somewhat ugly too, but switch() won't accept pointers for reasons unknown switch((uint16_t) heaters[i].heater_pwm) { @@ -216,17 +226,17 @@ void heater_init() { anything done by this function is overwritten by heater_tick above if the heater has an associated temp sensor */ -void heater_set(heater_t index, uint8_t value) { +void do_heater(heater_t index, uint8_t value) { if (index < NUM_HEATERS) { - heaters_runtime[index].heater_output = value; + if (heaters[index].heater_pwm >= (U8_HEATER_PWM)HARDWARE_PWM) { + uint8_t pwm_value; - if (heaters[index].heater_pwm) { - - value = (uint8_t)((heaters[index].max_value * value) / 256); + // Remember, we scale, and the timer inverts already. + pwm_value = (uint8_t)((heaters[index].max_value * value) / 256); *(heaters[index].heater_pwm) = heaters[index].invert ? - (255 - value) : value; + (255 - pwm_value) : pwm_value; if (DEBUG_PID && (debug_flags & DEBUG_PID)) sersendf_P(PSTR("PWM{%u = %u}\n"), index, *heaters[index].heater_pwm); diff --git a/heater-lpc.c b/heater-lpc.c index 871d142..02472c1 100644 --- a/heater-lpc.c +++ b/heater-lpc.c @@ -51,7 +51,7 @@ frequency, so you should bother about PWM_SCALE only of you need frequencies below 3 Hz. */ -#define PWM_SCALE 255 +#define PWM_SCALE 1020 /** \struct heater_definition_t @@ -59,6 +59,8 @@ pin, PWM channel if used. After inititalisation we can no longer do the #include "config_wrapper.h" trick. */ +#define U8_HEATER_PWM uint8_t + typedef struct { union { /// Pointer to the match register which changes PWM duty. @@ -67,7 +69,7 @@ typedef struct { __IO uint32_t* masked_port; }; uint16_t max_value; - uint8_t uses_pwm; + U8_HEATER_PWM heater_pwm;; uint8_t invert; } heater_definition_t; @@ -78,7 +80,7 @@ typedef struct { &(pin ## _TIMER->MR[pin ## _MATCH]) : \ &(pin ## _PORT->MASKED_ACCESS[MASK(pin ## _PIN)]) }, \ ((max_value * 64 + 12) / 25), \ - pwm && pin ## _TIMER, \ + ((pwm >= HARDWARE_PWM) ? ((pin ## _TIMER) ? HARDWARE_PWM : SOFTWARE_PWM) : pwm), \ invert ? 1 : 0 \ }, static const heater_definition_t heaters[NUM_HEATERS] = { @@ -86,6 +88,14 @@ static const heater_definition_t heaters[NUM_HEATERS] = { }; #undef DEFINE_HEATER_ACTUAL +// We test any heater if we need software-pwm +#define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, ...) \ + | (((pwm >= HARDWARE_PWM) ? ((pin ## _TIMER) ? HARDWARE_PWM : SOFTWARE_PWM) : pwm) == SOFTWARE_PWM) +static const uint8_t software_pwm_needed = 0 + #include "config_wrapper.h" +; +#undef DEFINE_HEATER_ACTUAL + /** Initialise heater subsystem. Initialise PWM timers, etc. Inspired by pwm.c in LPC1343CodeBase: @@ -133,7 +143,7 @@ void heater_init() { // Auto-generate pin setup. #undef DEFINE_HEATER_ACTUAL #define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, ...) \ - if (pwm && pin ## _TIMER) { \ + if ((pwm >= HARDWARE_PWM) && pin ## _TIMER) { \ uint32_t freq; \ \ if (pin ## _TIMER == LPC_TMR16B0) { \ @@ -187,13 +197,11 @@ void heater_init() { heater, every few milliseconds by its PID handler. Using M106 on an output with a sensor changes its setting only for a short moment. */ -void heater_set(heater_t index, uint8_t value) { +void do_heater(heater_t index, uint8_t value) { if (index < NUM_HEATERS) { - heaters_runtime[index].heater_output = value; - - if (heaters[index].uses_pwm) { + if (heaters[index].heater_pwm == HARDWARE_PWM) { uint32_t pwm_value; // Remember, we scale, and the timer inverts already. diff --git a/heater.c b/heater.c index 35af62d..02fd4b2 100644 --- a/heater.c +++ b/heater.c @@ -74,6 +74,7 @@ EE_factor EEMEM EE_factors[NUM_HEATERS]; heater_runtime_t heaters_runtime[NUM_HEATERS]; +soft_pwm_runtime_t soft_pwm_runtime[NUM_HEATERS]; /** Inititalise PID data structures. @@ -249,6 +250,60 @@ void heater_tick(heater_t h, temp_type_t type, uint16_t current_temp, uint16_t t heater_set(h, pid_output); } +/** \brief software PWM routine +*/ +#define PWM_MAX 255 + +void heater_soft_pwm(heater_t index) { + if (software_pwm_needed) { + int16_t pwm; + pwm = heaters_runtime[index].heater_output; + + // full off? then put it just off + if (pwm == 0) { + do_heater(index, 0); + return; + } + + // here we are doing a small trick. normally this is + // sd_accu += pwm - (sd_dir * PWM_MAX) + // here we scale the (sd_dir * PWM_MAX) -part with the max_value. + // so we get a smooth PWM also for downscaled heaters. the "pwm"-value + // is from 0 to 255 in any case, but the sd_accu becomes bigger with + // smaller max_values. + soft_pwm_runtime[index].sd_accu += pwm - soft_pwm_runtime[index].sd_dir; + + if (soft_pwm_runtime[index].sd_accu > 0) { + soft_pwm_runtime[index].sd_dir = PWM_MAX * 256 / heaters[index].max_value; + do_heater(index, 255); + } + else { + soft_pwm_runtime[index].sd_dir = 0; + do_heater(index, 0); + } + } +} + +/** + Called every 10ms from clock.c. Tick the softPWM procedure when the heater needs it. +*/ +void soft_pwm_tick() { + if (software_pwm_needed) { + uint8_t i; + for (i = 0; i < NUM_HEATERS; i++) { + if (heaters[i].heater_pwm == (U8_HEATER_PWM)SOFTWARE_PWM) + heater_soft_pwm(i); + } + } +} + +/** \brief set heater value and execute it +*/ +void heater_set(heater_t index, uint8_t value) { + heaters_runtime[index].heater_output = value; + do_heater(index, value); +} + /** \brief check whether all heaters are off */ uint8_t heaters_all_zero() { diff --git a/heater.h b/heater.h index da5b29a..8a2f61e 100644 --- a/heater.h +++ b/heater.h @@ -64,6 +64,17 @@ typedef struct { uint8_t heater_output; } heater_runtime_t; +typedef struct { + /// sigma delta values for software pwm + int16_t sd_accu; + int16_t sd_dir; +} soft_pwm_runtime_t; + +typedef enum { + NO_PWM = 0, + SOFTWARE_PWM = 1, + HARDWARE_PWM = 2 +} pwm_type_t; extern heater_runtime_t heaters_runtime[]; @@ -73,6 +84,8 @@ void pid_init(void); void heater_set(heater_t index, uint8_t value); void heater_tick(heater_t h, temp_type_t type, uint16_t current_temp, uint16_t target_temp); +void soft_pwm_tick(void); + uint8_t heaters_all_zero(void); #ifdef EECONFIG diff --git a/simulator/heater_sim.c b/simulator/heater_sim.c index 98cb3bf..5c41628 100644 --- a/simulator/heater_sim.c +++ b/simulator/heater_sim.c @@ -11,6 +11,9 @@ void heater_set(heater_t index, uint8_t value) { void heater_tick(heater_t h, temp_type_t type, uint16_t current_temp, uint16_t target_temp) { } +void soft_pwm_tick() { +} + uint8_t heaters_all_zero(void) { return 1; } diff --git a/testcases/board.regtest-no-endstops.h b/testcases/board.regtest-no-endstops.h index 986ad3c..4bd8a63 100644 --- a/testcases/board.regtest-no-endstops.h +++ b/testcases/board.regtest-no-endstops.h @@ -63,7 +63,7 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, AIO1, THERMISTOR_EXTRUDER) DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO2, THERMISTOR_BED) -DEFINE_HEATER(extruder, DIO4, 0, 1, 100) +DEFINE_HEATER(extruder, DIO4, 0, 2, 100) DEFINE_HEATER(bed, DIO3, 0, 1, 100) #define HEATER_EXTRUDER HEATER_extruder diff --git a/testcases/config.h.Profiling b/testcases/config.h.Profiling index eb26769..c9ecb67 100644 --- a/testcases/config.h.Profiling +++ b/testcases/config.h.Profiling @@ -551,8 +551,8 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO0, THERMISTOR_EXTRUDER) // #define HEATER_MAX_ACTIVE // name pin invert pwm -DEFINE_HEATER(extruder, DIO4, 0, 1, 100) -DEFINE_HEATER(bed, DIO3, 0, 1, 100) +DEFINE_HEATER(extruder, DIO4, 0, 2, 100) +DEFINE_HEATER(bed, DIO3, 0, 2, 100) /// and now because the c preprocessor isn't as smart as it could be, /// uncomment the ones you've listed above and comment the rest.