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).
I inserted three of these into the bit-stream and they are named: timer_0, timer_1, and timer_2, as shown below.
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.
/* 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
These timers are fully described in Xilinx's 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).
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:
xparameters.hfile to find out the frequency for the timers. Always use the provided
#defines as they are provided by
xparameters.h. Don't use the actual numerical constants.
intervalTimer.has given. No modifications are necessary or allowed.
Xil_Out32()to access the registers in the timer hardware. These functions were discussed in a previous lab.
/* * 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_ */
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:
Xil_In32(), Xil_Out32()) inside a helper function as demonstrated in the code provided for the buttons/switches lab.