You are on page 1of 15

University of Sydney

Faculty of
Engineering and IT

ELEC5614: Real-Time Computing


Lab 2 : Ardiunos, RTOS and Concurrent programming

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.

2.1 Part A: Arduino Install and Blink Example


1. Download and unzip the Arduino Enviroment and IDE (10.5 or 1.5.6) from
http://arduino.cc/en/Main/Software
2. Plug the Arduino into the USB port.
3. Wait for the drivers to install. If the installation fails
http://arduino.cc/en/Guide/Windows#toc4, or ask for the tutor help.

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.

2.2 Part B: Arduino Introduction


Hello World:
This part of the lab will describe the structure an Arduino Program. Arduino Programs
are written in an opensource language called Processing. Processing is written as an
imperative language and is most similar to C. In any Arduino program there are two
main routines; setup() and loop():
void setup() {}
void loop() {}
The setup routine is run when the Arduino is first intialised. This is mainly used for
loading libraries, assigning input/output PINs and setting up variables. The other

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);

The digital pins work in a similar fashion:


int res = digitalRead(digitalPin);

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.

2.3 Part C Problem 1


This section will require you to interface with a potentiometer and change the
brightness of an LED depending on the potentiometer position. This section will
require you to physically wire up the potentiometer and led and then create the
Arduino program to control the device. All of the necessary programing commands
have been provided in the above section.
The first step is to wire up the potentiometer, this requires us to connect it to the 5V,
GND and an Analog PIN. Next the LED is connected to the GND, and a digital PIN in
series with a 220 ohm resistor. This is illustrate below, please see the tutor if you
have any issues.

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.

2.4 Part C ChibiOS/RT


This final part of the lab will focus on installing the ChibiOS/RT and will walk through
the basic syntax an example program.
1. Download the ChibiOS/RT from
https://code.google.com/p/rtoslibs/downloads/detail?
name=ChibiOS20130710.zip
2. Unzip the file and open the libraries folder.
3. Copy the ChibiOS_AVR folder to your Arduino Library folder which can be
found:
a. Windows: C:/Program Files/Arduino/libraries
4. Next start up the Arduino IDE and navigate to File > Examples >
ChibiOS_AVR > chBlinkPrint
5. Compile and Run the example. Please see the tutor if you encounter any
issues.
ChibiOS/RT Introduction:
There are a few differences between a standard Arduino program and a program
written using ChibiOS. The key difference is that the loop() routine is no long used
and the mainThread functions replaces it. The execution path of a ChibiOS
application starts with the setup() routine which then calls the mainThread function
with chBegin command. This implements the RTOS which start the static threads.
Below is an example of a simple setup() routine. Note that as with every libraries it
need to be imported into the workspace.
#include <ChibiOS_AVR.h>
void setup() {
Serial.begin(9600);
chBegin(mainThread);
}
The mainThread is responsible to starting other the other threads in the program. An
example of starting a static thread is given below:
void mainThread() {
chThdCreateStatic(waThread1, sizeof(waThread1),
NORMALPRIO + 2, Thread1, NULL);
}
The chThdCreateStatic takes several arguments, the first is a staticly allocated
memory space expressed as:
static WORKING_AREA(waThread1, 64);

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.

3.1 Static Threads


Have a look at code sample 3.1a, and ensure you understand how this code creates
two concurrent threads. Note that each thread will not, in the initial version provided,
actually do anything terminating immediately.
Modify this code sample so that the first thread repeatedly turns the LED on, and then
sleeps for 1 second (Hint: use chThdSleepMilliseconds to implement the sleep). The
second thread should repeatedly turn the LED off and then sleep for 0.9 seconds.
Once you have modified the code then compile and execute it, and watch the
resultant behavior. Make sure you can understand why the LED on/off times vary (try
drawing a timing diagram showing the on/off events).

3.2 Dynamic Threads and Initialisation


Firstly, have a read of the following:
http://chibios.sourceforge.net/html/group__dynamic__threads.html
http://www.chibios.org/dokuwiki/doku.php?id=chibios:howtos:createthread
Using the template code provided in sample 3.2a, modify your example from section
3.1 so that the memory required by the thread is allocated dynamically rather than
statically.
Note: You will probably need to modify the configuration to enable dynamic
allocation. Edit the libraries/ChibiOS_AVR/utility/chconf.h file as follows:
#define
#define
#define
#define

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>?

3.4 Task Models


Consider the task model being used in the above examples, and see if you can
classify the model based on:
Structure: static, dynamic
Level: top level tasks only (flat); multilevel (nested)
Initialization: with or without parameter passing
Granularity: fine or coarse grained
Termination: natural; suicide; abortion; untrapped error; never; no longer needed
Representation: fork/join; cobegin; explicit task declarations

3.5 Thread termination


Challenge exercise: Write a short program that has a primary thread that reads in an
integer between 0 and 9. If a thread with that ID exists then terminate that thread. If it
does not exist then spawn a new thread with that ID. Each spawned thread should
print to serial output its ID once every 2 seconds.
The main components of the program are included in code sample 3.5a.
Once you have your program working demonstrate it for your tutor.

Appendix: Code Samples


4.1

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

static msg_t ThOFF(void *arg) {


// CODE HERE - Repeatedly turn LED off then sleep for 1.9 secs
return 0;
}
//-----------------------------------------------------------------------void setup() {
chBegin(chSetup);
while(1) { }
}
//-----------------------------------------------------------------------void chSetup() {
pinMode(LED_PIN, OUTPUT);
// start LED-on and LED-off threads
Thread *tpON = chThdCreateFromHeap(NULL, THD_WA_SIZE(128), NORMALPRIO+1,
ThON, NULL);
if (tpON == NULL) chSysHalt();
// Memory exhausted
Thread *tpOFF = chThdCreateFromHeap(NULL, THD_WA_SIZE(128), NORMALPRIO+1,
ThOFF, NULL);
if (tpOFF == NULL) chSysHalt();
// Memory exausted
// Now wait for threads to terminate
msg_t msgON = chThdWait(tpON);
msg_t msgOFF = chThdWait(tpOFF);
}
//-----------------------------------------------------------------------void loop() {
// not used
}

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");

if (tp1 == NULL) chSysHalt();


chThdSleepMilliseconds(2000);

// Memory exhausted

Thread *tp2

= chThdCreateFromHeap(NULL, THD_WA_SIZE(128), NORMALPRIO+1,


ThreadNums, (void *)"Th2");
if (tp2 == NULL) chSysHalt();
// Memory exhausted
chThdSleepMilliseconds(2000);
Thread *tp3

= chThdCreateFromHeap(NULL, THD_WA_SIZE(128), NORMALPRIO+1,


ThreadNums, (void *)"Th3");
if (tp3 == NULL) chSysHalt();
// Memory exhausted
// Now wait for threads to terminate
chThdWait(tp1);
chThdWait(tp2);
chThdWait(tp3);
}
//-----------------------------------------------------------------------void loop() {
// not used
}

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;
}

if (threads[newID] == NULL) { // create new thread


Serial.print("Adding thread ID: ");
Serial.println(newID);
// YOUR CODE HERE TO CREATE THREAD
}
else { // request thread termination
Serial.print("Terminating thread ID: ");
Serial.println(newID);
// YOUR CODE HERE TO TERMINATE THREAD
}
}
}
//-----------------------------------------------------------------------void loop() {
// not used
}

You might also like