diff options
Diffstat (limited to 'recipes-demo/de10-nano-gpio-apps/files/README_gpio.txt')
-rw-r--r-- | recipes-demo/de10-nano-gpio-apps/files/README_gpio.txt | 358 |
1 files changed, 358 insertions, 0 deletions
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. + +<linux-source-tree>/Documentation/gpio/gpio.txt +<linux-source-tree>/Documentation/gpio/sysfs.txt +<linux-source-tree>/Documentation/devicetree/bindings/gpio/gpio.txt +<linux-source-tree>/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt +<linux-source-tree>/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. + |