18-348 Lab #8

Spring 2016

NOTE: The oscilloscopes in the lab do not have an "autostore" feature. Instead they have an "infinite persistence" display feature that has the same functionality, so be sure to turn on infinite persistence when the lab asks for autostore.

Links to all files referenced in the lab and prelab can be found in the Files section at the end of this document.

NOTE: It is important to rename your source code files to include your andrew ID for prelab and your group number for the lab. This applies to any main.c, main.asm, and other files you are handing in


Prelab - Hardware interrupts and scheduling
Lab - Interrupts
Support Materials

Pre-Lab 8:




There are typically two methods by which a microcontroller can gather data from a device connected to it - polling and interrupts. Polling is the process of periodically reading the device to see if it has any information or if an event has occurred.  Using interrupts is slightly more complicated. Whenever new data is collected or an event occurs at the device, the device can generate a signal to notify the microcontroller that it should read from the device. When the microcontroller receives an interrupt, it suspends its current processing and passes control to a special subroutine called an interrupt service routine (ISR). The ISR is responsible for acknowledging the interrupt (e.g. clearing a flag) and doing some processing (i.e. reading and storing some new data, incrementing a counter, etc.) based on the interrupt before it returns control to the code that was executing when the interrupt occurred.

For the microcontroller used in the lab, there are on-chip peripherals which are interfaced to the CPU through various control registers.  Many of these devices (timers, A/D converters, UARTs, etc) can generate interrupts.  It is also possible to allow external devices to generate interrupts via some of the I/O pins, but this goes beyond the scope of this lab.

When an interrupt occurs, the microcontroller stores the current value of the PC to the stack and transfers control to the ISR.  The location of the ISR code is stored in a table called the interrupt vector table.  The vector table is located at a fixed location in the system.  The actual ISR code can reside anywhere in addressable program memory.  The processor references this vector table to find the starting address of the ISR.  The ISR should always terminate with an RTI instruction, which properly restores the stack and any other register values to the original value before the interrupt occurred. 

For any further information on interrupts, please refer to the lecture notes or Chapter 5 of the MC9S12 data sheet.

Task Scheduling

In this pre-lab, you will answer questions regarding a given schedule.  The following terminology is used in this lab:

Unless otherwise noted, latency we mean response time, which is time until the relevant ISR, task, etc. STARTS executing. We do not mean completion time.


In previous labs, you have used the APS12C128 to communicate with hardware devices such as the timer and the serial communications interface (SCI) through polling. In this lab, you will learn how to set-up the chip and these devices so that they can communicate using interrupts.  For parts 1 and 2, determine the correct control register settings.  For part 3, analyze task response times.

Part 1:    Timer Interrupts

Use the interrupt vector table in Section 1.6.1 of the MC9S12 data sheet and the Timer register information in section 15.3.2 of the MC9S12 data sheet.

Complete the following table so that the Timer peripheral:

Register bits
TSCR1: 7
TSCR2: 7
TSCR2: 2:0

Table 1.1:  Timer control register values

Part 2:    UART Interrupts

Use the interrupt vector table in Section 1.6.1 of the data sheet and the SCI register information in section 13.3.2 of the data sheet. Complete the following table so that:

Register Bits
SCIBDH: [4:0]

SCIBDL: [7:0]



Table 2.1:  SCI control register values

Part 3:    Task Scheduling

Complete the following tables and answer the corresponding questions.  In the tables below,  an empty row or column with a "..." symbol indicates you should add as many rows/columns as are appropriate to complete the calculation.

Review lectures 14 and 15 for more details on scheduling theory.

Part 3.1:    Main Loop Schedule

Task # Type Priority Period (ms) Execution Time (ms)
1 main loop n/a n/a 100 ms
2 main loop n/a n/a 150 ms
3 ISR 1 50 ms 3 ms
4 ISR 2 50 ms 3 ms
5 ISR 3 50 ms 6 ms
6 ISR 4 50 ms 6 ms

Table 3.1:  Task Schedule Data

Q1. Compute the worst-case latency for the main loop using the data from Table 3.1.   Fill the iterative values into a table like Table 3.2 below.   Complete enough iterations for the value of the main loop latency to converge.

Iteration 0 1 2 ...
Main loop contribution
ISR1 latency contribution
ISR2 latency contribution
Total latency

Table 3.2:  Template for main loop latency calculation.

