heater: add max_pwm and software pwm also for stm32

This commit is contained in:
Nico Tonnhofer 2017-03-21 14:58:06 +01:00
parent fbe1af4013
commit bcb6964ceb
3 changed files with 61 additions and 25 deletions

View File

@ -193,15 +193,19 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, PB_0, THERMISTOR_EXTRUDER)
* * * *
\***************************************************************************/ \***************************************************************************/
#ifndef DEFINE_HEATER /** \def FORCE_SOFTWARE_PWM
#define DEFINE_HEATER(...) Force software pwm when pwm is sets to 1.
#endif
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 /** \def HEATER_PIN
Heater pins a user should be able to choose from in configtool. All Heater pins a user should be able to choose from in configtool. All
commented out. commented out.
*/ */
//#define HEATER_PIN AIO2 //#define HEATER_PIN PA_5
/** \def DEFINE_HEATER /** \def DEFINE_HEATER
Define your heaters and devices here. 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. for this pin, e.g. for a MOSFET with a driver.
Set 'pwm' to ... Set 'pwm' to ...
1 for using PWM on a PWM-able pin and on/off on other pins. frequency in Hertz (Hz) on ARM based controllers to set PWM frequency of
0 for using on/off on a PWM-able pin, too. 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 Using PWM usually gives smoother temperature control but can conflict
with slow switches, like solid state relays. PWM frequency can be with slow switches, like solid state relays. A too high frequency can
influenced globally with FAST_PWM, see below. 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 //DEFINE_HEATERS_START
// name pin invert pwm max_pwm // name pin invert pwm max_pwm
DEFINE_HEATER(extruder, PA_5, 0, 10000, 100) DEFINE_HEATER(extruder, PA_5, 0, 10000, 100)

View File

@ -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 overheat MOSFETs; a too low frequency can make your heater to emit audible
noise; so choose wisely. 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 //DEFINE_HEATERS_START

View File

@ -48,7 +48,7 @@
frequency, so you should bother about PWM_SCALE only of you need frequencies frequency, so you should bother about PWM_SCALE only of you need frequencies
below 6 Hz. below 6 Hz.
*/ */
#define PWM_SCALE 255 #define PWM_SCALE 1020
// some helper macros // some helper macros
#define _EXPANDER(pre, val, post) pre ## val ## post #define _EXPANDER(pre, val, post) pre ## val ## post
@ -68,23 +68,44 @@ typedef struct {
__IO uint32_t* bsrr; __IO uint32_t* bsrr;
}; };
uint16_t masked_pin; 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; } 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 #undef DEFINE_HEATER_ACTUAL
#define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, ...) \ #define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, max_value) \
{ \ { \
{ pwm && pin ## _TIMER ? \ { (PWM_TYPE(pwm, pin) == HARDWARE_PWM) ? \
&(pin ## _TIMER-> EXPANDER(CCR, pin ## _CHANNEL,)) : \ &(pin ## _TIMER-> EXPANDER(CCR, pin ## _CHANNEL,)) : \
&(pin ## _PORT->BSRR) }, \ &(pin ## _PORT->BSRR) }, \
MASK(pin ## _PIN), \ MASK(pin ## _PIN), \
pwm && pin ## _TIMER \ (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] = { static const heater_definition_t heaters[NUM_HEATERS] = {
#include "config_wrapper.h" #include "config_wrapper.h"
}; };
#undef DEFINE_HEATER_ACTUAL #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 heater subsystem.
Initialise PWM timers, etc. Inspired by heater-arm_lpc11xx.c (pwm.c in LPC1343CodeBase): 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. // Auto-generate pin setup.
#undef DEFINE_HEATER_ACTUAL #undef DEFINE_HEATER_ACTUAL
#define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, ...) \ #define DEFINE_HEATER_ACTUAL(name, pin, invert, pwm, ...) \
if (pwm && pin ## _TIMER) { \ if (PWM_TYPE(pwm, pin) == HARDWARE_PWM) { \
uint32_t freq; \ uint32_t freq; \
uint8_t macro_mask; \ uint8_t macro_mask; \
if (pin ## _TIMER == TIM1) { \ if (pin ## _TIMER == TIM1) { \
@ -223,22 +244,22 @@ void heater_init() {
heater, every few milliseconds by its PID handler. Using M106 on an output heater, every few milliseconds by its PID handler. Using M106 on an output
with a sensor changes its setting only for a short moment. 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) { if (index < NUM_HEATERS) {
heaters_runtime[index].heater_output = value; if (heaters[index].pwm_type == HARDWARE_PWM) {
if (heaters[index].uses_pwm) {
// Remember, we scale, and duty cycle is inverted. // 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)) if (DEBUG_PID && (debug_flags & DEBUG_PID))
sersendf_P(PSTR("PWM %su = %lu\n"), index, *heaters[index].ccr); sersendf_P(PSTR("PWM %su = %lu\n"), index, *heaters[index].ccr);
} }
else { else {
*(heaters[index].bsrr) = *(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) if (value)
power_on(); power_on();