PetrSvetr
Posts: 20
Joined: Wed Mar 01, 2017 6:49 am
Location: The Czech Republic

how to trigger an action when input signal is detected

Wed Jun 07, 2017 8:49 pm

We are designing power source for RPI and we would like to be compatible to the HAT description.
The DT is kind of complex to us, but we are studying and trying to do our best to understand.
I understand how to set the GPIO output to provide signal for external watchdog for example.
https://community.nxp.com/thread/444423
viewtopic.php?f=29&t=108134

Now my question:
Is there a way to write dts code to set the GPIO input to trigger an action?
To be more specific, we would like to execute reboot or halt, when signal is detected on the input pin.

thanks for your hints
Petr

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2647
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: how to trigger an action when input signal is detected

Thu Jun 08, 2017 8:23 am

Device Tree is just a static configuration mechanism - it declares devices with enough information to allow the kernel to locate drivers for them. You can't add new functionality purely through Device Tree, but you can enable and configure existing modules in new ways.

What you need is something to actively monitor a GPIO signal and trigger a graceful shutdown when it changes to the required level. This could be done with a kernel module, but since I haven't found one you would have to write it yourself. Off the top of my head I'm not sure how you would trigger a shutdown from inside the kernel, but it shouldn't be too hard.

However, I think you will find it much easier to use a simple script - this Element14 tutorial includes a Python script that should work, along with information on how to run it automatically.

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: how to trigger an action when input signal is detected

Thu Jun 08, 2017 4:09 pm

A common pattern is to create a gpio keyboard with a power key.

This overlay creates a power button on GPIO26, which is active when pushed to gnd:

Code: Select all


/dts-v1/;
/plugin/;

/ {
	compatible = "brcm,bcm2835";

	[email protected] {
		target = <&gpio>;
		__overlay__ {
			powerbtn_pin: powerbtn_pin {
				brcm,pins = <26>;
				brcm,function = <0>; /* BCM2835_FSEL_GPIO_IN */
				brcm,pull = <2>; /* BCM2835_PUD_UP */
			};
		};
	};

	[email protected] {
		target-path = "/soc";
		__overlay__ {
			powerbtn {
				compatible = "gpio-keys";
				#address-cells = <1>;
				#size-cells = <0>;
				pinctrl-names = "default";
				pinctrl-0 = <&powerbtn_pin>;

				[email protected] {
					label = "KEY_POWER";
					linux,code = <116>;
					gpios = <&gpio 26 1>; /* GPIO_ACTIVE_LOW */
				};
			};
		};
	};
};

Test that it works:

Code: Select all

$ sudo apt install evtest
$ evtest
No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event0:      soc:powerbtn
Select the device event number [0-0]: 0
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "soc:powerbtn"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 116 (KEY_POWER)
Properties:
Testing ... (interrupt to exit)
Event: time 1496937683.446926, type 1 (EV_KEY), code 116 (KEY_POWER), value 1
Event: time 1496937683.446926, -------------- EV_SYN ------------
Event: time 1496937683.806920, type 1 (EV_KEY), code 116 (KEY_POWER), value 0
Event: time 1496937683.806920, -------------- EV_SYN ------------
systemd can be told to act on this button by tagging it:

Get ID_PATH:

Code: Select all

$ udevadm info /dev/input/event0
P: /devices/platform/soc/soc:powerbtn/input/input0/event0
N: input/event0
S: input/by-path/platform-soc:powerbtn-event
E: BACKSPACE=guess
E: DEVLINKS=/dev/input/by-path/platform-soc:powerbtn-event
E: DEVNAME=/dev/input/event0
E: DEVPATH=/devices/platform/soc/soc:powerbtn/input/input0/event0
E: ID_INPUT=1
E: ID_INPUT_KEY=1
E: ID_PATH=platform-soc:powerbtn
E: ID_PATH_TAG=platform-soc_powerbtn
E: LIBINPUT_DEVICE_GROUP=19/1/1/100:gpio-keys
E: MAJOR=13
E: MINOR=64
E: SUBSYSTEM=input
E: USEC_INITIALIZED=48119
E: XKBLAYOUT=gb
E: XKBMODEL=pc105
Create udev rule:
/etc/udev/rules.d/powerbtn.rules

Code: Select all

ACTION=="remove", GOTO="powerbtn_end"

SUBSYSTEM=="input", KERNEL=="event*", ENV{ID_PATH}=="platform-soc:powerbtn", ATTRS{keys}=="*", TAG+="power-switch" 

LABEL="powerbtn_end"
Reboot, and now it's tagged:

Code: Select all

$ udevadm info /dev/input/event0 | grep TAGS
E: TAGS=:power-switch:
Pushing the button will now result in poweroff.

See HandlePowerKey= for more info: https://www.freedesktop.org/software/sy ... .conf.html

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2647
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: how to trigger an action when input signal is detected

Thu Jun 08, 2017 4:16 pm

Thanks for the informative post, notro - that definitely counts as "sufficiently advanced technology".

PetrSvetr
Posts: 20
Joined: Wed Mar 01, 2017 6:49 am
Location: The Czech Republic

Re: how to trigger an action when input signal is detected

Thu Jun 08, 2017 5:07 pm

Wow, notro...
it is really high level reply. Thank you very much. In principle I understand, but it looks we have to study a lot!!!!

On the other hand, I am thinking how to prepare our hardware for users so the deployment on the user side is as smooth/simple as possible..
  • Empty EEPROM and navigate users how to generate eep file containing board definition (eeprom_config.txt) and device-tree and how to upload it to the EEPROM + instructions how to create /etc/udev/rules.d/powerbtn.rules?
  • EEPROM preprogrammed with above mentioned + instructions how to create /etc/udev/rules.d/powerbtn.rules?
  • Write a Python script (+ some config examples) which will execute all mentioned above and let the user to configure/run this script by himself?
  • Some other approach?

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: how to trigger an action when input signal is detected