Q2:  The system requirements for a system with the workload in Table 3.1 dictate that tasks 1 and 2 must be executed at least every 500 ms.  Can this requirement be met given your calculations from Table 2?

Q3:  What, if anything, must the main loop task periods be changed to in order to be schedulable with at least 10% margin?

Part 3.2:  Non-preemptive ISR

Task # ISR Priority Period (ms) Execution Time (ms)
1 1 50 ms 3 ms
2 2 50 ms 3 ms
3 3 50 ms 6 ms
4 4 50 ms 6 ms
5 5 100 ms 30 ms
6 6 100 ms 30 ms
7 7 100 ms 45 ms
8 8 130 ms 45 ms

Table 3.3:  ISR Task Data for Part 3.2

Q4: Suppose a system has the ISR tasks shown in Table 3.3.  Assume that interrupts are never disabled in the main program and that all ISRs run to completion (e.g. no preemption).
Complete Table 3.4 to show the iterative calculation for the worst-case latency for ISR 6.

Iteration 0 1 2 ...
Worst case lower priority task
ISR1 latency contribution
ISR2 latency contribution
Total latency

Table 3.4:  Template for ISR6 latency calculation

Q5:  What is the worst-case latency for ISR6?

Q6:  Does the result in question 5 depend on whether or not there is a main-loop (non-ISR code)?  Assume that no part of the (hypothetical) main loop disables interrupts.

Part 3.3:  Non-preemptive ISR with Blocking Tasks

Now assume that there are blocking tasks in the main loop that DO disable interrupts, according to the values given Table 3.5:

Main Loop Task # Blocking Time (ms)
1 45 ms
2 15 ms
3 77 ms

Table 3.5:  Main-loop tasks

Q7: Repeat the computation for worst case latency of ISR6.  Complete Table 3.6 with the iterative values for your solution

Iteration 0 1 2 ...
Worst case lower priority task
ISR1 latency contribution
ISR2 latency contribution
Total latency

Table 3.6:  Template for ISR6 latency calculation

Q8:  What is the worst-case latency of ISR6 given the blocking tasks in Table 6?

Part 3.4:  Preemptive ISR

For this part, assume that the hardware is capable of preempting an ISR when a higher priority interrupt occurs.  For this part, assume there are no blocking tasks.

Q9: Using the data in Table 3.3 above, compute the worst case latency for ISR6.  Complete Table 3.9 with the iterative values for the computation.

Iteration 0 1 2 ...
Worst case lower priority task
ISR1 latency contribution
ISR2 latency contribution
Total latency

Table 3.9:  Template for ISR6 latency calculation

Q10:  What is the worst-case latency for ISR6 under this system, assuming preemption.

Hand-in Checklist (90 + 9):

All non-code submissions shall be in a single PDF document.

All code submissions shall have Andrew ID in filename.

Part 1:  Timer Interrupts

  1. (5 points) Fill in Table 1.1 above.
  2. (5 points) What is the vector address for the Timer Overflow?
  3. (5 points) What is the name of the register that holds the TOF flag? What action must be performed in the ISR to clear the flag bit?

Part 2:  UART Interrupts

  1. (5 points) Fill in Table 2.1 above.
  2. (5 points) What is the vector address for the SCI?
  3. (5 points) If both transmit and receive interrupts are enabled for the SCI, how do you know which one caused the SCI interrupt?  What action do you perform (and what register is it performed on) to acknowledge a receiver interrupt? (100 words maximum)
  4. BONUS: (3 points) List 2 advantages of interrupts over polling.  This can be two advantages in the general case, not necessarily specific to the SCI or timer interrupts. (100 words maximum)
  5. BONUS: (6 points) Real systems are often a mix of preemptive and non-preemptive tasks. Figure out the worst case latency for the following task mix. We recommend a spreadsheet-type approach or timeline approach rather than an analytic (equation-based) approach, because the math gets complicated. Give the worst case completion time for every task under the following assumptions, and compare each task's completion time to its period. Show all work to receive credit. (So, to receive credit you will give worst case completion times for all five tasks, showing your work.)
You must make a reasonable attempt (i.e., be substantially correct) on all five tasks *including the main tasks* to receive any credit for this section. Attempting ONLY the ISR portion of this problem will result in no credit, since that analysis is right out of the course lecture notes.

Blocking time=4
Task Period (Pi)
Execution Time (Ci)
Main task 4
Main task 5

Part 3:  Task Scheduling

  1. (60 points) Complete questions Q1 through Q10

