Read Zynq clock frequencies

This example showing how to read the appropriate Zynq system registers to find the frequency of the ARM Cortex-A9 processor clock, and the four programmable logic clock frequencies.

Other system registers can be read in a similar way.

To find details on the Zynq system registers, see the Zynq TRM: http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf


In [1]:
# Example PS Register Access Python
# Calculating system clockrates from PS Register Values

from pynq import MMIO as mmio

# Zynq PS Constants
SCLR_BASE             = 0xf8000000
ZYNQ_NUM_FCLKS        = 4
FCLK_CTRL_REG_OFFSETS = [0x170,0x180,0x190,0x1a0]


def get_reg_value(addr):
    '''Returns register value at address given.'''
    return get_regfield_value(addr,0,0xffffffff)

def get_regfield_value(addr,shift,mask):
    '''Returns register field value at address.'''
    currval = mmio(addr).read()
    return (currval & (mask << shift)) >> shift

def get_zynq_clockrates(src_clockrate=50):
    '''Returns zynq system clockrates dictionary (in MHz).
    
    The returned dictionary has the following contents:
    'cpu'  : Cortex-A9 freqency
    'fclk0': PL fclk0 frequency
    'fclk1': PL fclk1 frequency
    'fclk2': PL fclk2 frequency
    'fclk3': PL fclk3 frequency
     
    '''  
    # Read Clock Registers from Zynq Memory Map
    arm_pll_fdiv = get_regfield_value(SCLR_BASE+0x100,12,0x7f)
    ddr_pll_fdiv = get_regfield_value(SCLR_BASE+0x104,12,0x7f)    
    io_pll_fdiv = get_regfield_value(SCLR_BASE+0x108,12,0x7f)
    
    arm_clk_sel = get_regfield_value(SCLR_BASE+0x120,4,0x3)
    arm_clk_div  = get_regfield_value(SCLR_BASE+0x120,8,0x3f)    
    
    fclk_config = list()
    for ix,offset in enumerate(FCLK_CTRL_REG_OFFSETS): 
        fclk_config.append(dict())
        fclk_config[ix]["src"] = get_regfield_value(
                                    SCLR_BASE+offset,4,0x3)
        fclk_config[ix]["div0"] = get_regfield_value(
                                    SCLR_BASE+offset,8,0x3f)  
        fclk_config[ix]["div1"] = get_regfield_value(
                                    SCLR_BASE+offset,20,0x3f)
        
    # Calculate Clock rates based on register reads above
    clock_values = list()
    
    # Arm clock
    if arm_clk_sel == 0 or arm_clk_sel == 1 :
        arm_clk_mult = arm_pll_fdiv
    elif arm_clk_sel == 2:
        arm_clk_mult = ddr_pll_fdiv
    else:
        arm_clk_mult = io_pll_fdiv
        
    armclk_value = src_clockrate*arm_clk_mult/arm_clk_div  
    clock_values.append({"cpu" : armclk_value})
    
    # x4 fclks
    for ix in range(4):
        if fclk_config[ix]["src"] == 0 or \
                    fclk_config[ix]["src"] == 1:
            fclk_mult = io_pll_fdiv            
        elif fclk_config[ix]["src"] == 2:
            fclk_mult = arm_pll_fdiv
        else:
            fclk_mult = ddr_pll_fdiv
                
        fclk_div0 = fclk_config[ix]["div0"]
        fclk_div1 = fclk_config[ix]["div1"]
    
        fclk_value = src_clockrate*fclk_mult/ \
                            (fclk_div0*fclk_div1)
        clock_values.append({"fclk" + str(ix) : \
                                     round(fclk_value,2)})
        
    return clock_values

In [2]:
from pprint import pprint
pprint(get_zynq_clockrates())


[{'cpu': 650.0},
 {'fclk0': 100.0},
 {'fclk1': 142.86},
 {'fclk2': 200.0},
 {'fclk3': 166.67}]

In [ ]: