1

On a Raspberry Pi you can set the GPIO pins as an output or an input. An output or an input can be either high or low.

For example, to monitor the input state (high or low) of GPIO pin 26 you can check the value of /sys/class/gpio/gpio26/value.

Now I want to monitor the input value of GPIO pin 26 continuesly and wrote this script.

#!/bin/bash
# return GPIO input status

# select pin
GPIO=26

# prepare the pin
if [ ! -d /sys/class/gpio/gpio${GPIO} ]; then
  echo "${GPIO}" > /sys/class/gpio/export
fi
echo "in" > /sys/class/gpio/gpio"${GPIO}"/direction

# continuously monitor current value
while true; do
  if [ 1 == "$(</sys/class/gpio/gpio"${GPIO}"/value)" ]; then
    printf "high \r"
  else
    printf "low  \r"
  fi
done

This script works as expected. My main concern is that it uses 30% CPU of one of the cores continuesly.

How can I improve this method of monitoring my GPIO pins without such a high CPU usage? Can I skip cycles? Can I use some kind of 'device event manager' or 'system call manager' like udev?

I really prefer to use Bash scripting only (I have seen some Python code that does this ;)

  • 2
    More likely it uses 30% of the total CPU availability, i.e., 100% of one core. That's a busy loop. It is almost never the appropriate solution to anything. ;) As joan says, at least put a short sleep in there. You can use a decimal value in seconds, e.g., sleep 0.05. – goldilocks Feb 20 '18 at 13:44
1

You are limited if you want to only use shell scripts and the sysfs interface to the GPIO.

All I can suggest is you add a short sleep in your script so it doesn't use as much CPU.

sleep (seconds)     CPU (%)
0.50                0.4%
0.25                1.0%
0.10                2.0%
0.07                2.5%
0.05                5.0%
0.01                7.0%
0.001              10.0%

Another easy addition would be to remember the previous GPIO state and only print a message on change.

  • 1
    printing a message on change would take the same amount of resources. The sleep might be the thing I am looking for. I was hoping for something cleaner. – CousinCocaine Feb 21 '18 at 14:01
  • Personally I would just write a few lines of C to pause until the GPIO changes level. You pays your money, you makes your choice. – joan Feb 21 '18 at 14:11
  • Can a GPIO change be captured in C without the infinit loop (=100% CPU)? Or is it the same code but than in C and an added sleep? – CousinCocaine Feb 21 '18 at 14:14
0

@Ingo I have seen some docs referenced elsewhere but I don't have a link. I was trying to solve the same problem as the OP but it seems that a simple loop continually checking the contents of the file is unfortunately the only way to achieve this in bash.

See here for a discussion of inotify limitations: https://unix.stackexchange.com/questions/90627/notify-of-changes-on-a-file-under-proc

Apparently languages that implement the select() system call can watch proc/sys but there is no bash command that does this: https://stackoverflow.com/questions/37049612/equivalent-of-select-system-call-in-bash

However I implemented the OPs loop and with a sleep of 0.1 I do not see any CPU issues so I am sticking with it.

  • Is this intended as an answer, or as a comment/follow-up to Ingo? If it's an answer, please edit it to tell specifically what that answer is. – Seamus Jul 28 '18 at 16:44
  • Have deleted my answer. You are right. It was simply wrong to use inotify on the /sys virtual filesystem. – Ingo Jul 31 '18 at 19:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.