AXI Clock Monitor
The AXI Clock Monitor IP is used to measure clocks in the system. It allows up to 16 clocks to be measured at a time.
Features
- Can measure up to 16 clocks (set to 1 by default) 
- AXI-based configuration 
- Vivado and Quartus compatible 
Files
| Name | Description | 
|---|---|
| Verilog source for the instance | |
| Tcl source describing the instance for Vivado | |
| Tcl source describing the instance for Quartus | 
Configuration Parameters
| Name | Description | Default Value | Choices/Range | 
|---|---|---|---|
| FPGA_TECHNOLOGY | Encoded value describing the technology/generation of the FPGA device (7series,ultrascale,ultradcale+,versal). | 0 | Unknown (0), 7series (1), ultrascale (2), ultrascale+ (3), versal (4) | 
| ID | Core ID should be unique for each IP in the system. | 0 | |
| NUM_OF_CLOCKS | Select number of CLOCKS. | 1 | From 1 to 16. | 
| DIV_RATE | This parameter can take the following values: 1, 2, 4, 8. | 1 | 
Interface
| Physical Port | Logical Port | Direction | Dependency | 
|---|---|---|---|
| s_axi_awaddr | AWADDR | in [15:0] | |
| s_axi_awprot | AWPROT | in [2:0] | |
| s_axi_awvalid | AWVALID | in | |
| s_axi_awready | AWREADY | out | |
| s_axi_wdata | WDATA | in [31:0] | |
| s_axi_wstrb | WSTRB | in [3:0] | |
| s_axi_wvalid | WVALID | in | |
| s_axi_wready | WREADY | out | |
| s_axi_bresp | BRESP | out [1:0] | |
| s_axi_bvalid | BVALID | out | |
| s_axi_bready | BREADY | in | |
| s_axi_araddr | ARADDR | in [15:0] | |
| s_axi_arprot | ARPROT | in [2:0] | |
| s_axi_arvalid | ARVALID | in | |
| s_axi_arready | ARREADY | out | |
| s_axi_rdata | RDATA | out [31:0] | |
| s_axi_rresp | RRESP | out [1:0] | |
| s_axi_rvalid | RVALID | out | |
| s_axi_rready | RREADY | in | 
| Physical Port | Logical Port | Direction | Dependency | 
|---|---|---|---|
| s_axi_aclk | CLK | in | 
| Physical Port | Logical Port | Direction | Dependency | 
|---|---|---|---|
| s_axi_aresetn | RST | in | 
| Physical Port | Logical Port | Direction | Dependency | 
|---|---|---|---|
| reset | RST | out | 
| Physical Port | Direction | Dependency | Description | 
|---|---|---|---|
| clock_* | in | 
Detailed Description
The top module instantiates:
How to instantiate it in your project:
- build this IP by going to the library/axi_clock_monitor folder and running make. For more details on building this, check out our guide. Another requirement is to have your desired project already built. 
- import the IP core to your block design, by opening the Block Design of the already built project, right-clicking in the Diagram then “Add IP” (or CTRL + I) and typing “axi_clock_monitor” 
- configure your IP by specifying how many clocks you want to monitor 
- connect the IP to the AXI interface 
- assign a base address to the IP core, such that it doesn’t overlap with other components 
- assign clock signals to the clock inputs 
- build again the HDL (now containing this module as well) by clicking “Generate Bitstream” from “Program and Debug” section in Vivado 
Register Map
| DWORD | BYTE | Reg Name | Description | |||
|---|---|---|---|---|---|---|
| BITS | Field Name | Type | Default Value | Description | ||
| 0x0 | 0x0 | PCORE_VERSION | PCORE Version Registers | |||
| [31:0] | PCORE_VERSION | RO | 0x00000001 | PCORE Version number | ||
| 0x1 | 0x4 | ID | ID Registers | |||
| [31:0] | ID | RW | 0x00000000 | Instance identifier number | ||
| 0x3 | 0xc | NUM_OF_CLOCKS | Number of Clocks Registers | |||
| [31:0] | NUM_OF_CLOCKS | RW | 0x00000008 | Number of clock inputs | ||
| 0x2 | 0x8 | DIV_RATE | Divider Rate Registers | |||
| [7:0] | DIV_RATE | RW | 0x01 | Number of divider rate | ||
| 0x4 | 0x10 | OUT_RESET | Reset Control Registers | |||
| [0] | RESET | RW | 0x0 | Control the out reset signal | ||
| 0x10 + 0x1*n | 0x40 + 0x4*n | CLOCK_n | Measured clock_n Where n is from 0 to 15. | |||
| [31:0] | CLOCK_n | RO | 0x00000000 | Measured frequency of clock_n | ||
Software Guidelines
Note
Only no-OS software is supported.
We use software to access the core’s registers to get the data from the IP.
The following example contains a simple function that reads all the info from the IP and prints it on the serial terminal:
 1void clock_monitor_info (uint32_t core_base_addr, uint32_t axi_clock_speed_mhz) {
 2   uint32_t clock_ratio = 0;
 3   uint32_t clk1_addr = 0x40;
 4   uint32_t n_clocks = 0;
 5   uint32_t info_var = 0;
 6   uint8_t n = 0;
 7
 8   info_var = axi_io_read(core_base_addr);
 9   printf("PCORE_VERSION = %d\n", info_var);
10
11   info_var = axi_io_read(core_base_addr, 4);
12   printf("ID = %d\n", info_var);
13
14   n_clocks = axi_io_read((core_base_addr, 12));
15   printf("n clocks = %d\n", n_clocks);
16
17   info_var = axi_io_read(core_base_addr, 16);
18   printf("RESET OUT = %d\n", info_var);
19
20   while (n < n_clocks & n < 16) {
21      clock_ratio = axi_io_read((core_base_addr, clk1_addr + 4*n));
22
23      if (clock_ratio == 0) {
24         printf("Measured clock_%d: off\n", n);
25      } else {
26         printf("Measured clock_%d: %d MHz\n", n,
27            (clock_ratio * axi_clock_speed_mhz + 0x7fff) >> 16);
28      }
29      n++;
30   }
31}
To call the function, consider the following parameters:
- core_base_addr will take the value of the base address set at step 5 of the HDL instantiation 
- axi_clock_speed_mhz will be the reference frequency. In most cases, we assume this parameter to be 100 [MHz]