Refer to the LAB FAQ for more information on lab handin procedures and file type requirements.  You MUST follow these procedures or we will not accept your submissions.

Lab 8:



In this lab you will build a cyclic executive with two interrupt service routines. The cyclic executive will combine both C code and assembly.  You will implement interrupt functions in both assembly and C.


Interrupts can be used to allow multiple tasks to run concurrently on the chip. The code that executes normally (i.e., once main() has started executing) can be considered a foreground task because it runs continuously. The code in an ISR can be considered a background task because it only executes when an interrupt is received and does not execute again until another interrupt is received. Full-scale operating systems are of course much more complex than this, but for many embedded systems this simple approach to tasking does just fine.

Cyclic Executive and ISRs

In the lab, you will use an oscilloscope to measure the performance of the a system which combines main-loop operations with the interrupt service routines (ISRs).

The program shall perform the following:

You have implemented a majority of this functionality in previous labs.  We encourage you to re-use that code for this lab.

In addition to the behaviors described above, the digital outputs on Port B are used to indicate the activity of the processor.  For example, while the timer overflow ISR is executing, bit 7 of Port B is set high and is set low otherwise.  Refer to the "defines" section of the code to see which bit corresponds to which activity.  The relative brightness and frequency of the LEDs connected to port B gives you a sense of which parts of the code are being executed more often.  In addition to observing them visually, you will use the oscilloscope monitor these outputs with the oscilloscope to make measurements of the program activity.

The oscilloscopes in the lab are Agilent Technologies DSO6012A. The manual is available here:  Agilent 5000/6000/7000 Series Oscilloscopes User Guide.

In this lab, you make use of a program called RateSender.  You can get the command-line syntax by running the program with no arguments.  Use Ctrl-C to terminate the program.  Note that the program may consume significant resources on your PC, so you may have to stop it in order to record data or use other programs.



  1. Wire the board for the wiper controller according to Lab #3 Part B.
  2. Wire Port B of the module to the project board LEDs.

Part 1 - Cyclic Executive:

Download the lab 8 skeleton project.  Rename your project folder to lab_8_gXX.  You will modify the C and assembly files to implement the foreground tasks.

  1. Add the wiper controller functionality in assembly code as the main foreground task.  You do not have to modify the main loop.  The main C program calls assembly functions to initialize and execute your wiper controller functionality.  Your foreground task shall have the same requirements as the windshield wiper task from Lab #3 (this means you can re-use code you already have implemented plus changes to meet further requirements).  You may use either the base implementation or the bonus implementation (with intermittent state) as you prefer.

Part 2 - Serial Interrupt:

Implement the serial interrupt service routine.  The setup code shall be in C code.  The ISR itself shall be written in assembly. This interrupt will read the most recent byte received by the UART and place it into the byte array sciRxBuf.  This buffer will hold the 8 most recent bytes received by the UART. 

serialSetup( ) is a C function which sets up the UART.  The routine shall meet the following requirements
  1. The UART shall operate at 38400 baud, with no parity enabled, one stop bit, and 8 bit data format.
  2. The UART receiver shall be enabled.
  3. An interrupt shall be generated when a character is received by the UART.
  4. The sciRxBuf array shall be initialized to all spaces.
sci_handle is an assembly interrupt service routine that handles interrupts generated by the UART.  The handler should meet the following requirements:
  1. Upon activation, the ISR shall store the byte value received from the UART in the buffer sciRxBuf. 

Q8: fill out Table 4 below per above procedure.

Send rate (RateSender argument in ms) Serial receive frequency (Hz) Cursor measurement (s) # of main loops Main loop execution time (s) Apparent effect on the chasing LED.
none (RateSender not running) 0 1.592 5 0.3184 Run normally
1000 1 1.600 5
0.3200 LEDs run more slowly

Table 4 - Main loop execution time measurements.  Some sample values have been filled in to help you understand the meaning of the columns.  Note that the data in the samples is NOT accurate and MUST be replaced with your own data.

Q9: Plot the data for Main loop execution time (col 5) vs the Serial receive frequency (col 2) of the data you recorded in table 4.  Do not plot the rows you marked as non-functional.

Part 4.3:

