2016年7月8日金曜日

Si5351Aの応用を考える

まだまだSi5351Aで引っ張りますよ!(笑)

同時3出力が可能という特徴を生かしてまずモノバンドトランシーバを製作しましたが、他にも色々と応用がききそうです。

無線関連では、SG、IMD測定やアンテナアナライザに使う発信源など測定機器に使ってみたいと考えています。

しかし既存のDDSと異なり、設定用レジスタやパラメータがやや複雑で直接周波数を指定できないため、まずは1MHzから36MHzまで1Hzオーダーで直接設定可能な関数を考えてみました。

おさらいとして、Si5351Aの周波数設定に関するパラメータと計算式をこちらに。

1.VCO周波数設定(PLLA, PLLB)

 fvco = fXTAL x (a + b / c)
    a...15~90, b...0~1048575, c...1~1048575, fXTAL = 25MHz or 27MHz

 fvco = 375MHz~900MHz

2.VCO分周設定(MultiSynth0,1,2,...)

 fout = fvco / (d + e / f)
    d...4~900, e...0~1048575, f...1~1048575

まず取っ掛かりとして1.のa値についてですが、15から90まで指定できるにもかかわらずfXTALとfvcoの関係から15~36の範囲に規定されます。その条件でaとbの値だけ変化させても周波数可変域は限定されてしまいます。もっと広範囲に周波数の設定を可能にするためには2.のMultiSynthの値も逐一変更しなければなりません。しかしこの値が変わると1.のbやcにも影響を及ぼすため、多少ややこしくなります。

25MHzのXTALを使用した場合、最初にMultiSynthのdの値を25とすると(eは0、fは1に固定)は、1.のaの値がそのままMHzに置き換わります。また、cの値を1000000にするとbの値はMHz以下の周波数そのものを表すことになります。

つまり、15MHzから36MHzまで周波数を1Hzオーダーでaとbに直接指定することが出来るというわけです。

次にMultiSynthのd値を倍の50にすると、7.5MHzから18MHzまでMHzオーダーを2倍にしてaに代入し、MHz以下の周波数をbに代入してC値を半分の500000に指定すれOKです。

 これを繰り返すことによって、より下の周波数まで一律1Hzオーダーの指定が可能になります。

以下出力周波数とa, c, d値の関係を下にまとめてみます。
 

a(16~32(36)) c d
16~36MHz F 1000000 25
8~16MHz 2F 500000 50
4~8MHz 4F 250000 100
2~4MHz 8F 125000 200
1~2MHz 16F 62500 400
(FはMHzオーダーの値)

この関係を満たすような関数をつくりまとめます。たとえばこんな感じで(無断転載禁)

void si5351_cmd(unsigned char reg, unsigned char data){                             
    I2C_send(0xC0);        // I2C_send()関数はI2C送信関数ですが汎用のものでOK
    I2C_send(reg);
    I2C_send(data);
}

