User Tools

Site Tools


lab_3

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Previous revision
lab_3 [2017/09/27 07:43]
lab_3 [2019/05/08 09:33] (current)
hutch [Interval Timers]
Line 1: Line 1:
 ===== Interval Timers ===== ===== Interval Timers =====
  
 +{{ ::​axitimerblockdiagram2.jpg?​600 }}
 ==== Overview ==== ==== Overview ====
  
Line 23: Line 24:
 You will develop a software driver (including test code) that will communicate with three interval timers that I installed in the bit-stream that you use for this class. Interval timers are essentially hardware counters that you can easily stop, start, and read. Because they are hardware-based counters, they don't interfere with your program or add to execution time while they are running. Interval timers can be very effective for measuring execution time for any part of your software. Do a nice job on this assignment. You will likely use these timers extensively in the remaining labs in this class and later in ECEn 390 when you implement your laser-tag game. You will develop a software driver (including test code) that will communicate with three interval timers that I installed in the bit-stream that you use for this class. Interval timers are essentially hardware counters that you can easily stop, start, and read. Because they are hardware-based counters, they don't interfere with your program or add to execution time while they are running. Interval timers can be very effective for measuring execution time for any part of your software. Do a nice job on this assignment. You will likely use these timers extensively in the remaining labs in this class and later in ECEn 390 when you implement your laser-tag game.
  
-==== Background ​====+==== Timer Hardware Details ​====
  
-The hardware timers that you will access are LogiCORE IP AXI Timer (axi_timer) (v1.03a) provided by Xilinx. Here's a block diagram of the AXI timer taken from the Xilinx documentation. Please refer to the Xilinx documentation for functional details ​of the AXI timer (see Resources Section below).+[[Timer Hardware|Timer overview and detailed description ​of timer operation.]]
  
