無線機の製作記録の全てを公開してます。 https://sites.google.com/view/ja2gqpから必要なファイルをダウンロードできます。 このBlogは、詳細な説明は一切行っておらず、ある程度のスキルが要求されます。 質問に応じますが、カスタマイズは対応しません。尚、コメントは誰でも出来る様に変更しました。
2018年12月30日日曜日
AFPSN PCB
ユニバーサル基板で作った 回路を見直し、PCB化した。主要部品は、マイクユニット、dsPIC33、MAX2452である。MAX2452の出力は-35dB位なので、十分ゲインを稼ぐため2SC3357を使用した。2SC3357は、広帯域増幅にして多バンド化への可能性を含ませた。キーパーツのMAX2452、マイクユニット、リレーは、Aliexpressで入手可能。
回路図である。マイクユニットは、AGC付きのMAX9814または、AGC無しのMAX4466が使える様にした。更に、ライン入力も選べる。ジェネレータ出力は、1mW~1.5mWである。
2018年11月20日火曜日
Prescaler 1/1,1/2
MAX2452 PSNにPIC12F1840 VXOを使っているが、PIC12F1840のメモリーが少ない為、表示器レスとした。しかし、試験を行っていると、周波数表示が欲しくなった。
そこで、MAX2452の周波数をsi5351aのclk0から直接拾って表示する事にした。その為、2倍となったMAX2452周波数データを1/2にするプリスケーラを作った。
MAX2452へ7.10MHzを指定する場合の周波数データ。si5351aのclk0を直接拾うと、14.20MHzが表示される。
1/1と1/2のプリスケーラ回路図である。
MAX2452へ7.10MHzを指定した周波数設定データの1/2を表示。小容量のPICも使い方次第で、上手いシステムが出来る。
そこで、MAX2452の周波数をsi5351aのclk0から直接拾って表示する事にした。その為、2倍となったMAX2452周波数データを1/2にするプリスケーラを作った。
MAX2452へ7.10MHzを指定する場合の周波数データ。si5351aのclk0を直接拾うと、14.20MHzが表示される。
1/1と1/2のプリスケーラ回路図である。
MAX2452へ7.10MHzを指定した周波数設定データの1/2を表示。小容量のPICも使い方次第で、上手いシステムが出来る。
2018年11月11日日曜日
PSN SSB Generator
MAX2452を使ったPSN SSB Generatorである。これは、JA2NKD/1松浦OM公開のPSN SSB主要部分を1ボードにしたジェネレータ。ユニット化したキーパーツを使う事で 、簡素化した。マイクアンプにAGC付きMAX9814を使用。また、LOにPICクリスタルもどきのPCB版(GQP VXO)使用。サンプルは、7.100MHzである。
回路図である。マイクユニットMAX9814、AF PSN dsPIC33そしてRF PSN MAX2452でPSN SSBが発生する。マイクアンプユニットのGain・A/Rは、ジャンパーチップで条件を変える事が出来る。MAX9814及びMAX2452はAliexpressで入手可能。
////////////////////////////////////////////////////////////
// si5351a PLL control(PIC12F1840) psn
//
// 2018/11/11
// JA2GQP
////////////////////////////////////////////////////////////
//
// Bug FIX LSB/USB Frequency 2011.11.16
//
//---------- Header file include -------------------------//
#include <xc.h>
//----------Configuration setting ------------------------//
////////////////////////////
// config1
////////////////////////////
#pragma config FOSC = INTOSC // Internal clock
#pragma config WDTE = OFF // Watchdog timer off
#pragma config PWRTE = ON // Power on start
#pragma config MCLRE = OFF // External reset not used
#pragma config CP = OFF // Program memory not protected
#pragma config CPD = OFF // Data memory not protected
#pragma config BOREN = ON // Power drop monitoring
#pragma config CLKOUTEN = OFF // Clock out pin is RA4
#pragma config IESO = OFF // No activation with clock switching
#pragma config FCMEN = OFF // Do not monitor external clock
////////////////////////////
// config2
////////////////////////////
#pragma config WRT = OFF // Flash memory not protected
#pragma config PLLEN = OFF // It does not work at 32 MHz
#pragma config STVREN = ON // Reset with stack overflow(underflow)
#pragma config BORV = HI // Voltage drop monitoring
#pragma config LVP = OFF // Low voltage programming not used
//---------- Define value setting ------------------------//
#define DEF_FREQ 7100000*MULTI-AD_OFFSET // Default frequency(7.100MHz)
#define EEP_ADR 0x00 // EEPROM address
#define SCL RA1 // I2C Clock
#define SDA RA2 // I2C Data
#define AD_OFFSET 1023 // Frequency offset
#define _XTAL_FREQ 16000000 // clock 16MHz(Use with delay)
#define MULTI 2 // Multiplication factor
////////////////////////////
// si5351a parameter
////////////////////////////
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define MSNA_ADDR 26
#define MSNB_ADDR 34
#define MS0_ADDR 42
#define MS1_ADDR 50
#define MS2_ADDR 58
#define CLK0_PHOFF 165
#define CLK1_PHOFF 166
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define Si5351A_ADDR 0xC0 // address(cip address<<1)
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
#define _6pF 0b01010010 // 6pF
#define _8pF 0b10010010 // 8pF
#define _10pF 0b11010010 // 10pF
#define XTAL_CL _8pF // XTAL_CL 8pF set
#define _2mA 0x4C // 2mA(1dBm))
#define _4mA 0x4D // 4mA(5dBm))
#define _6mA 0x4E // 6mA(10dBm))
#define _8mA 0x4F // 8mA(12dBm)
#define mA _2mA // output lebel 1dBm set
//---------- Memory define -------------------------------//
static unsigned long frequency=DEF_FREQ; // Frequency data
//------------- Initial proc. ----------------------------//
void PIC12F1840_set(){
OSCCON = 0b01111000 ; // clock set(16MHz=0x78,8MHz=0x70,4MHz=0x68)
ANSELA = 0b00010000 ; // Anarog = AN3,Othe digital
TRISA = 0b00011000; // I/O set(0=output,1=input)
PORTA = 0b00000000 ; // Output pin initial value
ADCON1 = 0b11010000 ; // FOSC/16,VDD=Ref
ADCON0 = 0b00001101 ;
__delay_us(5) ; // 5us(at clock 16MHz))
}
//------------- wait proc. -------------------------------//
void await(unsigned long ct){
while(ct>0) ct--;
}
//------------- I2C start proc. --------------------------//
void I2C_start(){
SCL = 1; // start condition
await(3);
SDA = 1;
await(3);
SDA = 0;
await(3);
SCL = 0;
await(3);
}
//------------- I2C stop proc. ---------------------------//
void I2C_stop(){
await(3);
SCL = 1; // stop condition
await(3);
SDA = 0;
await(3);
SDA = 1;
await(3);
SCL = 0;
await(3);
}
//------------- I2C write byte proc. ---------------------//
void wr_Byte(unsigned char x){
unsigned int k;
for(k=0;k<8;k++){
if(x & 0x80) SDA = 1; else SDA = 0;
await(3);
SCL = 1;
await(3);
SCL = 0;
await(3);
SDA = 0;
x <<= 1;
}
SCL = 1;
await(3);
SCL = 0;
}
//------------- si5351 command processing ----------------//
void Si5351_write(unsigned char reg_No, unsigned char x){
I2C_start();
wr_Byte(Si5351A_ADDR); // address set
wr_Byte(reg_No);
wr_Byte(x);
I2C_stop();
}
//------------- si5351 Initialization --------------------//
void Si5351_init(void){
SDA=1;
SCL=1;
await(200);
Si5351_write(XTAL_LOAD_C,XTAL_CL); // XTAL_CL set
Si5351_write(CLK0_CTRL,0x80); // Disable CLK0
Si5351_write(PLL_RESET,0xA0); // Reset PLL_A
Si5351_write(CLK0_CTRL,mA); // Enable CLK0 (MS0=Integer Mode, Source=PLL_A)
}
//------------- si5351 PLL data set --------------------------//
void setupPLL(unsigned char pll, unsigned char mult, unsigned long num, unsigned long denom){
unsigned long P1; // PLL config register P1
unsigned long P2; // PLL config register P2
unsigned long P3; // PLL config register P3
P1 = (unsigned long)(128 * ((float)num / (float)denom));
P1 = (unsigned long)(128 * (unsigned long)(mult) + P1 - 512);
P2 = (unsigned long)(128 * ((float)num / (float)denom));
P2 = (unsigned long)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
//------------- Set up MultiSynth --------------------------//
void setupMultisynth(unsigned char synth, unsigned long divider, unsigned char rDiv){
unsigned long P1; // Synth config register P1
unsigned long P2; // Synth config register P2
unsigned long P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
//------------- si5351 data set --------------------------//
void si5351aSetFrequency(unsigned long frequency){
unsigned long pllFreq;
unsigned long xtalFreq = XTAL_FREQ;
unsigned long l;
float f;
unsigned char mult;
unsigned long num;
unsigned long denom;
unsigned long divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
}
//------------- ADconverter ------------------------------//
unsigned int adconv(){
unsigned int temp;
GO_nDONE = 1 ; // Anarog read start
while(GO_nDONE) ; // PIC wait
temp = ADRESH ; // Data high set
temp = ( temp << 8 ) | ADRESL ; // low set
return temp*2; // (0-1023) * 2 = 0-2046
}
//------------- main -------------------------------------//
void main(){
int wk;
PIC12F1840_set(); // Cip Initialization
Si5351_init(); // si5351a Initialization
while(1){
wk = adconv();
si5351aSetFrequency(frequency + wk); // Frequency data set
__delay_ms(30);
}
}
スケッチ
必要なファイルは、JA2GQP's Download siteのpicフォルダからダウンロード可能。////////////////////////////////////////////////////////////
// si5351a PLL control(PIC12F1840) psn
//
// 2018/11/11
// JA2GQP
////////////////////////////////////////////////////////////
//
// Bug FIX LSB/USB Frequency 2011.11.16
//
//---------- Header file include -------------------------//
#include <xc.h>
//----------Configuration setting ------------------------//
////////////////////////////
// config1
////////////////////////////
#pragma config FOSC = INTOSC // Internal clock
#pragma config WDTE = OFF // Watchdog timer off
#pragma config PWRTE = ON // Power on start
#pragma config MCLRE = OFF // External reset not used
#pragma config CP = OFF // Program memory not protected
#pragma config CPD = OFF // Data memory not protected
#pragma config BOREN = ON // Power drop monitoring
#pragma config CLKOUTEN = OFF // Clock out pin is RA4
#pragma config IESO = OFF // No activation with clock switching
#pragma config FCMEN = OFF // Do not monitor external clock
////////////////////////////
// config2
////////////////////////////
#pragma config WRT = OFF // Flash memory not protected
#pragma config PLLEN = OFF // It does not work at 32 MHz
#pragma config STVREN = ON // Reset with stack overflow(underflow)
#pragma config BORV = HI // Voltage drop monitoring
#pragma config LVP = OFF // Low voltage programming not used
//---------- Define value setting ------------------------//
#define DEF_FREQ 7100000*MULTI-AD_OFFSET // Default frequency(7.100MHz)
#define EEP_ADR 0x00 // EEPROM address
#define SCL RA1 // I2C Clock
#define SDA RA2 // I2C Data
#define AD_OFFSET 1023 // Frequency offset
#define _XTAL_FREQ 16000000 // clock 16MHz(Use with delay)
#define MULTI 2 // Multiplication factor
////////////////////////////
// si5351a parameter
////////////////////////////
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define MSNA_ADDR 26
#define MSNB_ADDR 34
#define MS0_ADDR 42
#define MS1_ADDR 50
#define MS2_ADDR 58
#define CLK0_PHOFF 165
#define CLK1_PHOFF 166
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define Si5351A_ADDR 0xC0 // address(cip address<<1)
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
#define _6pF 0b01010010 // 6pF
#define _8pF 0b10010010 // 8pF
#define _10pF 0b11010010 // 10pF
#define XTAL_CL _8pF // XTAL_CL 8pF set
#define _2mA 0x4C // 2mA(1dBm))
#define _4mA 0x4D // 4mA(5dBm))
#define _6mA 0x4E // 6mA(10dBm))
#define _8mA 0x4F // 8mA(12dBm)
#define mA _2mA // output lebel 1dBm set
//---------- Memory define -------------------------------//
static unsigned long frequency=DEF_FREQ; // Frequency data
//------------- Initial proc. ----------------------------//
void PIC12F1840_set(){
OSCCON = 0b01111000 ; // clock set(16MHz=0x78,8MHz=0x70,4MHz=0x68)
ANSELA = 0b00010000 ; // Anarog = AN3,Othe digital
TRISA = 0b00011000; // I/O set(0=output,1=input)
PORTA = 0b00000000 ; // Output pin initial value
ADCON1 = 0b11010000 ; // FOSC/16,VDD=Ref
ADCON0 = 0b00001101 ;
__delay_us(5) ; // 5us(at clock 16MHz))
}
//------------- wait proc. -------------------------------//
void await(unsigned long ct){
while(ct>0) ct--;
}
//------------- I2C start proc. --------------------------//
void I2C_start(){
SCL = 1; // start condition
await(3);
SDA = 1;
await(3);
SDA = 0;
await(3);
SCL = 0;
await(3);
}
//------------- I2C stop proc. ---------------------------//
void I2C_stop(){
await(3);
SCL = 1; // stop condition
await(3);
SDA = 0;
await(3);
SDA = 1;
await(3);
SCL = 0;
await(3);
}
//------------- I2C write byte proc. ---------------------//
void wr_Byte(unsigned char x){
unsigned int k;
for(k=0;k<8;k++){
if(x & 0x80) SDA = 1; else SDA = 0;
await(3);
SCL = 1;
await(3);
SCL = 0;
await(3);
SDA = 0;
x <<= 1;
}
SCL = 1;
await(3);
SCL = 0;
}
//------------- si5351 command processing ----------------//
void Si5351_write(unsigned char reg_No, unsigned char x){
I2C_start();
wr_Byte(Si5351A_ADDR); // address set
wr_Byte(reg_No);
wr_Byte(x);
I2C_stop();
}
//------------- si5351 Initialization --------------------//
void Si5351_init(void){
SDA=1;
SCL=1;
await(200);
Si5351_write(XTAL_LOAD_C,XTAL_CL); // XTAL_CL set
Si5351_write(CLK0_CTRL,0x80); // Disable CLK0
Si5351_write(PLL_RESET,0xA0); // Reset PLL_A
Si5351_write(CLK0_CTRL,mA); // Enable CLK0 (MS0=Integer Mode, Source=PLL_A)
}
//------------- si5351 PLL data set --------------------------//
void setupPLL(unsigned char pll, unsigned char mult, unsigned long num, unsigned long denom){
unsigned long P1; // PLL config register P1
unsigned long P2; // PLL config register P2
unsigned long P3; // PLL config register P3
P1 = (unsigned long)(128 * ((float)num / (float)denom));
P1 = (unsigned long)(128 * (unsigned long)(mult) + P1 - 512);
P2 = (unsigned long)(128 * ((float)num / (float)denom));
P2 = (unsigned long)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
//------------- Set up MultiSynth --------------------------//
void setupMultisynth(unsigned char synth, unsigned long divider, unsigned char rDiv){
unsigned long P1; // Synth config register P1
unsigned long P2; // Synth config register P2
unsigned long P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
//------------- si5351 data set --------------------------//
void si5351aSetFrequency(unsigned long frequency){
unsigned long pllFreq;
unsigned long xtalFreq = XTAL_FREQ;
unsigned long l;
float f;
unsigned char mult;
unsigned long num;
unsigned long denom;
unsigned long divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
}
//------------- ADconverter ------------------------------//
unsigned int adconv(){
unsigned int temp;
GO_nDONE = 1 ; // Anarog read start
while(GO_nDONE) ; // PIC wait
temp = ADRESH ; // Data high set
temp = ( temp << 8 ) | ADRESL ; // low set
return temp*2; // (0-1023) * 2 = 0-2046
}
//------------- main -------------------------------------//
void main(){
int wk;
PIC12F1840_set(); // Cip Initialization
Si5351_init(); // si5351a Initialization
while(1){
wk = adconv();
si5351aSetFrequency(frequency + wk); // Frequency data set
__delay_ms(30);
}
}
2018年10月16日火曜日
GQP VXO
アナログ処理の変更点
周波数可変方法としてアナログ信号を利用し、ボリュームで周波数調整を行っているが、アナログ信号が故に揺らぎが発生する。この揺らぎにより、周波数を安定させる事が困難となっている。一般的な揺らぎ対策として、マルチサンプリングによる平均化があり、揺らぎを少なくする為の独特のアルゴリズムが存在する。今回は、少ないステップで十分な効果が期待できる、しきい値方式とした。VXOのSKIP
周波数可変方法にボリュームを使っており、SKIP SWと組合わせて周波数調整を行う。ボリューム中心値より小さい時-1kHz、ボリューム中心値より大きい時+1kHz周波数がSKIPする。今回、10kHzSKIP機能を追加した。操作方法は、ボリュームが最小の時-10kHz、ボリュームが最大の時+10kHz周波数SKIPである。位相出力
clk0とclk1で90度位相差のスケッチを追加した。可変範囲±1kHzとVXO版(可変範囲制限なし)がある。回路図
回路図である。PCBと一致する様に書き直した。位相出力
clk0とclk1を使った位相出力(0°、90°)である。7MHz帯で測定した画面。位相出力スケッチ(VXO版)
スケッチと回路図は、JA2GQP's Download site picフォルダからダウンロードできる。////////////////////////////////////////////////////////////
// si5351a PLL control(PIC12F1840) Phase & VXO
//
// 2018/10/15
// JA2GQP
////////////////////////////////////////////////////////////
//---------- Header file include -------------------------//
#include <xc.h>
//----------Configuration setting ------------------------//
////////////////////////////
// config1
////////////////////////////
#pragma config FOSC = INTOSC // Internal clock
#pragma config WDTE = OFF // Watchdog timer off
#pragma config PWRTE = ON // Power on start
#pragma config MCLRE = OFF // External reset not used
#pragma config CP = OFF // Program memory not protected
#pragma config CPD = OFF // Data memory not protected
#pragma config BOREN = ON // Power drop monitoring
#pragma config CLKOUTEN = OFF // Clock out pin is RA4
#pragma config IESO = OFF // No activation with clock switching
#pragma config FCMEN = OFF // Do not monitor external clock
////////////////////////////
// config2
////////////////////////////
#pragma config WRT = OFF // Flash memory not protected
#pragma config PLLEN = OFF // It does not work at 32 MHz
#pragma config STVREN = ON // Reset with stack overflow(underflow)
#pragma config BORV = HI // Voltage drop monitoring
#pragma config LVP = OFF // Low voltage programming not used
//---------- Define value setting ------------------------//
#define DEF_FREQ 7100000-AD_OFFSET // Default frequency
#define EEP_ADR 0x00 // EEPROM address
#define SCL RA1 // I2C Clock
#define SDA RA2 // I2C Data
#define AD_OFFSET 1024 // Frequency offset
#define _XTAL_FREQ 16000000 // clock 16MHz(Use with delay)
////////////////////////////
// si5351a parameter
////////////////////////////
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define MSNA_ADDR 26
#define MSNB_ADDR 34
#define MS0_ADDR 42
#define MS1_ADDR 50
#define MS2_ADDR 58
#define CLK0_PHOFF 165
#define CLK1_PHOFF 166
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define Si5351A_ADDR 0xC0 // address(cip address<<1)
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
#define _6pF 0b01010010 // 6pF
#define _8pF 0b10010010 // 8pF
#define _10pF 0b11010010 // 10pF
#define XTAL_CL _8pF // XTAL_CL 8pF set
#define _2mA 0x4C // 2mA(1dBm))
#define _4mA 0x4D // 4mA(5dBm))
#define _6mA 0x4E // 6mA(10dBm))
#define _8mA 0x4F // 8mA(12dBm)
#define mA _6mA // output lebel 10dBm set
//---------- Memory define -------------------------------//
static unsigned long frequency=DEF_FREQ; // Frequency data
//------------- Initial proc. ----------------------------//
void PIC12F1840_set(){
OSCCON = 0b01111000 ; // clock set(16MHz=0x78,8MHz=0x70,4MHz=0x68)
ANSELA = 0b00010000 ; // Anarog = AN3,Othe digital
TRISA = 0b00011000; // I/O set(0=output,1=input)
PORTA = 0b00000000 ; // Output pin initial value
EECON1bits.CFGS =0; // EEPROM
EECON1bits.EEPGD = 0;
ADCON1 = 0b11010000 ; // FOSC/16,VDD=Ref
ADCON0 = 0b00001101 ;
__delay_us(5) ; // 5us(at clock 16MHz))
}
//------------- wait proc. -------------------------------//
void await(unsigned long ct){
while(ct>0) ct--;
}
//------------- I2C start proc. --------------------------//
void I2C_start(){
SCL = 1; // start condition
await(3);
SDA = 1;
await(3);
SDA = 0;
await(3);
SCL = 0;
await(3);
}
//------------- I2C stop proc. ---------------------------//
void I2C_stop(){
await(3);
SCL = 1; // stop condition
await(3);
SDA = 0;
await(3);
SDA = 1;
await(3);
SCL = 0;
await(3);
}
//------------- I2C write byte proc. ---------------------//
void wr_Byte(unsigned char x){
unsigned int k;
for(k=0;k<8;k++){
if(x & 0x80) SDA = 1; else SDA = 0;
await(3);
SCL = 1;
await(3);
SCL = 0;
await(3);
SDA = 0;
x <<= 1;
}
SCL = 1;
await(3);
SCL = 0;
}
//------------- si5351 command processing ----------------//
void Si5351_write(unsigned char reg_No, unsigned char x){
I2C_start();
wr_Byte(Si5351A_ADDR); // address set
wr_Byte(reg_No);
wr_Byte(x);
I2C_stop();
}
//------------- si5351 Initialization --------------------//
void Si5351_init(void){
SDA=1;
SCL=1;
await(200);
Si5351_write(XTAL_LOAD_C,XTAL_CL); // XTAL_CL set
Si5351_write(CLK0_CTRL,0x80); // Disable CLK0
Si5351_write(CLK1_CTRL,0x80); // Disable CLK1
Si5351_write(PLL_RESET,0xA0); // Reset PLL_A
Si5351_write(CLK0_CTRL,mA); // Enable CLK0 (MS0=Integer Mode, Source=PLL_A)
Si5351_write(CLK1_CTRL,mA); // Enable CLK1 (MS0=Integer Mode, Source=PLL_A)
}
//------------- si5351 PLL data set --------------------------//
void setupPLL(unsigned char pll, unsigned char mult, unsigned long num, unsigned long denom){
unsigned long P1; // PLL config register P1
unsigned long P2; // PLL config register P2
unsigned long P3; // PLL config register P3
P1 = (unsigned long)(128 * ((float)num / (float)denom));
P1 = (unsigned long)(128 * (unsigned long)(mult) + P1 - 512);
P2 = (unsigned long)(128 * ((float)num / (float)denom));
P2 = (unsigned long)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
//------------- Set up MultiSynth --------------------------//
void setupMultisynth(unsigned char synth, unsigned long divider, unsigned char rDiv){
unsigned long P1; // Synth config register P1
unsigned long P2; // Synth config register P2
unsigned long P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
//------------- si5351 data set --------------------------//
void si5351aSetFrequency(unsigned long frequency){
unsigned long pllFreq;
unsigned long xtalFreq = XTAL_FREQ;
unsigned long l;
float f;
unsigned char mult;
unsigned long num;
unsigned long denom;
unsigned long divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
setupMultisynth(MS1_ADDR, divider, R_DIV_1);
Si5351_write(CLK0_PHOFF,0); // Phase offset clk0 set
Si5351_write(CLK1_PHOFF,divider); // clk1 set
Si5351_write(PLL_RESET,0xA0); // Reset PLL_A
}
//------------- ADconverter ------------------------------//
unsigned int adconv(){
unsigned int temp;
GO_nDONE = 1 ; // Anarog read start
while(GO_nDONE) ; // PIC wait
temp = ADRESH ; // Data high set
temp = ( temp << 8 ) | ADRESL ; // low set
return temp*2; // (0-1023) * 2 = 0-2046
}
//------------- EEPROM read ------------------------------//
unsigned long eep_rd(unsigned char address){
unsigned long temp = 0;
temp = eeprom_read(address+3);
temp = temp << 8;
temp = temp | eeprom_read(address+2);
temp = temp << 8;
temp = temp | eeprom_read(address+1);
temp = temp << 8;
temp = temp | eeprom_read(address+0);
return temp;
}
//------------- EEPROM write -----------------------------//
void eep_wt(unsigned char address,unsigned long frequency){
eeprom_write(address+0,(frequency & 0xff));
eeprom_write(address+1,((frequency >> 8) & 0xff));
eeprom_write(address+2,((frequency >> 16) & 0xff));
eeprom_write(address+3,((frequency >> 24) & 0xff));
}
//------------- EEPROM initialize -----------------------------//
void eep_init(){
if(RA3 == 0){
while(RA3 == 0)
;
eep_wt(EEP_ADR,frequency);
eeprom_write(0x0f,0x49);
}
if(eeprom_read(0x0f) == 0x49)
frequency = eep_rd(EEP_ADR);
}
//------------- main -------------------------------------//
void main(){
int wk,wk1;
eep_init();
PIC12F1840_set(); // Cip Initialization
Si5351_init(); // si5351a Initialization
wk1 = adconv();
si5351aSetFrequency(frequency + wk1); // Frequency data set
while(1){
wk = adconv();
if(RA3 == 0){
if(wk < 1024){
if(wk < 5)
frequency = frequency - 10000; // -10kHz skip
else
frequency = frequency - 1000; // -1kHz skip
}
else{
if(wk >= 2042)
frequency = frequency + 10000; // +10kHz skip
else
frequency = frequency + 1000; // +1kHz skip
}
eep_wt(EEP_ADR,frequency);
si5351aSetFrequency(frequency + wk); // Frequency data set
while(RA3 == 0)
;
}
else{
if(((wk1 + 10) <= wk) || ((wk1 - 10) >= wk)){
si5351aSetFrequency(frequency + wk); // Frequency data set
wk1 = wk;
}
}
__delay_ms(30);
}
}
2018年9月5日水曜日
si5351a VXO
VXOとVFOとの切り分けが難しいが、VXOはアナログ信号を利用したもので、表示器なしと勝手に定義。コントロールにはPIC112F1840を使い、si5351aの発振周波数にADCにボリュームを繋ぎ、加減算する事で周波数調整を行うVXOとした。アナログ入力を使用した時、 目標周波数=発振周波数+ADC値 で簡単に計算する事ができる。PIC12F1840のADCは10Bitの為、0から1023の変化量が得られる。従って、分解能1Hzとした場合、発振周波数+1023(Hz)の変化になる。
////////////////////////////////////////////////////////////
// si5351a PLL control(PIC12F1840)
//
// 2018/09/03
// JA2GQP
////////////////////////////////////////////////////////////
//---------- Header file include -------------------------//
#include <xc.h>
//----------Configuration setting ------------------------//
////////////////////////////
// config1
////////////////////////////
#pragma config FOSC = INTOSC // Internal clock
#pragma config WDTE = OFF // Watchdog timer off
#pragma config PWRTE = ON // Power on start
#pragma config MCLRE = OFF // External reset not used
#pragma config CP = OFF // Program memory not protected
#pragma config CPD = OFF // Data memory not protected
#pragma config BOREN = ON // Power drop monitoring
#pragma config CLKOUTEN = OFF // Clock out pin is RA4
#pragma config IESO = OFF // No activation with clock switching
#pragma config FCMEN = OFF // Do not monitor external clock
////////////////////////////
// config2
////////////////////////////
#pragma config WRT = OFF // Flash memory not protected
#pragma config PLLEN = OFF // It does not work at 32 MHz
#pragma config STVREN = ON // Reset with stack overflow(underflow)
#pragma config BORV = HI // Voltage drop monitoring
#pragma config LVP = OFF // Low voltage programming not used
//---------- Define value setting ------------------------//
#define DEF_FREQ 14000000-AD_OFFSET // Default frequency
#define EEP_ADR 0x00 // EEPROM address
#define SCL RA1 // I2C Clock
#define SDA RA2 // I2C Data
#define AD_OFFSET 1023 // Frequency offset
#define _XTAL_FREQ 16000000 // clock 16MHz(Use with delay)
////////////////////////////
// si5351a parameter
////////////////////////////
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define MSNA_ADDR 26
#define MS0_ADDR 42
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define Si5351A_ADDR 0xC0 // address(cip address<<1)
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
#define _6pF 0b01010010 // 6pF
#define _8pF 0b10010010 // 8pF
#define _10pF 0b11010010 // 10pF
#define XTAL_CL _8pF // XTAL_CL 8pF set
#define _2mA 0x4C // 2mA(1dBm))
#define _4mA 0x4D // 4mA(5dBm))
#define _6mA 0x4E // 6mA(10dBm))
#define _8mA 0x4F // 8mA(12dBm)
#define mA _6mA // output lebel 10dBm set
//---------- Memory define -------------------------------//
static unsigned long frequency=DEF_FREQ; // Frequency data
//------------- Initial proc. ----------------------------//
void PIC12F1840_set(){
OSCCON = 0b01111000 ; // clock set(16MHz=0x78,8MHz=0x70,4MHz=0x68)
ANSELA = 0b00010000 ; // Anarog = AN3,Othe digital
TRISA = 0b00011000; // I/O set(0=output,1=input)
PORTA = 0b00000000 ; // Output pin initial value
EECON1bits.CFGS =0; // EEPROM
EECON1bits.EEPGD = 0;
ADCON1 = 0b11010000 ; // FOSC/16,VDD=Ref
ADCON0 = 0b00001101 ;
__delay_us(5) ; // 5us(at clock 16MHz))
}
//------------- wait proc. -------------------------------//
void await(unsigned long ct){
while(ct>0) ct--;
}
//------------- I2C start proc. --------------------------//
void I2C_start(){
SCL = 1; // start condition
await(3);
SDA = 1;
await(3);
SDA = 0;
await(3);
SCL = 0;
await(3);
}
//------------- I2C stop proc. ---------------------------//
void I2C_stop(){
await(3);
SCL = 1; // stop condition
await(3);
SDA = 0;
await(3);
SDA = 1;
await(3);
SCL = 0;
await(3);
}
//------------- I2C write byte proc. ---------------------//
void wr_Byte(unsigned char x){
unsigned int k;
for(k=0;k<8;k++){
if(x & 0x80) SDA = 1; else SDA = 0;
await(3);
SCL = 1;
await(3);
SCL = 0;
await(3);
SDA = 0;
x <<= 1;
}
SCL = 1;
await(3);
SCL = 0;
}
//------------- si5351 command processing ----------------//
void Si5351_write(unsigned char reg_No, unsigned char x){
I2C_start();
wr_Byte(Si5351A_ADDR); // address set
wr_Byte(reg_No);
wr_Byte(x);
I2C_stop();
}
//------------- si5351 Initialization --------------------//
void Si5351_init(void){
SDA=1;
SCL=1;
await(200);
Si5351_write(XTAL_LOAD_C,XTAL_CL); // XTAL_CL set
Si5351_write(CLK0_CTRL,0x80); // Disable CLK0
Si5351_write(PLL_RESET,0xA0); // Reset PLL_A
Si5351_write(CLK0_CTRL,mA);
}
//------------- si5351 PLL data set --------------------------//
void setupPLL(unsigned char pll, unsigned char mult, unsigned long num, unsigned long denom){
unsigned long P1; // PLL config register P1
unsigned long P2; // PLL config register P2
unsigned long P3; // PLL config register P3
P1 = (unsigned long)(128 * ((float)num / (float)denom));
P1 = (unsigned long)(128 * (unsigned long)(mult) + P1 - 512);
P2 = (unsigned long)(128 * ((float)num / (float)denom));
P2 = (unsigned long)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
//------------- Set up MultiSynth --------------------------//
void setupMultisynth(unsigned char synth, unsigned long divider, unsigned char rDiv){
unsigned long P1; // Synth config register P1
unsigned long P2; // Synth config register P2
unsigned long P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
//------------- si5351 data set --------------------------//
void si5351aSetFrequency(unsigned long frequency){
unsigned long pllFreq;
unsigned long xtalFreq = XTAL_FREQ;
unsigned long l;
float f;
unsigned char mult;
unsigned long num;
unsigned long denom;
unsigned long divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
}
//------------- ADconverter ------------------------------//
unsigned int adconv(){
unsigned int temp;
GO_nDONE = 1 ; // Anarog read start
while(GO_nDONE) ; // PIC wait
temp = ADRESH ; // Data high set
temp = ( temp << 8 ) | ADRESL ; // low set
return temp * 2 ; // (0-1023) * 2 = 0-2046
}
//------------- EEPROM read ------------------------------//
unsigned long eep_rd(unsigned char address){
unsigned long temp = 0;
temp = eeprom_read(address+3);
temp = temp << 8;
temp = temp | eeprom_read(address+2);
temp = temp << 8;
temp = temp | eeprom_read(address+1);
temp = temp << 8;
temp = temp | eeprom_read(address+0);
return temp;
}
//------------- EEPROM write -----------------------------//
void eep_wt(unsigned char address,unsigned long frequency){
eeprom_write(address+0,(frequency & 0xff));
eeprom_write(address+1,((frequency >> 8) & 0xff));
eeprom_write(address+2,((frequency >> 16) & 0xff));
eeprom_write(address+3,((frequency >> 24) & 0xff));
}
//------------- EEPROM initialize -----------------------------//
void eep_init(){
if(RA3 == 0){
while(RA3 == 0)
;
eep_wt(EEP_ADR,frequency);
eeprom_write(0x0f,0x49);
}
if(eeprom_read(0x0f) == 0x49)
frequency = eep_rd(EEP_ADR);
}
//------------- main -------------------------------------//
void main(){
int wk,wk1,i;
char skip;
eep_init();
PIC12F1840_set(); // Cip Initialization
Si5351_init(); // si5351a Initialization
while(1){
wk = adconv();
if(RA3 == 0){
if(wk < 1024)
frequency = frequency - 1000;
else
frequency = frequency + 1000;
eep_wt(EEP_ADR,frequency);
si5351aSetFrequency(frequency + wk); // Frequency data set
while(RA3 == 0)
;
}
else{
if(wk != wk1){
si5351aSetFrequency(frequency + wk); // Frequency data set
wk1 = wk;
}
}
__delay_ms(30);
}
}
回路図
si5351a Xtal代替発振器の回路図通り。ボリューム変化量
10BitのADCの為、0-1023の値を持つ。この為、発振周波数+1023 が目標周波数でであれば簡単だが、VXOとして使える範囲が限定される。そこで、水晶発振子を使ったVXOと同等な性能を目指す事にした。目標可変範囲を±30kHzとした。これをADC分解能で現すと±30倍スケーリングしなければならない。1Bitの変化が30Hzとして計算されるので、ADCによる変換誤差、外来ノイズなど顕著に周波数に反映された結果、周波数が揺らぐ。この揺らぎは、5倍のスケーリングした時でも受信機にトーン変化として感じられた。使い勝手と揺らぎ有無判断から、ADC値2倍のスケーリング(分解能 2Hz)を行うことにした。従って、ADC*2(0-2046)がボリューム変化量となる。周波数中心値
ADC値を2倍した値をボリュームの最小位置から最大位置として使うので、ボリューム中心値を発振周波数(初期値)と操作性が良い。そこでオフセット 発振周波数ー1023 にした。可変範囲拡張方法
今迄の説明で、発振周波数±1023 即ち、発振周波数±1kHz変化する事が想像出来た思うが、30kHz程安定して可変させるには工夫がいる。SSB運用形態を観ていると、1kHzステップ刻みが多い。そこで1kHzスキップさせる為、SKIP SWを付けた。SKIPを押すと、+1kHzまたは-1kHzスキップさせる事にした。+またはー判断は、ボリュームの中心値を基準に大小判断にした。SKIPを押す度にEEPROMに周波数を保存して可変範囲を拡張した。このVXOを仮称「GQP VXO」と呼ぶ。EEPROM初期化の方法
表示器を持たないシステムの場合、初期化は重要である。SKIP SWを押しながら電源スイッチを投入すると、EEPROMが初期化される方式にした。(初めて使う時は、初期化が必要)スケッチ
Mplab X X8Cを使って開発を行った。スケッチはJA2GQP's Download siteのPICフォルダからダウンロード可能。////////////////////////////////////////////////////////////
// si5351a PLL control(PIC12F1840)
//
// 2018/09/03
// JA2GQP
////////////////////////////////////////////////////////////
//---------- Header file include -------------------------//
#include <xc.h>
//----------Configuration setting ------------------------//
////////////////////////////
// config1
////////////////////////////
#pragma config FOSC = INTOSC // Internal clock
#pragma config WDTE = OFF // Watchdog timer off
#pragma config PWRTE = ON // Power on start
#pragma config MCLRE = OFF // External reset not used
#pragma config CP = OFF // Program memory not protected
#pragma config CPD = OFF // Data memory not protected
#pragma config BOREN = ON // Power drop monitoring
#pragma config CLKOUTEN = OFF // Clock out pin is RA4
#pragma config IESO = OFF // No activation with clock switching
#pragma config FCMEN = OFF // Do not monitor external clock
////////////////////////////
// config2
////////////////////////////
#pragma config WRT = OFF // Flash memory not protected
#pragma config PLLEN = OFF // It does not work at 32 MHz
#pragma config STVREN = ON // Reset with stack overflow(underflow)
#pragma config BORV = HI // Voltage drop monitoring
#pragma config LVP = OFF // Low voltage programming not used
//---------- Define value setting ------------------------//
#define DEF_FREQ 14000000-AD_OFFSET // Default frequency
#define EEP_ADR 0x00 // EEPROM address
#define SCL RA1 // I2C Clock
#define SDA RA2 // I2C Data
#define AD_OFFSET 1023 // Frequency offset
#define _XTAL_FREQ 16000000 // clock 16MHz(Use with delay)
////////////////////////////
// si5351a parameter
////////////////////////////
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define MSNA_ADDR 26
#define MS0_ADDR 42
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define Si5351A_ADDR 0xC0 // address(cip address<<1)
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
#define _6pF 0b01010010 // 6pF
#define _8pF 0b10010010 // 8pF
#define _10pF 0b11010010 // 10pF
#define XTAL_CL _8pF // XTAL_CL 8pF set
#define _2mA 0x4C // 2mA(1dBm))
#define _4mA 0x4D // 4mA(5dBm))
#define _6mA 0x4E // 6mA(10dBm))
#define _8mA 0x4F // 8mA(12dBm)
#define mA _6mA // output lebel 10dBm set
//---------- Memory define -------------------------------//
static unsigned long frequency=DEF_FREQ; // Frequency data
//------------- Initial proc. ----------------------------//
void PIC12F1840_set(){
OSCCON = 0b01111000 ; // clock set(16MHz=0x78,8MHz=0x70,4MHz=0x68)
ANSELA = 0b00010000 ; // Anarog = AN3,Othe digital
TRISA = 0b00011000; // I/O set(0=output,1=input)
PORTA = 0b00000000 ; // Output pin initial value
EECON1bits.CFGS =0; // EEPROM
EECON1bits.EEPGD = 0;
ADCON1 = 0b11010000 ; // FOSC/16,VDD=Ref
ADCON0 = 0b00001101 ;
__delay_us(5) ; // 5us(at clock 16MHz))
}
//------------- wait proc. -------------------------------//
void await(unsigned long ct){
while(ct>0) ct--;
}
//------------- I2C start proc. --------------------------//
void I2C_start(){
SCL = 1; // start condition
await(3);
SDA = 1;
await(3);
SDA = 0;
await(3);
SCL = 0;
await(3);
}
//------------- I2C stop proc. ---------------------------//
void I2C_stop(){
await(3);
SCL = 1; // stop condition
await(3);
SDA = 0;
await(3);
SDA = 1;
await(3);
SCL = 0;
await(3);
}
//------------- I2C write byte proc. ---------------------//
void wr_Byte(unsigned char x){
unsigned int k;
for(k=0;k<8;k++){
if(x & 0x80) SDA = 1; else SDA = 0;
await(3);
SCL = 1;
await(3);
SCL = 0;
await(3);
SDA = 0;
x <<= 1;
}
SCL = 1;
await(3);
SCL = 0;
}
//------------- si5351 command processing ----------------//
void Si5351_write(unsigned char reg_No, unsigned char x){
I2C_start();
wr_Byte(Si5351A_ADDR); // address set
wr_Byte(reg_No);
wr_Byte(x);
I2C_stop();
}
//------------- si5351 Initialization --------------------//
void Si5351_init(void){
SDA=1;
SCL=1;
await(200);
Si5351_write(XTAL_LOAD_C,XTAL_CL); // XTAL_CL set
Si5351_write(CLK0_CTRL,0x80); // Disable CLK0
Si5351_write(PLL_RESET,0xA0); // Reset PLL_A
Si5351_write(CLK0_CTRL,mA);
}
//------------- si5351 PLL data set --------------------------//
void setupPLL(unsigned char pll, unsigned char mult, unsigned long num, unsigned long denom){
unsigned long P1; // PLL config register P1
unsigned long P2; // PLL config register P2
unsigned long P3; // PLL config register P3
P1 = (unsigned long)(128 * ((float)num / (float)denom));
P1 = (unsigned long)(128 * (unsigned long)(mult) + P1 - 512);
P2 = (unsigned long)(128 * ((float)num / (float)denom));
P2 = (unsigned long)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
//------------- Set up MultiSynth --------------------------//
void setupMultisynth(unsigned char synth, unsigned long divider, unsigned char rDiv){
unsigned long P1; // Synth config register P1
unsigned long P2; // Synth config register P2
unsigned long P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
//------------- si5351 data set --------------------------//
void si5351aSetFrequency(unsigned long frequency){
unsigned long pllFreq;
unsigned long xtalFreq = XTAL_FREQ;
unsigned long l;
float f;
unsigned char mult;
unsigned long num;
unsigned long denom;
unsigned long divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
}
//------------- ADconverter ------------------------------//
unsigned int adconv(){
unsigned int temp;
GO_nDONE = 1 ; // Anarog read start
while(GO_nDONE) ; // PIC wait
temp = ADRESH ; // Data high set
temp = ( temp << 8 ) | ADRESL ; // low set
return temp * 2 ; // (0-1023) * 2 = 0-2046
}
//------------- EEPROM read ------------------------------//
unsigned long eep_rd(unsigned char address){
unsigned long temp = 0;
temp = eeprom_read(address+3);
temp = temp << 8;
temp = temp | eeprom_read(address+2);
temp = temp << 8;
temp = temp | eeprom_read(address+1);
temp = temp << 8;
temp = temp | eeprom_read(address+0);
return temp;
}
//------------- EEPROM write -----------------------------//
void eep_wt(unsigned char address,unsigned long frequency){
eeprom_write(address+0,(frequency & 0xff));
eeprom_write(address+1,((frequency >> 8) & 0xff));
eeprom_write(address+2,((frequency >> 16) & 0xff));
eeprom_write(address+3,((frequency >> 24) & 0xff));
}
//------------- EEPROM initialize -----------------------------//
void eep_init(){
if(RA3 == 0){
while(RA3 == 0)
;
eep_wt(EEP_ADR,frequency);
eeprom_write(0x0f,0x49);
}
if(eeprom_read(0x0f) == 0x49)
frequency = eep_rd(EEP_ADR);
}
//------------- main -------------------------------------//
void main(){
int wk,wk1,i;
char skip;
eep_init();
PIC12F1840_set(); // Cip Initialization
Si5351_init(); // si5351a Initialization
while(1){
wk = adconv();
if(RA3 == 0){
if(wk < 1024)
frequency = frequency - 1000;
else
frequency = frequency + 1000;
eep_wt(EEP_ADR,frequency);
si5351aSetFrequency(frequency + wk); // Frequency data set
while(RA3 == 0)
;
}
else{
if(wk != wk1){
si5351aSetFrequency(frequency + wk); // Frequency data set
wk1 = wk;
}
}
__delay_ms(30);
}
}
2018年8月31日金曜日
si5351a Xtal代替発振器
si5351aをpic12f1840でコントロールしたX'tal代替発振器である。S/W I2Cコントロールを行っており、JE1AHW内田OMの「クリスタルもどきの製作」を参考にさせて頂いた。開発用ボードは、試験が容易な構造にした。si5351aを発振させた場合、PLLである為に周波数の微調整が難しい。今回、周波数のキャリブレーションを容易にする為、ポテンションメータで周波数の微調整(±1kHZ)が出来る様にした。
電源電圧3.3Vとし、レベルコンバータなしでI/F出来る様にした。試験では、si5351aボードにレベルコンバータ回路が搭載されたボードを使った。出力は、1chのみ。多回転半固定ボリュームを使うと小型化できると思う。
SKIP SWは、今回のスケッチでは使ってない。
必要なファイルは、JA2GQP's Download sitePICフォルダからダウンロードできる。
////////////////////////////////////////////////////////////
// si5351a PLL control(PIC12F1840)
//
// 2018/9/3
// JA2GQP
////////////////////////////////////////////////////////////
//---------- Header file include -------------------------//
#include <xc.h>
//----------Configuration setting ------------------------//
////////////////////////////
// config1
////////////////////////////
#pragma config FOSC = INTOSC // Internal clock
#pragma config WDTE = OFF // Watchdog timer off
#pragma config PWRTE = ON // Power on start
#pragma config MCLRE = OFF // External reset not used
#pragma config CP = OFF // Program memory not protected
#pragma config CPD = OFF // Data memory not protected
#pragma config BOREN = ON // Power drop monitoring
#pragma config CLKOUTEN = OFF // Clock out pin is RA4
#pragma config IESO = OFF // No activation with clock switching
#pragma config FCMEN = OFF // Do not monitor external clock
////////////////////////////
// config2
////////////////////////////
#pragma config WRT = OFF // Flash memory not protected
#pragma config PLLEN = OFF // It does not work at 32 MHz
#pragma config STVREN = ON // Reset with stack overflow(underflow)
#pragma config BORV = HI // Voltage drop monitoring
#pragma config LVP = OFF // Low voltage programming not used
//---------- Define value setting ------------------------//
#define DEF_FREQ 14000000-AD_OFFSET // Default frequency
#define EEP_ADR 0x00 // EEPROM address
#define SCL RA1 // I2C Clock
#define SDA RA2 // I2C Data
#define AD_OFFSET 1023 // Frequency offset
#define _XTAL_FREQ 16000000 // clock 16MHz(Use with delay)
////////////////////////////
// si5351a parameter
////////////////////////////
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define MSNA_ADDR 26
#define MS0_ADDR 42
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define Si5351A_ADDR 0xC0
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
#define _6pF 0b01010010 // 6pF
#define _8pF 0b10010010 // 8pF
#define _10pF 0b11010010 // 10pF
#define XTAL_CL _8pF // XTAL_CL 8pF set
#define _2mA 0x4C // 2mA(1dBm))
#define _4mA 0x4D // 4mA(5dBm))
#define _6mA 0x4E // 6mA(10dBm))
#define _8mA 0x4F // 8mA(12dBm)
#define mA _6mA // output lebel 10dBm set
//---------- Memory define -------------------------------//
unsigned long frequency=DEF_FREQ; // Frequency data
//------------- Initial proc. ----------------------------//
void PIC12F1840_set(){
OSCCON = 0b01111000 ; // clock set(16MHz=0x78,8MHz=0x70,4MHz=0x68)
ANSELA = 0b00010000 ; // Anarog = AN3,Othe digital
TRISA = 0b00011000; // I/O set(0=output,1=input)
PORTA = 0b00000000 ; // Output pin initial value
ADCON1 = 0b11010000 ; // FOSC/16,VDD=Ref
ADCON0 = 0b00001101 ;
__delay_us(5) ; // 5us(at clock 16MHz))
}
//------------- wait proc. -------------------------------//
void await(unsigned long ct){
while(ct>0) ct--;
}
//------------- I2C start proc. --------------------------//
void I2C_start(){
SCL = 1; // start condition
await(3);
SDA = 1;
await(3);
SDA = 0;
await(3);
SCL = 0;
await(3);
}
//------------- I2C stop proc. ---------------------------//
void I2C_stop(){
await(3);
SCL = 1; // stop condition
await(3);
SDA = 0;
await(3);
SDA = 1;
await(3);
SCL = 0;
await(3);
}
//------------- I2C write byte proc. ---------------------//
void wr_Byte(unsigned char x){
unsigned int k;
for(k=0;k<8;k++){
if(x & 0x80) SDA = 1; else SDA = 0;
await(3);
SCL = 1;
await(3);
SCL = 0;
await(3);
SDA = 0;
x <<= 1;
}
SCL = 1;
await(3);
SCL = 0;
}
//------------- si5351 command processing ----------------//
void Si5351_write(unsigned char reg_No, unsigned char x){
I2C_start();
wr_Byte(Si5351A_ADDR); // address set
wr_Byte(reg_No);
wr_Byte(x);
I2C_stop();
}
//------------- si5351 Initialization --------------------//
void Si5351_init(void){
SDA=1;
SCL=1;
await(200);
Si5351_write(XTAL_LOAD_C,XTAL_CL); // XTAL_CL set
Si5351_write(CLK0_CTRL,0x80); // Disable CLK0
Si5351_write(PLL_RESET,0xA0); // Reset PLL_A
Si5351_write(CLK0_CTRL,mA);
}
//------------- si5351 PLL data set --------------------------//
void setupPLL(unsigned char pll, unsigned char mult, unsigned long num, unsigned long denom){
unsigned long P1; // PLL config register P1
unsigned long P2; // PLL config register P2
unsigned long P3; // PLL config register P3
P1 = (unsigned long)(128 * ((float)num / (float)denom));
P1 = (unsigned long)(128 * (unsigned long)(mult) + P1 - 512);
P2 = (unsigned long)(128 * ((float)num / (float)denom));
P2 = (unsigned long)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
//------------- Set up MultiSynth --------------------------//
void setupMultisynth(unsigned char synth, unsigned long divider, unsigned char rDiv){
unsigned long P1; // Synth config register P1
unsigned long P2; // Synth config register P2
unsigned long P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
//------------- si5351 data set --------------------------//
void si5351aSetFrequency(unsigned long frequency){
unsigned long pllFreq;
unsigned long xtalFreq = XTAL_FREQ;
unsigned long l;
float f;
unsigned char mult;
unsigned long num;
unsigned long denom;
unsigned long divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
}
//------------- ADconverter ------------------------------//
unsigned int adconv(){
unsigned int temp;
GO_nDONE = 1 ; // Anarog read start
while(GO_nDONE) ; // PIC wait
temp = ADRESH ; // Data high set
temp = ( temp << 8 ) | ADRESL ; // low set
return temp * 2 ; // (0-1023) * 2 = 0-2026
}
//------------- main -------------------------------------//
void main(){
int wk,wk1;
PIC12F1840_set(); // Cip Initialization
Si5351_init(); // si5351a Initialization
while(1){
wk = adconv();
if(wk != wk1){
si5351aSetFrequency(frequency + wk); // Frequency data set
wk1 = wk;
}
__delay_ms(30);
}
}
回路図
電源電圧3.3Vとし、レベルコンバータなしでI/F出来る様にした。試験では、si5351aボードにレベルコンバータ回路が搭載されたボードを使った。出力は、1chのみ。多回転半固定ボリュームを使うと小型化できると思う。
SKIP SWは、今回のスケッチでは使ってない。
スケッチ
目標周波数をボリューム中心値となる様、周波数オフセットを行っている。ADC分解能が10Bitなので、1023*2を周波数データに加えている。従って、発振周波数=目標周波数-オフセット値(1023)+AD値(0-2026)となっている。開発は、Mplab X X8Cを使った。必要なファイルは、JA2GQP's Download sitePICフォルダからダウンロードできる。
////////////////////////////////////////////////////////////
// si5351a PLL control(PIC12F1840)
//
// 2018/9/3
// JA2GQP
////////////////////////////////////////////////////////////
//---------- Header file include -------------------------//
#include <xc.h>
//----------Configuration setting ------------------------//
////////////////////////////
// config1
////////////////////////////
#pragma config FOSC = INTOSC // Internal clock
#pragma config WDTE = OFF // Watchdog timer off
#pragma config PWRTE = ON // Power on start
#pragma config MCLRE = OFF // External reset not used
#pragma config CP = OFF // Program memory not protected
#pragma config CPD = OFF // Data memory not protected
#pragma config BOREN = ON // Power drop monitoring
#pragma config CLKOUTEN = OFF // Clock out pin is RA4
#pragma config IESO = OFF // No activation with clock switching
#pragma config FCMEN = OFF // Do not monitor external clock
////////////////////////////
// config2
////////////////////////////
#pragma config WRT = OFF // Flash memory not protected
#pragma config PLLEN = OFF // It does not work at 32 MHz
#pragma config STVREN = ON // Reset with stack overflow(underflow)
#pragma config BORV = HI // Voltage drop monitoring
#pragma config LVP = OFF // Low voltage programming not used
//---------- Define value setting ------------------------//
#define DEF_FREQ 14000000-AD_OFFSET // Default frequency
#define EEP_ADR 0x00 // EEPROM address
#define SCL RA1 // I2C Clock
#define SDA RA2 // I2C Data
#define AD_OFFSET 1023 // Frequency offset
#define _XTAL_FREQ 16000000 // clock 16MHz(Use with delay)
////////////////////////////
// si5351a parameter
////////////////////////////
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define MSNA_ADDR 26
#define MS0_ADDR 42
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define Si5351A_ADDR 0xC0
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
#define _6pF 0b01010010 // 6pF
#define _8pF 0b10010010 // 8pF
#define _10pF 0b11010010 // 10pF
#define XTAL_CL _8pF // XTAL_CL 8pF set
#define _2mA 0x4C // 2mA(1dBm))
#define _4mA 0x4D // 4mA(5dBm))
#define _6mA 0x4E // 6mA(10dBm))
#define _8mA 0x4F // 8mA(12dBm)
#define mA _6mA // output lebel 10dBm set
//---------- Memory define -------------------------------//
unsigned long frequency=DEF_FREQ; // Frequency data
//------------- Initial proc. ----------------------------//
void PIC12F1840_set(){
OSCCON = 0b01111000 ; // clock set(16MHz=0x78,8MHz=0x70,4MHz=0x68)
ANSELA = 0b00010000 ; // Anarog = AN3,Othe digital
TRISA = 0b00011000; // I/O set(0=output,1=input)
PORTA = 0b00000000 ; // Output pin initial value
ADCON1 = 0b11010000 ; // FOSC/16,VDD=Ref
ADCON0 = 0b00001101 ;
__delay_us(5) ; // 5us(at clock 16MHz))
}
//------------- wait proc. -------------------------------//
void await(unsigned long ct){
while(ct>0) ct--;
}
//------------- I2C start proc. --------------------------//
void I2C_start(){
SCL = 1; // start condition
await(3);
SDA = 1;
await(3);
SDA = 0;
await(3);
SCL = 0;
await(3);
}
//------------- I2C stop proc. ---------------------------//
void I2C_stop(){
await(3);
SCL = 1; // stop condition
await(3);
SDA = 0;
await(3);
SDA = 1;
await(3);
SCL = 0;
await(3);
}
//------------- I2C write byte proc. ---------------------//
void wr_Byte(unsigned char x){
unsigned int k;
for(k=0;k<8;k++){
if(x & 0x80) SDA = 1; else SDA = 0;
await(3);
SCL = 1;
await(3);
SCL = 0;
await(3);
SDA = 0;
x <<= 1;
}
SCL = 1;
await(3);
SCL = 0;
}
//------------- si5351 command processing ----------------//
void Si5351_write(unsigned char reg_No, unsigned char x){
I2C_start();
wr_Byte(Si5351A_ADDR); // address set
wr_Byte(reg_No);
wr_Byte(x);
I2C_stop();
}
//------------- si5351 Initialization --------------------//
void Si5351_init(void){
SDA=1;
SCL=1;
await(200);
Si5351_write(XTAL_LOAD_C,XTAL_CL); // XTAL_CL set
Si5351_write(CLK0_CTRL,0x80); // Disable CLK0
Si5351_write(PLL_RESET,0xA0); // Reset PLL_A
Si5351_write(CLK0_CTRL,mA);
}
//------------- si5351 PLL data set --------------------------//
void setupPLL(unsigned char pll, unsigned char mult, unsigned long num, unsigned long denom){
unsigned long P1; // PLL config register P1
unsigned long P2; // PLL config register P2
unsigned long P3; // PLL config register P3
P1 = (unsigned long)(128 * ((float)num / (float)denom));
P1 = (unsigned long)(128 * (unsigned long)(mult) + P1 - 512);
P2 = (unsigned long)(128 * ((float)num / (float)denom));
P2 = (unsigned long)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
//------------- Set up MultiSynth --------------------------//
void setupMultisynth(unsigned char synth, unsigned long divider, unsigned char rDiv){
unsigned long P1; // Synth config register P1
unsigned long P2; // Synth config register P2
unsigned long P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
//------------- si5351 data set --------------------------//
void si5351aSetFrequency(unsigned long frequency){
unsigned long pllFreq;
unsigned long xtalFreq = XTAL_FREQ;
unsigned long l;
float f;
unsigned char mult;
unsigned long num;
unsigned long denom;
unsigned long divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
}
//------------- ADconverter ------------------------------//
unsigned int adconv(){
unsigned int temp;
GO_nDONE = 1 ; // Anarog read start
while(GO_nDONE) ; // PIC wait
temp = ADRESH ; // Data high set
temp = ( temp << 8 ) | ADRESL ; // low set
return temp * 2 ; // (0-1023) * 2 = 0-2026
}
//------------- main -------------------------------------//
void main(){
int wk,wk1;
PIC12F1840_set(); // Cip Initialization
Si5351_init(); // si5351a Initialization
while(1){
wk = adconv();
if(wk != wk1){
si5351aSetFrequency(frequency + wk); // Frequency data set
wk1 = wk;
}
__delay_ms(30);
}
}