Difference between revisions of "EBC Exercise 11 gpio Polling and Interrupts"

From eLinux.org
Jump to: navigation, search
m (Modify gpio-int-test.c)
m
 
(13 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
[[Category:EmbeddedBeagleClass]]
 
[[Category:EmbeddedBeagleClass]]
 
[[Category:ECE497]]
 
[[Category:ECE497]]
 +
{{YoderHead}}
  
In the previous exercise ([[EBC Exercise 02 Flashing an LED]]) we saw how to interact with the general purpose I/O pins via the command shell and the sysfs files.  These are rather easy ways to work with gpio; however they tend to be slow and require a lot of the CPU.  In this exercise we explore using sysfs via C.  We also see how using interrupts can greatly reduce the CPU usage and increase our max output speed.
+
In the previous exercise ([[EBC Exercise 10 Flashing an LED]]) we saw how to interact with the general purpose I/O pins via the command shell and the sysfs files.  These are rather easy ways to work with gpio; however they tend to be slow and require a lot of the CPU.  In this exercise we explore using sysfs via C.  We also see how using interrupts can greatly reduce the CPU usage and increase our max output speed.
  
 
== <span style="color:green">gpio via C and sysfs </span>==
 
== <span style="color:green">gpio via C and sysfs </span>==
  
Since <code>/sys/class/gpio/gpio130/value</code> is just a file, we can read and write it from a C program just as easily as from the shell.  [http://www.avrfreaks.net/wiki/index.php/Documentation:Linux/GPIO#Example_of_GPIO_access_from_within_a_C_program Here] is a nice example of how it's done. I've cleaned it up a bit and put a copy called '''togglegpio.c''' [http://www.rose-hulman.edu/~yoder/Beagle/exercises/ here]. Get a copy and look it over.  It's presently hardwired to use gpio130.  Later you will get to make it work with any port.
+
Since <code>/sys/class/gpio/gpio60/value</code> is just a file, we can read and write it from a C program just as easily as from the shell.  [http://www.avrfreaks.net/wiki/index.php/Documentation:Linux/GPIO#Example_of_GPIO_access_from_within_a_C_program Example of GPIO access from within a C program] is a nice example of how it's done, but the page is gone. I've cleaned it up a bit and put a copy called '''togglegpio.c''' in '''exercises/gpio'''. If your git repository is set up just:
 +
beagle$ '''cd exercises'''
 +
beagle$ '''git pull'''
 +
beagle$ '''cd gpio'''
 +
beagle$ '''gedit togglegpio.c &'''
 +
(Follow the instructions [[EBC_Exercise_05_Getting_Exercise_Support_Materials]] if you aren't set up for git.)
 +
 
 +
It's presently hardwired to use gpio130.  Later you will get to make it work with any port.
  
 
# Compile and run it.  Does the correct waveform appear on the oscilloscope?   
 
# Compile and run it.  Does the correct waveform appear on the oscilloscope?   
Line 21: Line 29:
 
A better approach is to let the OS tell you when the input has changed.  In a traditional microprocessor one would set up the input pin to interrupt the processor when its input value has changed.  We'll do something similar here.
 
A better approach is to let the OS tell you when the input has changed.  In a traditional microprocessor one would set up the input pin to interrupt the processor when its input value has changed.  We'll do something similar here.
  
The folks at [https://www.ridgerun.com/ RidgeRun] have a nice [https://www.ridgerun.com/developer/wiki/index.php/How_to_use_GPIO_signals example] of how this is done.
+
The folks at [https://www.ridgerun.com/ RidgeRun] have a nice [https://developer.ridgerun.com/wiki/index.php/How_to_use_GPIO_signals example] of how this is done.
 
 
Look over the example.  The first part should be familiar.  The new stuff starts [https://www.ridgerun.com/developer/wiki/index.php/How_to_use_GPIO_signals#GPIO_interrupts_from_user_space here]. It describes how to use the '''poll()''' command to wait until the gpio pin has changed. Your process will block (i.e. let other processes run) while poll() waits for an interupt to occur.
 
 
 
I've put a modified copy of '''gpio-int-test.c''' [http://www.rose-hulman.edu/~yoder/Beagle/exercises/ here]. Get it.  Study it. Compile and run it.  You'll need to setup an input signal.  gpio4 is the User button.  Try it.  Does the program respond correctly?
 
 
 
== Assignments ==
 
 
 
=== <span style="color:green">Modify togglegpio.c </span>===
 
  
# Modify togglegpio.c to take the gpio number.
+
Look over the example.  The first part should be familiar.  The new stuff starts [https://developer.ridgerun.com/wiki/index.php/How_to_use_GPIO_signals#GPIO_interrupts_from_user_space here]. It describes how to use the '''poll()''' command to wait until the gpio pin has changed. Your process will block (i.e. let other processes run) while poll() waits for an interupt to occur.  
# Clean things up a bit and use the structure of '''gpio-int-test.c'''.  
 
# Presently one parameter specifies both the on and off time. Modify the code so the on and off times are controlled separately.
 
# Add in interrupt handler (see gpio-int-test.c) to trap ctrl-C and close things properly.
 
# What's the highest frequency you can see on the 'scope?
 
  
===<span style="color:green"> Modify gpio-int-test.c </span>===
+
I've put a modified copy of '''gpio-int-test.c''' in '''gpio'''. Get it.  Study it. Compile and run it.  You'll need to setup an input signal.  Use the switch from a previous exercise.  It is on gpio7.  Try it.  Does the program respond correctly?
  
# Modify gpio-init-test.c to count the number of times the User button has been pressed.  Set '''edge''' to only count releases.
+
{{YoderFoot}}
# Copy gpio-init-test.c to '''gpioThru.c''' and modify it to copy the value of one port to another.  You'll have to add code to open a second gpio port for writing (check '''gpio_set_dir''').
 
# gpio 131 is attached to pin 19 of the Main Extension Header on the Beagle.  Attach a function generator to this pin.  Be sure to set the HiLevel to 1.8V and the LoLevel to 0.  Does the output track the input?
 
# What's the highest frequency the output will track the input?  What's the CPU usage?
 
# What's the delay from when the input changes to when the output changes?
 

Latest revision as of 15:17, 13 September 2020

thumb‎ Embedded Linux Class by Mark A. Yoder


In the previous exercise (EBC Exercise 10 Flashing an LED) we saw how to interact with the general purpose I/O pins via the command shell and the sysfs files. These are rather easy ways to work with gpio; however they tend to be slow and require a lot of the CPU. In this exercise we explore using sysfs via C. We also see how using interrupts can greatly reduce the CPU usage and increase our max output speed.

gpio via C and sysfs

Since /sys/class/gpio/gpio60/value is just a file, we can read and write it from a C program just as easily as from the shell. Example of GPIO access from within a C program is a nice example of how it's done, but the page is gone. I've cleaned it up a bit and put a copy called togglegpio.c in exercises/gpio. If your git repository is set up just:

beagle$ cd exercises
beagle$ git pull
beagle$ cd gpio
beagle$ gedit togglegpio.c &

(Follow the instructions EBC_Exercise_05_Getting_Exercise_Support_Materials if you aren't set up for git.)

It's presently hardwired to use gpio130. Later you will get to make it work with any port.

  1. Compile and run it. Does the correct waveform appear on the oscilloscope?
  2. Use htop to measure the CPU usage.
  3. Try different periods. Make a chart of the input period vs. the measured period vs. CPU usage.
  4. How stable is the waveform? Look at several cycles. Are they always the same length. Explain.

This program is really interrupt based. When the usleep command is run, the process suspends until the correct time has elapsed. Other processes are allowed to run. When the time is up the CPU is interrupted and our process is allowed to continue.

gpio via Interrupts

Next we want to write some code that will read one gpio pin and copy its value to another. We could modify togglegpio.c to continually read one pin and write it to another, but that would wither be slow at responding to changes (a usleep is used between reads), or it would take all the CPU time (always reading in case a change was made).

A better approach is to let the OS tell you when the input has changed. In a traditional microprocessor one would set up the input pin to interrupt the processor when its input value has changed. We'll do something similar here.

The folks at RidgeRun have a nice example of how this is done.

Look over the example. The first part should be familiar. The new stuff starts here. It describes how to use the poll() command to wait until the gpio pin has changed. Your process will block (i.e. let other processes run) while poll() waits for an interupt to occur.

I've put a modified copy of gpio-int-test.c in gpio. Get it. Study it. Compile and run it. You'll need to setup an input signal. Use the switch from a previous exercise. It is on gpio7. Try it. Does the program respond correctly?




thumb‎ Embedded Linux Class by Mark A. Yoder