-{{ ::​axitimerblockdiagram2.jpg?​600 }} 
- 
----- 
- 
-I inserted three of these into the bit-stream and they are named: timer_0, timer_1, and timer_2, as shown below. 
- 
-{{ threeintervaltimerdiagram.jpg?​600 }}  
- 
----- 
----- 
- 
-Here's an excerpt from the ''​xparameters.h''​ file with definitions related to these three timers. As you should recall from Lab 2, the base address is your main concern. 
- 
-**NOTE: Do not copy the code below into your own code. Just include xparameters.h and use the defined values, e.g., XPAR_AXI_TIMER_2_BASEADDR.** 
- 
-<code C> 
-/* Definitions for driver TMRCTR */ 
-#define XPAR_XTMRCTR_NUM_INSTANCES 3 
- 
-/* Definitions for peripheral AXI_TIMER_0 */ 
-#define XPAR_AXI_TIMER_0_DEVICE_ID 0 
-#define XPAR_AXI_TIMER_0_BASEADDR 0x42800000 
-#define XPAR_AXI_TIMER_0_HIGHADDR 0x4280FFFF 
-#define XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ 100000000 
- 
- 
-/* Definitions for peripheral AXI_TIMER_1 */ 
-#define XPAR_AXI_TIMER_1_DEVICE_ID 1 
-#define XPAR_AXI_TIMER_1_BASEADDR 0x42840000 
-#define XPAR_AXI_TIMER_1_HIGHADDR 0x4284FFFF 
-#define XPAR_AXI_TIMER_1_CLOCK_FREQ_HZ 100000000 
- 
- 
-/* Definitions for peripheral AXI_TIMER_2 */ 
-#define XPAR_AXI_TIMER_2_DEVICE_ID 2 
-#define XPAR_AXI_TIMER_2_BASEADDR 0x42880000 
-#define XPAR_AXI_TIMER_2_HIGHADDR 0x4288FFFF 
-#define XPAR_AXI_TIMER_2_CLOCK_FREQ_HZ 100000000 
-</​code>​ 
-==== Resources ==== 
-These timers are fully described in Xilinx'​s documentation. ​ 
- 
-  * {{:​axi_timer_ds764.pdf|Xilinx Timer Documentation}} 
- 
-If the highlighting does not appear, make sure to read at least the following pages: 1, 2-3 (through Characteristics),​ 4-5 (Characteristics),​ 7 (Figure 2), and 11-14 (Register Definitions). 
-==== Overview of Timer Hardware ==== 
- 
-The timer hardware is pretty complex and provides lots of functionality. However, we will only use them in their simplest mode as interval timers. As such, you need to carefully study at least the highlighted sections of the Xilinx documentation. 
- 
-As discussed in the manual, the timer consists of two identical sections each containing a 32-bit counter and associated registers. The two counters can be cascaded to form a single 64-bit counter. This is referred to as cascade mode. In cascade mode, almost all of the control is done via a single control register (TCSR0) as the other control registers are mostly ignored in this mode. The counters can be configured to count up or down, you will configure them to count up. This makes the most sense for a simple timer. 
- 
-You will need to access the following registers in the timer hardware: 
-  * TCSR0: this control/​status register is used to control the cascaded 64-bit counter and to load values into the 32-bit counter. 
-  * TCSR1: you will use this control/​status register only to load a 0 into counter 1 to reset it. 
-  * TLR0: you will need to set both 32-bit counters to zero in order to reset the timer. You do this for counter 0 by loading a 0 into this register and loading the contents of TLR0 into the counter. 
-  * TLR1: you load a 0 into this and load the contents of TLR1 into counter 1 to reset it and set it to 0 (just like counter 0). 
-  * TCR0: you read this register to find out the current value of counter 0. 
-  * TCR1: you read this register to find out the current value of counter 1. 
- 
-  - To initialize the counters, you should do the following: 
-    - write a 0 to the TCSR0 register. 
-    - write a 0 to the TCSR1 register. 
-    - set the CASC bit and clear the UDT0 bit in the TCSR0 register (cascade mode and up counting). 
-  - To store a 0 into counter 0, do the following: 
-    - write a 0 into the TLR0 register. 
-    - write a 1 into the LOAD0 bit in the TCSR0. 
-  - To store a 0 into counter 1, do the following: 
-    - write a 0 into the TLR1 register. 
-    - write a 1 into the LOAD1 bit of the TCSR1 register. 
-  - To start the cascaded counter: 
-    - write a 1 to the ENT0 bit of the TCSR0 register. When you do this, you must not disturb the other bits in TCSR0. 
-  - To stop the cascaded counter: 
-    - clear the ENT0 bit in the TCSR0 register. Make sure not to clear out the CASC bit when you do this (or you will need to restore it). 
- 
-=== Additional Notes:=== 
- 
-  - After loading the counters with 0s to reset them, you must re-initialize them (see Step 1 above). In particular, make sure that you clear the load bit for both counters. 
-  - The process for reading the two 32-bit counters and reassembling them into a single 64-bit number is described on Page 5 of the documentation. 
-  - Search the ''​xparameters.h''​ file to find out the frequency for the timers. Always use the provided ''#​define''​s as they are provided by ''​xparameters.h''​. Don't use the actual numerical constants. 
-==== Requirements ==== 
-  - You must write the ''​intervalTimer.c''​ file. 
-  - You must use ''​intervalTimer.h''​ as given. No modifications are necessary or allowed. 
-  - You must follow the coding standard. 
-  - You must provide the following functions for the three interval timers (see below). 
-  - You must use the Xilinx low-level access functions ''​Xil_In32()''​ and ''​Xil_Out32()''​ to access the registers in the timer hardware. These functions were discussed in a previous lab. 
-  - You must define isr_function() in your code to avoid linking errors. Just use the same empty function from the helloWorld lab. 
-  - Run the the final pass-off code (see below) for the TA to demonstrate the accuracy of your timer. Compare the time printed by the program to your watch to demonstrate accuracy. 
- 
-<code C intervalTimer.h>​ 
-/* 
- * intervalTimer.h 
- * 
- ​* ​ Created on: Apr 2, 2014 
- ​* ​     Author: hutch 
- */ 
- 
-// Provides an API for accessing the three hardware timers that are installed 
-// in the ZYNQ fabric. 
- 
-#ifndef INTERVALTIMER_H_ 
-#define INTERVALTIMER_H_ 
- 
-#include <​stdint.h>​ 
- 
-// Used to indicate status that can be checked after invoking the function. 
-typedef uint32_t intervalTimer_status_t; ​ // Use this type for the return type of a function. 
- 
-#define INTERVAL_TIMER_STATUS_OK 1        // Return this status if successful. 
-#define INTERVAL_TIMER_STATUS_FAIL 0      // Return this status if failure. 
- 
-#define INTERVAL_TIMER_TIMER_0 0 
-#define INTERVAL_TIMER_TIMER_1 1 
-#define INTERVAL_TIMER_TIMER_2 2 
- 
-// You must initialize the timers before you use them the first time. 
-// It is generally only called once but should not cause an error if it  
-// is called multiple times. 
-// timerNumber indicates which timer should be initialized. 
-// returns INTERVAL_TIMER_STATUS_OK if successful, some other value otherwise. 
-intervalTimer_status_t intervalTimer_init(uint32_t timerNumber);​ 
- 
-// This is a convenience function that initializes all interval timers. 
-// Simply calls intervalTimer_init() on all timers. 
-// returns INTERVAL_TIMER_STATUS_OK if successful, some other value otherwise. 
-intervalTimer_status_t intervalTimer_initAll();​ 
- 
-// This function starts the interval timer running. 
-// If the interval timer is already running, this function does nothing. 
-// timerNumber indicates which timer should start running. 
-void intervalTimer_start(uint32_t timerNumber);​ 
- 
-// This function stops a running interval timer. 
-// If the interval time is currently stopped, this function does nothing. 
-// timerNumber indicates which timer should stop running. 
-void intervalTimer_stop(uint32_t timerNumber);​ 
- 
-// This function is called whenever you want to reuse an interval timer. 
-// For example, say the interval timer has been used in the past, the user 
-// will call intervalTimer_reset() prior to calling intervalTimer_start(). 
-// timerNumber indicates which timer should reset. 
-void intervalTimer_reset(uint32_t timerNumber);​ 
- 
-// Convenience function for intervalTimer_reset(). 
-// Simply calls intervalTimer_reset() on all timers. 
-void intervalTimer_resetAll();​ 
- 
-// Runs a test on a single timer as indicated by the timerNumber argument. 
-// Returns INTERVAL_TIMER_STATUS_OK if successful, something else otherwise. 
-intervalTimer_status_t intervalTimer_test(uint32_t timerNumber);​ 
- 
-// Convenience function that invokes test on all interval timers. 
-// Returns INTERVAL_TIMER_STATUS_OK if successful, something else otherwise. 
-intervalTimer_status_t intervalTimer_testAll();​ 
- 
-// Use this function to ascertain how long a given timer has been running. 
-// Note that it should not be an error to call this function on a running timer 
-// though it usually makes more sense to call this after intervalTimer_stop() has 
-// been called. 
-// The timerNumber argument determines which timer is read. 
-double intervalTimer_getTotalDurationInSeconds(uint32_t timerNumber);​ 
- 
-#endif /* INTERVALTIMER_H_ */ 
-</​code>​ 
- 
-The functions that accept a timerNumber argument operate on a single timer. The timer number must be: 0, 1, or 2. Anything else should generate an error message. The intervalTimer_initAll(),​ intervalTimer_resetAll(),​ and intervalTimer_testAll() operate on all three timers. intervalTimer_getTotalDurationInSeconds() reads the 64-bit value from the timer and returns the number of seconds that have transpired since the counter was last reset and started. 
- 
-intervalTimer_test() needs to see if the timers are working. In my code, I check things by: 
-  
-  - I reset the counter and see if it is reset by reading it. 
-  - I start the counter and read it a couple of times to see if it is actually changing value. 
-  - I stop the counter and read it a couple of times to see that it is not changing. 
 ==== Hints and Helps ==== ==== Hints and Helps ====
   - The register access functions that you wrote for Lab 2 could be used here with little or no modification.   - The register access functions that you wrote for Lab 2 could be used here with little or no modification.
