一、逻辑部分
1,需要添加两个ip,一个是是,altera_pll_reconfig,这个ip没啥要配的,主要就是搞个avalon总线出来提供寄存器给arm配
2,altera_pll
3,代码和连线。其中avalon总线从qsys引出来
pll_reconfig pll_reconfig_uut (
.mgmt_clk (w_sys_clk_100m ),//pic_eth_ref_clk
.mgmt_reset (ncs_reset),
.mgmt_waitrequest (),
.mgmt_read (rcf_mgmt_rd_spi),
.mgmt_write (rcf_mgmt_wr_spi),
.mgmt_readdata (rcf_mgmt_rdata_spi),
.mgmt_address (rcf_mgmt_addr_spi),
.mgmt_writedata (rcf_mgmt_wdata_spi),
.reconfig_to_pll (reconfig_to_pll_spi),
.reconfig_from_pll (reconfig_from_pll_spi)
);
pll_10M_reconfig pll_10M_reconfig_uut (
.refclk (w_sys_clk_100m ),//pic_eth_ref_clk
.rst (ncs_reset),
.outclk_0 (clk_spi),
.locked (),
.reconfig_to_pll (reconfig_to_pll_spi),
.reconfig_from_pll (reconfig_from_pll_spi)
);
二、软件部分
1,逻辑部分比较简单,没啥东西,主要软件如何通过avalon总线来配置这个reconfig ip比较麻烦点。本质是配置ip的144个寄存器,需要啃手册。
2,软件代码
void Pll1FreqReconfig(uint32 freq)
{
float freqTemp = (float)freq / 1000000;
int cIntCnt;
float cFloatCnt;
float fVco;
float multiCnt;
int multiIntPart;
int multiFracPart;
int vcoDiv2Enable;
int finDivBypassen;
int multiHCnt;
int multiLCnt;
int multiOddDiv;
int nCounter;
int mCounter;
int cCounter;
//计算 cIntCnt,vcoDiv2Enable,multiHCnt,multiLCnt,multiOddDiv
if((freqTemp < 1) || (freqTemp > 600))
return;
else if((freqTemp >= 1) && (freqTemp <= 50))
{
cFloatCnt = 200 / freqTemp;
cIntCnt = (int)cFloatCnt;
fVco = freqTemp * 4 * cIntCnt;
vcoDiv2Enable = 1;
finDivBypassen = 0;
}
else if((freqTemp > 50) && (freqTemp <= 600))
{
cFloatCnt = 600 / freqTemp;
cIntCnt = (int)cFloatCnt;
fVco = freqTemp * 2 * cIntCnt;
vcoDiv2Enable = 0;
finDivBypassen = 1;
}
multiCnt = fVco / 100;//ref_clk = 100
multiIntPart = (int)multiCnt;
multiFracPart = (int)((multiCnt - multiIntPart) * 16777216);
if (multiIntPart & 0x1)//multiIntPart为奇数
{
multiHCnt = (multiIntPart >> 1) + 1;
multiLCnt = multiIntPart >> 1;
multiOddDiv = 1;
}
else
{
multiHCnt = multiIntPart >> 1;
multiLCnt = multiIntPart >> 1;
multiOddDiv = 0;
}
//寄存器操作 addr:0x00-0x3f
WritePLL1Reg(PLL1_MODE_REGISTER, 0x1);//set the Altera PLL Reconfg IP core to operate in polling mode
nCounter = ((finDivBypassen << 16) + 0x0101) & 0x1ffff;
WritePLL1Reg(PLL1_N_COUNTER, nCounter);//set N counter Bypass or not
mCounter = ((multiOddDiv << 17) + (0 << 16) + (multiHCnt << 8) + multiLCnt) & 0x3ffff;
WritePLL1Reg(PLL1_M_COUNTER, mCounter);//reconfgure the M counter
WritePLL1Reg(PLL1_M_COUNTER_FRACTIONAL_VALUE_K, multiFracPart);//M counter Fractional Value (K) register
cCounter = ((cIntCnt << 8) + cIntCnt) & 0xffff;
WritePLL1Reg(PLL1_C_COUNTER, cCounter);//reconfgure the C0 counter
WritePLL1Reg(PLL1_VCO_DIV_SETTING, vcoDiv2Enable);//Enable or disable /2 divider for VCO
WritePLL1Reg(PLL1_START_REGISTER, 0x1);//start the reconfguration
ReadPLL1Reg(PLL1_STATUS_REGISTER);//until a value of 1 is read from the status register, indicating a successful reconfguration
}
枚举
enum
{
PLL0_MODE_REGISTER,
PLL0_STATUS_REGISTER,
PLL0_START_REGISTER,
PLL0_N_COUNTER,
PLL0_M_COUNTER,
PLL0_C_COUNTER,
PLL0_DYNAMIC_PHASE_SHIFT,
PLL0_M_COUNTER_FRACTIONAL_VALUE_K,
PLL0_BANDWIDTH_SETTING,
PLL0_CHARGE_PUMP_SETTING,
PLL0_VCO_DIV_SETTING = 0x1c,
PLL0_MIF_BASE_ADDRESS = 0x1f
};