From bcb6964cebedc3cab5f31ada4049825fc30b3600 Mon Sep 17 00:00:00 2001 From: Nico Tonnhofer Date: Tue, 21 Mar 2017 14:58:06 +0100 Subject: [PATCH] heater: add max_pwm and software pwm also for stm32 --- config/board.cnc-shield-v3-nucleo.h | 31 ++++++++++++----- config/board.gen7-arm.h | 2 +- heater-stm32.c | 53 ++++++++++++++++++++--------- 3 files changed, 61 insertions(+), 25 deletions(-) diff --git a/config/board.cnc-shield-v3-nucleo.h b/config/board.cnc-shield-v3-nucleo.h index 712087f..e43fbb5 100644 --- a/config/board.cnc-shield-v3-nucleo.h +++ b/config/board.cnc-shield-v3-nucleo.h @@ -193,15 +193,19 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, PB_0, THERMISTOR_EXTRUDER) * * \***************************************************************************/ -#ifndef DEFINE_HEATER - #define DEFINE_HEATER(...) -#endif +/** \def FORCE_SOFTWARE_PWM + Force software pwm when pwm is sets to 1. + + Normally any pwm value >= 1 will set the pin to hardware pwm, if available. + When FORCE_SOFTWARE_PWM is defined, pwm = 1 is always set to software pwm. +*/ +// #define FORCE_SOFTWARE_PWM /** \def HEATER_PIN Heater pins a user should be able to choose from in configtool. All commented out. */ -//#define HEATER_PIN AIO2 +//#define HEATER_PIN PA_5 /** \def DEFINE_HEATER Define your heaters and devices here. @@ -227,14 +231,25 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, PB_0, 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. - 0 for using on/off on a PWM-able pin, too. + 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. 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. + with slow switches, like solid state relays. A too high frequency can + overheat MOSFETs; a too low frequency can make your heater to emit audible + noise; so choose wisely. + + Pins which don't allow PWM are operated in software pwm mode. */ + //DEFINE_HEATERS_START + // name pin invert pwm max_pwm DEFINE_HEATER(extruder, PA_5, 0, 10000, 100) diff --git a/config/board.gen7-arm.h b/config/board.gen7-arm.h index f99182c..715bdf2 100644 --- a/config/board.gen7-arm.h +++ b/config/board.gen7-arm.h @@ -247,7 +247,7 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, PIO1_0,THERMISTOR_BED) overheat MOSFETs; a too low frequency can make your heater to emit audible noise; so choose wisely. - Pins which don't allow PWM are always operated in on/off mode. + Pins which don't allow PWM are operated in software pwm mode. */ //DEFINE_HEATERS_START diff --git a/heater-stm32.c b/heater-stm32.c index 5551c5c..ea4c369 100644 --- a/heater-stm32.c +++ b/heater-stm32.c @@ -48,7 +48,7 @@ frequency, so you should bother about PWM_SCALE only of you need frequencies below 6 Hz. */ -#define PWM_SCALE 255 +#define PWM_SCALE 1020 // some helper macros #define _EXPANDER(pre, val, post) pre ## val ## post @@ -68,23 +68,44 @@ typedef struct { __IO uint32_t* bsrr; }; uint16_t masked_pin; - uint8_t uses_pwm; + + uint16_t max_value; ///< max value for the heater, for PWM in percent * 256 + pwm_type_t pwm_type; ///< saves the pwm-type: NO_PWM, SOFTWARE_PWM, HARDWARE_PWM + uint8_t invert; ///< Wether the heater pin signal needs to be inverted. } heater_definition_t; +// When pwm >= 2 it's hardware pwm, if the pin has hardware pwm. +// When pwm == 1 it's software pwm. +// pwm == 0 is no pwm at all. +// Use this macro only in DEFINE_HEATER_ACTUAL-macros. +#define PWM_TYPE(pwm, pin) (((pwm) >= HARDWARE_PWM_START) ? ((pin ## _TIMER) ? HARDWARE_PWM : SOFTWARE_PWM) : (pwm)) + #undef DEFINE_HEATER_ACTUAL -#define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, ...) \ - { \ - { pwm && pin ## _TIMER ? \ - &(pin ## _TIMER-> EXPANDER(CCR, pin ## _CHANNEL,)) : \ - &(pin ## _PORT->BSRR) }, \ - MASK(pin ## _PIN), \ - pwm && pin ## _TIMER \ +#define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, max_value) \ + { \ + { (PWM_TYPE(pwm, pin) == HARDWARE_PWM) ? \ + &(pin ## _TIMER-> EXPANDER(CCR, pin ## _CHANNEL,)) : \ + &(pin ## _PORT->BSRR) }, \ + MASK(pin ## _PIN), \ + (PWM_TYPE(pwm, pin) != SOFTWARE_PWM) ? \ + ((max_value * 64 + 12) / 25) : \ + (uint16_t)(255UL * 100 / max_value), \ + PWM_TYPE(pwm, pin), \ + invert ? 1 : 0 \ }, static const heater_definition_t heaters[NUM_HEATERS] = { #include "config_wrapper.h" }; #undef DEFINE_HEATER_ACTUAL +// We test any heater if we need software-pwm +#define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, ...) \ + | (PWM_TYPE(pwm, pin) == 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 heater-arm_lpc11xx.c (pwm.c in LPC1343CodeBase): @@ -156,7 +177,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_TYPE(pwm, pin) == HARDWARE_PWM) { \ uint32_t freq; \ uint8_t macro_mask; \ if (pin ## _TIMER == TIM1) { \ @@ -223,22 +244,22 @@ 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].pwm_type == HARDWARE_PWM) { // Remember, we scale, and duty cycle is inverted. - *heaters[index].ccr = (uint32_t)value * (PWM_SCALE / 255); + *heaters[index].ccr = (uint32_t)((heaters[index].max_value * value) * (PWM_SCALE / 255) / 256); if (DEBUG_PID && (debug_flags & DEBUG_PID)) sersendf_P(PSTR("PWM %su = %lu\n"), index, *heaters[index].ccr); } else { *(heaters[index].bsrr) = - heaters[index].masked_pin << ((value >= HEATER_THRESHOLD) ? 0 : 16); + heaters[index].masked_pin << + ((value >= HEATER_THRESHOLD && ! heaters[index].invert) ? + 0 : 16); } if (value) power_on();