$30
1
Lab 2
Outline
In Lab2, we will go through the following steps:
• Add external buttons to the RPi setup to expand the control functions of
video_control.py from Lab1
• Compare performance of video_test.py in lab 1 and modified versions of this
program.
• Develop general methods for checking performance of applications on the Pi with
an eye towards performance tuning.
• Develop some test programs using the PyGame and expand these programs into
control panels for video_test.py
Lab safety
We have all been in lab before and handled electronic components. Please apply all the
cautions that you have learned including the items below:
Integrated electronics are REALLY susceptible to static discharge.
• Avoid walking around while holding bare components
• Confine assembly to the grounded mats on the lab bench
• Make sure you ground yourself by staying in contact with the mat.
Personal safety
• Safety goggles are REQUIRED for soldering
Experimental Safety
• If something on your board is
• Really hot
• Smoking
• Just doesn’t look right
• Immediately unplug power
• Train yourself so that this is your first reaction – know where the power
switch/cutoff is for your experiment.
Experimental assembly
• Before adding any hardware to the system, power should be OFF
• Before powering up the equipment, please have staff check your added circuit
2
video_control.py application from Lab1
A few more buttons
In the final step of Lab 1 (step 6), you created the video_control.py to control buttons on
the piTFT. This section includes some modifications to this program.
As a first step, make sure the original program, as defined in Lab 1, is working as
designed. A short description includes the button functions:
On the piTFT:
• Pause
• Fast-forward 10 seconds
• Rewind 10 seconds
• Quit
Reference step 5 and 6 in Lab 1, week 2 for additional details.
Using the breakout cable (‘Pi-cobbler’), add two additional buttons to the RPi setup used
for playing the video on the PiTFT.
Consider which GPIO pins to use, based on what free pins are available
• Once the cable is connected to the protoboard, check that the polarity of the plug is
correct. Using a voltmeter, check that the +5 pins and several of the +3.3 pins are
in the correct locations (according to the indications on the cable header). If not, or
if you are unsure, please check in with the TA.
• Use the safe development techniques discussed in class, so as not to ‘cook’ the
GPIO pins if something goes wrong.
• Once the buttons are wired correctly;
STOP and please check with the TA to insure correct connections and GPIO
selection.
3
A photo of a setup connected correctly:
Notes:
• The white stripe on the piCobbler breakout cable is on the same side as the piTFT
buttons
• On the protoboard, you can read the pin assignments (starting from the left) 3.3,
SDA, SCL, 4, Gnd, etc….
• The photo is a bit distorted on the left edge: The red wire is connected to 3.3 V
(the pin labeled 3V3), NOT SDA
• Note that the numbering on the piCobbler corresponds to BCM numbering (for
example pin ‘26’ on the piCobbler is GPIO26)
• The above example has a single button wired into GPIO26.
• Note wire insulation used on bare resistor leads to prevent shorts (please see
the’Lab2 parts’ video on Canvas for a demonstration)
4
Some references:
3.3 Volts 3.3 Volts
5
• Stop and check your wiring with a TA. Be prepared to show the connections over
zoom.
• Once checked, power up and extend four_buttons.py to create ‘six_buttons.py’ to
make sure you can correctly read the existing four, and two new buttons
• Extend ‘video_control.py’ to create ‘more_video_control.py’ to add two new
functions to video control; fast forward 30 seconds and rewind 30 seconds
• Modify the ‘start_video’ bash script to use the new code, more_video_control.py.
Step2: interrupt callbacks
Modification of video_control.py
Once more_video_control.py is running, copy the verified file into a new file,
more_video_control_cb.py. In this code, modify the button presses to use threaded
callback interrupt routines for button presses. Note:
• Most (all) of the buttons can be modified to use callback routines
• The polling loop used in more_video_control.py will require alteration
• The quit function may be a special case.
• For each button, you will need to:
o Setup a callback routine
o Define an event that accesses the callback routine
Once this routine has been redesigned, verify that it operates correctly in a bash script,
similar to the operation of start_video from lab1. Name this new bash script
start_video_cb. Confirm that the operation of all buttons in start_video_cb is identical to
the function in the original start_video script.
Take a backup of your SD card at this point in the lab.
The backup at this point is optional.
6
Performance measurement with ‘perf’ utilities
This section explores the Linux ‘perf’ utility to measure performance of applications on
the R-Pi. We will be looking into the performance difference between polling loop and
interrupt versions of programs implemented in Python during lab.
Step1: Install Perf with the following commands:
sudo apt-get install linux-tools
Try the command:
perf –help
And it should fail. The message will tell you that your system is missing the correct
version of perf. Example:
pi@RPi-jfs9:~ $ perf --help
/usr/bin/perf: line 13: exec: perf_4.19: not found
E: linux-perf-4.19 is not installed.
This error is caused by a quirk in the perf bash script. In fact, by installing the linux
tools, perf_4.9 has been installed. We are also going to install the latest version of perf by
running:
sudo apt-get install linux-perf-4.18
Step2:
Test that the latest version of perf is operating as designed by running:
perf_4.18 --help
perf_4.18 list
perf_4.18 --version
Notes:
1. Perf is able to track a number of different hardware and software events. Take a
look at the output of ‘list’, above, to get an idea of these events perf is able to track.
2. Keep in mind that not all of these measurements are available on all platforms.
3. With perf, there is a bash shell installed in /usr/bin/perf. Run this by issuing the
command ‘perf’. What error do you see? Take a look at the bash script and see if
you can form a theory for why this fails and how you might overcome the problem.
7
Step3: Create a python file named cal_v1.py containing the following statements:
import time
time.sleep(0.2) # sleep
Step4: Run the following:
sudo perf_4.18 stat -e task-clock,context-switches,cpumigrations,page-faults,cycles,instructions python cal_v1.py
This will show the following performance statistics:
• Task-clock: program execution time in milliseconds
• Context-switches: how many times the Linux process scheduler switched control
between running processes
• cpu-migration: how many times process was moved to a different cpu (or core)
• page-faults: How many times a part of the processes virtual memory was copied to
physical memory
• cycles: how many fetch-decode-execute instruction cycles were run
• instructions: How many instructions were actually run for this process.
This test gives a baseline set of statistics for a simple python code. Record the results.
Performance measurement of video_control.py
This section includes a series of tests to begin to characterize performance of the polling
and interrupt versions of the video_control routines. Use python2 for all runs for
consistency of measurement. Plan to record results from all runs for comparison.
In order to fairly compare the polling and interrupt versions of video_control, consider
how you might need to modify the codes to perform for a fixed amount of time; that is,
all codes in the experiment should run for a fixed time of 10 seconds (for example), then
quit. The idea is to determine how much overhead may be present in the programs
associated with button control; not the functions called by the button presses but, rather,
the logic used to establish the control for the buttons.
Step1: Modify more_video_control.py to introduce fixed timing prior to the perf run.
Rename this function ‘more_video_control_perf.py’. Run the perf tools for
more_video_control_perf.py , using a perf call:
8
sudo perf_4.18 stat -e task-clock,context-switches,cpumigrations,page-faults,cycles,instructions python
more_video_contol_perf.py
In the polling loop, make sure to start with a ‘sleep’ value of 200 milliseconds
( time.sleep(0.2) ).
Step2: Modify more_video_control_cb.py to introduce a fixed run-time prior to running
the perf tool. Once modified, run the perf tools, for more_video_control_cb_perf.py
Step3: make successive runs of more_video_control_perf.py, changing polling loop times
to 20 milliseconds, 2 milliseconds, 200 microseconds, 20 microseconds, and finally, with
no sleep statement at all
Step4: Note changes to the perf measurements and deduce impacts of changes and
compare the results between successive runs of more_video_control_perf.py and with
more_video_control_cb_perf.py. Include discussion in the Lab report.
PyGame: Bounce Program
Notes for bounce program:
• Plan to implement a physical quit button (one of the piTFT buttons works
well) and a timeout for the following codes.
• remember, from the lecture examples, that you’ll need to consider the
following environment variables when running on the piTFT:
import os
os.putenv('SDL_VIDEODRIVER', 'fbcon')
os.putenv('SDL_FBDEV', '/dev/fb1')
1. On your Raspberry Pi, implement the ‘Bounce’ code in python using pygame (you
can find pygame documentation in the Canvas ‘References’ section).
2. Extend this code to include 2 balls, two_bounce.py, where each ball moves on the
screen at a different speed. Note that the two bouncing balls are designed to be
‘transparent’ to one another. That is, although a ball bounces off the ‘walls’ at the
edge of the screen, balls may pass over each other when they intersect. Design this
code to run on the monitor (or /dev/fb0).
9
3. Expand two_bounce.py to create two_collide.py, so that the balls alter their
trajectories as they collide with one another.
o There are many techniques for collision of pygame objects. Have a look at
the Pygame reference document.
o Note that you can also check the ‘Dynamics’ section in:
http://people.ece.cornell.edu/land/courses/ece4760/labs/f2016/lab3_particle_beam.html
For one suggestion on how to alter velocity after collisions. [1]
4. Implement a version of two_collide.py that runs on the piTFT screen. Design this
code to run on the piTFT screen and to exit when one of the buttons is hit.
Example of a two_bounce.py screen:
10
Backup your SD card – Important as next section has some detailed changes.
Demonstrate your work to the TA; note that all demonstrations should be on the RPi and
PiTFT. Demonstrate all Codes to the TA including:
• six_buttons.py
• more_video_control.py and modified start_video script
• more_video_control_cb.py and start_video_cb bash script
• demonstrate perf runs with modified and more_video_control_perf.py
more_video_control_cb_perf.py
• bounce.py, two_bounce.py and two_collide.py
11
Week 2:
piTFT touch control
If you haven’t done it yet, backup your SD card….
The move from wheezy to Jessie, Stretch, and Buster has disrupted the control of the
touch screen a bit. In short, some of the SDL calls are broken in later kernel version; a
fix that seems to work reverts to some wheezy functions for these calls. In order to
proceed, please issue the following commands to enable the correct operation of the
touch function of the piTFT.
The following instructions, detailed below, were created by the Raspbian user community
and ultimately included into Adafruit instructions for using the PiTFT. The following
instructions originated in the reference [3] on the Adafruit site.
Note on the following instructions: If you are cutting and pasting these instructions
using a console window, I had some issues with the ‘dash’ character, ‘-‘ and the double
quote ‘ “ ‘ character. These characters do not seem to copy correctly and will lead to
install failures in the following commands. If the entries are typed into the console
window (rather than using a cut and paste), everything works correctly.
On to the commands:
1) Enable wheezy package sources by editing the new file: sudo vim /etc/apt/sources.list.d/wheezy.list
and adding the line: deb http://legacy.raspbian.org/raspbian wheezy main
Save and close the file
Note that the above commands will create a new file.
2) Set stable as default package source (for the wheezy changes) by editing the new file: sudo vim /etc/apt/apt.conf.d/10defaultRelease
and adding the line:
APT::Default-release “stable”;
Save and close the file
Note that the above commands will create a new file.
12
3) Set the priority for libsdl from wheezy higher than the Buster package by editing the
new file: sudo vim /etc/apt/preferences.d/libsdl
and adding the lines:
Package: libsdl1.2debian
Pin: release n=buster
Pin-Priority: -10
Package:libsdl1.2debian
Pin: release n=wheezy
Pin-Priority: 900
Save and close the file
The above commands also create a new file.
You can check the state of the sdl libraries before applying the changes by running the
following:
pi@RPi-jfs9:~ $ dpkg -l *libsdl*
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-==========================-===================-============-
=================================================================
un libsdl-1.3-0 <none> <none> (no description available)
ii libsdl-image1.2:armhf 1.2.12-10+deb10u1 armhf Image loading library for
Simple DirectMedia Layer 1.2, libraries
ii libsdl-mixer1.2:armhf 1.2.12-15 armhf Mixer library for Simple
DirectMedia Layer 1.2, libraries
ii libsdl-ttf2.0-0:armhf 2.0.11-6 armhf TrueType Font library for
Simple DirectMedia Layer 1.2, libraries
un libsdl1.2 <none> <none> (no description available)
un libsdl1.2-all <none> <none> (no description available)
un libsdl1.2-esd <none> <none> (no description available)
un libsdl1.2-nas <none> <none> (no description available)
un libsdl1.2-oss <none> <none> (no description available)
ii libsdl1.2debian:armhf 1.2.15+dfsg2-4+rpt2 armhf Simple DirectMedia Layer
un libsdl1.2debian-all <none> <none> (no description available)
un libsdl1.2debian-alsa <none> <none> (no description available)
un libsdl1.2debian-esd <none> <none> (no description available)
un libsdl1.2debian-nas <none> <none> (no description available)
un libsdl1.2debian-oss <none> <none> (no description available)
un libsdl1.2debian-pulseaudio <none> <none> (no description available)
ii libsdl2-2.0-0:armhf 2.0.9+dfsg1-1+rpt1 armhf Simple DirectMedia Layer
13
4) Install the changes by running the commands: sudo apt-get update
sudo apt-get –y –-allow-downgrades install libsdl1.2debian/wheezy
Example of the second command:
pi@RPi-jfs9:~ $ sudo apt-get -y --allow-downgrades install libsdl1.2debian/wheezy
Reading package lists... Done
Building dependency tree
Reading state information... Done
Selected version '1.2.15-5' (Raspbian:7.0/oldoldstable [armhf]) for 'libsdl1.2debian'
The following additional packages will be installed:
libdirectfb-1.2-9 libts-0.0-0 tsconf
The following packages will be REMOVED:
libts-bin libts0
The following NEW packages will be installed:
libdirectfb-1.2-9 libts-0.0-0 tsconf
The following packages will be DOWNGRADED:
libsdl1.2debian
0 upgraded, 3 newly installed, 1 downgraded, 2 to remove and 35 not upgraded.
Need to get 1,342 kB of archives.
After this operation, 1,757 kB of additional disk space will be used.
Get:1 http://legacy.raspbian.org/raspbian wheezy/main armhf tsconf all 1.0-11 [13.4 kB]
Get:2 http://legacy.raspbian.org/raspbian wheezy/main armhf libts-0.0-0 armhf 1.0-11 [31.0
kB]
Get:3 http://legacy.raspbian.org/raspbian wheezy/main armhf libdirectfb-1.2-9 armhf 1.2.10.0-
5 [1,094 kB]
Get:4 http://legacy.raspbian.org/raspbian wheezy/main armhf libsdl1.2debian armhf 1.2.15-5
[203 kB]
Fetched 1,342 kB in 1s (991 kB/s)
(Reading database ... 97046 files and directories currently installed.)
Removing libts-bin (1.19-1) ...
Removing libts0:armhf (1.19-1) ...
Selecting previously unselected package tsconf.
(Reading database ... 96984 files and directories currently installed.)
Preparing to unpack .../archives/tsconf_1.0-11_all.deb ...
Unpacking tsconf (1.0-11) ...
Selecting previously unselected package libts-0.0-0:armhf.
Preparing to unpack .../libts-0.0-0_1.0-11_armhf.deb ...
Unpacking libts-0.0-0:armhf (1.0-11) ...
Selecting previously unselected package libdirectfb-1.2-9:armhf.
Preparing to unpack .../libdirectfb-1.2-9_1.2.10.0-5_armhf.deb ...
Unpacking libdirectfb-1.2-9:armhf (1.2.10.0-5) ...
dpkg: warning: downgrading libsdl1.2debian:armhf from 1.2.15+dfsg2-4+rpt2 to 1.2.15-5
Preparing to unpack .../libsdl1.2debian_1.2.15-5_armhf.deb ...
Unpacking libsdl1.2debian:armhf (1.2.15-5) over (1.2.15+dfsg2-4+rpt2) ...
Setting up tsconf (1.0-11) ...
Installing new version of config file /etc/ts.conf ...
Setting up libts-0.0-0:armhf (1.0-11) ...
Setting up libdirectfb-1.2-9:armhf (1.2.10.0-5) ...
Setting up libsdl1.2debian:armhf (1.2.15-5) ...
Processing triggers for mime-support (3.62) ...
Processing triggers for gnome-menus (3.31.4-3) ...
Processing triggers for libc-bin (2.28-10+rpi1) ...
Processing triggers for man-db (2.8.5-2) ...
Processing triggers for desktop-file-utils (0.23-4) ...
pi@RPi-jfs9:~ $
14
After the update commands have run, you can check the status of the sdl libraries:
pi@RPi-jfs9:~ $ dpkg -l *libsdl*
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-==========================-==================-============-
=================================================================
un libsdl-1.3-0 <none> <none> (no description available)
ii libsdl-image1.2:armhf 1.2.12-10+deb10u1 armhf Image loading library for
Simple DirectMedia Layer 1.2, libraries
ii libsdl-mixer1.2:armhf 1.2.12-15 armhf Mixer library for Simple
DirectMedia Layer 1.2, libraries
ii libsdl-ttf2.0-0:armhf 2.0.11-6 armhf TrueType Font library for
Simple DirectMedia Layer 1.2, libraries
un libsdl1.2 <none> <none> (no description available)
un libsdl1.2-all <none> <none> (no description available)
un libsdl1.2-esd <none> <none> (no description available)
un libsdl1.2-nas <none> <none> (no description available)
un libsdl1.2-oss <none> <none> (no description available)
ii libsdl1.2debian:armhf 1.2.15-5 armhf Simple DirectMedia Layer
un libsdl1.2debian-all <none> <none> (no description available)
un libsdl1.2debian-alsa <none> <none> (no description available)
un libsdl1.2debian-esd <none> <none> (no description available)
un libsdl1.2debian-nas <none> <none> (no description available)
un libsdl1.2debian-oss <none> <none> (no description available)
un libsdl1.2debian-pulseaudio <none> <none> (no description available)
ii libsdl2-2.0-0:armhf 2.0.9+dfsg1-1+rpt1 armhf Simple DirectMedia Layer
Compare the output of the dpkg command to the command run before the changes for
wheezy downgrade were run. Do you notice any differences in the installed libsdl
package list when comparing the before and after dpkg runs?
Once the above changes have been completed, work may proceed on using touch screen
controls. The idea for the following codes will be to use touch as a mouse click to press
on-screen buttons controlling your software. It is MUCH easier to begin this process by
displaying the small screen on the monitor, or VNC (rather than the piTFT). Using the
monitor, you will be able to observe the impact of code changes and any debug/log
information and using a console window. In addition, you can add print statements to a
running program to indicate response to events (‘pause button hit’ for example).
Control for monitor use is determined by the environment variables:
os.putenv('SDL_VIDEODRIVER', 'fbcon') # Display on piTFT
os.putenv('SDL_FBDEV', '/dev/fb1') #
os.putenv('SDL_MOUSEDRV', 'TSLIB') # Track mouse clicks on piTFT
os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')
15
If you add these into your python program, comment them out to display the on the
monitor (or VNC window) instead of on the piTFT. You will also be using:
pygame.mouse.set_visible(False)
Which will turn off the mouse cursor. When debugging on the monitor, set this to True
so you can easily use the mouse to click the on-screen buttons.
Once you have your code debugged and running on the monitor, you can switch to the
actual piTFT. Un-comment the 4 environment variable settings and set the mouse to
invisible. If you now launch from an ssh window (on your laptop) the application should
run on the piTFT. You may also be able to start the piTFT code from a console window
in startx however, there may be a Linux problem that prevents this method from working
(might be fixed in Stretch and Buster); also, this may not work using VNC
As a final test, the code should be started from the command line on the piTFT to show
the embedded operation of the application. [2] Optionally, if you do not have a USB
keyboard available, you can demonstrate this running using ssh.
• Design a python application, quit_button.py, that displays a single ‘quit’ button on the
lower edge of the screen. The program should be designed so that touching the ‘quit’
button ends the program and returns to the Linux console screen. Initially, the quit
function may be implemented by touching at any location on the screen.
For easier control while debugging all touch screen programs:
• Implement a physical ‘bail out’ button. This button may be one of the
piTFT buttons or an external button. Hitting this button should end the
program.
• Also implement a code time-out that will end the program after a given time
interval. For example, when you are first starting to develop the code, you
may want to set this timeout to 30 seconds. This time-out can be
lengthened, or eliminated, as your code stabilizes.
These methods will prevent excessive power off/power on restarts of a hung RPi
system.
16
• Expand quit_button.py into a second python application, screen_coordinates.py.
The above example shows a screenshot of some test code to display button press (you
do not need to implement the start button for this step, only the quit button)
The operation of screen_coordinates.py should be:
• Display a single quit button at the bottom of the screen
• Tapping any location on the screen still display ‘Touch at x, y’ where x, y show
the screen coordinates of the hit. Note that the screen should be updated
correctly for successive screen hits.
• Tapping the ‘quit’ button will exit the program. Note that you may need to
iterate over several runs of screen_coordinates.py to refine the coordinates of
the quit button.
• All hits should be displayed on the Linux console as well
• Plan to include a copy of 20 screen taps, ranging over the extent of the piTFT
screen, in your lab report. Think about how best to collect these data on screen
taps; what are some simple ways to save all twenty events?
• Implement a physical bail-out button, and a time-out, for this code.
17
• Design a python program ‘two_button.py’ with the following functions:
• Two, on-screen buttons are displayed ‘start’ and ‘quit’
• Hitting ‘start’ begins playback of two_collide.py
• Hitting ‘quit’ ends the program and returns to the Linux console screen.
• Hitting any other location on the screen displays screen coordinates.
• The start and quit buttons should be displayed on the screen, and operate
whenever they are displayed, during the entire time the program is running
(including while the animation is playing)
• Note that button placement should be designed so as not to interfere with video
playback.
• Implement a physical bail-out button, and a time-out, for this code.
18
• Design a python program control_two_collide.py with the following functions:
Example screenshot showing implementation of second level touch controls
• As in ‘two_button.py’, start and quit are implemented with identical functions.
Screen coordinates should be displayed if hits occur outside of start and quit
buttons. This is the ‘level 1’ menu.
• Once the animation begins to play, a second level of button controls, shown
above on the ’level 2’ menu, should be displayed including the following
buttons and associated functions:
• Pause/restart: pause a running animation. Restart a paused animation
• Faster: speed up the animation by a fixed amount
• Slower: slow the animation by a fixed amount
• Back: stop the animation and return to the ‘top’ menu screen which
implements the start and quit buttons.
• Note that button placement should not interfere with the running animation. In
particular, watch out for the placement of level 1 ‘Quit’ and level2 ‘Back’.
Also, coordinates should be detected so as to separate button function (that is,
avoid a single tap causing multiple buttons to be hit)
• Implement a physical bail-out button, and a time-out, for this code.
19
Backup your SD card.
Demonstrate all codes to the TA:
• Quit_button.py
• Screen_coordinates.py
• Two_button.py running with two_collide.py functions
• Control_two_collide.py running with two_collide.py functions
• Correct function of ‘bail out’ button for all the above codes.
IMPORTANT: Backup your SD card.
References:
[1] From ECE4760, Lab 3, Professor Bruce Land. Link suggested by Junyin Chen,
ECE5725, Fall 2016 student, Cornell MEng 2016.
[2] This section on debugging with the monitor and piTFT paraphrases a note posted by
Junyin Chen, ECE5725, Fall 2016 student, Cornell MEng 2016.
[3] Detailed instructions for running PyGame touch features on a piTFT gathered from
user forums and consolidated in a single document by Adafruit:
https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/pitft-pygame-tips