- int main()
- {
- //用法
- //得到PLLCON寄存器的值
- // clk2pll<输入频率,输出频率>:PLLCON
- //得到实际输出频率(可用来预估精确度)
- // clk2pll<输入频率,输出频率>:output_clock
- typedef clk2pll<22118400, 48000000> clk_t;
- printf("LLCON = 0x%08x, output clock = %d\n",
- clk_t:LLCON,
- clk_t:utput_clock);
- return 0;
- }
完整代码
- #include <stdio.h>
- //PLL --
- // 2 <= NF <= 513
- // 2 <= NR <= 33
- // NO, 1, 2, 2, 4
- // 100M < FCO=FIN*NF/NR=clk*NO < 200M, (120M < FCO preferred)
- // 1.6M < FIN/NR=clk*NO/NF < 15M
- template<unsigned int a, unsigned int b>
- struct algo_max
- {
- enum{ v = (a < b ? b : a) };
- };
- template<unsigned int a, unsigned int b>
- struct algo_min
- {
- enum{ v = (a < b ? a : b) };
- };
- template<unsigned int a, unsigned int b>
- struct algo_abs
- {
- enum{ v = (a < b ? b - a : a - b) };
- };
- template
- <
- unsigned int clk_bak,
- unsigned int NO_bak,
- unsigned int NF_bak,
- unsigned int NR_bak,
- unsigned int FCO,
- unsigned int NO,
- unsigned int fin,
- unsigned int clk,
- unsigned int NF,
- unsigned int NF_max,
- bool loop
- >
- struct clk2pll_NO_NF
- {
- enum{ NR = (FCO == 0 ? 0 : fin*NF/(FCO?FCO:1)) };
- enum{ clk_temp_new = ((NR == 0 || NO == 0) ? 0 : fin*NF/(NR?NR:1)/(NO?NO:1)) };
-
- enum{ better =
- (NR >= 2 && NR <= 33)
- && (unsigned int)algo_abs<clk_temp_new, clk>::v < (unsigned int)algo_abs<clk_bak, clk>::v };
- enum{ clk_new1 = (better ? clk_temp_new : clk_bak) };
- enum{ NO_new1 = (better ? NO : NO_bak) };
- enum{ NF_new1 = (better ? NF : NF_bak) };
- enum{ NR_new1 = (better ? NR : NR_bak) };
-
- typedef clk2pll_NO_NF<clk_new1, NO_new1, NF_new1, NR_new1, FCO, NO, fin, clk,
- NF+1, NF_max, (NF <= NF_max)> type;
- enum{ clk_new = type::clk_new };
- enum{ NO_new = type::NO_new };
- enum{ NF_new = type::NF_new };
- enum{ NR_new = type::NR_new };
- };
- template
- <
- unsigned int clk_bak,
- unsigned int NO_bak,
- unsigned int NF_bak,
- unsigned int NR_bak,
- unsigned int FCO,
- unsigned int NO,
- unsigned int fin,
- unsigned int clk,
- unsigned int NF,
- unsigned int NF_max
- >
- struct clk2pll_NO_NF<clk_bak, NO_bak, NF_bak, NR_bak, FCO, NO, fin, clk, NF, NF_max, false>
- {
- enum{ clk_new = clk_bak };
- enum{ NO_new = NO_bak };
- enum{ NF_new = NF_bak };
- enum{ NR_new = NR_bak };
- };
- template
- <
- unsigned int clk_bak,
- unsigned int NO_bak,
- unsigned int NF_bak,
- unsigned int NR_bak,
-
- unsigned int fin,
- unsigned int clk,
- unsigned int NO,
- unsigned int NO_min,
- unsigned int NO_max,
- unsigned int direction,
- bool loop
- >
- struct clk2pll_NO
- {
- enum{
- FCO = clk*NO,
- NF_max = algo_min<FCO/1600000, 513>::v,
- NF_min = algo_max<FCO/15000000, 2>::v };
-
- typedef clk2pll_NO_NF<clk_bak, NO_bak, NF_bak, NR_bak, FCO, NO, fin, clk,
- NF_min, NF_max, (NF_min <= NF_max)> type;
-
- enum{ clk_new1 = type::clk_new };
- enum{ NO_new1 = type::NO_new };
- enum{ NF_new1 = type::NF_new };
- enum{ NR_new1 = type::NR_new };
-
- typedef clk2pll_NO<clk_new1, NO_new1, NF_new1, NR_new1,
- fin, clk, NO+direction, NO_min, NO_max, direction,
- (NO+direction >= NO_min && NO+direction <= NO_max)> type_next;
-
- enum{ clk_new = type_next::clk_new };
- enum{ NO_new = type_next::NO_new };
- enum{ NF_new = type_next::NF_new };
- enum{ NR_new = type_next::NR_new };
- };
- template
- <
- unsigned int clk_bak,
- unsigned int NO_bak,
- unsigned int NF_bak,
- unsigned int NR_bak,
-
- unsigned int fin,
- unsigned int clk,
- unsigned int NO_min,
- unsigned int NO_max,
- unsigned int direction,
- bool loop
- >
- struct clk2pll_NO<clk_bak, NO_bak, NF_bak, NR_bak, fin, clk, 3, NO_min, NO_max, direction, loop>
- {
- enum{ NO = 3 };
- typedef clk2pll_NO<clk_bak, NO_bak, NF_bak, NR_bak,
- fin, clk, NO+direction, NO_min, NO_max, direction,
- (NO+direction >= NO_min && NO+direction <= NO_max)> type_next;
-
- enum{ clk_new = type_next::clk_new };
- enum{ NO_new = type_next::NO_new };
- enum{ NF_new = type_next::NF_new };
- enum{ NR_new = type_next::NR_new };
- };
- template
- <
- unsigned int clk_bak,
- unsigned int NO_bak,
- unsigned int NF_bak,
- unsigned int NR_bak,
-
- unsigned int fin,
- unsigned int clk,
- unsigned int NO,
- unsigned int NO_min,
- unsigned int NO_max,
- unsigned int direction
- >
- struct clk2pll_NO<clk_bak, NO_bak, NF_bak, NR_bak, fin, clk, NO, NO_min, NO_max, direction, false>
- {
- enum{ clk_new = clk_bak };
- enum{ NO_new = NO_bak };
- enum{ NF_new = NF_bak };
- enum{ NR_new = NR_bak };
- };
- template
- <
- unsigned int clk_bak,
- unsigned int NO_bak,
- unsigned int NF_bak,
- unsigned int NR_bak,
-
- unsigned int fin,
- unsigned int clk,
- unsigned int NO_min,
- unsigned int NO_max,
- unsigned int direction
- >
- struct clk2pll_NO<clk_bak, NO_bak, NF_bak, NR_bak, fin, clk, 3, NO_min, NO_max, direction, false>
- {
- enum{ clk_new = clk_bak };
- enum{ NO_new = NO_bak };
- enum{ NF_new = NF_bak };
- enum{ NR_new = NR_bak };
- };
- template<unsigned int fin, unsigned int clk>
- struct clk2pll
- {
- enum{
- NO_min = algo_max<1, (100000000+clk-1)/(clk?clk:1)>::v,
- NO_max = algo_min<4, 200000000/(clk?clk:1)>::v,
- NO_pre = algo_max<NO_min, 120000000/(clk?clk:1)>::v };
- typedef clk2pll_NO<0, 0, 0, 0, fin, clk, NO_pre, NO_min, NO_max, +1, (NO_pre >= NO_min && NO_pre <= NO_max)> type0;
- typedef clk2pll_NO<
- type0::clk_new, type0::NO_new, type0::NF_new, type0::NR_new,
- fin, clk, NO_pre, NO_min, NO_max, -1, (NO_pre >= NO_min && NO_pre <= NO_max)> type;
-
- enum
- {
- OUT_DV = (type::NO_new == 1 ? 0 :
- type::NO_new == 2 ? 1 :
- type::NO_new == 4 ? 3 :
- 0),
- IN_DV = type::NR_new - 2,
- FB_DV = type::NF_new - 2
- };
-
- enum
- {
- PLLCON = (NO_min > NO_max || type::clk_new == 0 ? 0 : (OUT_DV << 14) + (IN_DV << 9) + FB_DV),
- output_clock = (NO_min > NO_max ? 0 : type::clk_new)
- };
- };
- template<unsigned int clk>
- struct clk2pll<0, clk>
- {
- enum {
- PLLCON = 0,
- output_clock = 0
- };
- };
- template<unsigned int fin>
- struct clk2pll<fin, 0>
- {
- enum
- {
- PLLCON = 0,
- output_clock = 0
- };
- };
- int main()
- {
- typedef clk2pll<12000000, 48000000> clk_t;
- printf("PLLCON = 0x%08x, output clock = %d\n",
- clk_t::PLLCON,
- clk_t::output_clock);
- return 0;
- }