关注、星标公众号,精彩内容每日送达
来源:网络素材
在做正点原子的hdmi显示实验时,在lcd显示部分Clocking Wizard都是动态调整输出时钟的,进入HDMI就直接固定值了,用起来一点也不方便,就想探索一下Clocking Wizard怎么配置输出两个时钟
看Xilinx的PG065手册可知
1. Configure Clock Configuration Register 0 (Address: C_BASEADDR + 0x200) with 0x00000A01. Writing this value sets DIVCLK_DIVIDE value to 1 and CLKFBOUT_MULT to 10.
2. Configure Clock Configuration Register 2 (Address: C_BASEADDR + 0x208) with 0x00000005. Writing this value sets CLKOUT0_DIVIDE to 5. The VCO frequency being 1000 MHz, dividing it by CLKOUT0_DIVIDE gives the 200 MHz frequency on the clkout1 in the IP. Check for the status register; if the status register value is 0x1, then go to step 3.
3. Configure Clock Configuration Register 23 (Address: C_BASEADDR + 0x25C) with 0x00000003 to set the LOAD and SEN bits.
4. Wait for the locked signal. The new frequency can be checked at the clkout1 output port.
输出单个时钟主要配置三个寄存器就够了
1、配置时钟倍频/分频系数
2、选择时钟输出,且配置单个时钟分频系数
3、使能输出
当需要两个及以上的输出时,要在block design里面设置好配置,可以动态配置,启用axi-lite接口,开启两个输出
当1080p输出的时候,两个时钟的值为
可以看到倍频系数为37.125分频系数为5,单个时钟的分频为5和1
我们进入vitis里面需要配置,总时钟倍频系数为37.125分频系数为5,单个时钟的分频为5和1
查手册可知,每个时钟的寄存器为下边地址
#define CLK_CFG2_OFFSET 0x208 //Clock0 Configuration Register#define CLK_CFG5_OFFSET 0x214 //Clock1 Configuration Register#define CLK_CFG8_OFFSET 0x220 //Clock2 Configuration Register#define CLK_CFG11_OFFSET 0x22C //Clock3 Configuration Register
我们再查看分频倍频的配置
#define CLK_CFG0_OFFSET 0x200 //Clock Configuration Register 0Bit[7:0] = DIVCLK_DIVIDEEight bit divide value applied to all output clocks.Bit[15:8] = CLKFBOUT_MULTInteger part of multiplier value i.e. For 8.125, this value is 8 = 0x8.Bit[25:16] = CLKFBOUT_FRAC Multiply (3)Fractional part of multiplier value i.e. For 8.125, this value is 125 = 0x7D.Note: You need not set any bit for specifying that the multiplier value is fractional. Just mention the fractional value in the register space.The value of CLKFBOUT fractional divide can be from 0 to 875 representing the fractional multiplied by 1000.
所以
计算37.125倍频5分频的寄存器设置:
DIVCLK_DIVIDE = 5 (5分频)Bit[7:0] = 0x05CLKFBOUT_MULT = 37 (37.125的整数部分)Bit[15:8] = 0x25CLKFBOUT_FRAC = 125 (37.125的小数部分×1000)Bit[25:16] = 0x07D
所以完整的寄存器值应该是:
Bit[25:16] = 0x07D (小数部分125)Bit[15:8] = 0x25 (整数部分37)Bit[7:0] = 0x05 (分频值5)
最终值 = 0x07D2505
这样就可以实现37.125倍频5分频的输出了。
最终输出两个时钟的代码如下
#include "xclk_wiz.h"#include "clk_wiz.h"#include "xparameters.h"#define CLK_WIZ_IN_FREQ 100 //时钟IP核输入100MhzXClk_Wiz clk_wiz_inst; //时钟IP核驱动实例//时钟IP核动态重配置//参数1:时钟IP核的器件ID//参数2:时钟IP核输出的时钟 单位:MHzvoid clk_wiz_cfg(u32 clk_device_id,double freq){ u32 status = 0; //初始化XCLK_Wiz XClk_Wiz_Config *clk_cfg_ptr; clk_cfg_ptr = XClk_Wiz_LookupConfig(clk_device_id); XClk_Wiz_CfgInitialize(&clk_wiz_inst,clk_cfg_ptr,clk_cfg_ptr->BaseAddr); if(freq <= 0) return; //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0x7D2505);//37.125倍频 5分频 //配置分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG2_OFFSET,5);//148.5 //配置分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG5_OFFSET,1);//742.5 //加载重配置的参数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG23_OFFSET,0x00000003); //获取时钟IP核的状态,判断是否重配置完成 while(1){ status = XClk_Wiz_ReadReg(clk_cfg_ptr->BaseAddr,CLK_SR_OFFSET); if(status&0x00000001) //Bit0 Locked信号 return ; }}
把完整代码呈现出来
#include "xclk_wiz.h"#include "clk_wiz.h"#include "xparameters.h"#define CLK_WIZ_IN_FREQ 100 //时钟IP核输入100MhzXClk_Wiz clk_wiz_inst; //时钟IP核驱动实例void clk_wiz_cfg(u32 clk_device_id,double freq){ u32 clk_divide = 0,clk_divide1 = 0; u32 status = 0; //初始化XCLK_Wiz XClk_Wiz_Config *clk_cfg_ptr; clk_cfg_ptr = XClk_Wiz_LookupConfig(clk_device_id); XClk_Wiz_CfgInitialize(&clk_wiz_inst,clk_cfg_ptr,clk_cfg_ptr->BaseAddr); if(freq <= 0) return; if(freq == 74.25)//1280 720 { //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0x7D2505);//37.125倍频 5分频 clk_divide=10; clk_divide1=2; } if(freq == 148.5)//1920 1080 { //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0x7D2505);//37.125倍频 5分频 clk_divide=5; clk_divide1=1; } if(freq == 108.0)//1280 1024 { //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0x3605);//54倍频 5分频 clk_divide=10; clk_divide1=2; } if(freq == 70.0)//1280 800 { //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0x1F40A01);//10.5倍频 1分频 clk_divide=15; clk_divide1=3; } if(freq == 50.0)//1024 600 { //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0xA01);//10倍频 1分频 clk_divide=20; clk_divide1=4; } if(freq == 40.0)//800 600 { //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0xA01);//10倍频 1分频 clk_divide=25; clk_divide1=5; } if(freq == 25.0)//640 480 { //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0xA01);//10倍频 1分频 clk_divide=40; clk_divide1=8; } if(freq == 33.0) { //配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0x1F43105);//49.5倍频 5分频 clk_divide=30; clk_divide1=6; } /*//配置时钟倍频/分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG0_OFFSET,0x00000a01); //10倍频,1分频 //计算分频系数 div_factor1 = CLK_WIZ_IN_FREQ * 10/ freq; div_factor_int1 = (u32)div_factor1; dviv_factor_frac1 = (u32)((div_factor1 - div_factor_int1) * 1000); clk_divide1 = div_factor_int1 | (dviv_factor_frac1<<8);*/ //配置分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG2_OFFSET,clk_divide); //配置分频系数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG5_OFFSET,clk_divide1); //加载重配置的参数 XClk_Wiz_WriteReg(clk_cfg_ptr->BaseAddr,CLK_CFG23_OFFSET,0x00000003); //获取时钟IP核的状态,判断是否重配置完成 while(1){ status = XClk_Wiz_ReadReg(clk_cfg_ptr->BaseAddr,CLK_SR_OFFSET); if(status&0x00000001) //Bit0 Locked信号 return ; }}
.h文件
#ifndef CLK_WIZ_H_#define CLK_WIZ_H_#include "xil_types.h"#define CLK_SR_OFFSET 0x04 //Status Register#define CLK_CFG0_OFFSET 0x200 //Clock Configuration Register 0#define CLK_CFG2_OFFSET 0x208 //Clock0 Configuration Register 2#define CLK_CFG5_OFFSET 0x214 //Clock1 Configuration Register#define CLK_CFG8_OFFSET 0x220 //Clock2 Configuration Register#define CLK_CFG11_OFFSET 0x22C //Clock3 Configuration Register#define CLK_CFG23_OFFSET 0x25C //Clock Configuration Register 23void clk_wiz_cfg(u32 clk_device_id,double freq);#endif /* CLK_WIZ_H_ */
主函数中只需要调用即可
//设置时钟IP核输出的时钟频率 clk_wiz_cfg(CLK_WIZ_ID,vd_mode.freq);