PA 8001 2013 Practical 1
Contents
Objectives
There are three objectives for this practical:
- Experiment with concurrency (without any underlying support) and observe its issues
- Apply the concepts of busy waiting for reading inputs
- Get more insight into the working of the AVR Butterfly board, particularly with respect to timing and output
Instructions
Submit a single .zip file on blackboard with four folders, each containing the solutions to the below-specified parts.
For each function in the code, you need to write a piece of comment, describing its pre- and post-condition and one or more test-cases.
In order to make the on-board processor run at its maximum speed, its CPU clock prescaler functionality must be disabled. This is achieved by writing the byte values 0x80 followed by 0x00 to the special register CLKPR when your program starts up. See the ATmega169 manual, pages 29-31, for further info.
Part 1: Prime Numbers
Write a C program for displaying numerical digits on the LCD of the Butterfly board. Use the same LCD configuration as in exercise 3 of Practical 0 (except that you might want to use default wave form instead of lowpower). Your function should have signature
void writeChar(char ch, int pos)
and should work properly for characters 0,1,2,3,4,5,6,7,8,9 (digits), we are not interested in displaying other ASCII characters.
Your function should turn on the segments needed for displaying the digits in any of the possible 6 positions. Use 0, 1, 2, 3, 4 or 5 to number the positions (called 2, 3, 4, 5, 6 and 7 in the documentation of the LCD). For other values of pos your function should do nothing.
When you have verified that individual digits can be properly displayed at the desired position, write a function
void writeLong(long i)
that uses writeChar with a proper position value for each of the digits of i. In case the i has more than 6 digits, your function should only display the six least significant digits.
Finally, demonstrate your LCD driver by implementing a program that continuously computes increasing prime numbers and prints them on the display. The prime numbers can be computed in the simplest possible way: a long variable is incremented for each turn in a loop, and a helper function
int is_prime(long i)
is called to determine whether the value is a prime number that has to be printed. The initial value for this variable can be any value you find meaningful. Implementing is_prime(i) could be done by computing i % n (i.e., the remainder from division i/n) for all 2 <= n < i, and returning false (0) if any such expression is 0, true (1) otherwise. Wrap up you solution in a function
void primes()
that is called directly from main() after device initialization.
Part 2: Marquee
The second task is to write a program that makes the illusion of a moving symbol at the topmost part of the LCD (symbols S1 to S5) of the LCD. This is performed by turning on and off the segments in an interleaving and circular fashion with a steady frequency of 1 Hz (a Hz is 1/second). This means that a segment is turned on during half a second and off during half a second, and then the next segment is turned on as long as the program is running.
For timing purposes you will do busy waiting with the 16-bit Timer/Counter1 unit. Details of this device can be found in pages 95-123 of the ATmega169 manual; however, most of this information is beyond the scope of this assignment. All we will need is a continuously running timer that can be read at any time and doesn't wrap around too often. A suitable configuration is to let Timer/Counter1 use the 8 MHz system clock with a pre-scaling factor of 256, this should make the 16 bits in register TCNT1 wrap around approximately every 2.1 seconds. The only register whose default values need to be changed in order to achieve this is TCCR1B.
Concretely, this program should maintain an unsigned integer variable representing the next timer value to wait for, and use busy-waiting to stop execution until register TCNT1 has reached that value. Note that turning the display on and off requires updating in two phases, that preferably last half the desired period. Note also that some special measures need to be taken to ensure proper operation when the timer wraps around to zero.
Wrap up you solution in a function
void marquee()
that is called directly from main() after device initialization.
Part 3: Joystick
The third part of this assignments is about dealing with external input. The task is to write a program that moves a symbol in the bottom row to right or left each time the joystick is moved to that direction and released. The joystick is connected to certain bits of I/O ports B and E; here it is recommended that bits 2 and 3 of port E are used, which corresponds to right and left movement of the joystick.
Details on how to operate the I/O ports are given in pages 55-78 of the ATmega169 manual; however, as with the section on 16-bit timers, most of this information is beyond the scope of the assignment. What is necessary to know is that the I/O ports can function as both inputs and outputs, and that the output register for port x (PORTx) controls pull-up resistors for the input register of port x (PINx) whenever port x is configured for input (the latter is controlled individually for each bit of port x by the settings in register DDRx). All ports are configured as inputs by default, but in order to obtain proper operation of the joystick switches, the pull-up resistors must be activated for the corresponding pins. For our purposes, this amounts to setting bits 2 and 3 high in register PORTE during program initialization.
The program should be implemented using busy-waiting for changes on bits 2 and 3 in register PINE. Notice that the joystick switches are active low, which means that they will cause a 0 in the input bit position as long as the switch is pressed, and a 1 otherwise.
Wrap up you solution in a function
void button()
that is called directly from main() after device initialization.
Part 4: Concurrency
The final part of the assignment consists of putting all the previous parts together as one single application. This will require some modifications to your existing code, and the purpose of this part is specifically to draw your attention to these modifications.
Use the simple technique explained in lecture 2: the cyclic execution and interleaving by hand. In order to compare with later implementations, you will not be allowed to modify any of your existing functions, instead you should create new copies of any functions that needs to be changed.
Try out your program for different start values for the prime number computations, for example 1, 5000, and 25000.
How do these values affect the display of the marquee?
How is the response time of the joystick affected?
What would it take to ensure a stable marquee and a responsive joystick, that are independent of the currently calculated prime number? Implementing your solution and showing that it works will lead to a bonus point. (If you would like to get the bonus put a separate folder called "bonus" in which your solution is implemented.)
Write a short text explaining the issues encountered and a possible solution. Include all the programs and the short report (in pdf) in the zip file under the folder Part 4.