Hardware PWM using rpi_hardware_pwm library
This commit is contained in:
22
README.md
22
README.md
@@ -36,7 +36,7 @@ Install the plugin using the Plugin Manager bundled with OctoPrint, you can sear
|
||||
|
||||
This plugin support many hardware temperature sensors, led, relays, heater...
|
||||
|
||||
Here are detailled instructions on how to setup them.
|
||||
Here are detailed instructions on how to setup them.
|
||||
|
||||
### Temperature sensors
|
||||
|
||||
@@ -136,7 +136,7 @@ If your setup does not have pip install pip:
|
||||
Install the required library:
|
||||
`sudo pip install rpi_ws281x`
|
||||
|
||||
rpi_ws281x really needs sudo, and you need to setup up so your rpi does not ask for a password when runing a python script, so run:
|
||||
rpi_ws281x really needs sudo, and you need to setup up so your rpi does not ask for a password when running a python script, so run:
|
||||
|
||||
`sudo visudo`
|
||||
|
||||
@@ -148,6 +148,20 @@ Also backlist the audio kernel:
|
||||
|
||||
add the `blacklist snd_bcm2835` to the end of the file.
|
||||
|
||||
### Hardware PWM
|
||||
|
||||
Hardware PWM is required in order to drive higher frequency signals, such as the 25000 Hz needed by Noctua PWM fans. The rpi-hardware-pwm module is used as a lightweight alternative to pigpio. Install the required library: `sudo pip install rpi-hardware-pwm`
|
||||
|
||||
Enable PWM0 (GPIO 18) by adding the following line to `/boot/config.txt`
|
||||
|
||||
```
|
||||
dtoverlay=pwm
|
||||
```
|
||||
|
||||
If you wish to use both PWM0 and PWM1 then use `dtoverlay=pwm-2chan` instead. If you wish to use the alternate PWM pin numbers, then read the [rpi-hardware-pwm module readme](https://github.com/Pioreactor/rpi_hardware_pwm) for how this can be configured.
|
||||
|
||||
After editing `boot/config.text` reboot your Raspberry Pi.
|
||||
|
||||
### GPIO
|
||||
|
||||
This release uses RPi.GPIO to control IO of raspberry pi, it should install and work automatically. If it doesn't please update your octoprint with the latest release of octopi.
|
||||
@@ -186,8 +200,8 @@ Outputs are meant to control THINGS (temperature, lights, locker, extra enclosur
|
||||
Outputs can be set to the following types:
|
||||
|
||||
* Regular GPIO
|
||||
* PWM GPIO
|
||||
* Neopixel Control via Microcontroler
|
||||
* PWM GPIO (Software or Hardware controlled PWM)
|
||||
* Neopixel Control via Microcontroller
|
||||
* Neopixel Control directly from raspberry pi
|
||||
* Temperature and Humidity Control
|
||||
* Temperature Alarm
|
||||
|
||||
@@ -55,6 +55,17 @@ def CheckInputActiveLow(Input_Pull_Resistor):
|
||||
else:
|
||||
return False
|
||||
|
||||
#Function that returns the hardware PWM channel or raises ValueError otherwise
|
||||
def Pwm_Channel(pin):
|
||||
pwm0_pins = [12, 18]
|
||||
pwm1_pins = [13, 19]
|
||||
if pin in pwm0_pins:
|
||||
return 0
|
||||
elif pin in pwm1_pins:
|
||||
return 1
|
||||
else:
|
||||
raise ValueError("Not a Hardware PWM pin")
|
||||
|
||||
class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplatePlugin, octoprint.plugin.SettingsPlugin,
|
||||
octoprint.plugin.AssetPlugin, octoprint.plugin.BlueprintPlugin,
|
||||
octoprint.plugin.EventHandlerPlugin):
|
||||
@@ -167,7 +178,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
|
||||
self.print_complete = False
|
||||
|
||||
def get_settings_version(self):
|
||||
return 10
|
||||
return 11
|
||||
|
||||
def on_settings_migrate(self, target, current=None):
|
||||
self._logger.warn("######### current settings version %s target settings version %s #########", current, target)
|
||||
@@ -175,8 +186,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
|
||||
self._logger.info("rpi_outputs: %s", self.rpi_outputs)
|
||||
self._logger.info("rpi_inputs: %s", self.rpi_inputs)
|
||||
self._logger.info("######### End Current Settings #########")
|
||||
if current >= 4 and target == 10:
|
||||
self._logger.warn("######### migrating settings to v10 #########")
|
||||
if current >= 4 and target == 11:
|
||||
self._logger.warn("######### migrating settings to v11 #########")
|
||||
old_outputs = self._settings.get(["rpi_outputs"])
|
||||
old_inputs = self._settings.get(["rpi_inputs"])
|
||||
for rpi_output in old_outputs:
|
||||
@@ -199,7 +210,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
|
||||
if 'gpio_i2c_register_status' not in rpi_output:
|
||||
rpi_output['gpio_i2c_register_status'] = 1
|
||||
if 'shutdown_on_error' not in rpi_output:
|
||||
rpi_output['shutdown_on_error'] = False
|
||||
rpi_output['shutdown_on_error'] = False
|
||||
if 'hw_pwm' not in rpi_output:
|
||||
rpi_output['hw_pwm'] = False
|
||||
self._settings.set(["rpi_outputs"], old_outputs)
|
||||
|
||||
old_inputs = self._settings.get(["rpi_inputs"])
|
||||
@@ -1546,15 +1559,27 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
|
||||
GPIO.setup(pin, GPIO.OUT, initial=initial_value)
|
||||
for gpio_out_pwm in list(filter(lambda item: item['output_type'] == 'pwm', self.rpi_outputs)):
|
||||
pin = self.to_int(gpio_out_pwm['gpio_pin'])
|
||||
self._logger.info("Setting GPIO pin %s as PWM", pin)
|
||||
pwm_freqency = self.to_int(gpio_out_pwm["pwm_frequency"])
|
||||
for pwm in (pwm_dict for pwm_dict in self.pwm_instances if pin in pwm_dict):
|
||||
self.pwm_instances.remove(pwm)
|
||||
self.clear_channel(pin)
|
||||
GPIO.setup(pin, GPIO.OUT)
|
||||
pwm_instance = GPIO.PWM(pin, self.to_int(gpio_out_pwm['pwm_frequency']))
|
||||
self._logger.info("starting PWM on pin %s", pin)
|
||||
pwm_instance.start(0)
|
||||
self.pwm_instances.append({pin: pwm_instance})
|
||||
try:
|
||||
if "hw_pwm" in gpio_out_pwm and gpio_out_pwm["hw_pwm"] is True:
|
||||
from rpi_hardware_pwm import HardwarePWM
|
||||
pwm_channel_number = Pwm_Channel(pin) # Raises valueError if not a hardware PWM pin
|
||||
self._logger.info("starting Hardware PWM on pin %i channel %i at %i Hz", pin, pwm_channel_number, pwm_freqency)
|
||||
# If RPi dtoverlay has not been configured this will throw rpi_hardware_pwm.HardwarePWMException with information on what to do.
|
||||
pwm_instance = HardwarePWM(pwm_channel=pwm_channel_number, hz=pwm_freqency)
|
||||
else:
|
||||
self._logger.info("starting PWM on pin %s at %i Hz", pin, pwm_freqency)
|
||||
GPIO.setup(pin, GPIO.OUT)
|
||||
pwm_instance = GPIO.PWM(pin, pwm_freqency)
|
||||
pwm_instance.start(0)
|
||||
self.pwm_instances.append({pin: pwm_instance})
|
||||
except ImportError as error:
|
||||
self._logger.error("HardwarePWM module not installed. Install using pip install rpi-hardware-pwm")
|
||||
except ValueError as error:
|
||||
self._logger.error("Invalid Hardware PMW pin. pwm0 is GPIO pin 18 is physical pin 12 and pwm1 is GPIO pin 19 is physical pin 13")
|
||||
for gpio_out_neopixel in list(
|
||||
filter(lambda item: item['output_type'] == 'neopixel_direct', self.rpi_outputs)):
|
||||
pin = self.to_int(gpio_out_neopixel['gpio_pin'])
|
||||
|
||||
@@ -380,6 +380,7 @@ $(function () {
|
||||
gpio_status: ko.observable(false),
|
||||
hide_btn_ui: ko.observable(false),
|
||||
active_low: ko.observable(true),
|
||||
hw_pwm: ko.observable(false),
|
||||
pwm_temperature_linked: ko.observable(false),
|
||||
toggle_timer: ko.observable(false),
|
||||
toggle_timer_on: ko.observable(0),
|
||||
|
||||
@@ -110,6 +110,21 @@
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "pwm" ) -->
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: hw_pwm"> {{ _('Use Hardware PWM') }}
|
||||
</label>
|
||||
<span class="help-inline">
|
||||
<span class="label label-important">Attention</span> You need to install and configure the rpi-hardware-pwm module to utilise the hardware PWM on the Pi, check
|
||||
the documentation on the plugin
|
||||
<a href=" https://github.com/vitormhenrique/OctoPrint-Enclosure">github</a> page. Note: Hardware PWM is only available on GPIO 18 (PWM0) and GPIO 19 (PWM1).</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "pwm" ) -->
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
|
||||
Reference in New Issue
Block a user