void pll_set(unsigned char pll, long a, long b, long c){        // PLL_x fvco setting by feedback multisynth divider
    unsigned char pll_reg;
    long P1, P2;
  
    switch(pll){
        case 'A': default:
            pll_reg = 26;
            break;
        case 'B':
            pll_reg = 34;
            break;
    }
  
    P1 = (a << 7) + ((b << 7) / c) - 512;
    P2 = (b << 7) - c * ((b << 7) / c);
//  P3 = c;

    si5351_cmd(pll_reg,((c & 0x0000FF00) >> 8));                                        // <MSNx_P3[15:8]>
    si5351_cmd((pll_reg + 1),(c & 0x000000FF));                                            // <MSNx_P3[7:0]>
    si5351_cmd((pll_reg + 2),((P1 & 0x00030000) >> 16));                                // <MSNx_P1[17:16]>
    si5351_cmd((pll_reg + 3),((P1 & 0x0000FF00) >> 8));                                    // <MSNx_P1[15:8]>
    si5351_cmd((pll_reg + 4),(P1 & 0x000000FF));                                        // <MSNx_P1[7:0]>
    si5351_cmd((pll_reg + 5),(((c & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16)));    // <MSNx_P3[19:16], MSNx_P2[19:16]>
    si5351_cmd((pll_reg + 6),((P2 & 0x0000FF00) >> 8));                                    // <MSNx_P2[15:8]>
    si5351_cmd((pll_reg + 7),(P2 & 0x000000FF));                                        // <MSNx_P2[7:0]>
}

void ms_set(unsigned char i, long a, long b, long c){        // Multisynth_x divider setting
    long P1, P2;

    P1 = (a << 7) + ((b << 7) / c) - 512;
    P2 = (b << 7) - c * ((b << 7) / c);
//  P3 = c;

    si5351_cmd((42 + (i << 3)),((c & 0x0000FF00) >> 8));                                // <MSx_P3[15:8]>
    si5351_cmd((43 + (i << 3)),(c & 0x000000FF));                                        // <MSx_P3[7:0]>
    si5351_cmd((44 + (i << 3)),((P1 & 0x00030000) >> 16));                                // <0, Rx_DIV[2:0], MSx_DIVBY4[1:0], MSx_P1[17:16]>
    si5351_cmd((45 + (i << 3)),((P1 & 0x0000FF00) >> 8));                                // <MSx_P1[15:8]>
    si5351_cmd((46 + (i << 3)),(P1 & 0x000000FF));                                        // <MSx_P1[7:0]>
    si5351_cmd((47 + (i << 3)),(((c & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16)));    // <MSx_P3[19:16], MSx_P2[19:16]>
    si5351_cmd((48 + (i << 3)),((P2 & 0x0000FF00) >> 8));                                // <MSx_P2[15:8]>
    si5351_cmd((49 + (i << 3)),(P2 & 0x000000FF));                                        // <MSx_P2[7:0]>
}


 int Si5351A_fset(unsigned char pll, unsigned char clk, long freq){
    long a=0, b=0, c=1000000, d=25;

    a = freq;

    b = a % 1000000;
    a = a / 1000000;
  
    if(a > 0 && a < 36){
        while(a < 16){
            a <<= 1;
            c >>= 1;
            d <<= 1;
        }
    }
    else return 1;
  
    pll_set(pll, a, b, c);
    ms_set(clk, d, 0, 1);
  
    return 0;
}


メインは Si5351a_fset()関数で、仮引数のpllは使用するPLL(A or B)、clkはCLK出力番号(0, 1 or 2)、freqは設定周波数(Hz表示)です。

関数の内訳は、設定周波数のMHzオーダーの値をaに代入し、MHzオーダー以下の周波数値をbに代入します。aはVCO設定値で16以上36未満の場合そのままpll_set()関数とms_set()関数に各値を渡しますが、aが16未満の場合は16以上になるまでa, d(MultiSynthの設定値)値を倍にしてc値を半分にします。

Si5351A_fset()関数でセットした後出力させるCLKをオンにするコマンドを送れば指定した周波数で出力されます。(fXTALの周波数ズレによる出力周波数誤差を修正するコードも書きましたが、ここでは省略します)

Si5351Aのプログラムを作る一助になれば幸いです。

閑話休題。

この設定パラメータを眺めていてふと疑問に思ったことがありました。

VCO周波数設定のa値は15から90とありますが、fXTALが25MHzの場合90に設定するとfvcoが2250MHzとなりVCO発振可能周波数域を完全に逸脱してしまいます。aが36程度までという規定ならば納得しますが、ではなぜ90までとされているのでしょうか?

まだ実験していませんが、おそらくfXTALは25か27MHz以外も使えることを示しているのではないかと想像しています。具体的には10MHzのXTALであればa値90でfvcoは上限の900MHzになり、これは40MHzから90MHz辺りまでの周波数で1Hzオーダーの設定が可能になることを表しています。

また裏技で10MHzのTCXOやOCXOなど出力をSi5351AのXAピンにつなげれば比較的高い任意の周波数で安定した発信源を得ることが出来そうです。

どちらさまか追試をお願いします!

0 件のコメント:

コメントを投稿