Line 209: Line 39:
   - **Milestone 2**: Complete all of the lab requirements for all timers (timer_0, timer_1, and timer_2). Demonstration of this milestone (all lab requirements) is worth **50%** of the total credit for this lab. **Your program must work correctly each time it is executed. It must not depend upon the board being reset.**   - **Milestone 2**: Complete all of the lab requirements for all timers (timer_0, timer_1, and timer_2). Demonstration of this milestone (all lab requirements) is worth **50%** of the total credit for this lab. **Your program must work correctly each time it is executed. It must not depend upon the board being reset.**
   - **Code quality and adherence to the coding standard** is worth **25%** of the total credit for this lab.    - **Code quality and adherence to the coding standard** is worth **25%** of the total credit for this lab. 
 +
 +==== Submitting Source Code ====
 +Follow [[http://​ecen330wiki.groups.et.byu.net/​wiki/​doku.php?​id=submitting_source_code|this procedure]] to submit your source code to learning-suite.
  
 === Notes to TAs === === Notes to TAs ===
Line 223: Line 56:
  
 The "​.."​ tells the compiler to go up to the next directory. The "​.."​ tells the compiler to go up to the next directory.
- 
----- 
- 
- 
----- 
  
 ==== Milestone 1 and 2 Test Programs: Use This Code to Pass Off Milestone 1 and 2 ==== ==== Milestone 1 and 2 Test Programs: Use This Code to Pass Off Milestone 1 and 2 ====
  
-<code+I provide the [[Timer Test Source Code|source ​code]] that you must use for pass-offCall this code from your ''​main()'' ​function.
-#include "​supportFiles/​intervalTimer.h" ​ // Modify this to reflect the location of your intervalTimer.h +
-#include "​supportFiles/​buttons.h" ​       // Modify this to reflect the location of your buttons.h +
-#include "​supportFiles/​utils.h"​ +
-#include <​stdio.h>​ +
-#include "​xil_io.h"​ +
- +
-#define TCR0_OFFSET 0x08  // register offset for TCR0 +
-#define TCR1_OFFSET 0x18  // register offset for TCR1 +
- +
-// Reads the timer1 registers based upon the offset. +
-u32 readTimer1Register(uint32_t registerOffset) { +
-  uint32_t address = XPAR_AXI_TIMER_0_BASEADDR + registerOffset; ​ // Add the offset to the base address. +
-  return Xil_In32(address); ​ // Read the register at that address. +
-+
- +
-#define DELAY_COUNT 3 +
-// Simple busy-wait function. +
-void waitALongTime() { +
-  volatile int32_t a = 0;        // Use volatile so that optimizer doesn'​t mess things up. +
-  int32_t i, j;  // Simple index variables. +
-  ​for (i=0; i<​DELAY_COUNT;​ i++)        // Outer delay-loop. +
-    for (j=0; j<​INT32_MAX;​ j++)  // Inner delay-loop. +
-      a++; +
-+
- +
-void milestone1() { +
-  printf("​=============== Starting milestone 1 ===============\n\r"​);​ +
-  intervalTimer_init(INTERVAL_TIMER_TIMER_0); ​ // Init timer 0. +
-  intervalTimer_reset(INTERVAL_TIMER_TIMER_0);​ // Reset timer 0. +
-  // Show that the timer is reset. +
-  // Check lower register. +
-  printf("​timer_0 TCR0 should be 0 at this point:​%ld\n\r",​ readTimer1Register(TCR0_OFFSET)); +
-  // Check upper register. +
-  printf("​timer_0 TCR1 should be 0 at this point:​%ld\n\r",​ readTimer1Register(TCR1_OFFSET));​ +
-  intervalTimer_start(INTERVAL_TIMER_TIMER_0); ​ // Start timer 0. +
-  // Show that the timer is running. +
-  printf("​The following register values should be changing while reading them.\n\r"​);​ +
-  // Just checking multiple times to see if the timer is running. +
-  printf("​timer_0 TCR0 should be changing at this point:​%ld\n\r",​ readTimer1Register(TCR0_OFFSET));​ +
-  printf("​timer_0 TCR0 should be changing at this point:​%ld\n\r",​ readTimer1Register(TCR0_OFFSET));​ +
-  printf("​timer_0 TCR0 should be changing at this point:​%ld\n\r",​ readTimer1Register(TCR0_OFFSET));​ +
-  printf("​timer_0 TCR0 should be changing at this point:​%ld\n\r",​ readTimer1Register(TCR0_OFFSET));​ +
-  printf("​timer_0 TCR0 should be changing at this point:​%ld\n\r",​ readTimer1Register(TCR0_OFFSET));​ +
-  // Wait about 2 minutes so that you roll over to TCR1. +
-  // If you don't see a '1' or '​2'​ in TCR1 after this long wait you probably haven'​t programmed the timer correctly. +
-  waitALongTime();​ +
-  // Check lower register. +
-  printf("​timer_0 TCR0 value after wait:​%lx\n\r",​ readTimer1Register(TCR0_OFFSET));​ +
-  // Check upper register. +
-  printf("​timer_0 TCR1 should have changed at this point:​%ld\n\r",​ readTimer1Register(TCR1_OFFSET));​ +
-+
- +
-#define TEST_ITERATION_COUNT 4 +
-#define ONE_SECOND_DELAY 1000 +
-void milestone2() { +
-  printf("​=============== Starting milestone 2 ===============\n\r"​);​ +
-  double duration0, duration1, duration2; ​ // Will hold the duration values for the various timers. +
-  buttons_init(); ​          // init the buttons package. +
-  intervalTimer_initAll(); ​ // init all of the interval timers. +
-  intervalTimer_resetAll();​ // reset all of the interval timers. +
-  // Poll the push-buttons waiting for BTN0 to be pushed. +
-  printf("​Interval Timer Accuracy Test\n\r"​); ​    // User status message. +
-  printf("​waiting until BTN0 is pressed.\n\r"​); ​  // Tell user what you are waiting for. +
-  while (!(buttons_read() & BUTTONS_BTN0_MASK)); ​ // Loop here until BTN0 pressed. +
-  // Start all of the interval timers. +
-  intervalTimer_start(INTERVAL_TIMER_TIMER_0);​ +
-  intervalTimer_start(INTERVAL_TIMER_TIMER_1);​ +
-  intervalTimer_start(INTERVAL_TIMER_TIMER_2);​ +
-  printf("​started timers.\n\r"​);​ +
-  printf("​waiting until BTN1 is pressed.\n\r"​); ​ // Poll BTN1. +
-  while (!(buttons_read() & BUTTONS_BTN1_MASK));​ // Loop here until BTN1 pressed. +
-  // Stop all of the timers. +
-  intervalTimer_stop(INTERVAL_TIMER_TIMER_0);​ +
-  intervalTimer_stop(INTERVAL_TIMER_TIMER_1);​ +
-  intervalTimer_stop(INTERVAL_TIMER_TIMER_2);​ +
-  printf("​stopped timers.\n\r"​);​ +
-  // Get the duration values for all of the timers. +
-  duration0 = intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_0);​ +
-  duration1 = intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_1);​ +
-  duration2 = intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_2);​ +
-  // Print the duration values for all of the timers. +
-  printf("​Time Duration 0: %6.2e seconds.\n\r",​ duration0);​ +
-  printf("​Time Duration 1: %6.2e seconds.\n\r",​ duration1);​ +
-  printf("​Time Duration 2: %6.2e seconds.\n\r",​ duration2);​ +
-  // Now, test to see that all timers can be restarted multiple times. +
-  printf("​Iterating over fixed delay tests\n\r"​);​ +
-  printf("​Delays should approximately be: 1, 2, 3, 4 seconds.\n\r"​);​ +
-  printf("​Note that delays may be about 25%%-30%% lower if your compiler optimizations are set to -O2 or -O3\n\r"​);​ +
-  for (int i=0; i<​TEST_ITERATION_COUNT;​ i++) { +
-    // Reset all the timers. +
-    intervalTimer_resetAll();​ +
-    // Start all the timers. +
-    intervalTimer_start(INTERVAL_TIMER_TIMER_0);​ +
-    intervalTimer_start(INTERVAL_TIMER_TIMER_1);​ +
-    intervalTimer_start(INTERVAL_TIMER_TIMER_2);​ +
-    // Delay is based on the loop count. +
-    utils_msDelay((i+1)*ONE_SECOND_DELAY);​ +
-    // Stop all of the timers. +
-    intervalTimer_stop(INTERVAL_TIMER_TIMER_0);​ +
-    intervalTimer_stop(INTERVAL_TIMER_TIMER_1);​ +
-    intervalTimer_stop(INTERVAL_TIMER_TIMER_2);​ +
-    // Print the duration of all of the timers. The delays should be approximately 1, 2, 3, and 4 seconds. +
-    printf("​timer:​(%d) duration:​%f\n\r",​ INTERVAL_TIMER_TIMER_0,​ intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_0));​ +
-    printf("​timer:​(%d) duration:​%f\n\r",​ INTERVAL_TIMER_TIMER_1,​ intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_1));​ +
-    printf("​timer:​(%d) duration:​%f\n\r",​ INTERVAL_TIMER_TIMER_2,​ intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_2));​ +
-  } +
-  // Now, test for increment timing (start-stop-start-stop...) +
-  // Reset all the timers. +
-  intervalTimer_resetAll();​ +
-  for (int i=0; i<​TEST_ITERATION_COUNT;​ i++) { +
-    // Start all the timers. +
-    intervalTimer_start(INTERVAL_TIMER_TIMER_0);​ +
-    intervalTimer_start(INTERVAL_TIMER_TIMER_1);​ +
-    intervalTimer_start(INTERVAL_TIMER_TIMER_2);​ +
-    // Delay is based on the loop count. +
-    utils_msDelay((i+1)*ONE_SECOND_DELAY);​ +
-    // Stop all of the timers. +
-    intervalTimer_stop(INTERVAL_TIMER_TIMER_0);​ +
-    intervalTimer_stop(INTERVAL_TIMER_TIMER_1);​ +
-    intervalTimer_stop(INTERVAL_TIMER_TIMER_2);​ +
-    // Print the duration of all of the timers. The delays should be approximately 1, 3, 6, and 10 seconds. +
-    printf("​Delays should approximately be: 1, 3, 6, 10 seconds keeping in mind that you times may be lower due to compiler-optimization settings.\n\r"​);​ +
-    printf("​timer:​(%d) duration:​%f\n\r",​ INTERVAL_TIMER_TIMER_0,​ intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_0));​ +
-    printf("​timer:​(%d) duration:​%f\n\r",​ INTERVAL_TIMER_TIMER_1,​ intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_1));​ +
-    printf("​timer:​(%d) duration:​%f\n\r",​ INTERVAL_TIMER_TIMER_2,​ intervalTimer_getTotalDurationInSeconds(INTERVAL_TIMER_TIMER_2));​ +
-  } +
- +
-  printf("​intervalTimer Test Complete.\n\r"​);​ +
-+
- +
-// main executes both milestones. +
-int main() { +
-  milestone1(); ​ // Execute milestone 1 +
-  milestone2(); ​ // Execute milestone 2 +
-+
- +
-void isr_function(){} +
-</​code>​+
  
----- 
  
lab_3.1506519835.txt.gz · Last modified: 2019/04/08 20:12 (external edit)