RASPI Manual 2020
RASPI Manual 2020
RASPI Manual 2020
Cyber-Physical Systems
Fall 2020
Prof. Dola Saha
Assistant Professor
Department of Electrical & Computer Engineering
University at Albany, SUNY
Chapter 1
This tutorial is to setup the Raspberry Pi without requirement of any keyboard, mouse or monitor. You should be able
to login to the Pi from your laptop or desktop using your home Wi-Fi.
1
If you are using Linux or OSX, you can use the following command to ssh in with X-forwarding enabled:
ssh -Y [email protected]
If you are using Windows, choose PuTTY to ssh in with the same credentials.
3. Expand the Filesystem: Use the following command: sudo raspi-config. Choose Option 7, Advanced
Options, then choose A1 Expand Filesystem. Save the changes and reboot when prompted.
4. At this point, you may choose to create a new user with unique ID and password and delete the default one, just
like you would do in a Linux system.
2
Chapter 2
(a) Red line matching positive. (b) Red line not matching positive.
The first circuit that we will work on is shown in Figure 2.3. It is the simplest circuit, where the circuit is always
connected to +3.3V line. This will keep the LED turned on until the circuit is disconnected.
Once you complete the circuit and LED is turned on, you have completed the first circuit. Congratulations!
3
(a) Schematic Diagram.
(b) Circuit on breadboard.
The steps for controlling the GPIO pin using sysfs is given below.
1. Become the Sudo user to access sysfs.
dsaha@sahaPi:˜ $ sudo su
2. Go to the GPIO folder and list the contents
root@sahaPi:/home/dsaha# cd /sys/class/gpio/
root@sahaPi:/sys/class/gpio# ls
export gpiochip0 gpiochip128 unexport
3. Export gpio 4
root@sahaPi:/sys/class/gpio# echo 4 > export
root@sahaPi:/sys/class/gpio# ls
export gpio4 gpiochip0 gpiochip504 unexport
4
4. Go to the gpio4 folder and list contents
root@sahaPi:/sys/class/gpio# cd gpio4/
root@sahaPi:/sys/class/gpio/gpio4# ls
active_low device direction edge power subsystem uevent value
5. Set direction (in or out) of pin
root@sahaPi:/sys/class/gpio/gpio4# echo out > direction
6. Set value to be 1 to turn on the LED
root@sahaPi:/sys/class/gpio/gpio4# echo 1 > value
7. Set value to be 0 to turn off the LED
root@sahaPi:/sys/class/gpio/gpio4# echo 0 > value
8. Check the status (direction and value) of the pin
root@sahaPi:/sys/class/gpio/gpio4# cat direction
out
root@sahaPi:/sys/class/gpio/gpio4# cat value
0
9. Ready to give up the control? Get out of gpio4 folder and list contents, which shows gpio4 folder
root@sahaPi:/sys/class/gpio/gpio4# cd ../
root@sahaPi:/sys/class/gpio# ls
export gpio4 gpiochip0 gpiochip128 unexport
10. Unexport gpio 4 and list contents showing removal of gpio4 folder
root@sahaPi:/sys/class/gpio# echo 4 > unexport
root@sahaPi:/sys/class/gpio# ls
export gpiochip0 gpiochip504 unexport
5
echo "The LED command that was passed is: $1"
if [ "$1" == "setup" ]; then
echo "Exporting GPIO number $1"
echo $LED_GPIO >> "/sys/class/gpio/export"
sleep 1 # to ensure gpio has been exported before next step
echo "out" >> "/sys/class/gpio/gpio$LED_GPIO/direction"
elif [ "$1" == "on" ]; then
echo "Turning the LED on"
setLED 1 # 1 is received as $1 in the setLED function
elif [ "$1" == "off" ]; then
echo "Turning the LED off"
setLED 0 # 0 is received as $1 in the setLED function
elif [ "$1" == "status" ]; then
state=$(cat "/sys/class/gpio/gpio$LED_GPIO/value")
echo "The LED state is: $state"
elif [ "$1" == "close" ]; then
echo "Unexporting GPIO number $LED_GPIO"
echo $LED_GPIO >> "/sys/class/gpio/unexport"
fi
import sys
from time import sleep
LED4_PATH = "/sys/class/gpio/gpio4/"
SYSFS_DIR = "/sys/class/gpio/"
LED_NUMBER = "4"
6
writeLED (filename="unexport", value=LED_NUMBER, path=SYSFS_DIR)
elif sys.argv[1]=="status":
print "Getting the LED state value"
fo = open( LED4_PATH + "value", "r")
print fo.read()
fo.close()
else:
print "Invalid Command!"
print "End of Python script"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
7
}
else if (strcmp(argv[1],"off")==0){
printf("Turning the LED off\n");
writeGPIO(GPIO4_PATH "value", "0");
}
else if (strcmp(argv[1],"status")==0){
FILE* fp; // see writeGPIO function above for description
char line[80], fullFilename[100];
sprintf(fullFilename, GPIO4_PATH "/value");
fp = fopen(fullFilename, "rt"); // reading text this time
while (fgets(line, 80, fp) != NULL){
printf("The state of the LED is %s", line);
}
fclose(fp);
}
else{
printf("Invalid command!\n");
}
printf("Finished the makeLED Program\n");
return 0;
}
8
2.5 Use GPIO Pins for Input
In the next experiment, we will use GPIO Pin as an input. The circuit is shown as in figure 2.5. A button switch,
when pressed, will be detected by the program and a message will be printed accordingly. In this case, the process
continuously polls the status of the input pin. Listings 2.6 and 2.7 shows the code using RPi and gpiozero libraries.
Listing 2.6: Button Press detection code using RPi Library in Python
import RPi.GPIO as GPIO
import time
Listing 2.7: Button Press detection code using GPIOZero Library in Python
from gpiozero import Button
import time
9
Chapter 3
In this lab, we will use memory mapped I/O to a) change the GPIO pin output and b) control the pull-up/down resistor
configuration.
Get the value of GPIO pin 4 using the sysfs file system.
10
3.2.1 Pull-down Configuration
1. GPPUD Enable Pull-down
sudo /home/dsaha/myCode/devmem2 0x3F200094 w 0x01
5. cat value
value: 0
3.2.2 Pull-up Configuration
1. GPPUD Enable Pull-up
sudo /home/dsaha/myCode/devmem2 0x3F200094 w 0x02
5. cat value
value: 1
First, set up the circuit similar to figure 2.3 so that an LED can be turned on via GPIO17. Rest of the values below are
specified for GPIO 17. So, it is important to check the pin connection at this point.
1. Read the status of the Function Select Registry
sudo /home/dsaha/myCode/devmem2 0x3F200004
2. Set GPIO17 to be an output (Bits 23,22,21 are set to 001 in GPFSEL1 registry, detailed in Tables 6-2 to 6-7)
sudo /home/dsaha/myCode/devmem2 0x3F200004 w 0x200000
11
3. Check the value/status of GPIO17 pi (using the GPVL0 registry, detailed in Table 6-12 and 6-13)
sudo /home/dsaha/myCode/devmem2 0x3F200034
4. Clear the output of GPIO17 (Bit 17 is set to 1 in GPCLR0 registry, detailed in Table 6-12 and 6-13)
sudo /home/dsaha/myCode/devmem2 0x3F200028 w 0x20000
5. Set the output of GPIO17 to 1 (Bit 17 is set to 1 in GPSET0 registry, detailed in Table 6-8 and 6-9)
sudo /home/dsaha/myCode/devmem2 0x3F20001C w 0x20000
6. Set GPIO17 to be an input (Bits 23,22,21 are set to 000 in GPFSEL1 registry)
sudo /home/dsaha/myCode/devmem2 0x3F200004 w 0x00
12
Chapter 4
The RPi has pulse-width modulation (PWM) capabilities that can provide digital-to-analog conversion (DAC), or
generate control signals for motors and certain types of servos. The number of PWM outputs is very limited on the
RPi boards. The RPi B+ model has two PWMs (PWM0 & PWM1) output at Pins 12 and 33 (GPIO18, GPIO13).
19.2M Hz
P W M f requency = (4.1)
(divisor × range)
The PWM device on the RPi is clocked at a fixed base-clock frequency of 19.2 MHz, and therefore integer divisor and
range values are used to tailor the PWM frequency for your application according to the following expression: where
the range is subsequently used to adjust the duty cycle of the PWM signal. RPi PWMs share the same frequency but
have independent duty cycles. The default PWM mode of operation on the RPi is to use balanced PWM. Balanced
PWM means that the frequency will change as the duty cycle is adjusted, therefore to control the frequency you need
to use the call pwmSetMode(PWM MODE MS) to change the mode to mark-space.
13
cout << "The PWM Output is enabled" << endl;
pwmWrite(PWM0, 32); // duty cycle of 25% (32/128)
pwmWrite(PWM1, 64); // duty cycle of 50% (64/128)
return 0; // PWM output stays on after exit
}
pwmWrite(PWM_LED, 1023);
cout << "LED Off: Program has finished gracefully!" << endl;
return 0;
}
#define GPIO1 4
#define GPIO2 17
pinMode(GPIO1, OUTPUT);
digitalWrite(GPIO1, LOW);
//int softPwmCreate (int pin, int initialValue, int pwmRange) ;
14
softPwmCreate(GPIO1, 0, 200);
// void softPwmWrite (int pin, int value) ;
softPwmWrite(GPIO1, 15);
pinMode(GPIO2, OUTPUT);
digitalWrite(GPIO2, LOW);
softPwmCreate(GPIO2, 0, 500);
softPwmWrite(GPIO2, 15);
sleep(10);
}
This can also be done using the gpiozero using the following scripts.
led = PWMLED(17)
while True:
led.value = 0 # off
sleep(1)
led.value = 0.5 # half brightness
sleep(1)
led.value = 1 # full brightness
sleep(1)
led = PWMLED(17)
led.pulse()
pause()
15
Chapter 5
Analog Input
In this lab we will work learn how to use the Raspberry pi for Analog input.
The default configurations of the RPi GPIO pins can be viewed by querying the following in termianl:
sudo gpio readall
This will display the default configurations as shown in Figure 5.1. Make sure to use the correct pin as initialized in
the initial setup of wiringPi (http://wiringpi.com/reference/setup/).
16
Figure 5.2: Temperature & Humidity Sensor circuit.
GPIO can then be sampled over time to read the sensor’s response. Communication takes place when the RPi pulls
the GPIO low for 18ms and then releases the line high for a further 20–40µs. The GPIO switches to read mode and
ignores the 80µs low level and the 80µs high pulse that follows. The sensor then returns 5 bytes of data (i.e., 40-bits)
in most-significant bit (MSB) first form, where the first 2 bytes represent the humidity value, the following 2 bytes
represent the temperature, and the final byte is a parity-sum, which can be used to verify that the received data is valid
(it is the 8-bit bounded sum of the preceding 4 bytes). The bits are sent by varying the duration of high pulses. When
DHT is sending data to MCU, every bit of data begins with the 50µs low-voltage-level and the length of the following
high-voltage-level signal determines whether data bit is “0” or “1” A high for 26µs–28µs signifies a binary 0, and a
high for 70µs signifies a binary 1. Figure 5.3 illustrates an actual oscilloscope data capture and worked calculations to
explain the process for the DHT11.
17
#include<unistd.h>
#include<wiringPi.h>
#include<iomanip>
using namespace std;
int main(){
int humid = 0, temp = 0;
cout << "Starting the one-wire sensor program" << endl;
wiringPiSetupGpio();
piHiPri(99);
TRYAGAIN: // If checksum fails (come back here)
unsigned char data[5] = {0,0,0,0,0};
pinMode(DHT_GPIO, OUTPUT); // gpio starts as output
digitalWrite(DHT_GPIO, LOW); // pull the line low
usleep(18000); // wait for 18ms
digitalWrite(DHT_GPIO, HIGH); // set the line high
pinMode(DHT_GPIO, INPUT); // now gpio is an input
// need to ignore the first and second high after going low
do { delayMicroseconds(1); } while(digitalRead(DHT_GPIO)==HIGH);
do { delayMicroseconds(1); } while(digitalRead(DHT_GPIO)==LOW);
do { delayMicroseconds(1); } while(digitalRead(DHT_GPIO)==HIGH);
// Remember the highs, ignore the lows -- a good philosophy!
for(int d=0; d<5; d++) { // for each data byte
// read 8 bits
for(int i=0; i<8; i++) { // for each bit of data
do { delayMicroseconds(1); } while(digitalRead(DHT_GPIO)==LOW);
int width = 0; // measure width of each high
do {
width++;
delayMicroseconds(1);
if(width>1000) break; // missed a pulse -- data invalid!
} while(digitalRead(DHT_GPIO)==HIGH); // time it!
// shift in the data, msb first if width > the threshold
data[d] = data[d] | ((width > LH_THRESHOLD) << (7-i));
}
}
if (USING_DHT11){
humid = data[0] * 10; // one byte - no fractional part
temp = data[2] * 10; // multiplying to keep code concise
}
else { // for DHT22 (AM2302/AM2301)
humid = (data[0]<<8 | data[1]); // shift MSBs 8 bits left and OR LSBs
temp = (data[2]<<8 | data[3]); // same again for temperature
}
unsigned char chk = 0; // the checksum will overflow automatically
for(int i=0; i<4; i++){ chk+= data[i]; }
if(chk==data[4]){
cout << "The checksum is good" << endl;
cout << "The temperature is " << (float)temp/10 << "C" << endl;
cout << "The humidity is " << (float)humid/10 << "%" << endl;
}
else {
cout << "Checksum bad - data error - trying again!" << endl;
usleep(2000000); // have to delay for 1-2 seconds between readings
18
goto TRYAGAIN; // a GOTO!!! call yourself a C/C++ programmer!
}
return 0;
}
19
Chapter 6
In this lab, we will work on another input and output device. We will use the code that came with your Sensor kit. For
that, you can use the following command in your terminal to get all the code.
$git clone
https://github.com/adeept/Adeept Ultimate Starter Kit C Code for RPi.git
Figure 6.2 shows the circuit diagram for a common cathode 7 segment display. We will use the code at
Adeept Ultimate Starter Kit C Code for RPi/09 segment/segment.c to determine the wiring.
20
Figure 6.2: Circuit for 7 segment display with common cathode.
int main(void)
{
int i;
while(1){
for(i = 0; i < sizeof(SegCode)/sizeof(uchar); i++){ // display 0˜9,A˜F
digitalWriteByte(SegCode[i]);
delay(500);
}
digitalWriteByte(0x00); //segment off
delay(1000);
21
}
return 0;
}
You may notice that the leads are addressed using pins 0-7. Also, notice that wiringPiSetup() is used for setting
up, which uses wiringPi pin numbers. Make sure that you are connecting to the correct pin number by checking
the mapping using the command in th terminal: $gpio readall.
The output of $gpio readall is shown in Figure 6.3.
int getKey(void)
{
int i;
int tmpRead;
int rowVal = -1;
int colVal = -1;
char keyVal;
22
Figure 6.4: 4x4 Matrix Keyboard.
pinMode(COLUMN[i], OUTPUT);
digitalWrite(COLUMN[i], LOW);
}
pinMode(ROW[rowVal], OUTPUT);
digitalWrite(ROW[rowVal], LOW);
23
Figure 6.5: 4x4 Matrix Keyboard internal connections.
}
}
24
case 1: keyVal = 13; break;
case 2: keyVal = 14; break;
case 3: keyVal = 15; break;
default:
break;
}
break;
default:
break;
}
return keyVal;
}
int main(void)
{
int i;
int key = -1;
if(wiringPiSetup() == -1){
printf("setup wiringPi failed !\n");
return -1;
}
while(1){
key = getKey();
if(key != -1){
switch(key){
case 0: printf("1\n"); break;
case 1: printf("2\n"); break;
case 2: printf("3\n"); break;
case 3: printf("A\n"); break;
case 4: printf("4\n"); break;
case 5: printf("5\n"); break;
case 6: printf("6\n"); break;
case 7: printf("B\n"); break;
case 8: printf("7\n"); break;
case 9: printf("8\n"); break;
case 10: printf("9\n"); break;
case 11: printf("C\n"); break;
case 12: printf("*\n"); break;
case 13: printf("0\n"); break;
case 14: printf("#\n"); break;
case 15: printf("D\n"); break;
default:
break;
}
}
delay(200);
}
return 0;
}
25
Chapter 7
I2C Communication
In this chapter, we will study I2C. I2C on the RPi is implemented using the Broadcom Serial Controller (BSC), which
supports 7-bit/10-bit addressing and bus frequencies of up to 400 kHz.
We will use ADXL345 or MPU-6050 Accelerometer in this example. The level of acceleration supported by a sensor’s
output signal specifications is specified in ±g. This is the greatest amount of acceleration the part can measure and
accurately represent as an output. For example, the output of a ±2g accelerometer is linear with acceleration up to
±2g. If it is accelerated at 4g, the output may saturate.
1. We begin by enabling the I2C interface on the RPi by typing the following in terminal:
$sudo raspi-config
Choose Interfacing Options → I2C → Yes.
2. Check whether I2C is enabled. /dev is the location of device files. If I2C was enabled correctly, it will show
up in /dev/. Type the following in terminal.
$sudo ls /dev/i2c*
Your output will be similar to:
/dev/i2c-1
Then check if the kernel module is loaded by issuing lsmod command, which outputs information for each
loaded kernel module on a new line:
$lsmod | grep i2c
Your output will be similar to:
i2c bcm2835 16384 0
i2c dev 16384 0
If those two modules are not loaded, we can use modprobe to load the modules in Linux Kernel.
$modprobe i2c dev
$modprobe i2c bcm2835
3. In the next step, we need to create the circuit as below:
(a) Connect SCL on the RPi to SCL on the ADXL345
(b) Connect SDA on the RPi to SDA in the ADXL345
(c) Connect GND on the RPi to GND on the ADXL345
(d) Connect 3.3V on the RPi to VIN on the ADXL345
4. The I2 C bus can be probed to detect connected devices by using the following command:
sudo i2cdetect -y -r 1
The output shows the I2C addresses of the attached devices. For example, when ADXL345 (0x53), MPU-6050
(0x68) and PCF8591T (0x48) are attached to the I2C bus, we get the following output.
5. Refer to the manual (ADXL345 or MPU6050) for understanding the functionality and registers.
26
Figure 7.1: I2C Detect Output.
6. We will use the code that came with your Sensor kit. For ADXL345, the code resides in folder
Adeept Ultimate Starter Kit C Code for RPi/25 ADXL345/.
For MPU6050, clone the repository as below:
$git clone https://github.com/adeept/Adeept Ultimate Starter Kit for RPi.git
The code for MPU6050 is available at
Adeept Ultimate Starter Kit for RPi/Lesson05 MPU6050/code/c/Lesson05 MPU6050.c
7. Both the codes use wiringPi, for which you need to compile with lwiringPi. MPU6050 code also uses
math library, for which you need to compile it with -lm.
8. WiringPi implementation for I2C is available at https://github.com/WiringPi/WiringPi/blob/
master/wiringPi/wiringPiI2C.c
9. Note that calibration should be performed for correct values, which can be set in the offset registers.
https:
//learn.adafruit.com/adxl345-digital-accelerometer?view=all#programming
27
Chapter 8
Servo Motor
In this chapter, we will discuss Servo Motors and learn how to control it with the Raspberry Pi.
The Servo motor is a type of geared motor that can rotate 180 degrees. It is controlled by sending pulses signal from
your microcontroller. These pulses tell the servo what position it should move to. The Servo motor consists of a shell,
circuit board, non-core motor, gear and location detection modules. Its working principle is as follow:
1. The Raspberry Pi sends a PWM signal to the servo motor.
2. This signal is processed by an IC on circuit board to calculate the rotation direction to drive the motor, and then
this driving power is transferred to the swing arm by a reduction gear.
3. The position detector returns the location signal to gauge whether the set location is reached or not.
The relationship between the rotation angle of the servo and pulse width is shown in Figure 8.1.
There are three pins in a Servo motor, where you should use 5V for power supply. The color coding of wiring of the
servo can be of three different types as shown in Table 8.1.
28
(a) Circuit Connection. (b) Servo Connected with Raspberry Pi.
In the next step, you should connect the Servo motor with the Raspberry Pi as shown in Figure 8.2, using the color
code in Table 8.1.
The script, as shown in Listing 8.1, is available at:
/home/Adeept Ultimate Starter Kit C Code for RPi/23 servo/servo.c.
It generates software PWM signals for moving the Servo clockwise and anticlockwise.
#define Servo 0
int main(void)
{
int i, j;
pinMode(Servo, OUTPUT);
while(1){
29
servo(500);
delay(500);
for(i=500; i <=2500; i=i+500){
servo(i);
printf("i = %d\n", i);
delay(500);
}
servo(2500);
delay(500);
for(i=2500; i >=500; i=i-500){
servo(i);
printf("............i = %d\n", i);
delay(500);
}
}
return 0;
}
30
Chapter 9
Stepper Motor
In this lab, we will learn the principles of Stepper Motor and how to control it with Raspberry Pi.
Stepper Motor: A stepper motor is a motor that converts electrical pulse signals into corresponding angular or linear
displacements. Unlike DC motors, which rotate continuously when a DC voltage is applied, stepper motors normally
rotate in discrete fixed-angle steps. Each time a pulse signal is input, the rotor rotates by an angle or a step forward. The
output angular displacement or linear displacement is proportional to the number of pulses input, and the rotation speed
is proportional to the pulse frequency. Therefore, stepper motors are also called pulse motors. Stepper motors can be
positioned very accurately, because they typically have a positioning error of less than 5% of a step (i.e., typically
0.1o ). The error does not accumulate over multiple steps, so stepper motors can be controlled in an open-loop form,
without the need for feedback. The motor from your Sensor kit is shown in Figure 9.1.
ULN2003 Driver Module: The Raspberry Pi’s GPIO cannot directly drive a stepper motor due to the weak current.
Therefore, a driver circuit is necessary to control the stepper motor. This experiment uses the ULN2003 driver module.
There are four LEDs on the module to indicate stepping state. The white socket in the middle is for connecting a stepper
motor. IN1, IN2, IN3, IN4 are used to connect with the microcontroller. The power supply [5V to 12V DC] and an
On/Off jumper also resides on the board as shown in Figure 9.1.
Microcontroller Step
Connection State
LEDs
31
Circuit: Figure 9.2 shows the circuit connection for the stepper motor with the driver and the Microcontroller. The
script to control the Stepper Motor can be accessed at:
/home/Adeept Ultimate Starter Kit C Code for RPi/24 stepperMotor.c. It is also shown in
Listing 9.1. Based on the code that you will be using, connect 4 GPIO pins from your Raspberry Pi to the four
inputs of the ULN2003A. When connecting the circuit, we should pay attention to the difference between positive and
negative poles.
IN1 (A)
IN2 (B)
GPIOs
Microcontroller IN3 (C) ULN2003A Stepper Motor
IN4 (D)
5V
GND
void stop(void)
{
setStep(0, 0, 0, 0);
}
32
void forward(int t, int steps)
{
int i;
int main(void)
{
if (wiringPiSetup() < 0) {
printf("Setup wiringPi failed!\n");
return -1;
}
while (1){
printf("forward...\n");
forward(3, 512);
printf("stop...\n");
stop();
delay(2000); // 2s
printf("backward...\n");
backward(3, 256); // 512 steps ---- 360 angle
printf("stop...\n");
stop();
33
delay(2000); // 2s
}
return 0;
}
34