2023年5月1日月曜日

Si5351Aクロックジェネレータ(90度位相シフト)

JH7UBCサイト[Si5351Aの実験その5(位相制御)]を使い90度位相が違う2つのクロックを発生するテストを行いました。[frequency]に周波数を設定するとCLK0・CLK1から設定周波数が出力しCLK0・CLK1は90度位相がシフトします。http://jh7ubc.1web.fc2.com/arduino/Si5351A_Phase.html




●位相レジスタ
 N = CLKx_PHOFF [6:0] = ROUND(DesiredOffset (sec) x 4 x  fvco)
 レジスタ165【CLK0】166【CLK1)】167【CLK2】

 ■N = dt * 4 *  fvco --- (1) (Nは0~127 )
        dt = DesiredOffset(delay time)
        fvco = PLL周波数
 ■dt = 1 / (4 * fout) --- (2)     (90度位相差)
        fout = 出力周波数
        dt = T / 4 = 1 / (4 * fout) (T = 周期)
 (1) (2) の式を代入
 N = 1 / (4 * fout) * 4 *  fvco(Nは0~127 )
    = fvco / fout
 ■N = divider = fvco / fout


回路図





















CLK0(CH1) CLK1(CH2) 7MHz





7MHzはCLK0が遅れます
















CLK0(CH1) CLK1(CH2) 10MHz





















CLK0(CH1) CLK1(CH2) 50MHz






















CLK0(CH1) CLK1(CH2) 100MHz



















プログラム Arduino IDE【ボード:Raspberry Pi Pico】
#include <Wire.h>

#define Si5351A_ADDR 0x60
#define OUTPUT_CTRL 3 //Output Enable Control
#define CLK0_CTRL 16  //CLK0 Control
#define CLK1_CTRL 17  //CLK1 Control
#define CLK2_CTRL 18  //CLK2 Control
#define MSNA_ADDR 26  //Multisynth NA Parameters
#define MSNB_ADDR 34  //Multisynth NB Parameters
#define MS0_ADDR 42   //Multisynth0 Parameters
#define MS1_ADDR 50   //Multisynth1 Parameters
#define MS2_ADDR 58   //Multisynth2 Parameters
#define CLK0_PHOFF 165  //CLK0 Initial Phase Offset
#define CLK1_PHOFF 166  //CLK1 Initial Phase Offset
#define PLL_RESET 177   //PLL Reset
#define XTAL_LOAD_C 183 //Crystal Internal Load Capacitance

uint32_t frequency;
const uint32_t XtalFreq = 25000000; //25MHz

uint32_t P1;
uint32_t P2;
uint32_t P3;
uint32_t PllFreq;
uint32_t l;
float f;
uint8_t mult;
uint32_t num;
uint32_t denom;
uint32_t divider;
char PLL;
uint8_t PLL_ADDR;
uint8_t MS_ADDR;


void setup(){
Wire.setSDA(12);  //SDA 
Wire.setSCL(13);  //SCL  
Wire.begin(); // Arduino is Master
Si5351_init(); //Si5351 initialize

//PLLAのセット 900MHz,CLK0=10MHz 
//N(divider) = fvco(PLLA) / fout(CLK0)
frequency = 10000000;
divider = 900000000 / frequency; //divider = fvco / fout
if (divider % 2) divider--;
PLL_Set('A',frequency,divider);

//CLK0の設定
Si5351_write(CLK0_CTRL,0x4C); //Reg16 Sorce PLLA
MS_Set(0,divider);
Si5351_write(CLK0_PHOFF,0);//CLK0 delay 0

//CLK1の設定
Si5351_write(CLK1_CTRL,0x4C); //Reg17 Sorce PLLA
MS_Set(1,divider);
Si5351_write(CLK1_PHOFF,divider);//Reg166 delay T/4 (90degree)

Si5351_write(PLL_RESET,0xA0); //Reg177 PLLA and PLLB
}

void loop(){

}

