From 9a293641b9abf9e4fca34f46a2de781f50847da9 Mon Sep 17 00:00:00 2001 From: "Westergreen, Dalon" Date: Wed, 29 Mar 2017 15:41:36 -0700 Subject: Initial commit of de10-nano recipes Please note that this is purely for development. Only superficial efforts have been made to resolve security concerns, and it should be noted that the board ships with an EMPTY ROOT PASSWORD and support for root login via ssh. This allows passwordless access to the board via ssh. recipes-bsp/u-boot: Contains the uboot 2017.03rc2 recipe and patches to support the de10-nano board recipes-connectivity/avahi: bbappend to remove unwanted packages recipes-connectivity/bluez: bbappend to add --compat to the bluetooth service to support legacy SDP APIs recipes-connectivity/openssh: bbappend to add a custom sshd_config recipes-core/base-files: bbappend to customize fstab and inputrc recipes-core/imagemagick: bbappend to change build configuration for the de10-nano board recipes-core/packagegroups: bbappend to remove an unwanted package recipes-core/webkit: bbappend to remove support for opengl recipes-demo: Various demo applications recipes-devtools: MRAA and UPM recipes recipes-images/angstrom/de10-nano-image.bb: DE10-Nano image definition recipes-kernel/de10-nano-linux-firmware: FPGA related firmware required for fpga configuration and devicetree overlay support recipes-kernel/linux: bbappend to customize configuration of linux kernel as well as patch in the de10-nano devicetree recipes-misc: various initialization and systemd scripts recipes-qt/qt5: bbappend to modify qt build options recipes-support/neon: bbappend to remove unwanted package recipes-support/upower: bbappend to remove unwanted package recipes-webserver: webserver configuration and webcontent for board hostedweb portal recipes-xfce/thunar-volman: bbappend to remove unwanted package recipes-xfce/xfce-pointers: add configuration so that xfce does not use the adxl input as a mouse recipes-xfce/xfce4-settings: bbappend to remove unwanted package Signed-off-by: Westergreen, Dalon --- .../de10-nano-gpio-apps/de10-nano-gpio-apps.bb | 84 +++++ recipes-demo/de10-nano-gpio-apps/files/LICENSE | 22 ++ .../de10-nano-gpio-apps/files/README_first.txt | 31 ++ .../de10-nano-gpio-apps/files/README_gpio-keys.txt | 232 +++++++++++++ .../de10-nano-gpio-apps/files/README_gpio-leds.txt | 182 +++++++++++ .../de10-nano-gpio-apps/files/README_gpio.txt | 358 +++++++++++++++++++++ .../files/build_poll_KEY0_pb_state.sh | 22 ++ .../files/build_show_KEY0_pb_state.sh | 22 ++ .../files/build_toggle_fpga_leds.sh | 22 ++ .../files/build_watch_switch_events.sh | 22 ++ .../files/build_watch_switch_events_ioctl.sh | 22 ++ .../files/find_gpio_controllers_dt.src | 27 ++ .../files/find_gpio_keys_dt.src | 36 +++ .../files/find_gpio_leds_dt.src | 34 ++ .../de10-nano-gpio-apps/files/poll_KEY0_pb_state.c | 221 +++++++++++++ .../de10-nano-gpio-apps/files/show_KEY0_pb_state.c | 186 +++++++++++ .../files/show_KEY0_pb_state.sh | 24 ++ .../de10-nano-gpio-apps/files/toggle_fpga_leds.c | 133 ++++++++ .../de10-nano-gpio-apps/files/toggle_fpga_leds.sh | 28 ++ .../files/watch_switch_events.c | 60 ++++ .../files/watch_switch_events.sh | 47 +++ .../files/watch_switch_events_ioctl.c | 74 +++++ 22 files changed, 1889 insertions(+) create mode 100644 recipes-demo/de10-nano-gpio-apps/de10-nano-gpio-apps.bb create mode 100644 recipes-demo/de10-nano-gpio-apps/files/LICENSE create mode 100644 recipes-demo/de10-nano-gpio-apps/files/README_first.txt create mode 100644 recipes-demo/de10-nano-gpio-apps/files/README_gpio-keys.txt create mode 100644 recipes-demo/de10-nano-gpio-apps/files/README_gpio-leds.txt create mode 100644 recipes-demo/de10-nano-gpio-apps/files/README_gpio.txt create mode 100755 recipes-demo/de10-nano-gpio-apps/files/build_poll_KEY0_pb_state.sh create mode 100755 recipes-demo/de10-nano-gpio-apps/files/build_show_KEY0_pb_state.sh create mode 100755 recipes-demo/de10-nano-gpio-apps/files/build_toggle_fpga_leds.sh create mode 100755 recipes-demo/de10-nano-gpio-apps/files/build_watch_switch_events.sh create mode 100755 recipes-demo/de10-nano-gpio-apps/files/build_watch_switch_events_ioctl.sh create mode 100644 recipes-demo/de10-nano-gpio-apps/files/find_gpio_controllers_dt.src create mode 100644 recipes-demo/de10-nano-gpio-apps/files/find_gpio_keys_dt.src create mode 100644 recipes-demo/de10-nano-gpio-apps/files/find_gpio_leds_dt.src create mode 100644 recipes-demo/de10-nano-gpio-apps/files/poll_KEY0_pb_state.c create mode 100644 recipes-demo/de10-nano-gpio-apps/files/show_KEY0_pb_state.c create mode 100755 recipes-demo/de10-nano-gpio-apps/files/show_KEY0_pb_state.sh create mode 100644 recipes-demo/de10-nano-gpio-apps/files/toggle_fpga_leds.c create mode 100755 recipes-demo/de10-nano-gpio-apps/files/toggle_fpga_leds.sh create mode 100644 recipes-demo/de10-nano-gpio-apps/files/watch_switch_events.c create mode 100755 recipes-demo/de10-nano-gpio-apps/files/watch_switch_events.sh create mode 100644 recipes-demo/de10-nano-gpio-apps/files/watch_switch_events_ioctl.c (limited to 'recipes-demo/de10-nano-gpio-apps') diff --git a/recipes-demo/de10-nano-gpio-apps/de10-nano-gpio-apps.bb b/recipes-demo/de10-nano-gpio-apps/de10-nano-gpio-apps.bb new file mode 100644 index 0000000..aee2942 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/de10-nano-gpio-apps.bb @@ -0,0 +1,84 @@ +SUMMARY = "Example applications for DE-Nano FPGA GPIO manipulation" +SECTION = "DE10-Nano" +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://LICENSE;md5=d252b8b27e3e6ea89c9c6912b3c4373d" + +PACKAGE_ARCH = "${MACHINE_ARCH}" + +PR = "r0" +PV = "1.0" +PV_append = "+${PR}" + +SRC_URI = "\ + file://build_poll_KEY0_pb_state.sh \ + file://build_show_KEY0_pb_state.sh \ + file://build_toggle_fpga_leds.sh \ + file://build_watch_switch_events_ioctl.sh \ + file://build_watch_switch_events.sh \ + file://LICENSE \ + file://poll_KEY0_pb_state.c \ + file://README_first.txt \ + file://README_gpio-keys.txt \ + file://README_gpio-leds.txt \ + file://README_gpio.txt \ + file://show_KEY0_pb_state.c \ + file://show_KEY0_pb_state.sh \ + file://toggle_fpga_leds.c \ + file://toggle_fpga_leds.sh \ + file://watch_switch_events.c \ + file://watch_switch_events_ioctl.c \ + file://watch_switch_events.sh \ + file://find_gpio_controllers_dt.src \ + file://find_gpio_leds_dt.src \ + file://find_gpio_keys_dt.src \ +" +TOP_FILES = "LICENSE" +TOP_FILES += "README_first.txt" + +RAW_GPIO_FILES = "build_poll_KEY0_pb_state.sh" +RAW_GPIO_FILES += "build_show_KEY0_pb_state.sh" +RAW_GPIO_FILES += "poll_KEY0_pb_state.c" +RAW_GPIO_FILES += "README_gpio.txt" +RAW_GPIO_FILES += "show_KEY0_pb_state.c" +RAW_GPIO_FILES += "show_KEY0_pb_state.sh" +RAW_GPIO_FILES += "find_gpio_controllers_dt.src" + +GPIO_LEDS_FILES = "build_toggle_fpga_leds.sh" +GPIO_LEDS_FILES += "README_gpio-leds.txt" +GPIO_LEDS_FILES += "toggle_fpga_leds.c" +GPIO_LEDS_FILES += "toggle_fpga_leds.sh" +GPIO_LEDS_FILES += "find_gpio_leds_dt.src" + +GPIO_KEYS_FILES = "build_watch_switch_events_ioctl.sh" +GPIO_KEYS_FILES += "build_watch_switch_events.sh" +GPIO_KEYS_FILES += "README_gpio-keys.txt" +GPIO_KEYS_FILES += "watch_switch_events.c" +GPIO_KEYS_FILES += "watch_switch_events_ioctl.c" +GPIO_KEYS_FILES += "watch_switch_events.sh" +GPIO_KEYS_FILES += "find_gpio_keys_dt.src" + +S = "${WORKDIR}" + +do_install () { + + cd ${S} + + install -d ${D}/examples/gpio/sandbox + cp -a ${TOP_FILES} ${D}/examples/gpio/sandbox + + install -d ${D}/examples/gpio/sandbox/raw-gpio + cp -a ${RAW_GPIO_FILES} ${D}/examples/gpio/sandbox/raw-gpio + + install -d ${D}/examples/gpio/sandbox/gpio-leds + cp -a ${GPIO_LEDS_FILES} ${D}/examples/gpio/sandbox/gpio-leds + + install -d ${D}/examples/gpio/sandbox/gpio-keys + cp -a ${GPIO_KEYS_FILES} ${D}/examples/gpio/sandbox/gpio-keys + + rm -f gpio_sandbox.tgz + tar czf gpio_sandbox.tgz -C ${D}/examples/gpio sandbox + cp -a gpio_sandbox.tgz ${D}/examples/gpio +} + +FILES_${PN} += "examples/gpio/" + diff --git a/recipes-demo/de10-nano-gpio-apps/files/LICENSE b/recipes-demo/de10-nano-gpio-apps/files/LICENSE new file mode 100644 index 0000000..ab84792 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) +Copyright (c) 2016 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + diff --git a/recipes-demo/de10-nano-gpio-apps/files/README_first.txt b/recipes-demo/de10-nano-gpio-apps/files/README_first.txt new file mode 100644 index 0000000..fd26d84 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/README_first.txt @@ -0,0 +1,31 @@ +This directory contains three different example directories that contain +documentation and examples for interacting with the GPIO resources on the Altas +board. + +raw-gpio - contains a README file that describes how to discover and interact + with the gpio framework provided by the linux environment on the + DE10-Nano target. There is a script and two C programs that + demonstrate how to programmatically detect the state of the KEY0 push + button on the DE10-Nano board. The script and one C program simply + read the state, output it and exit, the second C program enables the + interrupt functionality for the GPIO and waits for the push button + press to generate the interrupt that it waits for. + +gpio-keys - contains a README file that describes how to discover and interact + with the gpio-keys framework provided by the linux environment on + the DE10-Nano target. There is a script and two C programs that + demonstrate how to programmatically detect the input events + generated by the SW0, SW1, SW2 and SW3 switches on the DE10-Nano + board. The script and one C program simply report the input events + as they are detected, the second C program adds a call to the + ioctl() function to read the current state of all four switches as + each input event is processed. + +gpio-leds - contains a README file that describes how to discover and interact + with the gpio-leds framework provided by the linux environment on + the DE10-Nano target. There is a script and a C program that + demonstrate how to programmatically control the LEDS on the + DE10-Nano board. + +Please see the README files in each sub directory for more information. + diff --git a/recipes-demo/de10-nano-gpio-apps/files/README_gpio-keys.txt b/recipes-demo/de10-nano-gpio-apps/files/README_gpio-keys.txt new file mode 100644 index 0000000..d5b0ac2 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/README_gpio-keys.txt @@ -0,0 +1,232 @@ +This readme describes the linux kernel gpio-keys framework as it deploys on the +DE10-Nano target environment. You may find the following references useful for +more information on this topic as well. + +/Documentation/gpio/gpio.txt +/Documentation/gpio/sysfs.txt +/Documentation/input/input.txt +/Documentation/input/event-codes.txt +/Documentation/input/input-programming.txt +/Documentation/devicetree/bindings/gpio/gpio.txt +/Documentation/devicetree/bindings/input/gpio-keys.txt +/Documentation/devicetree/bindings/input/gpio-keys-polled.txt + +If you cut and paste the following function into a console running on the +DE10-Nano target you can extract the useful information contained in the run +time devicetree maintained by the kernel in the procfs. + +################################################################################ +# find gpio-keys in device tree +################################################################################ +function find_gpio_keys_dt () +{ + for NEXT in $(find -L /proc/device-tree -name "compatible" | sort); + do + cat ${NEXT} | grep -xz "gpio-keys" > /dev/null && { + KEYS_DIRNAME="$(dirname ${NEXT})"; + KEYS_COMPATIBLE="$(cat ${KEYS_DIRNAME}/compatible)"; + echo "${KEYS_DIRNAME}"; + echo -e "\tcompatible = '${KEYS_COMPATIBLE}'"; + for NEXT_KEY in $(find -L "${KEYS_DIRNAME}" -name "gpios" | sort); + do + NEXT_KEY_DIR="$(dirname ${NEXT_KEY})"; + echo "${NEXT_KEY_DIR}"; + KEYS_GPIOS="$(hexdump -v -e '"0x" 4/1 "%02x" " "' "${NEXT_KEY}")"; + CONTROLLER_PHANDLE_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 1); + GPIO_BIT_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 2); + INVERTED_FLAG_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 3); + printf " gpios = ('%d', '%d', '%d') : ('%s', '%s', '%s')\n" "${CONTROLLER_PHANDLE_HEX}" "${GPIO_BIT_HEX}" "${INVERTED_FLAG_HEX}" "controller" "bit" "flag"; + KEYS_CODE="$(hexdump -v -e '"0x" 4/1 "%02x"' "${NEXT_KEY_DIR}/linux,code")"; + printf " code = '%d'\n" "${KEYS_CODE}"; + GPIO_CONTROLLER="unknown"; + CONTROLLER_PHANDLE_DEC="$(printf "%d" "${CONTROLLER_PHANDLE_HEX}")"; + for NEXT in $(find -L /proc/device-tree -name "phandle" | sort); + do + PHANDLE_HEX="$(hexdump -v -e '"0x" 4/1 "%02x"' "${NEXT}")"; + PHANDLE_DEC="$(printf "%d" "${PHANDLE_HEX}")"; + [ "${PHANDLE_DEC}" -eq "${CONTROLLER_PHANDLE_DEC}" ] && { + GPIO_CONTROLLER="$(dirname ${NEXT})" + }; + done; + printf " controller = '%s'\n" "${GPIO_CONTROLLER}"; + done + }; + done +} +################################################################################ + +The function above is provided in the file 'find_gpio_keys_dt.src', which you +can source into your environment by running 'source find_gpio_keys_dt.src'. + +When we run the function above on the DE10-Nano target it searches for nodes +containing the 'compatible' string 'gpio-keys', there should be only one node +located. The function then prints the path to the node that it found and +extracts the 'gpios' binding and the 'linux,code' binding for each key node and +prints these statistics. + +root@DE10-Nano:~# find_gpio_keys_dt +/proc/device-tree/soc/keys + compatible = 'gpio-keys' +/proc/device-tree/soc/keys/sw0 + gpios = ('50', '0', '1') : ('controller', 'bit', 'flag') + code = '64' + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000' +/proc/device-tree/soc/keys/sw1 + gpios = ('50', '1', '1') : ('controller', 'bit', 'flag') + code = '65' + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000' +/proc/device-tree/soc/keys/sw2 + gpios = ('50', '2', '1') : ('controller', 'bit', 'flag') + code = '66' + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000' +/proc/device-tree/soc/keys/sw3 + gpios = ('50', '3', '1') : ('controller', 'bit', 'flag') + code = '67' + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000' +root@DE10-Nano:~# + +For more information on the gpio controllers framework, please read the +README_gpio.txt document. The 'gpio@0x100004000' controller identified above +maps to the 'dipsw_pio' controller that provides a 4-bit input, fpga based gpio, +registered as 'gpio-keys' in the device tree to be used in the gpio-keys +framework to receive input events from switches SW0-SW3 on the DE10-Nano board. + +The gpio-keys framework will register an input event device that will post input +events when the gpios above change their state. The 'code' associated with each +gpio above will be encoded in the input event message along with the state of +the switch. We can see the input device in the devfs like this: + +root@DE10-Nano:~# ls -lR /dev/input +/dev/input: +total 0 +drwxr-xr-x 2 root root 80 Jul 9 16:25 by-path +crw-rw---- 1 root input 13, 64 Jan 1 1970 event0 +crw-rw---- 1 root input 13, 65 Jul 9 16:25 event1 +crw-rw---- 1 root input 13, 63 Jan 1 1970 mice +crw-rw---- 1 root input 13, 32 Jan 1 1970 mouse0 + +/dev/input/by-path: +total 0 +lrwxrwxrwx 1 root root 9 Jan 1 1970 platform-ffc04000.i2c-event -> ../event0 +lrwxrwxrwx 1 root root 9 Jul 9 16:25 platform-soc:base-fpga-region:keys-event -> ../event1 + +In this case the event1 device is the device for our gpio-keys input, we can +tell this from the '/dev/input/by-path' links that have more descriptive names. + +The sysfs also describes the input device environment for us in a useful way. + +root@DE10-Nano:~# ls -l /sys/class/input/ +total 0 +lrwxrwxrwx 1 root root 0 Jan 1 1970 event0 -> ../../devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0/event0 +lrwxrwxrwx 1 root root 0 Jul 14 19:17 event1 -> ../../devices/platform/soc/soc:keys/input/input1/event1 +lrwxrwxrwx 1 root root 0 Jan 1 1970 input0 -> ../../devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0 +lrwxrwxrwx 1 root root 0 Jul 14 19:17 input1 -> ../../devices/platform/soc/soc:keys/input/input1 +lrwxrwxrwx 1 root root 0 Jan 1 1970 mice -> ../../devices/virtual/input/mice +lrwxrwxrwx 1 root root 0 Jan 1 1970 mouse0 -> ../../devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0/mouse0 + +And from the above we can see that the 'soc:keys' device exists in the sysfs. + +root@DE10-Nano:~# ls /sys/devices/platform/soc/soc:keys +disabled_keys driver_override modalias switches +disabled_switches input power uevent +driver keys subsystem +root@DE10-Nano:~# ls /sys/devices/platform/soc/soc:keys/input +input1 +root@DE10-Nano:~# ls /sys/devices/platform/soc/soc:keys/input/input1 +capabilities event1 modalias phys properties uevent +device id name power subsystem uniq +root@DE10-Nano:~# ls /sys/devices/platform/soc/soc:keys/input/input1/event1 +dev device power subsystem uevent +root@DE10-Nano:~# cat /sys/devices/platform/soc/soc:keys/input/input1/name +soc:keys +root@DE10-Nano:~# cat /sys/devices/platform/soc/soc:keys/input/input1/event1/dev +13:65 +root@DE10-Nano:~# ls -l /dev/input/event1 +crw-rw---- 1 root input 13, 65 Jul 9 16:25 /dev/input/event1 + +So now that we know what our input event device is, we can simply read from it +to capture the input events as they arrive. The device will block until the +next event message is received. We can do this like so: + +root@DE10-Nano:~# hexdump -C /dev/input/event1 +00000000 ca 61 a5 55 a4 44 08 00 01 00 40 00 00 00 00 00 |.a.U.D....@.....| +00000010 ca 61 a5 55 a4 44 08 00 00 00 00 00 00 00 00 00 |.a.U.D..........| +00000020 cc 61 a5 55 24 2a 02 00 01 00 40 00 01 00 00 00 |.a.U$*....@.....| +00000030 cc 61 a5 55 24 2a 02 00 00 00 00 00 00 00 00 00 |.a.U$*..........| +00000040 cd 61 a5 55 04 a0 0b 00 01 00 41 00 00 00 00 00 |.a.U......A.....| +00000050 cd 61 a5 55 04 a0 0b 00 00 00 00 00 00 00 00 00 |.a.U............| +00000060 cf 61 a5 55 bf 21 06 00 01 00 41 00 01 00 00 00 |.a.U.!....A.....| +00000070 cf 61 a5 55 bf 21 06 00 00 00 00 00 00 00 00 00 |.a.U.!..........| +00000080 d1 61 a5 55 7c 14 03 00 01 00 42 00 00 00 00 00 |.a.U|.....B.....| +00000090 d1 61 a5 55 7c 14 03 00 00 00 00 00 00 00 00 00 |.a.U|...........| +000000a0 d2 61 a5 55 22 2a 02 00 01 00 42 00 01 00 00 00 |.a.U"*....B.....| +000000b0 d2 61 a5 55 22 2a 02 00 00 00 00 00 00 00 00 00 |.a.U"*..........| +000000c0 d4 61 a5 55 8d ac 05 00 01 00 43 00 00 00 00 00 |.a.U......C.....| +000000d0 d4 61 a5 55 8d ac 05 00 00 00 00 00 00 00 00 00 |.a.U............| +000000e0 d7 61 a5 55 8c ac 05 00 01 00 43 00 01 00 00 00 |.a.U......C.....| +000000f0 d7 61 a5 55 8c ac 05 00 00 00 00 00 00 00 00 00 |.a.U............| +^C + +The output above results after we start hexdump reading from the input event1 +device, and then we toggle SW0 on and off, then we toggle SW1 on and off, then +we toggle SW2 on and off, and then we toggle SW3 on and off. In 16 byte event +messages that appear above, we can see the first 4 bytes that represent the +second of the event, followed by the next 4 bytes that represent the millisecond +of the event, followed by the next 2 bytes that represent the event type, +followed by the next 2 bytes that represent the event code, followed by the +last 4 bytes that represent the event value. So we can see the first line 0x00 +is an EV_KEY event for SW0 with code 0x40 and value 0. Then line 0x10 is an +EV_SYN event, followed by line 0x20 which is the next EV_KEY event for SW0 with +code 0x40 and value 1. Then line 0x30 is another EV_SYN event. This pattern +repeats itself for the SW1 events with code 0x41, then the SW2 events with code +0x42 and finally the SW3 events with code 0xx43. + +-------------------------------------------------------------------------------- +Example programs and scripts +-------------------------------------------------------------------------------- +This directory contains a few examples to demonstrate how to interact with the +switches on the DE10-Nano board that have been registered in the gpio-keys +framework. There is a shell script called 'watch_switch_events.sh' and a C +program called 'watch_switch_events.c'. Each of these examples monitor the FPGA +gpio-keys input event in exactly the same way. Then there is a C program called +'watch_switch_events_ioctl.c' which simply adds an ioctl() call to the +'watch_switch_events.c' program so that it can detect the current state of all +the switches, which can only be accomplished with the ioctl() call. + +To build the 'watch_switch_events.c' application simply run the +'build_watch_switch_events.sh' shell script. That will compile the +'watch_switch_events.c' source file and produce the executable +'watch_switch_events' application. Refer to the 'build_watch_switch_events.sh' +script to see how the application is actually compiled and refer to the C +program source file for more details on how it actually works. + +To build the 'watch_switch_events_ioctl.c' application simply run the +'build_watch_switch_events_ioctl.sh' shell script. That will compile the +'watch_switch_events_ioctl.c' source file and produce the executable +'watch_switch_events_ioctl' application. Refer to the +'build_watch_switch_events_ioctl.sh' script to see how the application is +actually compiled and refer to the C program source file for more details on how +it actually works. + +Refer to the 'watch_switch_events.sh' source file for more details on how it +actually works. + +Once you've built the applications, you can run both the script and the +applications like this: + +./watch_switch_events.sh <<< to run the script +./watch_switch_events <<< to run the program +./watch_switch_events_ioctl <<< to run the program with ioctl() + +The programs and script will monitor the input events for the gpio-keys device +registered in the system. To generate an input event slide the switches SW0, +SW1, SW2 and SW3 on the DE10-Nano board. As you slide the switches you will see +the programs and script print out the input events that they receive from the +system. The ioctl version of the program will additionally print out the +current state of all the switches at each input event as well. To terminate the +script or programs just type CTRL-C on the console that you launched them from. + +Both the programs and the script monitor the switches by interacting with the +input event device node provided by the gpio-keys framework which leverages the +linux gpio controller framework. + diff --git a/recipes-demo/de10-nano-gpio-apps/files/README_gpio-leds.txt b/recipes-demo/de10-nano-gpio-apps/files/README_gpio-leds.txt new file mode 100644 index 0000000..21cc5dc --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/README_gpio-leds.txt @@ -0,0 +1,182 @@ +This readme describes the linux kernel gpio-leds framework as it deploys on the +DE10-Nano target environment. You may find the following references useful for +more information on this topic as well. + +/Documentation/leds/leds-class.txt +/Documentation/devicetree/bindings/leds/common.txt +/Documentation/devicetree/bindings/leds/leds-gpio.txt + +If you cut and paste the following function into a console running on the +DE10-Nano target you can extract the useful information contained in the run +time devicetree maintained by the kernel in the procfs. + +################################################################################ +# find gpio-leds in device tree +################################################################################ +function find_gpio_leds_dt () +{ + for NEXT in $(find -L /proc/device-tree -name "compatible" | sort); + do + cat ${NEXT} | grep -xz "gpio-leds" > /dev/null && { + LEDS_DIRNAME="$(dirname ${NEXT})"; + LEDS_COMPATIBLE="$(cat ${LEDS_DIRNAME}/compatible)"; + echo "${LEDS_DIRNAME}"; + echo -e "\tcompatible = '${LEDS_COMPATIBLE}'"; + for NEXT_LED in $(find -L "${LEDS_DIRNAME}" -name "gpios" | sort); + do + NEXT_LED_DIR="$(dirname ${NEXT_LED})"; + echo "${NEXT_LED_DIR}"; + LEDS_GPIOS="$(hexdump -v -e '"0x" 4/1 "%02x" " "' "${NEXT_LED}")"; + CONTROLLER_PHANDLE_HEX=$(echo ${LEDS_GPIOS} | cut -d ' ' -f 1); + GPIO_BIT_HEX=$(echo ${LEDS_GPIOS} | cut -d ' ' -f 2); + INVERTED_FLAG_HEX=$(echo ${LEDS_GPIOS} | cut -d ' ' -f 3); + printf " gpios = ('%d', '%d', '%d') : ('%s', '%s', '%s')\n" "${CONTROLLER_PHANDLE_HEX}" "${GPIO_BIT_HEX}" "${INVERTED_FLAG_HEX}" "controller" "bit" "flag"; + GPIO_CONTROLLER="unknown"; + CONTROLLER_PHANDLE_DEC="$(printf "%d" "${CONTROLLER_PHANDLE_HEX}")"; + for NEXT in $(find -L /proc/device-tree -name "phandle" | sort); + do + PHANDLE_HEX="$(hexdump -v -e '"0x" 4/1 "%02x"' "${NEXT}")"; + PHANDLE_DEC="$(printf "%d" "${PHANDLE_HEX}")"; + [ "${PHANDLE_DEC}" -eq "${CONTROLLER_PHANDLE_DEC}" ] && { + GPIO_CONTROLLER="$(dirname ${NEXT})" + }; + done; + printf " controller = '%s'\n" "${GPIO_CONTROLLER}"; + done + }; + done +} +################################################################################ + +The function above is provided in the file 'find_gpio_leds_dt.src', which you +can source into your environment by running 'source find_gpio_leds_dt.src'. + +When we run the function above on the DE10-Nano target it searches for nodes +containing the 'compatible' string 'gpio-leds', there should be only one node +located. The function then prints the path to the node that it found and +extracts the 'gpios' binding for each led node and prints these statistics. + +root@DE10-Nano:~# find_gpio_leds_dt +/proc/device-tree/leds + compatible = 'gpio-leds' +/proc/device-tree/leds/hps0 + gpios = ('51', '24', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/gpio@ff709000/gpio-controller@0' +/proc/device-tree/soc/leds + compatible = 'gpio-leds' +/proc/device-tree/soc/leds/fpga0 + gpios = ('49', '0', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000' +/proc/device-tree/soc/leds/fpga1 + gpios = ('49', '1', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000' +/proc/device-tree/soc/leds/fpga2 + gpios = ('49', '2', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000' +/proc/device-tree/soc/leds/fpga3 + gpios = ('49', '3', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000' +/proc/device-tree/soc/leds/fpga4 + gpios = ('49', '4', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000' +/proc/device-tree/soc/leds/fpga5 + gpios = ('49', '5', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000' +/proc/device-tree/soc/leds/fpga6 + gpios = ('49', '6', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000' +/proc/device-tree/soc/leds/fpga7 + gpios = ('49', '7', '0') : ('controller', 'bit', 'flag') + controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000' + +For more information on the gpio controllers framework, please read the +README_gpio.txt document. The 'gpio@0x100003000' controller identified above +maps to the 'led_pio' controller that provides an 8-bit output, fpga based gpio, +registered as 'gpio-leds' in the device tree to be used in the gpio-leds +framework to drive LED0-LED7 on the DE10-Nano board. The 'gpio@ff709000' +controller identified above maps to the 'gpio1' controller that provides a +29-bit, hps based gpio controller, the HPS GPIO53 port served by this controller +is registered as 'gpio-leds' in the device tree to be used in the gpio-leds +framework to drive the USERLED on the Altas board. + +The gpio-led framework will register sysfs entries for each led port, and +provide files that we can use to control and query the state of the leds. If we +look at the sysfs led class directory like this: + +root@DE10-Nano:~# ls /sys/class/leds/ +fpga_led0 fpga_led2 fpga_led4 fpga_led6 hps_led0 +fpga_led1 fpga_led3 fpga_led5 fpga_led7 + +We see all the led entries that the gpio-leds framework has registered for us. +Each of these directories contain the following format: + +root@DE10-Nano:~# ls /sys/class/leds/fpga_led0 +brightness max_brightness subsystem uevent +device power trigger +root@DE10-Nano:~# ls /sys/class/leds/hps_led0 +brightness max_brightness subsystem uevent +device power trigger + +There are two files in these entries that are particularly useful to us, the +'trigger' file and the 'brightness' file. The 'trigger' file identifies what +automatic triggers get applied to the led port, by default the 'hps_led0' port +is assigned to be triggered as 'heartbeat' and if we examine the 'trigger' file +we should see that: + +root@DE10-Nano:~# cat /sys/class/leds/hps_led0/trigger +none nand-disk mmc0 timer oneshot [heartbeat] backlight gpio cpu0 cpu1 default-on + +If we look at any of the 'fpga_led*' entiries we should see no trigger applied +to them; + +root@DE10-Nano:~# cat /sys/class/leds/fpga_led0/trigger +[none] nand-disk mmc0 timer oneshot heartbeat backlight gpio cpu0 cpu1 default-on + +The 'brightness' file allows us to turn the led on or off and query the state of +the led. Like this + +root@DE10-Nano:~# cat /sys/class/leds/fpga_led0/brightness +0 + +The 'fpga_led0' port is currently off, so if we set this port to anything but +zero, we will turn that led on, like this: + +root@DE10-Nano:~# echo 1 > /sys/class/leds/fpga_led0/brightness +root@DE10-Nano:~# cat /sys/class/leds/fpga_led0/brightness +1 + +Now the 'fpga_led0' port is on, if we sest this port back to zero the we will +turn that led off, like this: + +root@DE10-Nano:~# echo 0 > /sys/class/leds/fpga_led0/brightness +root@DE10-Nano:~# cat /sys/class/leds/fpga_led0/brightness +0 + +-------------------------------------------------------------------------------- +Example programs and scripts +-------------------------------------------------------------------------------- +This directory contains a few examples to demonstrate how to control the LEDs on +the DE10-Nano board. There is a shell script called 'toggle_fpga_leds.sh' and a C +program called 'toggle_fpga_leds.c'. Each of these examples toggle the FPGA +LEDs in exactly the same way. + +To build the 'toggle_fpga_leds' application simply run the +'build_toggle_fpga_leds.sh' shell script. That will compile the +'toggle_fpga_leds.c' source file and produce the executable 'toggle_fpga_leds' +application. Refer to the 'build_toggle_fpga_leds.sh' script to see how the +application is actually compiled and refer to the C program source file and the +shell script source file for more details on how they actually work. + +Once you've built the application, you can run both the script and the +application like this: + +./toggle_fpga_leds.sh <<< to run the script +./toggle_fpga_leds <<< to run the program + +The program and script will exit automatically after they sequentially turn each +led on and then off. + +Both the program and the script manipulate the LEDs by interacting with the +sysfs file entries provided by the linux gpio-led framework which leverages the +linux gpio controller framework. + diff --git a/recipes-demo/de10-nano-gpio-apps/files/README_gpio.txt b/recipes-demo/de10-nano-gpio-apps/files/README_gpio.txt new file mode 100644 index 0000000..ba0b0f4 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/README_gpio.txt @@ -0,0 +1,358 @@ +This readme describes the linux kernel gpio framework as it deploys on the +DE10-Nano target environment. You may find the following references useful for +more information on this topic as well. + +/Documentation/gpio/gpio.txt +/Documentation/gpio/sysfs.txt +/Documentation/devicetree/bindings/gpio/gpio.txt +/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt +/Documentation/devicetree/bindings/gpio/gpio-altera.txt + +If you cut and paste the following function into a console running on the +DE10-Nano target you can extract the useful information contained in the run +time devicetree maintained by the kernel in the procfs. + +################################################################################ +# find gpio controllers in device tree +################################################################################ +function find_gpio_controllers_dt () +{ + for NEXT in $(find -L /proc/device-tree -name "compatible" | sort); + do + cat ${NEXT} | grep -xz "snps,dw-apb-gpio" > /dev/null && { + GPIO_DIRNAME="$(dirname ${NEXT})"; + echo ${GPIO_DIRNAME}; + GPIO_COMPATIBLE="$(cat ${GPIO_DIRNAME}/compatible)"; + echo -e "\tcompatible = '${GPIO_COMPATIBLE}'"; + WF="${GPIO_DIRNAME}/gpio-controller@0/snps,nr-gpios"; + GPIO_HEX_WIDTH="$(hexdump -v -e '"0x"' -e '4/1 "%02x"' "${WF}")"; + GPIO_WIDTH=$(printf "%d" ${GPIO_HEX_WIDTH}); + echo -e "\t width = '${GPIO_WIDTH}'" + }; + cat ${NEXT} | grep -e "altr,pio" > /dev/null && { + GPIO_DIRNAME="$(dirname ${NEXT})"; + echo ${GPIO_DIRNAME}; + GPIO_COMPATIBLE="$(cat ${GPIO_DIRNAME}/compatible)"; + echo -e "\tcompatible = '${GPIO_COMPATIBLE}'"; + WF="${GPIO_DIRNAME}/altr,gpio-bank-width"; + GPIO_HEX_WIDTH="$(hexdump -v -e '"0x"' -e '4/1 "%02x"' "${WF}")"; + GPIO_WIDTH=$(printf "%d" ${GPIO_HEX_WIDTH}); + echo -e "\t width = '${GPIO_WIDTH}'" + }; + done +} +################################################################################ + +The function above is provided in the file 'find_gpio_controllers_dt.src', which +you can source into your environment by running +'source find_gpio_controllers_dt.src'. + +When we run the function above on the DE10-Nano target it searches for nodes +containing the 'compatible' string fragments of 'snps,dw-apb-gpio' or 'altr,pio' +which are the identifiers for the hard GPIO controllers and the soft GPIO +controllers, respectively, in our system. The function then prints the path to +the node that it found and extracts the compatible string and width of the gpio +controller and prints those statistics out as well. It does this for all gpio +controller nodes that it locates in the device tree. + +root@DE10-Nano:~# find_gpio_controllers_dt +/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100003000 + compatible = 'altr,pio-15.0altr,pio-1.0' + width = '8' +/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000 + compatible = 'altr,pio-15.0altr,pio-1.0' + width = '4' +/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100005000 + compatible = 'altr,pio-15.0altr,pio-1.0' + width = '2' +/proc/device-tree/soc/gpio@ff708000 + compatible = 'snps,dw-apb-gpio' + width = '29' +/proc/device-tree/soc/gpio@ff709000 + compatible = 'snps,dw-apb-gpio' + width = '29' +/proc/device-tree/soc/gpio@ff70a000 + compatible = 'snps,dw-apb-gpio' + width = '27' + +Now the run time binary device tree blob does not contain some of the useful +labels that were used in the original DTS source files that can help us +understand what gpio controllers belong to what functions on the board. These +fragments out of the original DTS source file contain the labels which show +the functions of the various gpio controllers a little better: + +led_pio: gpio@0x100003000 { +}; +dipsw_pio: gpio@0x100004000 { +}; +button_pio: gpio@0x100005000 { +}; +gpio@ff708000 { + gpio0: gpio-controller@0 { + }; +}; +gpio@ff709000 { + gpio1: gpio-controller@0 { + }; +}; +gpio@ff70a000 { + gpio2: gpio-controller@0 { + }; +}; + +This is how these gpio controllers are implemented on the DE10-Nano target: + +led_pio - 8-bit output, fpga based gpio, registered as 'gpio-leds' in the device + tree to be used in the gpio-leds framework to drive LED0-LED7 on the + DE10-Nano board. + +dipsw_pio - 4-bit input, fpga based gpio, registered as 'gpio-keys' in the + device tree to be used in the gpio-keys framework to receive input + events from switches SW0-SW3 on the DE10-Nano board. + +button_pio - 2-bit input, fpga based gpio, receives input from push buttons + KEY0 and KEY1 on the DE10-Nano board. + +gpio0 - 29-bit, hps based gpio controller, no interfaces connected to these pins + on the Altas board. + +gpio1 - 29-bit, hps based gpio controller, the HPS GPIO53 port served by this + controller is registered as 'gpio-leds' in the device tree to be used in + the gpio-leds framework to drive the USERLED on the Altas board. The + HPS GPIO54 port served by this controller receives input from push + button KEY2 on the DE10-Nano board. + +gpio2 - 27-bit, hps based gpio controller, no interfaces connected to these pins + on the DE10-Nano board. + +The kernel gpio framework creates some sysfs entries for all the gpio +controllers that we can interact with to gain access to and manipulate the gpio +ports that we are interested in. These sysfs entries are located in +'/sys/class/gpio', like this: + +root@DE10-Nano:~# ls /sys/class/gpio +export gpiochip415 gpiochip427 gpiochip483 +gpiochip413 gpiochip419 gpiochip454 unexport + +Each of the gpio controllers is represented by a gpiochip* entry in the display +above. To determine which gpiochip* entry corresponds to which gpio controller +we can run a loop like this to discover them: + +for NEXT in $(find /sys/class/gpio/ -name "gpiochip*" | sort) +do +echo ${NEXT} = $(cat ${NEXT}/label) +done + +/sys/class/gpio/gpiochip413 = /soc/bridge@0xc0000000/gpio@0x100005000 +/sys/class/gpio/gpiochip415 = /soc/bridge@0xc0000000/gpio@0x100004000 +/sys/class/gpio/gpiochip419 = /soc/bridge@0xc0000000/gpio@0x100003000 +/sys/class/gpio/gpiochip427 = ff70a000.gpio +/sys/class/gpio/gpiochip454 = ff709000.gpio +/sys/class/gpio/gpiochip483 = ff708000.gpio + +You should be able to correlate the string from the 'label' file with the output +that we saw from the device tree entries. We can also extract the width of each +gpio controller from the sysfs entries like this: + +for NEXT in $(find /sys/class/gpio/ -name "gpiochip*" | sort) +do +echo ${NEXT} = $(cat ${NEXT}/ngpio) +done + +/sys/class/gpio/gpiochip413 = 2 +/sys/class/gpio/gpiochip415 = 4 +/sys/class/gpio/gpiochip419 = 8 +/sys/class/gpio/gpiochip427 = 27 +/sys/class/gpio/gpiochip454 = 29 +/sys/class/gpio/gpiochip483 = 29 + +These widths should correlate to what was reported out of the device tree. + +Now if we want to work with a raw gpio we can use the gpio framework to do so. +There are a few raw gpios on the DE10-Nano system that we can demonstrate. We +cannot demonstrate any interaction with the gpios that were registered with the +gpio-leds or gpio-keys framework since those frameworks are in control of those +gpio ports, but those are demonstrated in their own specific readme files. + +Let's try to read the state of the 'button_pio' ports that are controlled by the +'gpio@0x100005000' controller which maps into 'gpiochip157' for the 2-bits that +are connected to the KEY0 and KEY1 push buttons. To being we 'export' the two +gpio ports that we're interested in like this: + +root@DE10-Nano:~# echo 413 > /sys/class/gpio/export +root@DE10-Nano:~# echo 414 > /sys/class/gpio/export + +And now you can see that we have two new entires in the sysfs, each representing +the individual gpio port that we exported. + +root@DE10-Nano:~# ls /sys/class/gpio +export gpio414 gpiochip415 gpiochip427 gpiochip483 +gpio413 gpiochip413 gpiochip419 gpiochip454 unexport + +Each of these individual gpio directories contain the following files: + +root@DE10-Nano:~# ls /sys/class/gpio/gpio413 +active_low direction edge power subsystem uevent value +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/active_low +0 +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/direction +in +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/edge +none +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/value +1 + +We can see from above that this port is defined as an active high input with no +edge detection interrupt currently enabled and the value of the port is +currently 1. Reading the 'value' sysfs file will always return the live state +of this gpio port. If we read the 'value' file a few times as we press and +release the KEY0 push button we can see the live state change: + +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/value +1 +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/value +0 +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/value +1 +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/value +0 +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/value +1 + +Now if we write the phrase 'falling' into the 'edge' file then the edge capture +interrupt functionality will be enabled for this gpio: + +root@DE10-Nano:~# echo falling > /sys/class/gpio/gpio413/edge +root@DE10-Nano:~# cat /sys/class/gpio/gpio413/edge +falling + +At this point two things occur, if we could call poll() or select() against the +file descriptor for the 'value' file, it would block until the interrupt fired, +if we simply read() the 'value' file then we will continue to see the live state +of the port. The second thing that we can observe is that the +'/proc/interrupts' file shows our newly active IRQ for this PIO that has been +registered: + +root@DE10-Nano:~# cat /proc/interrupts | grep 144 +144: 1 0 altera-gpio 0 gpiolib + +If we press and release the KEY0 push button a few times we should see the +interrupt count increase. + +root@DE10-Nano:~# cat /proc/interrupts | grep 144 +144: 5 0 altera-gpio 0 gpiolib + +Now the gpio414 that we exported for the KEY1 push button will operate the same +way. If we press and release KEY1 while we monitor the 'value' file for gpio414 +we should see the same behavior appear: + +root@DE10-Nano:~# cat /sys/class/gpio/gpio414/value +1 +root@DE10-Nano:~# cat /sys/class/gpio/gpio414/value +0 +root@DE10-Nano:~# cat /sys/class/gpio/gpio414/value +1 +root@DE10-Nano:~# cat /sys/class/gpio/gpio414/value +0 + +There is one other raw gpio on the DE10-Nano board that we could interact with, +it's the KEY2 push button connected to the HPS GPIO54 input which comes in +through the gpio1 controller that is assigned to gpiochip198. To export this +gpio port we calculate it's position in gpio1 by using this equation: + +root@DE10-Nano:~# expr 454 + 54 - 29 +479 + ^ ^ ^ + | | | + | | +--- the number of HPS GPIO ports in gpio0 + | +-------- the HPS GPIO we want + +-------------- the base gpio in gpiochip454 + +So we want to export gpio 479 to gain access to this port, like this: + +root@DE10-Nano:~# echo 479 > /sys/class/gpio/export +root@DE10-Nano:~# ls /sys/class/gpio/ +export gpio414 gpiochip413 gpiochip419 gpiochip454 unexport +gpio413 gpio479 gpiochip415 gpiochip427 gpiochip483 + +And we see the gpio479 file in the sysfs now. We can interact with this gpio +the same way that we did the others: + +root@DE10-Nano:~# cat /sys/class/gpio/gpio479/value +1 +root@DE10-Nano:~# cat /sys/class/gpio/gpio479/value +0 +root@DE10-Nano:~# cat /sys/class/gpio/gpio479/value +1 + +And if we enable interrupts for this port like we did on the other port: + +root@DE10-Nano:~# echo falling > /sys/class/gpio/gpio479/edge +root@DE10-Nano:~# cat /sys/class/gpio/gpio479/edge +falling + +Then we see this gpio controller appear in the '/proc/interrupts' listing: + +root@DE10-Nano:~# cat /proc/interrupts | grep 116 +116: 0 0 gpio-dwapb 3 0-0053 + +When we are done using these gpio ports that we have exported into user space we +can 'unexport' them by passing the same values into the 'unexport' sysfs file +that we used to export the ports originally: + +root@DE10-Nano:~# echo 413 > /sys/class/gpio/unexport +root@DE10-Nano:~# echo 414 > /sys/class/gpio/unexport +root@DE10-Nano:~# echo 479 > /sys/class/gpio/unexport +root@DE10-Nano:~# ls /sys/class/gpio +export gpiochip415 gpiochip427 gpiochip483 +gpiochip413 gpiochip419 gpiochip454 unexport + +And we can see that the exported entries have been removed from the sysfs. + +-------------------------------------------------------------------------------- +Example programs and scripts +-------------------------------------------------------------------------------- +This directory contains a few examples to demonstrate how to interact with the +push buttons on the DE10-Nano board that have been registered in the gpio +framework. There is a shell script called 'show_KEY0_pb_state.sh' and a C +program called 'show_KEY0_pb_state.c'. Each of these examples query the gpio +state in exactly the same way. Then there is a C program called +'poll_KEY0_pb_state.c' which simply adds a poll() call to the +'show_KEY0_pb_state.sh' program to demonstrate the interrupt functionality +provided by the gpio framework to detect the push button press via a hardware +interrupt, which can only be accomplished with the poll() or select() type of +system call. + +To build the 'show_KEY0_pb_state.c' application simply run the +'build_show_KEY0_pb_state.sh' shell script. That will compile the +'show_KEY0_pb_state.c' source file and produce the executable +'show_KEY0_pb_state' application. Refer to the 'build_show_KEY0_pb_state.sh' +script to see how the application is actually compiled and refer to the C +program source file for more details on how it actually works. + +To build the 'poll_KEY0_pb_state.c' application simply run the +'build_poll_KEY0_pb_state.sh' shell script. That will compile the +'poll_KEY0_pb_state.c' source file and produce the executable +'poll_KEY0_pb_state' application. Refer to the 'build_poll_KEY0_pb_state.sh' +script to see how the application is actually compiled and refer to the C +program source file for more details on how it actually works. + +Refer to the 'show_KEY0_pb_state.sh' source file for more details on how it +actually works. + +Once you've built the applications, you can run both the script and the +applications like this: + +./show_KEY0_pb_state.sh <<< to run the script +./show_KEY0_pb_state <<< to run the program +./poll_KEY0_pb_state <<< to run the program with poll() + +The 'show' program and script will read the current state of the KEY0 push +button input and print it out, and then exit. The 'poll' program will enable +the KEY0 push button to generate a falling edge interrupt when it is pressed and +then ask you to press the KEY0 push button. When the 'poll' program detects the +interrupt event it prints that status out and exits. + +Both the programs and the script monitor the push buttons by interacting with +the linux gpio controller framework. + diff --git a/recipes-demo/de10-nano-gpio-apps/files/build_poll_KEY0_pb_state.sh b/recipes-demo/de10-nano-gpio-apps/files/build_poll_KEY0_pb_state.sh new file mode 100755 index 0000000..eeb792e --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/build_poll_KEY0_pb_state.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +gcc \ + -march=armv7-a \ + -mfloat-abi=hard \ + -mfpu=vfp3 \ + -mthumb-interwork \ + -mthumb \ + -O2 \ + -g \ + -feliminate-unused-debug-types \ + -std=gnu99 \ + -W \ + -Wall \ + -Werror \ + -Wc++-compat \ + -Wwrite-strings \ + -Wstrict-prototypes \ + -pedantic \ + -o poll_KEY0_pb_state \ + poll_KEY0_pb_state.c + diff --git a/recipes-demo/de10-nano-gpio-apps/files/build_show_KEY0_pb_state.sh b/recipes-demo/de10-nano-gpio-apps/files/build_show_KEY0_pb_state.sh new file mode 100755 index 0000000..5d222cf --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/build_show_KEY0_pb_state.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +gcc \ + -march=armv7-a \ + -mfloat-abi=hard \ + -mfpu=vfp3 \ + -mthumb-interwork \ + -mthumb \ + -O2 \ + -g \ + -feliminate-unused-debug-types \ + -std=gnu99 \ + -W \ + -Wall \ + -Werror \ + -Wc++-compat \ + -Wwrite-strings \ + -Wstrict-prototypes \ + -pedantic \ + -o show_KEY0_pb_state \ + show_KEY0_pb_state.c + diff --git a/recipes-demo/de10-nano-gpio-apps/files/build_toggle_fpga_leds.sh b/recipes-demo/de10-nano-gpio-apps/files/build_toggle_fpga_leds.sh new file mode 100755 index 0000000..8980aba --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/build_toggle_fpga_leds.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +gcc \ + -march=armv7-a \ + -mfloat-abi=hard \ + -mfpu=vfp3 \ + -mthumb-interwork \ + -mthumb \ + -O2 \ + -g \ + -feliminate-unused-debug-types \ + -std=gnu99 \ + -W \ + -Wall \ + -Werror \ + -Wc++-compat \ + -Wwrite-strings \ + -Wstrict-prototypes \ + -pedantic \ + -o toggle_fpga_leds \ + toggle_fpga_leds.c + diff --git a/recipes-demo/de10-nano-gpio-apps/files/build_watch_switch_events.sh b/recipes-demo/de10-nano-gpio-apps/files/build_watch_switch_events.sh new file mode 100755 index 0000000..57cb588 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/build_watch_switch_events.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +gcc \ + -march=armv7-a \ + -mfloat-abi=hard \ + -mfpu=vfp3 \ + -mthumb-interwork \ + -mthumb \ + -O2 \ + -g \ + -feliminate-unused-debug-types \ + -std=gnu99 \ + -W \ + -Wall \ + -Werror \ + -Wc++-compat \ + -Wwrite-strings \ + -Wstrict-prototypes \ + -pedantic \ + -o watch_switch_events \ + watch_switch_events.c + diff --git a/recipes-demo/de10-nano-gpio-apps/files/build_watch_switch_events_ioctl.sh b/recipes-demo/de10-nano-gpio-apps/files/build_watch_switch_events_ioctl.sh new file mode 100755 index 0000000..d615926 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/build_watch_switch_events_ioctl.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +gcc \ + -march=armv7-a \ + -mfloat-abi=hard \ + -mfpu=vfp3 \ + -mthumb-interwork \ + -mthumb \ + -O2 \ + -g \ + -feliminate-unused-debug-types \ + -std=gnu99 \ + -W \ + -Wall \ + -Werror \ + -Wc++-compat \ + -Wwrite-strings \ + -Wstrict-prototypes \ + -pedantic \ + -o watch_switch_events_ioctl \ + watch_switch_events_ioctl.c + diff --git a/recipes-demo/de10-nano-gpio-apps/files/find_gpio_controllers_dt.src b/recipes-demo/de10-nano-gpio-apps/files/find_gpio_controllers_dt.src new file mode 100644 index 0000000..9fd38f8 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/find_gpio_controllers_dt.src @@ -0,0 +1,27 @@ +function find_gpio_controllers_dt () +{ + for NEXT in $(find -L /proc/device-tree -name "compatible" | sort); + do + cat ${NEXT} | grep -xz "snps,dw-apb-gpio" > /dev/null && { + GPIO_DIRNAME="$(dirname ${NEXT})"; + echo ${GPIO_DIRNAME}; + GPIO_COMPATIBLE="$(cat ${GPIO_DIRNAME}/compatible)"; + echo -e "\tcompatible = '${GPIO_COMPATIBLE}'"; + WF="${GPIO_DIRNAME}/gpio-controller@0/snps,nr-gpios"; + GPIO_HEX_WIDTH="$(hexdump -v -e '"0x"' -e '4/1 "%02x"' "${WF}")"; + GPIO_WIDTH=$(printf "%d" ${GPIO_HEX_WIDTH}); + echo -e "\t width = '${GPIO_WIDTH}'" + }; + cat ${NEXT} | grep -e "altr,pio" > /dev/null && { + GPIO_DIRNAME="$(dirname ${NEXT})"; + echo ${GPIO_DIRNAME}; + GPIO_COMPATIBLE="$(cat ${GPIO_DIRNAME}/compatible)"; + echo -e "\tcompatible = '${GPIO_COMPATIBLE}'"; + WF="${GPIO_DIRNAME}/altr,gpio-bank-width"; + GPIO_HEX_WIDTH="$(hexdump -v -e '"0x"' -e '4/1 "%02x"' "${WF}")"; + GPIO_WIDTH=$(printf "%d" ${GPIO_HEX_WIDTH}); + echo -e "\t width = '${GPIO_WIDTH}'" + }; + done +} + diff --git a/recipes-demo/de10-nano-gpio-apps/files/find_gpio_keys_dt.src b/recipes-demo/de10-nano-gpio-apps/files/find_gpio_keys_dt.src new file mode 100644 index 0000000..e5c150d --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/find_gpio_keys_dt.src @@ -0,0 +1,36 @@ +function find_gpio_keys_dt () +{ + for NEXT in $(find -L /proc/device-tree -name "compatible" | sort); + do + cat ${NEXT} | grep -xz "gpio-keys" > /dev/null && { + KEYS_DIRNAME="$(dirname ${NEXT})"; + KEYS_COMPATIBLE="$(cat ${KEYS_DIRNAME}/compatible)"; + echo "${KEYS_DIRNAME}"; + echo -e "\tcompatible = '${KEYS_COMPATIBLE}'"; + for NEXT_KEY in $(find -L "${KEYS_DIRNAME}" -name "gpios" | sort); + do + NEXT_KEY_DIR="$(dirname ${NEXT_KEY})"; + echo "${NEXT_KEY_DIR}"; + KEYS_GPIOS="$(hexdump -v -e '"0x" 4/1 "%02x" " "' "${NEXT_KEY}")"; + CONTROLLER_PHANDLE_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 1); + GPIO_BIT_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 2); + INVERTED_FLAG_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 3); + printf " gpios = ('%d', '%d', '%d') : ('%s', '%s', '%s')\n" "${CONTROLLER_PHANDLE_HEX}" "${GPIO_BIT_HEX}" "${INVERTED_FLAG_HEX}" "controller" "bit" "flag"; + KEYS_CODE="$(hexdump -v -e '"0x" 4/1 "%02x"' "${NEXT_KEY_DIR}/linux,code")"; + printf " code = '%d'\n" "${KEYS_CODE}"; + GPIO_CONTROLLER="unknown"; + CONTROLLER_PHANDLE_DEC="$(printf "%d" "${CONTROLLER_PHANDLE_HEX}")"; + for NEXT in $(find -L /proc/device-tree -name "phandle" | sort); + do + PHANDLE_HEX="$(hexdump -v -e '"0x" 4/1 "%02x"' "${NEXT}")"; + PHANDLE_DEC="$(printf "%d" "${PHANDLE_HEX}")"; + [ "${PHANDLE_DEC}" -eq "${CONTROLLER_PHANDLE_DEC}" ] && { + GPIO_CONTROLLER="$(dirname ${NEXT})" + }; + done; + printf " controller = '%s'\n" "${GPIO_CONTROLLER}"; + done + }; + done +} + diff --git a/recipes-demo/de10-nano-gpio-apps/files/find_gpio_leds_dt.src b/recipes-demo/de10-nano-gpio-apps/files/find_gpio_leds_dt.src new file mode 100644 index 0000000..37e46a2 --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/find_gpio_leds_dt.src @@ -0,0 +1,34 @@ +function find_gpio_leds_dt () +{ + for NEXT in $(find -L /proc/device-tree -name "compatible" | sort); + do + cat ${NEXT} | grep -xz "gpio-leds" > /dev/null && { + LEDS_DIRNAME="$(dirname ${NEXT})"; + LEDS_COMPATIBLE="$(cat ${LEDS_DIRNAME}/compatible)"; + echo "${LEDS_DIRNAME}"; + echo -e "\tcompatible = '${LEDS_COMPATIBLE}'"; + for NEXT_LED in $(find -L "${LEDS_DIRNAME}" -name "gpios" | sort); + do + NEXT_LED_DIR="$(dirname ${NEXT_LED})"; + echo "${NEXT_LED_DIR}"; + LEDS_GPIOS="$(hexdump -v -e '"0x" 4/1 "%02x" " "' "${NEXT_LED}")"; + CONTROLLER_PHANDLE_HEX=$(echo ${LEDS_GPIOS} | cut -d ' ' -f 1); + GPIO_BIT_HEX=$(echo ${LEDS_GPIOS} | cut -d ' ' -f 2); + INVERTED_FLAG_HEX=$(echo ${LEDS_GPIOS} | cut -d ' ' -f 3); + printf " gpios = ('%d', '%d', '%d') : ('%s', '%s', '%s')\n" "${CONTROLLER_PHANDLE_HEX}" "${GPIO_BIT_HEX}" "${INVERTED_FLAG_HEX}" "controller" "bit" "flag"; + GPIO_CONTROLLER="unknown"; + CONTROLLER_PHANDLE_DEC="$(printf "%d" "${CONTROLLER_PHANDLE_HEX}")"; + for NEXT in $(find -L /proc/device-tree -name "phandle" | sort); + do + PHANDLE_HEX="$(hexdump -v -e '"0x" 4/1 "%02x"' "${NEXT}")"; + PHANDLE_DEC="$(printf "%d" "${PHANDLE_HEX}")"; + [ "${PHANDLE_DEC}" -eq "${CONTROLLER_PHANDLE_DEC}" ] && { + GPIO_CONTROLLER="$(dirname ${NEXT})" + }; + done; + printf " controller = '%s'\n" "${GPIO_CONTROLLER}"; + done + }; + done +} + diff --git a/recipes-demo/de10-nano-gpio-apps/files/poll_KEY0_pb_state.c b/recipes-demo/de10-nano-gpio-apps/files/poll_KEY0_pb_state.c new file mode 100644 index 0000000..f0c253f --- /dev/null +++ b/recipes-demo/de10-nano-gpio-apps/files/poll_KEY0_pb_state.c @@ -0,0 +1,221 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(void) { + DIR *gpio_dir; + const char *gpio_dir_path = "/sys/class/gpio"; + const char *gpiochip_str = "gpiochip"; + const char *gpio_label = "gpio@0x100005000"; + size_t gpiochip_str_len = strlen(gpiochip_str); + int result; + struct dirent *dir_entry; + char path[PATH_MAX]; + int path_length; + int file_fd; + char buffer[PATH_MAX+1] = {0}; + char gpio_number_buffer[PATH_MAX+1] = {0}; + char *str_result = NULL; + char *newline_ptr; + struct pollfd pollfd_struct; + + // open the sysfs gpio directory + gpio_dir = opendir(gpio_dir_path); + if(gpio_dir == NULL) + error(1, errno, "could not open directory '%s'", gpio_dir_path); + + // find the gpio controller for the KEY0 push button 'gpio@0x100005000' + while(1) { + // read the next directory entry + errno = 0; + dir_entry = readdir(gpio_dir); + if(dir_entry == NULL) { + if(errno != 0) + error(1, errno, "reading directory '%s'", + gpio_dir_path); + else + break; + } + + // check if this is a gpio controller entry + result = strncmp(dir_entry->d_name, gpiochip_str, + gpiochip_str_len); + if(result != 0) + continue; + + // open the gpio controller label file and read label value + path_length = snprintf(path, PATH_MAX, "%s/%s/label", + gpio_dir_path, dir_entry->d_name); + if(path_length < 0) + error(1, 0, "path output error"); + if(path_length >= PATH_MAX) + error(1, 0, "path length overflow"); + + file_fd = open(path, O_RDONLY | O_SYNC); + if(file_fd < 0) + error(1, errno, "could not open file '%s'", path); + + result = read(file_fd, buffer, PATH_MAX); + if(result < 0) + error(1, errno, "reading from '%s'", path); + if(result == PATH_MAX) + error(1, errno, "buffer overflow reading '%s'", path); + + result = close(file_fd); + if(result < 0) + error(1, errno, "could not close file '%s'", path); + + buffer[PATH_MAX] = 0; + // test the gpio controller label value for our gpio controller + str_result = strstr(buffer, gpio_label); + if(str_result != NULL) + break; + } + + if(str_result == NULL) + error(1, 0, "unable to locate gpio controller"); + + // open the gpio controller base file and read base value + path_length = snprintf(path, PATH_MAX, "%s/%s/base", + gpio_dir_path, dir_entry->d_name); + if(path_length < 0) + error(1, 0, "path output error"); + if(path_length >= PATH_MAX) + error(1, 0, "path length overflow"); + + file_fd = open(path, O_RDONLY | O_SYNC); + if(file_fd < 0) + error(1, errno, "could not open file '%s'", path); + + result = read(file_fd, gpio_number_buffer, PATH_MAX); + if(result < 0) + error(1, errno, "reading from '%s'", path); + if(result == PATH_MAX) + error(1, errno, "buffer overflow reading '%s'", path); + + result = close(file_fd); + if(result < 0) + error(1, errno, "could not close file '%s'", path); + + gpio_number_buffer[PATH_MAX] = 0; + + // remove the newline at the end of the string + newline_ptr = strchr(gpio_number_buffer,'\n'); + if(newline_ptr != NULL) + memset(newline_ptr, '\0', 1); + + // open the gpio export file and write our gpio number + path_length = snprintf(path, PATH_MAX, "%s/export", + gpio_dir_path); + if(path_length < 0) + error(1, 0, "path output error"); + if(path_length >= PATH_MAX) + error(1, 0, "path length overflow"); + + file_fd = open(path, O_WRONLY | O_SYNC); + if(file_fd < 0) + error(1, errno, "could not open file '%s'", path); + + result = write(file_fd, gpio_number_buffer, strlen(gpio_number_buffer)); + // NOTE: we don't bother checking for errors here because if this gpio + // has already been exported this write will receive a device busy error + // which is perfectly normal. + + result = close(file_fd); + if(result < 0) + error(1, errno, "could not close file '%s'", path); + + // open the gpio edge file and write 'falling' to it + path_length = snprintf(path, PATH_MAX, "%s/gpio%s/edge", + gpio_dir_path, gpio_number_buffer); + if(path_length < 0) + error(1, 0, "path output error"); + if(path_length >= PATH_MAX) + error(1, 0, "path length overflow"); + + file_fd = open(path, O_WRONLY | O_SYNC); + if(file_fd < 0) + error(1, errno, "could not open file '%s'", path); + + result = write(file_fd, "falling", 7); + if(result < 0) + error(1, errno, "writing to '%s'", path); + if(result != 7) + error(1, errno, "buffer underflow writing '%s'", path); + + result = close(file_fd); + if(result < 0) + error(1, errno, "could not close file '%s'", path); + + // open the gpio value file and poll the file + path_length = snprintf(path, PATH_MAX, "%s/gpio%s/value", + gpio_dir_path, gpio_number_buffer); + if(path_length < 0) + error(1, 0, "path output error"); + if(path_length >= PATH_MAX) + error(1, 0, "path length overflow"); + + file_fd = open(path, O_RDONLY | O_SYNC); + if(file_fd < 0) + error(1, errno, "could not open file '%s'", path); + + // we first need to read the file before we can poll it, otherwise poll + // will not block + result = read(file_fd, buffer, PATH_MAX); + if