久しぶりにブログを更新します。
この2週間ほど、SDRのフロントエンドの試作をしていました。
私が所属しているFCWA(福島CW愛好会)では毎年、電子工作講習会を開催しています。その担当のJA7UCA石井さんからの提案で、来年度は、SDRはどうかということになりました。
以前にSi5351Aを使った7MHz CW トランシーバを製作したときに実験したものをフロントエンドだけを取り出して、実験をしました。JA7UCAさんとは、その都度メールでやりとりしながらアドバイスをいただいています。
今回実験したSDRフロントエンドは、有名なsoft66等で使われているダイレクトコンバージョン受信機で、ミキサーにアナログスイッチ74HC4066を使い、局部発振器からの位相差90°の信号でスイッチングしてIQ信号を得る方法をとっています。
局部発振器として、当初は水晶発振器を考えていたのですが、必要な7.040MHzと3.5375MHzの水晶が手に入りにくく、特注するとコストが高くなってしまうことから、3チャンネルクロックジャネレータSi5351Aを使って実験を進めました。講習会では、作りやすさとコストが安いことが重要な要素になっています。
受信バンドは、7MHzと3,5MHzで、CWバンドとSSBバンドの両方をワッチできるということで、局部発振器の周波数が上記の周波数にしてあります。
回路図です。
soft66では、74HC4066の後にオペアンプを使ったローパスフィルタが入っていますが、今回はRCのローパスフィルタ(カットオフ周波数約100KHz)だけにしています。
電源は、乾電池2本(3V)です。I2CとBAND SWのプルアップ抵抗は、PIC側でウィークプルアップすることにより、プルアップ抵抗を省略しました。
ブレッドボードです。
タクトスイッチを押すたびに7MHz/3.5MHzが切り替わり、バンド表示用のLEDが(7MHzが緑、3,5MHzが黄色)点灯します。
Si5351Aは、7MHzと3,5MHzで位相が90°ずれた信号を発生します。これが、7MHzは既に実験済みで簡単なのですが3.5MHzで位相差90°の信号を作るのには、PLL周波数が400MHzと規格外になり、実験が必要でした。
Si5351AのCLK0,CLK1信号のリサージュです。
7MHz
3.5MHz
ほぼ90°です。
SDRソフトは、JA7UCA局のすすめもあり、Rockyを使いました。フロントエンドに実際に7MHzのアンテナを接続して受信し、Rockyで見てみました。
中央が、7.040MHzで右の方に見えるのが、SSBの信号、左の方に線上のピークが見られるのがCW信号です。
モードを選択し、信号にカーソル合わせてクリックするとCWとSSBの信号を聞くことができました。
Si5351Aのコントロールは、PIC12F1822を使い、MPLABX XC8でプログラムをコンパイルしました。
参考までに、今の状態でのプログラムです。まだ実験段階ですので、今後変更の可能性が十分にあります。
/*
* File: main.c
* Author: JH7UBC Keiji Hata
* PIC12F1822 Si5351A test
* Created on 2019/02/15
*/
* File: main.c
* Author: JH7UBC Keiji Hata
* PIC12F1822 Si5351A test
* Created on 2019/02/15
*/
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <stdlib.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG2
#pragma config WRT = OFF
#pragma config PLLEN = ON
#pragma config STVREN = ON
#pragma config BORV = HI
#pragma config LVP = OFF
#pragma config WRT = OFF
#pragma config PLLEN = ON
#pragma config STVREN = ON
#pragma config BORV = HI
#pragma config LVP = OFF
#define _XTAL_FREQ 32000000
#define SW RA3
#define LED RA0
#define SW RA3
#define LED RA0
/* Si5351A関係定義*/
#define Si5351_ADDR 0xC0 //60<<1
#define MSNA_ADDR 26
#define MS0_ADDR 42
#define MS1_ADDR 50
#define CLK0_CTRL 16
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define OUTPUT_CTRL 3
#define PLL_RESET 177
#define XTAL_LC 183
#define CLK0_PHOFF 165
#define CLK1_PHOFF 166
#define Si5351_ADDR 0xC0 //60<<1
#define MSNA_ADDR 26
#define MS0_ADDR 42
#define MS1_ADDR 50
#define CLK0_CTRL 16
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define OUTPUT_CTRL 3
#define PLL_RESET 177
#define XTAL_LC 183
#define CLK0_PHOFF 165
#define CLK1_PHOFF 166
unsigned long P1;
unsigned long P2;
unsigned long P3;
unsigned char PHASE;
unsigned char val; //RA3の値
unsigned char val_old; //RA3の前の値
unsigned char flag=0; //7MHz:flag=0 3.5MHz:flag=1
unsigned long P2;
unsigned long P3;
unsigned char PHASE;
unsigned char val; //RA3の値
unsigned char val_old; //RA3の前の値
unsigned char flag=0; //7MHz:flag=0 3.5MHz:flag=1
/* I2C 初期化*/
void I2C_init(){
SSP1CON1 = 0x28; //SSPEN = 1,I2C Master Mode
SSP1STATbits.SMP = 1; //標準速度モード(100KHz)
SSP1ADD = 0x4F; //Fosc/(4*Clock)-1 Clock=100kHz,Fosc=32MHz
}
/* スタートコンディション */
void I2C_start(){
SEN = 1;
while(SEN);
}
void I2C_start(){
SEN = 1;
while(SEN);
}
/* ストップコンディション */
void I2C_stop(){
SSP1IF = 0;
PEN = 1;
while(PEN);
SSP1IF = 0;
}
void I2C_stop(){
SSP1IF = 0;
PEN = 1;
while(PEN);
SSP1IF = 0;
}
/* I2Cに1byte送信 */
void I2C_write(unsigned char dat){
SSP1IF = 0;
SSP1BUF = dat;
while(!SSP1IF);
}
void I2C_write(unsigned char dat){
SSP1IF = 0;
SSP1BUF = dat;
while(!SSP1IF);
}
/* Si5351A関係関数*/
/* Si5351Aのレジスタにデータ送信*/
void Si5351_write(unsigned char Reg , unsigned char Data){
I2C_start();
I2C_write(Si5351_ADDR);
I2C_write(Reg);
I2C_write(Data);
I2C_stop();
}
/* Si5351Aのレジスタにデータ送信*/
void Si5351_write(unsigned char Reg , unsigned char Data){
I2C_start();
I2C_write(Si5351_ADDR);
I2C_write(Reg);
I2C_write(Data);
I2C_stop();
}
/* Si5351A初期化 */
void Si5351_init(){
Si5351_write(OUTPUT_CTRL,0xFF); //Disable oll output
Si5351_write(CLK0_CTRL,0x80); //CLOCK0 power down
Si5351_write(CLK1_CTRL,0x80); //CLOCK1 power down
Si5351_write(CLK2_CTRL,0x80); //CLOCK2 power down
Si5351_write(XTAL_LC,0x92); //Crystal Load Capasitance=8pF
Si5351_write(PLL_RESET,0xA0); //Reset PLLA and PLLB
Si5351_write(CLK0_CTRL,0b01001110); //CLOCK0 Power up 6mA,Sorce PLLA
Si5351_write(CLK1_CTRL,0b01001110); //CLOCK1 Power up 6mA,Sorce PLLA
Si5351_write(OUTPUT_CTRL,0b11111100); //Enable CLOCK0 & CLOCK1
}
void Si5351_init(){
Si5351_write(OUTPUT_CTRL,0xFF); //Disable oll output
Si5351_write(CLK0_CTRL,0x80); //CLOCK0 power down
Si5351_write(CLK1_CTRL,0x80); //CLOCK1 power down
Si5351_write(CLK2_CTRL,0x80); //CLOCK2 power down
Si5351_write(XTAL_LC,0x92); //Crystal Load Capasitance=8pF
Si5351_write(PLL_RESET,0xA0); //Reset PLLA and PLLB
Si5351_write(CLK0_CTRL,0b01001110); //CLOCK0 Power up 6mA,Sorce PLLA
Si5351_write(CLK1_CTRL,0b01001110); //CLOCK1 Power up 6mA,Sorce PLLA
Si5351_write(OUTPUT_CTRL,0b11111100); //Enable CLOCK0 & CLOCK1
}
//レジスタにパラメータP1,P2,P3を書き込む。
void Parameter_write(unsigned char REG_ADDR,unsigned long Pa1,unsigned long Pa2,unsigned long 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));
}
void Parameter_write(unsigned char REG_ADDR,unsigned long Pa1,unsigned long Pa2,unsigned long 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));
}
void PLLA_set(unsigned char bd){
if(bd == 0){
P1 = 3072; //7MHz
}else{
P1 = 1536; //3.5MHz
}
P2 = 0;
P3 = 1;
Parameter_write(MSNA_ADDR,P1,P2,P3);
}
if(bd == 0){
P1 = 3072; //7MHz
}else{
P1 = 1536; //3.5MHz
}
P2 = 0;
P3 = 1;
Parameter_write(MSNA_ADDR,P1,P2,P3);
}
void MS0_set(unsigned char bd){
if(bd == 0){
P1 = 12215;
P2 = 78920;
}else{
P1 = 13961;
P2 = 273216;
}
P3 = 1000000;
Parameter_write(MS0_ADDR,P1,P2,P3);
Si5351_write(CLK0_PHOFF,0); //CLK0 delay 0
}
if(bd == 0){
P1 = 12215;
P2 = 78920;
}else{
P1 = 13961;
P2 = 273216;
}
P3 = 1000000;
Parameter_write(MS0_ADDR,P1,P2,P3);
Si5351_write(CLK0_PHOFF,0); //CLK0 delay 0
}
void MS1_set(unsigned char bd){
if(bd == 0){
P1 = 12215;
P2 = 78920;
PHASE = 93;
}else{
P1 = 13961;
P2 = 273216;
PHASE = 127;
}
P3 = 1000000;
Parameter_write(MS1_ADDR,P1,P2,P3);
Si5351_write(CLK1_PHOFF,PHASE); //CLK1 delay T/4 (90degree)
}
if(bd == 0){
P1 = 12215;
P2 = 78920;
PHASE = 93;
}else{
P1 = 13961;
P2 = 273216;
PHASE = 127;
}
P3 = 1000000;
Parameter_write(MS1_ADDR,P1,P2,P3);
Si5351_write(CLK1_PHOFF,PHASE); //CLK1 delay T/4 (90degree)
}
void Band(unsigned char bnd){
PLLA_set(bnd);
MS0_set(bnd);
MS1_set(bnd);
Si5351_write(PLL_RESET,0xA0); //Reset PLLA and PLLB
}
void main() {
OSCCON = 0b01110000 ; // 内部クロック8MHz
ANSELA = 0b00000000 ; // アナログは使用しない
TRISA = 0b00001110 ; // RA1,RA2,RA3は入力、他は出力
OPTION_REGbits.nWPUEN = 0;//week pull up有効
WPUA = 0b00001110; // RA1,RA2,RA3 pull up
PORTA = 0b00000000 ; // 出力ピンの初期化
PLLA_set(bnd);
MS0_set(bnd);
MS1_set(bnd);
Si5351_write(PLL_RESET,0xA0); //Reset PLLA and PLLB
}
void main() {
OSCCON = 0b01110000 ; // 内部クロック8MHz
ANSELA = 0b00000000 ; // アナログは使用しない
TRISA = 0b00001110 ; // RA1,RA2,RA3は入力、他は出力
OPTION_REGbits.nWPUEN = 0;//week pull up有効
WPUA = 0b00001110; // RA1,RA2,RA3 pull up
PORTA = 0b00000000 ; // 出力ピンの初期化
I2C_init();
Si5351_init();
val = SW; //SWの値
val_old = val;
Band(flag);
while(1){
val = SW;
if((val == 0)&&(val_old == 1)){
flag = 1 - flag; //flagを反転させる
LED = flag;
__delay_ms(10);
Band(flag);
}else if((val == 1)&&(val_old == 0)){
__delay_ms(10);
}
val_old = val;
}
}
Si5351_init();
val = SW; //SWの値
val_old = val;
Band(flag);
while(1){
val = SW;
if((val == 0)&&(val_old == 1)){
flag = 1 - flag; //flagを反転させる
LED = flag;
__delay_ms(10);
Band(flag);
}else if((val == 1)&&(val_old == 0)){
__delay_ms(10);
}
val_old = val;
}
}