Embedded Systems Development with XMOS Assignment #1
Instructor:
1 Subversion Setup
During this course, all code will be turned in via Subversion ”commit”. Until you have committed your files, they are not visible to the GTA or instructor, and so have not been turned in. This part of the lab will go through the process of committing a file.
Instructions below are for either TortoiseSVN (windows) or command-line Subversion. They should be easily portable to other clients.
Please use your subversion client to “checkout” a local copy of your repository folder. The URL is:
https://svn.cs.du.edu/courses/comp3704-4704/f2018/<cs-user-name>
Where <cs-user-name> is replaced by your Computer Science user name. This will create a folder on your computer with the same name as your CS user name. Please do the following steps:
1. [ ] Create a new file in the top-level folder called “lab1.txt” (you can use Notepad or whatever you want to do this), with the contents “Do you hear me now?”
2. [ ] Use subversion to “add” this file:
• [ ] TortoiseSVN: Right-click on the file, and select “SVN-Add”
• [ ] Command-line: Change into the folder, and type svn add lab1.txt 3. [ ] Use subversion to “commit” this file:
- [ ] TortoiseSVN: Right-click on the file, and select “SVN-Commit”, then supply a log message.
- [ ] Command-line: Change into the folder, and type svn commit -m ‘‘My log message.’’ lab1.txt
4. [ ] Ask the instructor to verify that this file was successfully checked in. 1
2 Workspace Setup
Now, go through the steps to set the xTIMEcomposer workspace location to your subver- sion folder:
1. [ ] Launch the xTIMEcomposer application
2. [ ] Click File ⇒ Switch Workspace ⇒ Other…
3. [ ] Click Browse and navigate to the top-level directory of your subversion folder.
Make sure to use this workspace location for all the projects you create in this class.
3 Lab1-Hello
Now we will go through the steps to create a very basic new project:
- [ ] Launch the xTIMEcomposer application, and select the workspace for this class.
- [ ] Click File ⇒ New ⇒ xTIMEcomposer Project
- [ ] Enter in the name: Lab01-Hello
- [ ] Under Location, select “Create new project in workspace”
- [ ] Under “Platform” select XMOS startKIT (this is very important, nothing will work if you fail to do this).
- [ ] Click Finish – you now have an empty project!
- [ ] Right-click on the project in the “Project Explorer” pane, and select New ⇒
Source File
- [ ] Enter in the name main.xc
- [ ] In this file enter the following code:
#include <stdio .h> int main(void)
{ }
printf(”Hello from XMOS.”); return 0;
2
- [ ] Click on the icon to compile the project.
- [ ] Click on the icon to run the project
• [ ] Select “Run As – xCORE Application” – this will run the program on the board without flashing the program to memory. It makes it easier to use printf for debugging, and it is quicker to launch.
• [ ] Select “XMOS startKIT connected to …” – this means you will actually run it on the board, over the USB.
- [ ] Verify that you see “Hello from XMOS.” printed on the Console pane at the bottom of XDE.
- [ ] Use subversion to “add” the folder for this project, and then “commit” it to push it up to the server.
4 Lab1-LEDs
4.1 Illuminating the LEDs
Now we will experiment with the LEDs on your XMOS board. Please do the following:
- [ ] Create a new project called “Lab1-LEDs” using the process described above, making sure to create a new folder in your workspace, and selecting the “XMOS startKIT” target board.
- [ ] Create a new source file in this project, again called main.xc
- [ ] In this file add the following code:
#include <xs1.h>
out port oLEDs = XS1 PORT 32A;
int main() {
unsigned p a t t e r n = 0b01000001010100000000 ; oLEDs <: pattern;
while (1);
return 0;
}
Here are a few notes about this code: 3
4.
5.
4.2
- [ ] xs1.h contains the port definitions.
- [ ] XS1 PORT 32A specifies the 32-bit port that is used to control the 3×3 LEDs.
- [ ] 0b01000001010100000000 defines a specific bit pattern to be set on the 32-bit port. If you refer to the startKIT Hardware Manual, Figure 14, you will see that the 9 LEDs are wired to different ports referred to something like: P32A17. This indicates that the 18th bit (pin bits are zero-based) of “Port 32A” is associated with this LED.
- [ ] So, with this constant, the 4 “true” values are at bits 8, 10, 12, and 18 which correspond to LEDs C2, B3, B1, and A2 respectively (make sure this makes sense to you).
- [ ] The hardware manual also states that these “LED pins are active low”. This means that for the 3×3 LEDs, when a zero value (low) is set on that pin, the LEDs will light up. So, with the constant above, all 9 LEDs are on, except for the ones that have been turned off (C2, B3, B1 and A2). Look at your hardware and make sure this is true when the program is running.
- [ ] while(1); is an infinite loop with an empty body – this is needed so the chip keeps running.
- [ ] return 0; is never actually executed, but is needed to stop the compiler from complaining.
[ ] Build and run the code, observe the LEDs being displayed in the pattern dictated by the code. Change the binary constant value to adjust the LED pattern. Try to get stripes in both directions, and a box around the outside.
Build and run the code again to make sure it works.
Flashing the LEDs
In the previous section, once set, the LEDs did not change. Now we will add a timer so we can flash the LEDs.
- [ ] In XMOS, there are 10 timers per core. All timers run at the same frequency (100MHz), and all are 32-bit timers (meaning the values range from 0 to 232 − 1 = 0xFFFFFFFF. The timers start at zero, and count upwards, wrapping around when they overflow.
- [ ] There is a constant defined in xs1.h called XS1 TIMER HZ which is equal to 100 × 106; this is the number of timer ticks that occur per second.
- [ ] Add a #define to your file to represent the delay:
4
#define FLASH DELAY (XS1 TIMER HZ/4)
- [ ] To make use of a timer, you need a timer object, and a variable that can store timestamps. So, add this at the top of your main function:
- [ ] Before the while loop, sample the timer and save the current timestamp into the variable:
- [ ] In the body of the while loop, illuminate the LEDs:
- [ ] Now, you must figure out a timestamp in the future that we want to wait for by adding a fixed number of ticks to the previous timestamp. Then use the timerafter() function to tell the processor to wait for the timer to reach that value:
Notes:
• [ ] You don’t have to worry about overflow in this because the timerafter() function is smart enough to handle this gracefully.
• [ ] The effect of timerafter() is to block the program at that statement until the condition is met. The XMOS does this very efficiently.
• [ ] By using :> void, you are discarding the actual timestamp (which is possibly a few ticks more than the value in t). You do it this way so that those few ticks do not accumulate over time. By only sampling the clock once (outside the while loop), you make sure that the period is always relative to that starting timestamp.
- [ ] Finally, we just need to change the pattern using the bitwise complement oper- ator which flips the value of all bits.
5
timer tmr ; unsigned int t;
tmr :> t;
while (1){
oLEDs <: pattern;
…
}
t += FLASH DELAY;
tmr when timerafter(t) :> void;
pattern = ̃pattern; // that character is a tilde
9. [ ] When all is said and done, you have something like:
#define FLASH DELAY XS1 TIMER HZ/4 int main()
{
timer tmr ;
unsigned int t;
unsigned i n t p a t t e r n = 0b01000001010100000000 ;
tmr :> t; while (1) {
oLEDs <: pattern; t += FLASH DELAY;
tmr when timerafter(t) :> void;
pattern = ̃ pattern ; return 0;
} }
- [ ] Build and run the program, observe the flashing lights!
- [ ] Play around with the initial bit pattern, and the value for FLASH DELAY and make
sure you understand the effect.
- [ ] Challenge: change the logic so that only one LED is illuminated, and the lit one moves around the outside of the 9×9 LED grid.
- [ ] Add the folder using subversion and commit it.
5 Lab1-Buttons
5.1 Continuous Sampling of Button State
The next section of the lab deals with reading input from the user through one of the buttons on the XMOS board. Please do the following:
1. [ ] Create a new XC project called Lab1-Buttons and add a new source code file called main.xc. This should go in your subversion folder as before.
2. [ ] In this file, include xs1.h.
6
- [ ] Define a global input port for the button, and a global output port for one of the single LEDs (see the startKIT hardware manual for the ports / pins associated with the button and the single LEDs):
- [ ] Implement a main function with an infinite loop.
- [ ] Initially, we are going to illuminate the LED when the button is pressed, and turn it off otherwise. First do this by continuously sampling the button state into a local variable, and then using an if-else statement to determine what to do with the LEDs. On the startKIT, the buttons have a value of 1 when not pressed, 0 when pressed. So, inside the loop you’ll have:
in port iButton = XS1 PORT 32A; out port oLed = XS1 PORT 1A;
iButton :> value ;
if(/∗ TODO: button is pressed ∗/){
/∗ TODO: illuminate the LED ∗/ }
else {
/∗ TODO: turn off the LED ∗/
}
- [ ] The button is “active low” – meaning that when it is pressed, the pin shows a value of zero. Also, the button is attached to the 0th bit of the 32-bit port, so you only want to be looking at that one bit to make your decision.
- [ ] Note, while the 3×3 LEDs are “active low” (i.e., they are illuminated when the bit controlling them receives a zero value), these single LEDs are “active high” (i.e., they are illuminated when the bit controlling them receives a one value).
- [ ] Build and run the program, test that the LEDs react correctly to the button press.
5.2 Using Blocking I/O to Avoid Continuous Sampling
The XMOS process supports blocking I/O, so we can tell the processor to wait for a specific state, and it will do so efficiently (similar to when we waited for a timer value above).
- [ ] Change the name of your previous main() function to main sampling(), and create a new main, with a similar structure as main sampling().
- [ ] Because the 32-bit port that the button is associated with is also tied with other pins, we need to “sample” the initial state of that entire port before we go into the loop (we will assume that the button is unpressed that this point):
7
iButton :> value ;
- [ ] Now, in the body of the while loop, we just wait for a change in the state of this entire port:
Notes:
• Here we wait for a change in the port state, and store the new state into thesame variable (:> value at the end).
- [ ] At this point in your code, you know that something changed with that port, but it is not necessarily the button state. Use some basic logic to determine whether the button state did in fact change and take these actions
• If the button is pressed (low), then illuminate the LED. • If the button is released (high), then turn off the LED.
- [ ] Build and run the program.
5.3 Measuring Button Press Time
With the code written above, it should be straightforward to implement logic that will mea- sure the amount of time the button was depressed for.
1. Define a new function that will return the number of ticks between two timestamps. It should have the prototype:
t1 );
iButton when pinsneq ( value ) :> value ;
unsigned int compute difference (unsigned int t0 , unsigned int
• Think about how a timer works – it counts up from zero to 232 − 1, and then wraps around to zero. So, while t1 is always “after” t0, it might have a smaller value. Your function should deal with this correctly.
2. Once you have that function in place, change the previous code to take a timestamp from a timer when the button is pressed, and another timestamp when it is released. Use your function to compute the number of timer ticks between the two events. Print out the time in microseconds (10−6 seconds), and in seconds using printf after each button press / release:
8
Delay was 4994470 microseconds (4.994470 seconds )
6 HW1-ReactionTime
NOTE: PLEASE READ THROUGH THIS BEFORE LEAVING CLASS
Using the building blocks from above, the homework assignment is to create a “reaction time” game. The basic idea is that your board will illuminate LEDs randomly and measure how long it takes the user to press the button after that time. After doing this 10 times, your program should print out some statistics, and then start over.
Here are the detailed requirements for your program:
- Your program will read inputs from the button, and will send output to the two “User
LEDs”, and will print information to the console using printf().
- Create a new project as before called HW01-ReactionTime with a single source file
called main.xc. This should be in your subversion folder.
- The main function will consist of an infinite loop. Each time through the loop, it will
do the following:
- Flash the two User LEDs three times with a period of 1 second. This means the they will be on for half of a second, and off for half of a second.
- Delay 1 second plus a random delay up to another second. The rand() function picks a random 32-bit number, this is defined in stdlib.h, and can be used to do this:
- Illuminate the User LEDs, this is the start of the response time.
- Wait until the button is pressed, and then sample the timer and turn off the User LEDs.
- Compute the delay between the time the LEDs were illuminated and the button was pressed using the compute difference () function implemented during the lab sections above.
- Record the delay in an array.
- Once 10 samples have been taken, print out the following statistics, and then start over, collecting more samples.
– minimum, maximum, and average response time in microseconds
– median response time in microseconds (yes, you’ll have to sort the valuesfor this one – just use something simple like bubble sort).
- Delay one second before ending the while loop.
Here are a few coding practices that you should take care to observe: 9
delay = XS1 TIMER HZ + rand () % XS1 TIMER HZ;
• All constants (the number of flashes at the start of the loop, the number of samples, the flash period, . . . ) should be defined using #define.
• Use functions to modularize your code, try not to have one big chunk of code.
10