From 35bbd989e4383193b8ef4cfef0b262831e611f75 Mon Sep 17 00:00:00 2001 From: Lucio Tarantino Date: Sat, 13 Jun 2020 02:32:12 +0200 Subject: [PATCH] docs: LinuxMCU doc & script (#2956) Signed-off-by: Lucio Tarantino --- config/sample-raspberry-pi.cfg | 45 ++++++++++ docs/RPi_microcontroller.md | 148 +++++++++++++++++++++++++++++++++ scripts/flash-linux.sh | 8 +- scripts/klipper-mcu-start.sh | 78 +++++++++++++++++ 4 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 config/sample-raspberry-pi.cfg create mode 100644 docs/RPi_microcontroller.md create mode 100644 scripts/klipper-mcu-start.sh diff --git a/config/sample-raspberry-pi.cfg b/config/sample-raspberry-pi.cfg new file mode 100644 index 00000000..06d612c7 --- /dev/null +++ b/config/sample-raspberry-pi.cfg @@ -0,0 +1,45 @@ +# This file contains an example configuration with RPi as secondary mcu + +# See both the example.cfg and example-extras.cfg file for a +# description of available parameters. + +# The rpi microcontroller is used as secondary. +# Typically, both the X and Y axes +# are connected to the main micro-controller. The rpi microcontroller is used +# on non time-critical functions such as enclosure sensors, additional fan or +# light sources +[mcu host] +serial: /tmp/klipper_host_mcu + +# Example1: A led strip controlled by the GPIO20 on the RPi +[output_pin caselight] +pin: host:gpio20 +# You can also write the pin in extended form by specifying +# the reference gpiochip. +#pin: host:gpiochip0/gpio20 + +[gcode_macro TOGGLE_CASELIGHT] +gcode: + SET_PIN PIN=caselight VALUE={(not printer['output_pin caselight'].value)|int} + + +# Example2: Using the i2c bus of the RPi to read a sensor +[temperature_sensor enclosure_temp] +sensor_type: HTU21D +i2c_mcu: host +i2c_bus: i2c.1 +htu21d_hold_master: False + +[gcode_macro QUERY_ENCLOSURE] +default_parameter_SENSOR: htu21d enclosure_temp +gcode: + {printer.gcode.action_respond_info( + "Temperature: %.2f C\n" + "Humidity: %.2f%%" % ( + printer[SENSOR].temperature, + printer[SENSOR].humidity))} + +# Example 3:Using a pin on another gpiochip connected to the RPi +# (in this case on an MCP23017) +[fan] +pin: host:gpiochip2/gpio7 diff --git a/docs/RPi_microcontroller.md b/docs/RPi_microcontroller.md new file mode 100644 index 00000000..63f2d3c8 --- /dev/null +++ b/docs/RPi_microcontroller.md @@ -0,0 +1,148 @@ +This document describes the process of running Klipper on a RPi +and use the same RPi as secondary mcu. + +Why use RPi as a secondary MCU? +=============================== +Often the MCUs dedicated to controlling 3D printers have a limited and +pre-configured number of exposed pins to manage the main printing +functions (thermal resistors, extruders, steppers ...). +Using the RPi where Klipper is installed as a secondary MCU gives the +possibility to directly use the GPIOs and the buses (i2c, spi) of the RPi +inside klipper without using Octoprint plugins (if used) or external +programs giving the ability to control everything within the print GCODE. + +**Warning**: If your platform is a _Beaglebone_ and you have correctly followed the installation steps, the linux mcu is already installed and configured for your system. + +Install the rc script +===================== + +If you want to use the host as a secondary MCU the klipper_mcu process must run before the klippy process. + +After installing Klipper, install the script. run: +``` +cd ~/klipper/ +sudo cp "./scripts/klipper-mcu-start.sh" /etc/init.d/klipper_mcu +sudo update-rc.d klipper_mcu defaults +``` + +Building the micro-controller code +================================== + +To compile the Klipper micro-controller code, start by configuring it +for the "Linux process": +``` +cd ~/klipper/ +make menuconfig +``` + +To build and install the new micro-controller code, run: +``` +sudo service klipper stop +make flash +sudo service klipper start +``` + +Remaining configuration +======================= + +Complete the installation by configuring Klipper secondary MCU +following the instructions in +[RasperryPi example config](../config/example-rasperry-pi.cfg) and +[Multi MCU example config](../config/example-multi-mcu.cfg). + +Optional: Identify the correct gpiochip +======================================= +On Rasperry and on many clones the pins exposed on the GPIO belong to the first gpiochip. They can therefore be used on klipper simply by referring them with the name `gpio0..n`. +However, there are cases in which the exposed pins belong to gpiochips other than the first. For example in the case of some OrangePi models or if a Port Expander is used. In these cases it is useful to use the commands to access the _Linux GPIO character device_ to verify the configuration. + +To install the _Linux GPIO character device - binary_ on a debian based distro like octopi run: +``` +sudo apt-get install gpiod +``` + +To check available gpiochip run: +``` +gpiodetect +``` + +To check the pin number and the pin availability tun: +``` +gpioinfo +``` + +The chosen pin can thus be used within the configuration as `gpiochip/gpio` where **n** is the chip number as seen by the `gpiodetect` command and **o** is the line number seen by the` gpioinfo` command. + +***Warning:*** only gpio marked as `unused` can be used. It is not possible for a _line_ to be used by multiple processes simultaneously. + +For example on a RPi 3B+ where klipper use the GPIO20 for a switch: +``` +$ gpiodetect +gpiochip0 [pinctrl-bcm2835] (54 lines) +gpiochip1 [raspberrypi-exp-gpio] (8 lines) + +$ gpioinfo +gpiochip0 - 54 lines: + line 0: unnamed unused input active-high + line 1: unnamed unused input active-high + line 2: unnamed unused input active-high + line 3: unnamed unused input active-high + line 4: unnamed unused input active-high + line 5: unnamed unused input active-high + line 6: unnamed unused input active-high + line 7: unnamed unused input active-high + line 8: unnamed unused input active-high + line 9: unnamed unused input active-high + line 10: unnamed unused input active-high + line 11: unnamed unused input active-high + line 12: unnamed unused input active-high + line 13: unnamed unused input active-high + line 14: unnamed unused input active-high + line 15: unnamed unused input active-high + line 16: unnamed unused input active-high + line 17: unnamed unused input active-high + line 18: unnamed unused input active-high + line 19: unnamed unused input active-high + line 20: unnamed "klipper" output active-high [used] + line 21: unnamed unused input active-high + line 22: unnamed unused input active-high + line 23: unnamed unused input active-high + line 24: unnamed unused input active-high + line 25: unnamed unused input active-high + line 26: unnamed unused input active-high + line 27: unnamed unused input active-high + line 28: unnamed unused input active-high + line 29: unnamed "led0" output active-high [used] + line 30: unnamed unused input active-high + line 31: unnamed unused input active-high + line 32: unnamed unused input active-high + line 33: unnamed unused input active-high + line 34: unnamed unused input active-high + line 35: unnamed unused input active-high + line 36: unnamed unused input active-high + line 37: unnamed unused input active-high + line 38: unnamed unused input active-high + line 39: unnamed unused input active-high + line 40: unnamed unused input active-high + line 41: unnamed unused input active-high + line 42: unnamed unused input active-high + line 43: unnamed unused input active-high + line 44: unnamed unused input active-high + line 45: unnamed unused input active-high + line 46: unnamed unused input active-high + line 47: unnamed unused input active-high + line 48: unnamed unused input active-high + line 49: unnamed unused input active-high + line 50: unnamed unused input active-high + line 51: unnamed unused input active-high + line 52: unnamed unused input active-high + line 53: unnamed unused input active-high +gpiochip1 - 8 lines: + line 0: unnamed unused input active-high + line 1: unnamed unused input active-high + line 2: unnamed "led1" output active-low [used] + line 3: unnamed unused input active-high + line 4: unnamed unused input active-high + line 5: unnamed unused input active-high + line 6: unnamed unused input active-high + line 7: unnamed unused input active-high +``` diff --git a/scripts/flash-linux.sh b/scripts/flash-linux.sh index ea2e3070..2da91804 100755 --- a/scripts/flash-linux.sh +++ b/scripts/flash-linux.sh @@ -15,6 +15,12 @@ sync # Restart (if system install script present) if [ -f /etc/init.d/klipper_pru ]; then - echo "Attempting host MCU restart..." + echo "Attempting host PRU restart..." service klipper_pru restart fi + +# Restart (if system install script present) +if [ -f /etc/init.d/klipper_mcu ]; then + echo "Attempting host MCU restart..." + service klipper_mcu restart +fi diff --git a/scripts/klipper-mcu-start.sh b/scripts/klipper-mcu-start.sh new file mode 100644 index 00000000..f58a6298 --- /dev/null +++ b/scripts/klipper-mcu-start.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# System startup script to start the MCU Linux firmware + +### BEGIN INIT INFO +# Provides: klipper_mcu +# Required-Start: $local_fs +# Required-Stop: +# Default-Start: 3 4 5 +# Default-Stop: 0 1 2 6 +# Short-Description: Klipper_MCU daemon +# Description: Starts the MCU for Klipper. +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +DESC="klipper_mcu startup" +NAME="klipper_mcu" +KLIPPER_HOST_MCU=/usr/local/bin/klipper_mcu +KLIPPER_HOST_ARGS="-r" +PIDFILE=/var/run/klipper_mcu.pid + +. /lib/lsb/init-functions + +mcu_host_stop() +{ + # Shutdown existing Klipper instance (if applicable). The goal is to + # put the GPIO pins in a safe state. + if [ -c /tmp/klipper_host_mcu ]; then + log_daemon_msg "Attempting to shutdown host mcu..." + set -e + ( echo "FORCE_SHUTDOWN" > /tmp/klipper_host_mcu ) 2> /dev/null || ( log_action_msg "Firmware busy! Please shutdown Klipper and then retry." && exit 1 ) + sleep 1 + ( echo "FORCE_SHUTDOWN" > /tmp/klipper_host_mcu ) 2> /dev/null || ( log_action_msg "Firmware busy! Please shutdown Klipper and then retry." && exit 1 ) + sleep 1 + set +e + fi + + log_daemon_msg "Stopping klipper host mcu" $NAME + killproc -p $PIDFILE $KLIPPER_HOST_MCU +} + +mcu_host_start() +{ + [ -x $KLIPPER_HOST_MCU ] || return + + if [ -c /tmp/klipper_host_mcu ]; then + mcu_host_stop + fi + + log_daemon_msg "Starting klipper MCU" $NAME + start-stop-daemon --start --quiet --exec $KLIPPER_HOST_MCU \ + --background --pidfile $PIDFILE --make-pidfile \ + -- $KLIPPER_HOST_ARGS + log_end_msg $? +} + +case "$1" in +start) + mcu_host_start + ;; +stop) + mcu_host_stop + ;; +restart) + $0 stop + $0 start + ;; +reload|force-reload) + log_daemon_msg "Reloading configuration not supported" $NAME + log_end_msg 1 + ;; +status) + status_of_proc -p $PIDFILE $KLIPPER_HOST_MCU $NAME && exit 0 || exit $? + ;; +*) log_action_msg "Usage: /etc/init.d/klipper_mcu {start|stop|status|restart|reload|force-reload}" + exit 2 + ;; +esac +exit 0