//Si5351のレジスタに1バイトデータを書き込む。
void Si5351_write(byte Reg , byte Data)
{
Wire.beginTransmission(Si5351A_ADDR);
Wire.write(Reg);
Wire.write(Data);
Wire.endTransmission();
}


//Si5351Aの初期化
void Si5351_init(){
Si5351_write(OUTPUT_CTRL,0xFF); //Reg3 Disable Output
Si5351_write(CLK0_CTRL,0x80); //Reg16 CLOCK0 Power down
Si5351_write(CLK1_CTRL,0x80); //Reg17 CLOCK1 Power down
Si5351_write(CLK2_CTRL,0x80); //Reg18 CLOCK2 Power down
Si5351_write(XTAL_LOAD_C,0x92); //Reg183 Crystal Load Capasitance=8pF
Si5351_write(PLL_RESET,0xA0); //Reg177 Reset PLLA and PLLB
Si5351_write(CLK0_CTRL,0x4F); //Reg16 CLOCK0 Power up
Si5351_write(CLK1_CTRL,0x4F); //Reg17 CLOCK0 Power up
// Si5351_write(CLK2_CTRL,0x4F); //Reg18 CLOCK0 Power up
Si5351_write(OUTPUT_CTRL,0xFC); //Reg3 Enable CLOCK0,CLOCK1
}


//PLLの設定
void PLL_Set(char Pll,uint32_t Freq,uint32_t Div){
PllFreq = Div * Freq; //fvco =d * fout
mult = PllFreq / XtalFreq; //整数部 mult = a = fvco / fxtal
l = PllFreq % XtalFreq; // L = fvco % fxtal
f = l;
f *= 1048575;
f /= XtalFreq;
num = f;
denom = 1048575;

P1 = (uint32_t)(128 * ((float)num /(float)denom)); //128*(b/c)
P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512); //128*a + (128*(b/c))-512 
P2 = (uint32_t)(128 * ((float)num / (float)denom)); //128*(b/c)
P2 = (uint32_t)(128 * num -denom * P2); //128*b–c*(128*(b/c))
P3=denom;

if (Pll == 'A')
{
PLL_ADDR = MSNA_ADDR;
}else
{
PLL_ADDR = MSNB_ADDR;
}
Parameter_write(PLL_ADDR,P1,P2,P3);
}

//MultiSynth(分周器)のセット
void MS_Set(uint8_t MS_No,uint32_t Div){
P1 = 128 * Div - 512;
P2 = 0;
P3 = 1;
switch(MS_No){
case 0:
MS_ADDR = MS0_ADDR;
break;
case 1:
MS_ADDR = MS1_ADDR;
break;
case 2:
MS_ADDR = MS2_ADDR;
break;
default:
MS_ADDR = MS0_ADDR;
}
Parameter_write(MS_ADDR,P1,P2,P3);
}

//レジスタにパラメータP1,P2,P3を書き込む。
void Parameter_write(uint8_t REG_ADDR,uint32_t Pa1,uint32_t Pa2,uint32_t Pa3)
{
Si5351_write(REG_ADDR + 0,(Pa3 & 0x0000FF00) >> 8);
Si5351_write(REG_ADDR + 1,(Pa3 & 0x000000FF));
Si5351_write(REG_ADDR + 2,(Pa1 & 0x00030000) >> 16);
Si5351_write(REG_ADDR + 3,(Pa1 & 0x0000FF00) >> 8);
Si5351_write(REG_ADDR + 4,(Pa1 & 0x000000FF));
Si5351_write(REG_ADDR + 5,((Pa3 & 0x000F0000) >> 12) | ((Pa2 & 0X000F0000) >> 16));
Si5351_write(REG_ADDR + 6,(Pa2 & 0x0000FF00) >> 8);
Si5351_write(REG_ADDR + 7,(Pa2 & 0x000000FF));


0 件のコメント:

コメントを投稿

Raspberry Pi Donkey Car スマートカー

  2020年に製作したDonkey Car スマートカー について記事にしました。 Donkey CarはRaspberry Pi のカメラからコースを ディープラーニングさせ自動走行を行います。(動画は白線上を自動走行)   動画