In this section, you will measure the response time of the receive interrupt.  The procedure for this section assumes you have already loaded the code and connected the serial port as in Part 1.

  1. Connect channel 1 of the oscilloscope to RXD0 pin on the J1 connector.  This is the raw serial data coming from the PC.
  2. Connect channel 2 of the oscilloscope to RDRF_INDICATOR pin of Port B.
  3. Run RateSender with any message you wish and a send rate of 100 ms.
  4. Change the oscilloscope to trigger on the falling edge of RXD0 (channel 1).  This is the beginning of the start bit.  You may need to increase the holdoff on the trigger to stabilize the waveform.
  5. Set the timebase to 200 us/div.  Adjust the delay so you can see the entire serial frame and the beginning of the RDRF_INDICATOR pulse.
  6. Use the cursors to measure the time between the final rising edge in the serial frame (note that this is the beginning of the stop bit) and the beginning of the RDRF_INDICATOR pulse.  Record this value and answer question 10 below.
  7. Measure the length of time the receive ISR takes to execute (this is the width of the pulse).

Q10:  What is the time between the beginning of the stop bit and the beginning of the RDRF pulse?  How does this compare to the width of one baud (symbol) at the baud rate being used in the code?

Q11:  How long does it take the receive ISR to execute?

Part 4.4:

In this section, you will see the effect of blocking tasks on interrupt latency.

  1. Modify lab_8_main.c by uncommenting the "#define BLOCK_DURING_LCD " compiler directive.  With this modification, interrupts are masked during the LCD write sequence, making it a blocking task.
  2. Compile and load the modified program.
  3. Run RateSender with any message you wish at a rate of 50 ms.
  4. Adjust the timebase to 5 ms/div.  Turn on the Autostore feature.  Allow the program to run for 3 minutes.
  5. After 3 minutes, there will be a cloud that represents the various ISR executions.  Measure the time from the beginning of the cloud to the end.  Use this measurement and the value you measured in step 7 of part 4.3 to compute the maximum latency of the receive ISR.  Record this value and answer the questions 12 and 13 below.

Q12:  What is the maximum latency of the receive ISR?  What can you infer about the length of the blocking task from this information?

Bonus: Q13:  The cloud in the measurements you took for part 4.4 indicates that the ISR latency can be any value from a few microseconds to the maximum value you computed in question 6.  Explain why the latency can be any value in this range (as opposed to only being the maximum value). (100 words maximum)

Bonus Part 5 - Mutex Demonstration - Optional:

For this bonus section you're going to implement a very simple timer-tick scheduler and mutex system to write and test a mutex for correct operation. We leave the details up to you, but the point of this exercise is to write a mutex and demonstrate it really works. You must meet the following requirements:
It is expected that version 1 will only work incorrectly sometimes. We strongly recommend you find a way to make it work incorrectly on average once every 30 seconds or so for the sake of a practical demo (faster is better). It is reasonable to run version 2 for 10 times the version 1 problem inter-arrival time to demonstrate that version 2 is operating problem-free under the same circumstances. It is OK to have two separate programs for version 1 and version 2, but a combined program to test both versions is also acceptable.

Bonus: Q14. Describe the general strategy used to create the test system for version 1 and version 2 of the code above (100 words or fewer).

Demo Checklist: (60 + 5 points)

  1. (30 points) Demo your program to the TA with RateSender running at a rate of 100 ms. You must show that both your windshield wiper functionality and UART functionality and timer functionality work correctly (i.e. both will properly process their input if you simultaneously give both types of input).
  2. (30 points) Demo one measurement selected by the TA.
  3. Bonus: (5 points) Optional.  Demo your mutex test program from Part 5.

Hand-in Checklist: (115 + 13 points)

All non-code submissions shall be in a single PDF document.

All code submissions shall have group name in filename.

  1. (5 points) List any problems you encountered in the lab and pre-lab, and suggestions for future improvement of this lab. If none, then state so to get these points.
  2. (50 points) Submit your lab_8_gXX project folder. The coding style sheet must be followed to receive full credit.
  3. (60 points) Answer the questions Q1-12.
  4. Bonus: (3 points) Optional. Answer question Q13.
  5. Bonus: (10 points) Optional. Answer question Q14 and submit your project folder for Part 5. Name the folder lab_8_mutex_gXX.  The coding style sheet must be followed to receive full credit.

Refer to the LAB FAQ for more information on lab handin procedures and file type requirements.  You MUST follow these procedures or we will not accept your submissions.

Hints and Suggestions:

FILES for this lab:

Relevant reading:

Also, see the course materials repository page.

Change notes for 2016: