In the last blog we looked at Zynq timers. In this new instalment, we will start looking at how we can use these resources starting with the private timer. Like most of the Zynq peripherals, the private timer has a number of predefined functions and macros to help the engineer use the resource efficiently. These are contained within
Xscutimer.h contains functions (macros) that:
Initialize the timer
Run a timer self test
Start and stop the timer
Manage the timer (restart, check if expired, load the timer, enable/disable auto loading)
Set the pre-scaler
Get the pre-scaler value
Setup, enable, disable, clear, and manage timer interrupts
The timer itself is controlled via four registers in the Zynq All Programmable SoC:
Private Timer Load Register – used in auto reload mode. This register contains the value to be reloaded into the Private Timer Counter Register when auto reload is enabled.
Private Timer Counter Register – This register is the actual counter itself. When the value in this register reaches zero, an interrupt event flag is set (when enabled).
Private Timer Control Register – This control register enables or disables the timer, auto reload mode, and interrupt generation. It also contains the timer pre-scaler.
Private Timer Interrupt Status Register – This register contains the Private timer interrupt status event flag
The timer device ID and timer interrupt ID, which are needed to set up the timer, are contained within XParameters.h.
In this example, the timer will be loaded and will start running when the button is pressed. (Note: the timer will not be run in auto-reload mode). The timer will generate an interrupt when the preset timer countdown value reaches zero. The resulting interrupt triggers output of a message out over STDOUT and the interrupt will then be cleared to await the next button press.
This example always loads the same value into the counter. Hence the declarations at the top of the file where the timer count value is declared
#define TIMER_LOAD_VALUE 0xFFFFFFFF
The next step is to configure and initialize the private timer, perform a self-test, and load the timer count value into the timer:
We also need to update the interrupt setup subroutine to connect the timer interrupts to the GIC (General Interrupt controller) and enable the timer interrupt:
//set up the timer interrupt
//enable the interrupt for the Timer at GIC
//enable interrupt on the timer
Where TimerIntrHandler is the name of the function to be called when the interrupt occurs.
Next, the timer interrupt must be enabled on the GIC and within the timer itself. The timer interrupt service routine is very simple. It just clears the pending interrupt and writes out a message over the STDOUT:
The final step is to modify the GPIO interrupt service routine to start the timer each time the button is pushed:
To do this, we first load the timer value into the timer and then call the timer start function, before again clearing the push button interrupt and resume processing.
To reduce the number of messages being output over STDOUT, the reading of XADC within the main loop of this program has been removed in this example. Here’s what the output from this program now looks like:
Downloadable sample code is attached to this blog post.
In the next blog we will look at using the private watchdog.
Please see the previous entries in this MicroZed series by Adam Taylor: