Professional Documents
Culture Documents
Faculty of
Engineering and IT
Davids
Lowe
8th March 2014
Frank
Unclassified
Document: ELEC5714 2014 Lab 2
Print date: 3/26/14
Document contact: david.lowe@sydney.edu.au
Moisiadis
93515653
Duncan
Moss
1 Overview
This laboratory (across two weeks) focuses on basic multi-threaded real-time
programming. In order to allow you experiment as freely as possible (as well as to
understand some of the constraints that can occur especially when interfacing to real
physical devices) we will using simple Arduino devices. Arduinos are a family of
single-board microcontroller designed around the family of Atmel AVR
microcontrollers. (See http://en.wikipedia.org/wiki/Arduino for some background, and
http://arduino.cc/ for more complete information).
You will be able to borrow an Arduino for the semester, though you might prefer to
buy your own Ardunio so that you can continue to use it beyond the current semester.
Typically Arduinos can be purchased for as little as $15, or kits from $40, and the
software is generally open source. For places to purchase arduinos and assoiated
kits you might like to look at:
https://www.sparkfun.com/arduino_guide
http://www.jaycar.us/ard_index.asp
http://littlebirdelectronics.com/collections/arduino
http://www.element14.com/community/groups/arduino
Beng a relatively low-powered device, the Arduino was not originally desiged to be
multithreaded or real-time but a number of lightweight real-time operating systems
have been developed for Arduinos. Examples include NilRTOS, ChibiOS/RT and
FreeRTOS (see https://code.google.com/p/rtoslibs/). The RTOS capalities upported
by each of these RTOSs varies. For example, NilRTOS is very lightweight, but does
not support various functionality, such as dynamically created threads.
In this laboratory we will introduce the Arduino and the processes and tools for
programming it. We will then show how to install ChibiOS/RT and use it to explore
various mutti-threaded programming examples. You will be expected to examine the
example programs (or partial programs) provided, read and understand them, and
then make some changes to them. This will be followed by a set of program designs.
You should ensure that you demonstrate both the exercises and the program designs
to your tutor.
2 Week 5 Lab:
Introduction and simple multithreading
This weeks lab focuses on developing an initial understanding of the Ardiuno boards
and then installing the ChibiOS/RT library.
refer
to
4. Once the driver have been installed, start up the Arduino IDE and navigate to
the blink example: File > Examples >1. Basics > Blink
5. Ensure that Arduino Uno is selected in the devices list: Tools > Board >
Arduino Uno
6. Next Compile and Upload the blink example to the Arduino using the =>
button.
7. Once uploaded you should see LED 13 (near PIN 13) blinking orange at one
second intervals.
8. After confirming that the blink example is working move onto Part B,
otherwise see the tutor.
routine is loop(), this acts like an infinite loop that continuously executes until either
the power is lost, or a new program is uploaded to the Arduino. This is where the
main bulk of the work occurs.
There are several ways to retrieve information from the Arduino. The main one that
we will be using is the serial monitor. This will be the main way in which we
communicate with the Arduino and it is fairly easy to setup. When using the serial
monitor the first step is to load the library and initialise the PC-Arduino connection,
this is done with:
Serial.begin(9600)
The value 9600 represents the Baud Rate which we will not be touching for the
remainder of this lab. This command is placed in the setup() function as illustrated
below:
void setup() {
Serial.begin(9600);
}
Now that the serial monitor has been started the next step is to write a value. To do
this the print and println statements are used. For example a simple Hello World
program can be written as so:
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Hello World");
}
Reading and Writing from PINs:
This next section covers the steps necessary to read and write from the IO PINs.
There are two types of PINs on the Arduino Uno, these are digital and analog pins.
Each PIN can be assigned as either an INPUT or OUTPUT.
pinMode(pinNumber, INPUT)
pinMode(pinNumber, OUTPUT)
Once the pinMode has been set the signals can be read or wirtten to as follows.
Analog signals can be read from the an Analog pin using:
int res = analogRead(analogPin);
Once these value have been read the can sent to the serial monitor using the same
method described in the Hello World example.
int d_res = digitalRead(digitalPin);
int a_res = analogRead(analogPin);
Serial.println("Digital Read: %d,
Analog Read: %d", d_res,
a_res);
For more information on analogRead and digitalRead please refer to:
http://arduino.cc/en/Reference/analogRead
http://arduino.cc/en/Reference/digitalRead
It is also possible to write Digital Signals to the PINs and a signal can either by
HIGH(on - 5v) or LOW(off 0V). It is important to note that the Arduino Uno does not
have a Digital-to-Analog Converter (DAC). To make up for this the Arduino has a
number of Pulse-Width Modulated (PWM) Digital PINs that act as a sudo-analog
signal. In essence a PWM PIN operates by switching the digital signal HIGH and
LOW. The amount of time the signal is HIGH corresponds to the Duty Cycle. For
more information on PWM PINS please see http://arduino.cc/en/Tutorial/PWM
Similar to read, the PINS can be written to via:
digitalWrite(digitalPin, HIGH); // Set the Signal HIGH
digitalWrite(digitalPin, LOW); // Set the Signal LOW
analogWrite(PWMPin,
Duty Cycle
duty_cycle);
//
PWM
Write
with
specific
Be combining the above commands we can interface devices and circuits connected
to the Arduino.
Illustration
0:
http://cs.curs.pub.ro/wiki/pm/_media/eestec
/arduino_pot_led.png
The final step is to write the program. First we being by describing the setup() routine.
int ledPin = 6;
int potPin = 0;
void setup() {
pinMode(ledPin, OUTPUT);
}
In this example the potentiometer is connected to analog pin 2 and the LED is
connected to digital pin 9. Note it is not necessary to set the analog pin as output.
Next we want to construct the the loop() routine. The goal is to set the LED brightness
depending on the value received from the potentiometer. Since the analogRead
function returns a value between 0-1023 and the analogWrite function takes a duty
cycle between 0-255 we need to perform a mapping. Below is the loop() routine:
void loop() {
int potVal = analogRead(potPin);
ledVal = map(potVal, 0, 1023, 0, 255);
analogWrite(ledPin, ledVal);
}
Please show the tutor that this is working.
The second argument is the size of the memory space, the third argument is the
proitoy of the thread and the four is the thread function itself. And example thread is
given below:
static msg_t Thread1(void *arg) {
Serial.println("Hello World");
return 0;
}
Using the above command create a multi-thread example where one thread prints
Hello Word! and another thread prints I love using an RTOS.
3 Week 6 Lab:
Concurrent Programming
This weeks lab focuses on concurrent programming, and in particular the processes
for creation and termination of multiple threads. It will continuing using the
ChibiOS/RT operating system running on Ardiunos used in the previous week.
CH_USE_HEAP
CH_USE_MALLOC_HEAP
CH_USE_MEMPOOLS
CH_USE_DYNAMIC
TRUE
TRUE
TRUE
TRUE
Once this is working, then progressively increase the memory required by each
thread (by increasing the parameter referenced in THD_WA_SIZE(128) which
determines the working area total size for the thread) until the program runs out of
heap memory when trying to spawn a thread.
Now modify your code so that you pass a parameter to each thread, specifying the
amount of time (in milliseconds) between each LED on or off event.
3.3 Scheduling
The code in sample 3.3a spawns 3 threads, each 2 seconds apart. Each of these
threads has an inner loop that uses a calculation loop as a busy delay (about 0.5
seconds). An outer loop repeatedly runs the inner loop to create a delay, and then
prints out a thread identification and a count.
Look at the code, and see if you can predict what will occur when you run the
program. Then execute the program and see if you were correct.
Explain to your tutor why the second thread not start until 2 seconds after the first
thread completes? (The tutor will confirm whether you are correct!)
Can you predict what would occur if the three threads were spawned with the
following priorities:
Thread *tp1
Thread *tp2
Thread *tp3
= chThdCreateFromHeap(...NORMALPRIO-1 ...);
= chThdCreateFromHeap(...NORMALPRIO-1 ...);
= chThdCreateFromHeap(...NORMALPRIO-1 ...);
And
Thread *tp1
Thread *tp2
Thread *tp3
= chThdCreateFromHeap(...NORMALPRIO-3 ...);
= chThdCreateFromHeap(...NORMALPRIO-2 ...);
= chThdCreateFromHeap(...NORMALPRIO-1 ...);
And finally
Thread *tp1
Thread *tp2
Thread *tp3
= chThdCreateFromHeap(...NORMALPRIO+1 ...);
= chThdCreateFromHeap(...NORMALPRIO+2 ...);
= chThdCreateFromHeap(...NORMALPRIO+3 ...);
Again, if you cannot understand the behavior in each case and why the threads are
scheduled in the way they are then ask the tutor. Finally, can you modify the code
so that the three threads do run concurrently?
Optional challenge exercise: Repeatedly read 2 integers (D1, D2) from the serial in.
For each pair, spawn a thread that lives for D1 mSecs, and blinks the LED on a 50%
duty cycle of D2 mSecs duration.
Consider how the different threads 'interact' - i.e. what happens when you enter
<10000, 2000> and <10000,400>?
Code 3.1a
// ELEC5614 Lab 2 Code 3.1a (Simple static threads)
#include <ChibiOS_AVR.h>
const uint8_t LED_PIN = 13;
//--------------------------------------------------------------------------// Thread 1, turn the LED on
static WORKING_AREA(waThON, 64);
static msg_t ThON(void *arg) {
// CODE HERE - Repeatedly turn LED on then sleep for 1 sec
return 0;
}
//--------------------------------------------------------------------------// Thread 2, turn the LED off
static WORKING_AREA(waThOFF, 64);
static msg_t ThOFF(void *arg) {
// CODE HERE - Repeatedly turn LED off then sleep for 0.9 secs
return 0;
}
//-----------------------------------------------------------------------void setup() {
chBegin(chSetup);
while(1) { }
}
//-----------------------------------------------------------------------void chSetup() {
pinMode(LED_PIN, OUTPUT);
// start LED-on and LED-off threads
chThdCreateStatic(waThON, sizeof(waThON), NORMALPRIO, ThON, NULL);
chThdCreateStatic(waThOFF, sizeof(waThOFF), NORMALPRIO, ThOFF, NULL);
}
//-----------------------------------------------------------------------void loop() {
// not used
}
4.2
Code 3.2a
// ELEC5614 Lab 2 Code 3.2a (Dynamic thread example)
#include <ChibiOS_AVR.h>
const uint8_t LED_PIN = 13;
//--------------------------------------------------------------------------// Thread 1, turn the LED on
static msg_t ThON(void *arg) {
// CODE HERE - Repeatedly turn LED on then sleep for 2 secs
return 0;
}
//--------------------------------------------------------------------------// Thread 2, turn the LED off
4.3
Code 3.3a
// ELEC5614 Lab 2 Code 3.3a (Scheduling example)
// ELEC5614 Lab 2 Code 3.3a (Scheduling example)
#include <ChibiOS_AVR.h>
//--------------------------------------------------------------------------// Thread to print numbers
static msg_t ThreadNums(void *arg) {
// loop and print
uint32_t i,j;
double k=1.0;
for (i=0;i<10;i++) {
// Use a busy wait
for (j=0; j<500000; j++) { k = k*1.1; if (k>10) k=1.0; }
Serial.print("Thread: ");
Serial.print((const char*)arg);
Serial.print(", Count: ");
Serial.println(i);
}
return 0;
}
//-----------------------------------------------------------------------void setup() {
Serial.begin(9600);
chBegin(chSetup);
while(1) { }
}
//-----------------------------------------------------------------------void chSetup() {
// start threads
Thread *tp1 = chThdCreateFromHeap(NULL, THD_WA_SIZE(128), NORMALPRIO+1,
ThreadNums, (void *)"Th1");
// Memory exhausted
Thread *tp2
4.4
Code 3.5a
// ELEC5614 Lab 2 Code 3.5a (Thread termination example)
#include <ChibiOS_AVR.h>
//--------------------------------------------------------------------------// Thread to print ID every 5 seconds
static msg_t ThreadNums(void *arg) {
int myID = (int)arg;
// YOUR CODE HERE TO PRINT ID EVERY 2 SECS AND TERMINATE WHEN REQUESTED
return 0;
}
//-----------------------------------------------------------------------void setup() {
Serial.begin(9600);
chBegin(chSetup);
while(1) { }
}
//-----------------------------------------------------------------------void chSetup() {
// set up array IDs
Thread *threads[10];
for(int i=0;i<sizeof(threads);i++) { threads[i]=NULL; }
// Repeatedly read in new IDs
int newID;
Serial.println("Enter integers (0..9) and press return.");
while(1) {
while (!Serial.available()) { }
newID = Serial.parseInt();
if ((newID<0)||(newID>9)) {
Serial.print("Not an allowed ID: ");
Serial.println(newID);
continue;
}