Showing results for 
Show  only  | Search instead for 
Did you mean: 

Implementing the Zynq SoC's Private Timer: Adam Taylor’s MicroZed Chronicles Part 15

Xilinx Employee
Xilinx Employee
0 0 61.8K

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


#include "xscutimer.h"


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.


The example in this blog post uses the push-button interrupt, which we have developed previously. See “Using the MicroZed Button for Input: Adam Taylor’s MicroZed Chronicles Part 11”  and “MicroZed Timers, Clocks and Watchdogs: Adam Taylor’s MicroZed Chronicles Part 14.”


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




The next step is to configure and initialize the private timer, perform a self-test, and load the timer count value into the timer:


     //timer initialization

     TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);

     XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr);


     //load the timer

     XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);


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

      XScuGic_Connect(GicInstancePtr, TimerIntrId,


                                    (void *)TimerInstancePtr);

      //enable the interrupt for the Timer at GIC

      XScuGic_Enable(GicInstancePtr, TimerIntrId);

      //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:


static void TimerIntrHandler(void *CallBackRef)



      XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;


      printf("****Timer Event!!!!!!!!!!!!!****\n\r");




The final step is to modify the GPIO interrupt service routine to start the timer each time the button is pushed:


      //load timer

      XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);

      //start timer



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:


Output window for Part 15.jpg 



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:


MicroZed Timers, Clocks and Watchdogs: Adam Taylor’s MicroZed Chronicles Part 14


More About MicroZed Interrupts: Adam Taylor’s MicroZed Chronicles Part 13


MicroZed Interrupts: Adam Taylor’s MicroZed Chronicles Part 12


Using the MicroZed Button for Input: Adam Taylor’s MicroZed Chronicles Part 11


Driving the Zynq SoC's GPIO: Adam Taylor’s MicroZed Chronicles Part 10


Meet the Zynq MIO: Adam Taylor’s MicroZed Chronicles Part 9


MicroZed XADC Software: Adam Taylor’s MicroZed Chronicles Part 8


Getting the XADC Running on the MicroZed: Adam Taylor’s MicroZed Chronicles Part 7


A Boot Loader for MicroZed. Adam Taylor’s MicroZed Chronicles, Part 6 


Figuring out the MicroZed Boot Loader – Adam Taylor’s MicroZed Chronicles, Part 5


Running your programs on the MicroZed – Adam Taylor’s MicroZed Chronicles, Part 4


Zynq and MicroZed say “Hello World”-- Adam Taylor’s MicroZed Chronicles, Part 3


Adam Taylor’s MicroZed Chronicles: Setting the SW Scene


Bringing up the Avnet MicroZed with Vivado


Tags (1)