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
This commit is contained in:
Nico Tonnhofer 2017-03-14 18:22:56 +01:00
parent fb83d2de57
commit 4abc3aa2f0
27 changed files with 197 additions and 88 deletions

View File

@ -147,6 +147,8 @@ static void clock_10ms(void) {
temp_sensor_tick();
soft_pwm_tick();
ifclock(clock_flag_250ms) {
clock_250ms();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
>=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.
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.
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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() {

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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.