Cannot setup a generic_heater for my enclosure (MCU 'mcu' shutdown: Missed scheduling of next digital out event)

I have an ender 3 with creality 4.2.7 mainboard, fully working with klipper on a raspberry pi4.
I’m trying to integrate into klipper a temperature sensor (BME680) for my enclosure, along with a relay for turning on/off a ptc heater.
I’ve configured a “generic_heater” in my printer.cfg file:

[heater_generic enclosure]
heater_pin: host:gpio12
sensor_type: BME280
i2c_address: 119
i2c_software_scl_pin: PB10
i2c_software_sda_pin: PB11
control: watermark

The BME680 is hooked to the creality mainboard, while the gpio12 (the one which controls the heater relay) is on the raspberry.
With this configuration, I can see correctly the readings of the temperature sensor, but as soon as I change the target temperature, after about 5 seconds, I get the error:

MCU ‘mcu’ shutdown: Missed scheduling of next digital out event and I have to restart the firmware.

What I’ve tried until now:

  • Updating klipper, moonraker and everything else via KIAUH, and updating the firmware on the creality mainboard
  • Using a DS18B20 sensor instead of the BME680
  • Hook the sensor directly into the raspberry instead of the creality mainboard
  • Using pid instead of watermark

The behavior is the same in all cases, I correctly can see the temperature of the sensor, even of the DS18B20, but as soon as I change the target temperature, I get this error after a few seconds.
When I use the sensor and the heater separately (via [output pin]) they both work correctly, I get this error only when I use them both in the same generic_heater.

At this point I’m lost. Do you have any idea?

Have you checked on these explanations: Configuration reference - Klipper documentation ?

1 Like

Yes… I think I have checked everything… I also tried changing i2c speed with various settings but no luck. I also reinstalled klipper from scratch on RaspberrypiOS 32 bit instead of 64 bit but I get the same exact issue…

EDIT: If I use [temperature_fan] instead of [generic_heater], with the same sensor and the same pins, everything works. Since [temperature_fan] is meant to run when the temperature is above the target temperature (and not under, like an heater) I have to reverse the pin direction with “!” (pin: !host:gpio12). In this way everything works like it should, but it is a workaround that I don’t like. But since it is working with [temperature_fan] I can assume that is a software bug rather than an hardware issue…

FWIW, I2C has nothing to do this the error here.
The error is that, for some reason, there is no updated value in the several seconds, which leads to this error.
Like the host does not send a new value, before the last PWM expires.

It still would be nice to have logs. There are requirements in this section.

I use BME to control the chamber temperature, and it works.
Ah, yes, I use combined_sensor over BME data, so I still see the gas/humidity numbers.
I suspect this is why it is works for me.

Or you can just use combined sensor which will wrap the BME data and provide them to the heater with higher frequency.
But this is a hack.

[temperature_sensor chamber]
sensor_type: BME280
# i2c_address: 118 # 0x76 BME280
i2c_address: 119 # 0x77 BME680
i2c_mcu: host
i2c_bus: i2c.1   # optional

[heater_generic chamber]
sensor_type: temperature_combined
sensor_list:
    temperature_sensor chamber
combination_method: mean
maximum_deviation: 10
heater_pin: PB0 # HE2
pwm_cycle_time: 0.203
control: pid
max_power: 0.6
pid_kp: 55
pid_ki: 0.5
pid_kd: 20
min_temp: 10
max_temp: 85

I can only guess that the low update frequency of BME is somewhat messing with the PWM time scheduling.
And something like that could help:

diff --git a/klippy/extras/heaters.py b/klippy/extras/heaters.py
index 157f150c4..0416f3701 100644
--- a/klippy/extras/heaters.py
+++ b/klippy/extras/heaters.py
@@ -80,7 +80,7 @@ class Heater:
             # No significant change in value - can suppress update
             return
         pwm_time = read_time + self.pwm_delay
-        self.next_pwm_time = pwm_time + 0.75 * MAX_HEAT_TIME
+        self.next_pwm_time = pwm_time + 0.5 * MAX_HEAT_TIME
         self.last_pwm_value = value
         if not self.fast_pwm:
             self.mcu_pwm.set_pwm(pwm_time, value)
1 Like

It is a long-standing topic that BMEs are not well-suited for control tasks. There have been quite a few issues reported in the past. IIRC, the recommendation so far has been to use regular thermistors instead.

Problem is I do not have any ADC pin available… So I must stick with digital. Anyway I know nothing about coding but [temperature_fan] should do the same thing as [generic_heater] but in reverse (turns pin high when temperature is above target) so I doubt there is a problem with the sensor… Also DS18B20 fails the same way. It looks to me that there’s an issue with the [generic_heater] component but I need more testing

I will try the combined sensor and post an update… With klippy.log

Ok, I tried with temperature_combined and it does work.
I reverted back to old configuration to reproduce the issue and grab the klippy.log.

klippy (1).log (145.0 KB)

While fiddling I also got another error, but was not able to grab klippy.log
(MCU ‘host’ shutdown: Scheduled digital out event will exceed max_duration)

1 Like

Well, yes, it has died precisely in 3s.

(760038879 - 610037731) / 50_000_000 = 3.000

So, the thing is, current PWM hysteresis is too aggressive for the BME.
Like:

0.3 + 0.75 * 3 = 2.55
3 - 2.55 = 0.45s

And BME has REPORT_TIME = 0.8

Which just does not fit there.
Even for a default 300ms ADC, it is a little tight.
(Before, it was 0.3 + 0.75 * 5 = 4.05, so 0.95s windows).

temperature_combined just emulates the 0.3s report interval.