Thu Jun 08, 2017 10:40 pm

As a customer I would want the Device Tree overlay preinstalled on the eeprom and download and run a script for the rest.
If I remove the HAT, the Pi should continue to work without error messages if possible.

PetrSvetr
Posts: 20
Joined: Wed Mar 01, 2017 6:49 am
Location: The Czech Republic

Re: how to trigger an action when input signal is detected

Sun Sep 03, 2017 8:43 am

Partial success here.
Generally my aim is to solve below described tasks using dts stored in the HAT EEPROM:
  • trigger shut-down when signal detected on GPIO input
  • feeding external watchdog by ticking on the GPIO output
  • predictably change the state of the GPIO output to signalize clean shut down using gpio-poweroff
Thanks to following excellent blog-posts I am able to solve first two tasks using modified gpio-shutdown-overlay.dts, mentioned in the first link (see my code below). I can create the binary, store it to the EEPROM, reboot and everything works as expected: GPIO 19 is ticking, grounding GPIO 13 trigger shutdown. So far so good.
The problem comes, when I try to add the definition for gpio-poweroff, as I have found in this example (see /*comented*/ code in my dts below).
When uncomment and store the binary in EEPROM, Raspberry hangs during the boot.
Photo of the printscreen here: Image

To be honest the syntax and complexity of dts is kind of difficult to me.
Your comments how to write the dts code properly will be more than welcome.

Code: Select all

// Definitions for gpio-poweroff module
/dts-v1/;
/plugin/;

// This overlay sets up an input device that generates KEY_POWER events
// when a given GPIO pin changes. It defaults to using GPIO3, which can
// also be used to wake up (start) the Rpi again after shutdown. Since
// wakeup is active-low, this defaults to active-low with a pullup
// enabled, but all of this can be changed using overlay parameters (but
// note that GPIO3 has an external pullup on at least some boards).

/ {
	compatible = "brcm,bcm2708";

	[email protected] {
		// Configure the gpio pin controller
		target = <&gpio>;
		__overlay__ {
			// Define a pinctrl state, that sets up the gpio
			// as an input with a pullup enabled. This does
			// not take effect by itself, only when referenced
			// by a "pinctrl client", as is done below. See:
			//   https://www.kernel.org/doc/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
			//   https://www.kernel.org/doc/Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt
			pin_state: shutdown_button_pins {
				brcm,pins = <13>; // gpio number
				brcm,function = <0>; // 0 = input, 1 = output
				brcm,pull = <2>; // 0 = none, 1 = pull down, 2 = pull up
			};
		};
	};
	[email protected] {
		// Add a new device to the /soc devicetree node
		target-path = "/soc";
		__overlay__ {
			shutdown_button {
				// Let the gpio-keys driver handle this device. See:
				// https://www.kernel.org/doc/Documentation/devicetree/bindings/input/gpio-keys.txt
				compatible = "gpio-keys";

				// Declare a single pinctrl state (referencing the one declared above) and name it
				// default, so it is activated automatically.
				pinctrl-names = "default";
				pinctrl-0 = <&pin_state>;

				// Enable this device
				status = "okay";

				// Define a single key, called "shutdown" that monitors the gpio and sends KEY_POWER
				// (keycode 116, see
				// https://github.com/torvalds/linux/blob/v4.12/include/uapi/linux/input-event-codes.h#L190)
				button: shutdown {
					label = "shutdown";
					linux,code = <116>; // KEY_POWER
					gpios = <&gpio 13 1>; // GPIO_ACTIVE_LOW 
				};
			};
		};
	};


	[email protected] {
        	target = <&leds>;
        	__overlay__ {
            		my_led: myled {
                		label = "MYLED";
                		gpios = <&gpio 19 0>;
                		linux,default-trigger = "timer";
			};
		};
	};



/*	[email protected] {
		target-path = "/";
		__overlay__ {
			power_ctrl: power_ctrl {
				compatible = "gpio-poweroff";
				gpios = <&gpio 26 0>;
				force;
			};
		};
	};

	[email protected] {
		target = <&gpio>;
		__overlay__ {
			power_ctrl_pins: power_ctrl_pins {
				brcm,pins = <26>;
				brcm,function = <1>; // 0 = input, 1 = output
			};
		};
	};


*/

	// This defines parameters that can be specified when loading
	// the overlay. Each foo = line specifies one parameter, named
	// foo. The rest of the specification gives properties where the
	// parameter value is inserted into (changing the values above
	// or adding new ones).
	__overrides__ {
		// Allow overriding the GPIO number.
		gpio_pin = <&button>,"gpios:4",
		           <&pin_state>,"brcm,pins:0";

		// Allow changing the internal pullup/down state. 0 = none, 1 = pulldown, 2 = pullup
		// Note that GPIO3 and GPIO2 are the I2c pins and have an external pullup (at least
                // on some boards).
		gpio_pull = <&pin_state>,"brcm,pull:0";

		// Allow setting the active_low flag. 0 = active high, 1 = active low
		active_low = <&button>,"gpios:8";
	};

};

PetrSvetr
Posts: 20
Joined: Wed Mar 01, 2017 6:49 am
Location: The Czech Republic

Re: how to trigger an action when input signal is detected

Sun Sep 03, 2017 8:46 am

link to the print-screen photo didn’t work in my previous post, here is the link again
https://goo.gl/photos/Ekiy3k6jnBZZ4HbW9

Return to “Device Tree”