2017年6月3日土曜日

si5351a TFT VFO Ver.1.1

 2.2"TFTが入手難の為、1.8"TFTにダウンサイジングを行った。今回の移植作業と合わせ、機能追加を行う事にした。追加変更内容は、Lowerヘテロダイン対応とBFO追加である。理由は、BITX40がLowerヘテロダインである事と、si5351aのマルチ出力が生かされて無かったからである。
回路図、スケッチはダウンロードサイトsi5351a TFTフォルダに2種類有ります。
si5351_TFT18.zip,si5351_TFT181.zip



回路図である。si5351aモジュールのclk2からBFO出力を行っている。













インクルードファイル

si5351aの制御は、ライブラリを使わずに、インクルードファイルで行っている。このファイルをスケッチと同じフォルダーに保存して使う。周波数が変わる毎に発生するクリック低減のため、PLLリセットを行わない事(コメントアウトしてある)とした。但し、位相制御などタイミングを重視する場合、PLLリセットを行う必要が有るであろう。

si5351a2.hの内容。


////////////////////////////////////////////////////////////////////////
// Author: Hans Summers, 2015
// Website: http://www.hanssummers.com
//
// A very very simple Si5351a demonstration
// using the Si5351a module kit http://www.hanssummers.com/synth
// Please also refer to SiLabs AN619 which describes all the registers to use
//----------------------------------------------------------------------
// Modifications: JA2GQP,2017/5/20
//     1)Output is CLK0 and CLK2.
//     2)Arduino and stm32duino Operable.
////////////////////////////////////////////////////////////////////////

#include <Wire.h>

#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 PLL_RESET   177
#define XTAL_LOAD_C 183

#define R_DIV_1      0b00000000     // R-division ratio definitions
#define R_DIV_2      0b00010000
#define R_DIV_4      0b00100000
#define R_DIV_8      0b00110000
#define R_DIV_16     0b01000000
#define R_DIV_32     0b01010000
#define R_DIV_64     0b01100000
#define R_DIV_128    0b01110000

#define Si5351A_ADDR  0x60

#define CLK_SRC_PLL_A 0b00000000
#define CLK_SRC_PLL_B 0b00100000

#define XTAL_FREQ     25000000    // Crystal frequency for Hans' board

////////////////////////////////////////////////////////////////////////
// I2C write
////////////////////////////////////////////////////////////////////////

void Si5351_write(byte Reg , byte Data){
  Wire.beginTransmission(Si5351A_ADDR);
  Wire.write(Reg);
  Wire.write(Data);
  Wire.endTransmission();
}

////////////////////////////////////////////////////////////////////////
// Set up specified PLL with mult, num and denom
// mult is 15..90
// num is 0..1,048,575 (0xFFFFF)
// denom is 0..1,048,575 (0xFFFFF)
///////////////////////////////////////////////////////////////////////

void setupPLL(uint8_t pll, uint8_t mult, uint32_t num, uint32_t denom){
  uint32_t P1;                            // PLL config register P1
  uint32_t P2;                            // PLL config register P2
  uint32_t P3;                            // PLL config register P3

  P1 = (uint32_t)(128 * ((float)num / (float)denom));
  P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512);
  P2 = (uint32_t)(128 * ((float)num / (float)denom));
  P2 = (uint32_t)(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 with integer divider and R divider
// R divider is the bit value which is OR'ed onto the appropriate
// register, it is a #define in si5351a.h
////////////////////////////////////////////////////////////////////////

void setupMultisynth(uint8_t synth, uint32_t divider, uint8_t rDiv){
  uint32_t P1;                          // Synth config register P1
  uint32_t P2;                          // Synth config register P2
  uint32_t 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));
}

////////////////////////////////////////////////////////////////////////
// Switches off Si5351a output
// Example: si5351aOutputOff(CLK0_CTRL);
// will switch off output CLK0
////////////////////////////////////////////////////////////////////////

void si5351aOutputOff(uint8_t clk){
  Si5351_write(clk, 0x80);              // Refer to SiLabs AN619 to see
                                        //bit values - 0x80 turns off the output stage
}

////////////////////////////////////////////////////////////////////////
// Set CLK0 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL A
// and MultiSynth 0
// and produces the output on CLK0
////////////////////////////////////////////////////////////////////////

void si5351aSetFrequency(uint32_t frequency){
  uint32_t pllFreq;
  uint32_t xtalFreq = XTAL_FREQ;
  uint32_t l;
  float f;
  uint8_t mult;
  uint32_t num;
  uint32_t denom;
  uint32_t 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);
                                          // Reset the PLL. This causes a glitch in the output. For small changes to
                                          // the parameters, you don't need to reset the PLL, and there is no glitch
//  Si5351_write(PLL_RESET, 0x20);
                                          // Finally switch on the CLK0 output (0x4F)
                                          // and set the MultiSynth0 input to be PLL A
  Si5351_write(CLK0_CTRL, 0x4F | CLK_SRC_PLL_A);    // Strength 8mA
}

////////////////////////////////////////////////////////////////////////
// Set CLK1 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency2(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL B
// and MultiSynth 1
// and produces the output on CLK1
////////////////////////////////////////////////////////////////////////

void si5351aSetFrequency2(uint32_t frequency){
  uint32_t pllFreq;
  uint32_t xtalFreq = XTAL_FREQ;
  uint32_t l;
  float f;
  uint8_t mult;
  uint32_t num;
  uint32_t denom;
  uint32_t 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 B with the calculated  multiplication ratio
  setupPLL(MSNB_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(MS2_ADDR, divider, R_DIV_1);
                                          // Reset the PLL. This causes a glitch in the output. For small changes to
                                          // the parameters, you don't need to reset the PLL, and there is no glitch
//  Si5351_write(PLL_RESET, 0x80);
                                          // Finally switch on the CLK1 output
                                          // and set the MultiSynth0 input to be PLL B
  Si5351_write(CLK2_CTRL, 0x6F | CLK_SRC_PLL_B);    // Strength 8mA
}

スケッチ

BFO出力とLOwerヘテロダインに対応。BITX40の設定は、仕様周波数で記述してあるので必要であれば、実周波数に変更する程度で良いだろう。ただ、BITX40実機を持ってないので未確認。

//////////////////////////////////////////////////////////////////////////////
//       Copyright©2016.JA2GQP.All rights reserved.
//            si5351a PLL VFO Ver1.101      << JA2NKD sketch is based >>      
//                                                    2017/6/3
//                                                    JA2GQP  
//                      << Aruduino IDE 1.8.2 >>
//
//----------------------------------------------------------------------------  
//  Function
//    1.RIT Operation(-10kHZ to 10kHZ)
//    2.STEP(10,100,1k,10k)
//    3.Memory Operation is Push RIT
//    4.Protection Operation At The Time Of Transmission
//    5.Memory 4ch(LSB,USB.CW,AM)
//    6.IF shift
//----------------------------------------------------------------------------  
//  Library
//          <Rotary.h>    https://github.com/brianlow/Rotary
//          "Ucglib.h"    https://github.com/olikraus/ucglib
//
//////////////////////////////////////////////////////////////////////////////

//---------- include Files ---------------

#include "si5351a2.h"
#include <SPI.h>
#include <Rotary.h>
#include <EEPROM.h>
#include "Ucglib.h"

//----------   TFT setting  ---------------

  Ucglib_ST7735_18x128x160_HWSPI ucg(/*sclk= 13, data= 11, */ /*cd=*/ 9 , /*cs=*/ 10, /*reset=*/ 8);

//----------   Encorder setting  ---------------

#define   ENC_A       2                   // Encorder A
#define   ENC_B       3                   // Encoeder B

Rotary r=Rotary(ENC_A,ENC_B);

//----------   I/O setting  -------------------

#define   modeout1    7                   // DIO7
#define   modeout2    12                  // DIO12
#define   modesw      6                   // DIO6
#define   stepsw      4                   // DIO4
#define   ritsw       5                   // DIO5
#define   txsw        A3                  // A3
#define   s_meter     A0                  // A0
#define   t_meter     A1                  // A1

//----------  EEPROM Memory Address   ----------

#define   Frq_Eep     0x00                // Frequency(4byte*4)
#define   Stp_Eep     0x10                // STEP(4byte*4)
#define   Chn_Eep     0x20                // Channel(1byte*1)
#define   Mode_Eep    0x22                // Mode(1byte*1)
#define   Eep_Int     0x2e                // Eep Init(1byte*1)

#define   Max_Chn     4                   // Max Channel(4ch)
#define   Int_End     73                  // Initial end code

//----------- Default Frequency Value --------------------

#define   UPPER      0                    // Upoper heterodyne
#define   LOWER      1                    // Lower heterodyne

////////////////////////////////////////////////////////////////
//  BITX40 Setting example(Upper heterodyne)      No.1
////////////////////////////////////////////////////////////////


#define   DEF_FRQ    7050000L             // Init Frequency
#define   DEF_FMAX   7200000L             // Frequency Max
#define   DEF_FMIN   7000000L             //           Min
#define   DEF_RLSB   10698500L            // RX IF Shift LSB
#define   DEF_RUSB   10701500L            //             USB
#define   DEF_RCW    10699200L            //             CW
#define   DEF_RAM    10700000L            //             AM
#define   DEF_TLSB   10698500L            // TX IF Shift LSB
#define   DEF_TUSB   10701500L            //             USB
#define   DEF_TCW    10700000L            //             CW
#define   DEF_TAM    10700000L            //             AM

byte   hetero = UPPER;                         // Lower heterodyne set


////////////////////////////////////////////////////////////////
//  BITX40 Setting example(Lower heterodyne)      No.2
////////////////////////////////////////////////////////////////

/*
#define   DEF_FRQ    7050000L             // Init Frequency
#define   DEF_FMAX   7200000L             // Frequency Max
#define   DEF_FMIN   7000000L             //           Min
#define   DEF_RLSB   11998500L            // RX IF Shift LSB
#define   DEF_RUSB   12001500L            //             USB
#define   DEF_RCW    11999400L            //             CW
#define   DEF_RAM    12000000L            //             AM
#define   DEF_TLSB   11998500L            // TX IF Shift LSB
#define   DEF_TUSB   12001500L            //             USB
#define   DEF_TCW    12000000L            //             CW
#define   DEF_TAM    12000000L            //             AM

byte   hetero = LOWER;                    // Lower heterodyne set
*/

//----------- Default ETC. Value --------------------

#define   DEF_STP    100L                 // Init STEP
#define   DEF_Mode   0                    // 0=LSB 1=USB 2=CW 3=AM

//----------  Memory Assign  ------------------

long freq    = DEF_FRQ;                   // Frequency data
long freqb;                               //           old data
long freqmax = DEF_FMAX;                  // VFO Upper Limit
long freqmin = DEF_FMIN;                  //     Lower Limit
long freqold = 0;
long freqrit = 0;
String freqt=String(freq);
long ifshift = 0;
long ifshiftb;
long ifshiftLSB = DEF_RLSB;               // RX IF Shift LSB
long ifshiftUSB = DEF_RUSB;               //             USB
long ifshiftCW = DEF_RCW;                 //             CW
long ifshiftAM = DEF_RAM;                 //             AM
long txshiftLSB = DEF_TLSB;               // TX IF Shift LSB
long txshiftUSB = DEF_TUSB;               //             USB
long txshiftCW = DEF_TCW;                 //             CW
long txshiftAM = DEF_TAM;                 //             AM
long vfofreq = 0;                         // VFO data
long vfofreqb;                            //     old
char f100m,f10m,fmega,f100k,f10k,f1k,f100,f10,f1;
int vfostep=2;
int rit=0;
int fstep = DEF_STP;                      // Default Step
int fmode;
int fmodeold=1;
int flagrit=0;
int fritold=0;
int flagmode=0;
int smeterval1=0;
int tmeterval=0;
byte Byt_Chn;                             // Channel SW
byte Byt_Chnb;                            //            Old

//----------  Initialization  Program  ----------------------

void setup() {
  Wire.begin();                

  delay(100);
  ucg.begin(UCG_FONT_MODE_TRANSPARENT);
  ucg.clearScreen();
  ucg.setRotate90();

  pinMode (stepsw,INPUT_PULLUP);
  pinMode (ritsw,INPUT_PULLUP);
  pinMode(txsw,INPUT_PULLUP);
  pinMode(modesw,INPUT_PULLUP);
  pinMode(modeout1,OUTPUT);
  pinMode(modeout2,OUTPUT);

  PCICR |=(1<<PCIE2);
  PCMSK2 |=(1 << PCINT18) | (1 << PCINT19);
  sei();

  screen01();

  if(EEPROM.read(Eep_Int) != Int_End){  // Eep initialaz
    delay(10);
    Fnc_Eep_Int();
  }

  Byt_Chn = EEPROM.read(Chn_Eep);       // Channel
  Byt_Chnb = Byt_Chn;                    //
  Fnc_Eep_Rd();                          // EEPROM Read

  modeset();                             // modeset * 4 times
  modeset();
  modeset();
  modeset();

  steplcd();
  freqt=String(freq);
  freqlcd();
 }

//----------  Main program  ---------------------------------

void loop() {
  if (digitalRead(stepsw)==LOW){setstep();}
  if (digitalRead(modesw)==LOW){modeset();}
  if (digitalRead(ritsw)==LOW){setrit();Fnc_Eep_Wt(Byt_Chn);}
  if (digitalRead(txsw)==LOW){txset();}

    if(Byt_Chnb != Byt_Chn){             // CH SW OLD != NEW?
      Fnc_Eep_Wt(Byt_Chnb);
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
      steplcd();
    }
     
  if (flagrit==1){
    if (freqrit == fritold){
      smeter();
    }  

    if (freqrit!=fritold){
      Vfo_write();
      ritlcd();
      fritold=freqrit;
    }
  }
  else{
    if (freq == freqold){
        smeter();
    }
    Vfo_write();
    freqt=String(freq);
    freqlcd();
    freqold=freq;
  }
}

//---------- Function Eeprom Initialization ------------

void Fnc_Eep_Int(){
  int i;

  for (i=0;i<48;i++)                               // 0 clear(48byte)
    EEPROM.write(i, 0);

  for(i=0;i<Max_Chn;i++){
    Fnc_Eep_Sav4(DEF_FRQ,Frq_Eep+i*4);            // Frequency(7.10MHz)
    Fnc_Eep_Sav4(DEF_STP,Stp_Eep+i*4);            // Step(100Hz)
  }

  EEPROM.write(Chn_Eep,0);
  EEPROM.write(Mode_Eep,DEF_Mode);
  EEPROM.write(Eep_Int,Int_End);                 // Init end set(73)
}

//----------  Function EEPROM Read  ---------          

void Fnc_Eep_Rd(){
  if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
    freq = Fnc_Eep_Lod4(Frq_Eep+Byt_Chn*4);
  else{
    freq = Fnc_Eep_Lod4(Frq_Eep+0);
    Byt_Chn = 0;
  }

  if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
    fstep = Fnc_Eep_Lod4(Stp_Eep+Byt_Chn*4);
  else
    fstep = Fnc_Eep_Lod4(Stp_Eep+0);
 
  fmode = EEPROM.read(Mode_Eep);
}

//----------  Function EEPROM Write  -------------------

void Fnc_Eep_Wt(byte chn){
  if((0 <= chn) && (chn < Max_Chn)){
    Fnc_Eep_Sav4(freq,Frq_Eep+chn*4);
    Fnc_Eep_Sav4(fstep,Stp_Eep+chn*4);
  }

  EEPROM.write(Chn_Eep,Byt_Chn);
  EEPROM.write(Mode_Eep,fmode);
}

//----------  Function Save EEPROM 4byte  --------  

void Fnc_Eep_Sav4(long value,int address){
  address += 3;
  for(int i = 0;i < 4;i++){
    byte toSave = value & 0xFF;
    if(EEPROM.read(address) != toSave){
      EEPROM.write(address,toSave);
      }
    value = value >> 8;
    address--;
  }
}

//----------  Function Load EEPROM 4byte  ---------  

long Fnc_Eep_Lod4(int address){
  long value = 0;
  for(int i = 0;i < 4;i++){
    value = value | EEPROM.read(address);
    if( i < 3){
      value = value << 8;
      address++;
      }
  }
  return value;
}

//----------  VFO out  ---------------      

void Vfo_out(long frequency){
  if(vfofreq != vfofreqb){
    si5351aSetFrequency(frequency);
    vfofreqb = vfofreq;
  }
}

//----------  BFO out  ---------------      

void Bfo_out(long frequency){
  if(ifshift != ifshiftb){
    si5351aSetFrequency2(frequency);
    ifshiftb = ifshift;
  }
}

//---------- S-meter --------------------------

void smeter(){
 smeterval1=analogRead(s_meter);
 smeterval1=smeterval1/50;
 if (smeterval1>14){smeterval1=14;}     //15
  int sx1=sx1+(smeterval1*9);           //16
  sx1=sx1+21;                           //41
  int sx2=0;
  sx2=sx2+(40+((15-smeterval1)*9));     //ucg_font_6x10_mf
  ucg.setFont(ucg_font_fub20_tn);       //ucg_font_fub35_tn
  ucg.setColor(0,0,0);                  // BLACK
  ucg.drawBox(sx1,99,sx2,8);
  ucg.setPrintPos(20,109);              //40,200
  for(int i=1;i<=smeterval1;i++){
    if (i<=8){
      ucg.setColor(0,255,255);
      ucg.print("-");
    }
    else{
      ucg.setColor(255,0,0);
      ucg.print("-");
    }
  }
}

//---------- Transmission Power meter ------------------

void tmeter(){
 ucg.setColor(0,0,0);                   // BLACK
 ucg.drawBox(20,99,135,8);              //41,180,270,16
 tmeterval=analogRead(t_meter);
 tmeterval=tmeterval/50;
 if (tmeterval>14){tmeterval=14;}
  int sx1=sx1+(tmeterval*9);
  sx1=sx1+21;
  int sx2=0;
  sx2=sx2+(40+((15-tmeterval)*9));
  ucg.setFont(ucg_font_fub20_tn);       //35ucg_font_fub20_tn
  ucg.setColor(0,0,0);                  //BLACK
  ucg.drawBox(sx1,78,sx2,8);
  ucg.setPrintPos(20,90);               //85(40,165)
  for(int i=1;i<=tmeterval;i++){
    if (i<=9){
      ucg.setColor(250,80,0);
      ucg.print("-");
    }
    else{
      ucg.setColor(250,0,0);
      ucg.print("-");
    }
  }
}

//---------- Encoder Interrupt -----------------------

ISR(PCINT2_vect) {
  if (flagrit==1){
  unsigned char result = r.process();
    if(result) {
      if(result == DIR_CW){
        freqrit=freqrit+fstep;
        if (freqrit>=10000){
          freqrit=10000;
        }
      }
     else{
        freqrit=freqrit-fstep;
        if (freqrit<=-10000){
          freqrit=-10000;
        }
     }
    }
  }

  else{
    unsigned char result = r.process();
      if(result) {
        if(result == DIR_CW){
          freq=freq+fstep;
          if (freq>=freqmax){freq=freqmax;}
        }
        else{
          freq=freq-fstep;
          if (freq<=freqmin){freq=freqmin;}
        }
     }
  }

}

//------------ On Air -----------------------------

void txset(){
  long vfofreq_RX = vfofreq;;
  long ifshift_RX = ifshift;;
//  noInterrupts();
  if(hetero == UPPER){                          // Upper heterodyne
    if (flagmode==0){ifshift=txshiftLSB;}
    if (flagmode==1){ifshift=txshiftUSB;}
    if (flagmode==2){ifshift=txshiftCW;}
    if (flagmode==3){ifshift=txshiftAM;}
    vfofreq=freq+ifshift;
  }
  else{                                                  // Lower heterodyne
    if (flagmode==0){ifshift=txshiftLSB;}
    if (flagmode==1){ifshift=txshiftUSB;}
    if (flagmode==2){ifshift=txshiftCW;}
    if (flagmode==3){ifshift=txshiftAM;}
    vfofreq=ifshift-freq;
  }

  Vfo_out(vfofreq);                               // vfo out
  Bfo_out(ifshift);                                 // BFO out
 
  ucg.setPrintPos(70,75);                      //140,140
  ucg.setFont(ucg_font_6x10_mf);        //17ucg_font_fub11_tn
  ucg.setColor(255,0,0);
  ucg.print("ON AIR");
  while(digitalRead(txsw) == LOW){
    tmeter();
  }
  vfofreq = vfofreq_RX;
  ifshift = ifshift_RX;

  ucg.setColor(0,0,0);
  ucg.drawBox(15,63,95,15);                   //30,120,250,30 // ON AIR Erase
  Vfo_write();
  ucg.drawBox(20,80,135,8);                   //41,145,270,16  // Level Erase
//    interrupts();
}

//------------- Mode change(LSB-USB-CW-AM) ------------

void modeset(){
  ucg.setFont(ucg_font_6x10_mf);  //17ucg_font_fub11_tn
//  if (fmode==0){                          
  if (fmode==1){                              // 2016/8/3
    ifshift=ifshiftUSB;
    flagmode = 1;                             // 2016/8/3
    ucg.setColor(255,255,0);                  //Black?
    ucg.setPrintPos(44,43);                   //(82,82
    ucg.print("USB");
    ucg.setPrintPos(9,43);                    //12,82
    ucg.setColor(0,0,0);                      //Black Yellow
    ucg.print("LSB");  
    digitalWrite(modeout1,HIGH);
    digitalWrite(modeout2,LOW);  
  }

//  if(fmode==1){                          
  if(fmode==2){                                // 2016/8/3
    ifshift=ifshiftCW;
    flagmode = 2;                             // 2016/8/3
    ucg.setPrintPos(9,60);                    //12,112
    ucg.setColor(255,255,0);                  //Yellow
    ucg.print("C W");
    ucg.setPrintPos(44,43);                   //82,82
    ucg.setColor(0,0,0);                      //Black
    ucg.print("USB");
    digitalWrite(modeout1,LOW);
    digitalWrite(modeout2,HIGH);
  }

//  if (fmode==2){                          
  if (fmode==3){                              // 2016/8/3
    ifshift=ifshiftAM;
    flagmode = 3;                             // 2016/8/3
    ucg.setPrintPos(44,60);                   //82,112
    ucg.setColor(255,255,0);                  //Yellow
    ucg.print("A M");
    ucg.setColor(0,0,0);                      //Black  
    ucg.setPrintPos(9,60);                    //12,112
    ucg.print("C W");
    digitalWrite(modeout1,HIGH);
    digitalWrite(modeout2,HIGH);
    }

//  if (fmode==3){                          
  if (fmode==0){                              // 2016/8/3
    ifshift=ifshiftLSB;
    flagmode = 0;                             // 2016/8/3
    ucg.setPrintPos(9,43);                    //12,82
    ucg.setColor(255,255,0);                  //Yellow
    ucg.print("LSB");
    ucg.setPrintPos(44,60);                   //82,112
    ucg.setColor(0,0,0);                      //Black
    ucg.print("A M");
    digitalWrite(modeout1,LOW);
    digitalWrite(modeout2,LOW);
  }

  fmode=fmode+1;

  Byt_Chn++;                              
  if(Byt_Chn > 3)            
    Byt_Chn = 0;

  if (fmode==4){fmode=0;}
  Vfo_write();
  while(digitalRead(modesw) == LOW);
}

//------------ Rit SET ------------------------------

void setrit(){
  if(flagrit==0){
    flagrit=1;
    ucg.setFont(ucg_font_6x10_mf);            //11ucg_font_fub11_tn
    ucg.setPrintPos(95,55);                   //190,110
    ucg.setColor(255,0,0);
//    freqrit=0;
    ritlcd();
  }
  else {
    flagrit=0;

    if(hetero == UPPER)
      vfofreq=freq+ifshift;
    else
      vfofreq=ifshift-freq;
    Vfo_out(vfofreq);                       // vfo Out

    freqt=String(freq);
    ucg.setFont(ucg_font_6x10_mf);          //11ucg_font_fub11_tn
    ucg.setPrintPos(95,55);                 //190,110
    ucg.setColor(255,255,255);
   // ucg.print("RIT");
    ucg.setColor(0,0,0);
    ucg.drawRBox(112,52,44,10,1);           //222,92,91,21,3
    freqrit=0;
  }
  while(digitalRead(ritsw) == LOW);
}

//----------- Rit screen ----------------------

void ritlcd(){
  noInterrupts();
  ucg.setColor(0,0,0);
  ucg.drawBox(111,51,45,13);              //222,92,91,21 110,50,47,15,
  ucg.setFont(ucg_font_6x10_mf);          //17 ucg_font_fub11_tn
  ucg.setColor(0,255,255);
  ucg.setPrintPos(115,61);                //230,110
  ucg.print(freqrit);
  interrupts();
}

//-------------- encorder frequency step set -----------

void setstep(){
  noInterrupts();
  if (fstep==10000){
    fstep=10;
  }
  else{
    fstep=fstep * 10;
  }

 steplcd();
 while(digitalRead(stepsw) == LOW);
 interrupts();
}

//------------- Step Screen ---------------------------

void steplcd(){
  ucg.setColor(0,0,0);                    //0,0,0
  ucg.drawRBox(111,33,45,11,1);           //221,61,93,23,3
  ucg.setFont(ucg_font_6x10_mf);          //17ucg_font_fub11_tn
  ucg.setColor(255,255,255);
  ucg.setPrintPos(110,43);                //220,80
  if (fstep==10000){ucg.print("  10KHz");}
  if (fstep==1000){ucg.print("   1KHz");}
  if (fstep==100){ucg.print("  100Hz");}
  if (fstep==10){ucg.print("  10Hz");}
}

//----------- Main frequency screen -------------------

void freqlcd(){
  ucg.setFont(ucg_font_osr18_tn);         //35 ucg_font_fub20_tn
  int mojisuu=(freqt.length());

  if(freq<1000000){
    ucg.setColor(0,0,0);
    ucg.drawBox(52,7,9,20);               //103,9,15,36
    }
  if(f100k !=(freqt.charAt(mojisuu-6))){
    ucg.setColor(0,0,0);
    ucg.drawBox(59,7,15,20);              //118,9,28,36
    ucg.setPrintPos(59,24);               //118,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-6));
    f100k = (freqt.charAt(mojisuu-6));
  }
 
  if(freq<100000){
    ucg.setColor(0,0,0);
    ucg.drawBox(59,7,15,20);              //118,9,28,36
  }
  if(f10k !=(freqt.charAt(mojisuu-5))){
    ucg.setColor(0,0,0);
    ucg.drawBox(73,6,15,20);              //146,9,28,36
    ucg.setPrintPos(73,24);               //146,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-5));
    f10k = (freqt.charAt(mojisuu-5));
  }
 
  if(freq<10000){
    ucg.setColor(0,0,0);
    ucg.drawBox(73,6,14,19);              //146,9,28,36
    }
  if(f1k !=(freqt.charAt(mojisuu-4))){
    ucg.setColor(0,0,0);
    ucg.drawBox(87,6,14,19);              //174,9,28,36
    ucg.setPrintPos(87,24);               //(174,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-4));    
    f1k  = (freqt.charAt(mojisuu-4));
  }

  if(freq>=1000){
    ucg.setPrintPos(101,24);              //202,45
    ucg.setColor(0,255,0);
    ucg.print(".");
  }

  if(freq<1000){
    ucg.setColor(0,0,0);
    ucg.drawBox(101,6,8,19);              //   (202,9,15,36
    }
  if(f100 !=(freqt.charAt(mojisuu-3))){
    ucg.setColor(0,0,0);
    ucg.drawBox(109,6,14,19);             //217,9,28,36
    ucg.setPrintPos(108,24);              //(215,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-3));
    f100 = (freqt.charAt(mojisuu-3));
  }

  if(freq<100){
    ucg.setColor(0,0,0);
    ucg.drawBox(109,6,14,19);             //217,9,28,36
  }
  if(f10 !=(freqt.charAt(mojisuu-2))){
    ucg.setColor(0,0,0);
    ucg.drawBox(123,6,14,19);           //245,9,28,36
    ucg.setPrintPos(123,24);            //(245,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-2));
    f10 = (freqt.charAt(mojisuu-2));
  }
/*
  if(freq<10){
    ucg.setColor(0,0,0);
    ucg.drawBox(245,9,28,36);  
     }
  if(f1 !=(freqt.charAt(mojisuu-1))){
    ucg.setColor(0,0,0);
    ucg.drawBox(273,9,28,36);
    ucg.setPrintPos(273,45);
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-1));  
    f1  = (freqt.charAt(mojisuu-1));
  }
*/
}

//----------- Basic Screen -------------------------

void screen01(){
  ucg.setColor(255,255,255);            //
  ucg.drawRFrame(0,0,160,28,3);         //0,0,320,55,5 OUTside
  //ucg.drawRFrame(0,0,159,27,2);       //1,1,318,53,5  INside
  ucg.setColor(0,128,255);              //FILL COLOR for MODE back
  ucg.drawRBox(2,33,30,12,1);           //5,60,60,25,3  LSB
  ucg.drawRBox(37,33,30,12,1);          //75,60,60,25,3 USB
  ucg.drawRBox(2,50,30,12,1);           //5,90,60,25,3  CW
  ucg.drawRBox(37,50,30,12,1);          //(75,90,60,25,3  AM
  ucg.setFont(ucg_font_6x10_mf);        //17
  ucg.setPrintPos(9,43);                //12,82
  ucg.setColor(0,0,0);
  ucg.print("LSB");
  ucg.setPrintPos(44,43);               //82,82
  ucg.print("USB");
  ucg.setPrintPos(9,60);                //12,112
  ucg.print("C W");
  ucg.setPrintPos(44,60);               //(82,112
  ucg.print("A M");
  ucg.setColor(255,255,255);
  ucg.drawRFrame(110,32,47,15,1);       //220,60,95,25,3 STEP frame
  ucg.drawRFrame(110,50,47,15,1);       //220,90,95,25,3 RIT frame
  ucg.setColor(255,255,100);            //100,100,100
  ucg.setPrintPos(7,105);               //15,200
  ucg.print("S:");
  ucg.setPrintPos(7,85);                //15,165
  ucg.print("P:");
  ucg.setFont(ucg_font_6x10_mf);        //11ucg_font_fub11_tn
  ucg.setColor(250,255,0);
  ucg.setPrintPos(80,43);               //175,80
  ucg.print("STEP");
  ucg.setPrintPos(80,60);               //190,110
  ucg.setColor(255,255,0);
  ucg.print("RIT");
  ucg.setColor(255,255,255);            //100,100,100
  ucg.setPrintPos(20,115);              //40,210
  ucg.print("1--3---6---9--Over---");
  ucg.setPrintPos(20,95);               //40,175
  ucg.print("1--3---5-----10------");
  ucg.setPrintPos(5,127);               //10,230
  ucg.setColor(235,0,200);
  ucg.print("si5351a VFO Ver1.1 JA2GQP" );

  ucg.setFont(ucg_font_osr18_tn);       //35 ucg_font_fub20_tf???
    ucg .setPrintPos(37,24);            //75,45
    ucg.setColor(0,255,0);
    ucg.print("7");                     //Frequency
    ucg.setPrintPos(51,24);             //103,45
    ucg.print(".");
    ucg.setPrintPos(138,24);            //273,45
    ucg.print("0");                     //Frequency  end
}

//--------------- VFO Write -------------------------------

void Vfo_write(){
  if (flagrit==0){
    if(hetero == UPPER)
      vfofreq=freq+ifshift;
    else
      vfofreq=ifshift-freq;
    Vfo_out(vfofreq);                               // DDS out
  }

  if(flagrit==1){
    if(hetero == UPPER)
      vfofreq=freq+ifshift+freqrit;
    else
      vfofreq=ifshift-freqrit-freq;
    Vfo_out(vfofreq);                              // DDS out
  }
  Bfo_out(ifshift);                                // BFO
}



      

2017年5月26日金曜日

si5351a phase out

以前から気になっていたのが、si5351aを使った位相出力である。身近にあるArduino IDE位相出力のスケッチは、Etherkitのサンプルがある。その他、Web検索しても一部分の公開が有る物の、参考になるスケッチを見つけられなかった。
そこで、位相出力に特化した考え方の、TJ Labのコードを使用させて頂く事にした。スケッチの動作試験環境は、si5351VFOのH/Wを流用した。

試験に使ったH/Wの写真。無改造で使用している。









回路図。













スケッチ

ch0とch1が位相差90度出力を行う。出力範囲は、7.0MHz~7.2MHzに制限した。
特化した機能なので、通常のVFOとして使用できないであろう。割り込み処理が異なるので、ロータリエンコーダ処理とI/O割付を替えれば、stm32duinoでも動作可能。
ファイルは、JA2GQP's Download siteのsi5351aフォルダ。

//////////////////////////////////////////////////////////////////////
//  si5351 phase out(ch0,ch1) VFO program ver.1.0
//    Copyright(C)2017.JA2GQP.All rights reserved.
//
//                                Arduino IDE 1.8.2 Compiled                                  
//
//                                                2017/5/26
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.STEP(1k,100,10)
//    2.Frequency limit(7.00MHz - 7.20MHz)
//////////////////////////////////////////////////////////////////////

#include <LCD5110_Basic.h>
#include <Rotary.h>
#include <Wire.h>


//////////////////////////
// Si5351A
//////////////////////////
#define   Si5351A_ADDR  0x60
#define   CLK0_CTRL   16
#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


//////////////////////////
// system clock
//////////////////////////
const unsigned long XtalFreq = 25000000;


//////////////////////////
// I/O assign
//////////////////////////
#define   ENC_A   2                 //Rotary encoder A
#define   ENC_B   3                 //Rotary encoder B
#define   SW_STEP 4                 // Step SW


//////////////////////////
// Register set
//////////////////////////
const long LOW_FREQ = 7000000;    // lower frequency limit
const long HI_FREQ = 7200000;     // upper frequency limit
unsigned long FREQ = 7000000;     // default frequency
unsigned long FREQ_OLD = FREQ;    // old frequency
int STEP = 1000;                  // STEP(default)


//////////////////////////
// LCD assign
//////////////////////////
LCD5110 myGLCD(8,9,10,11,12);    // SCK,MOSI,DC,RST,CS

extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];


//////////////////////////
// Rotal encorder
//////////////////////////
Rotary r = Rotary(ENC_A,ENC_B); //ENC_A=2,ENC_B=3


//------------------ setup --------------------

void setup()
{
  Wire.begin();                
  si5351_init();                
  freq_set(FREQ);            
  myGLCD.InitLCD();                 // nokia5110 initialyze
  pinMode(SW_STEP,INPUT_PULLUP);    // STEP SW pullup

  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();                            // int enable

  myGLCD.setFont(SmallFont);
  myGLCD.print("STEP",12,32);
  myGLCD.print(".",12,16);
  myGLCD.print(".",54,16);
  freq_disp();
  step_disp();
}

//------------- Main program -------------------

void loop(){
  if(digitalRead(SW_STEP) == LOW){step_set();}

  if(FREQ != FREQ_OLD){
    freq_set(FREQ);
    freq_disp();
    FREQ_OLD = FREQ;          
  }
  delay(10);
}

//---------- rotaly encorder int proc. ------------

ISR(PCINT2_vect){
  unsigned char result = r.process();
  if(result){
    if(result == DIR_CW){
      FREQ = FREQ + STEP;
    }
    else{
      FREQ = FREQ - STEP;
    }
  }
  FREQ = constrain(FREQ,LOW_FREQ,HI_FREQ);  
}

//---------- step set -----------

void step_set(){
  if(STEP == 10){
    STEP = 1000;
  }
  else{
    STEP= STEP / 10;
  }
  delay(10);
  step_disp();
  while(digitalRead(SW_STEP) == LOW){
    delay(10);
  }
}

//---------- frequency display -----------

void freq_disp(){
  myGLCD.setFont(MediumNumbers);
  long freqH = FREQ / 1000000;
  myGLCD.printNumI(freqH,0,8);
  long freqL = FREQ - freqH * 1000000;
  long fM = freqL /1000;
  int fL = (freqL - fM * 1000) / 10;
  myGLCD.printNumI(fM,18,8,3,'0');
  myGLCD.printNumI(fL,60,8,2,'0');
}

//---------- step display  ----------

void step_disp(){
  myGLCD.setFont(SmallFont);
  myGLCD.printNumI(STEP,12,40,4,' ');
}

//---------- si5351a register write 1 byte----------

void cmd_si5351(byte Reg , byte Data){
  Wire.beginTransmission(Si5351A_ADDR);
  Wire.write(Reg);
  Wire.write(Data);
  Wire.endTransmission();
}

//---------- si5351A initialyze ----------

void si5351_init(){
  cmd_si5351(XTAL_LOAD_C,0b10010010);   // CL=8pF
  cmd_si5351(CLK0_CTRL,0x80);           // Disable CLK0
  cmd_si5351(CLK1_CTRL,0x80);           // Disable CLK1
  cmd_si5351(PLL_RESET,0xA0);           // Reset PLL_A
  cmd_si5351(CLK0_CTRL,0x4F);           // Enable CLK0 (MS0=Integer Mode, Source=PLL_A)
  cmd_si5351(CLK1_CTRL,0x4F);           // Enable CLK1 (MS1=Integer Mode, Source=PLL_A)
}

//---------- set frequency ----------

void freq_set(unsigned long freq){
//    freq [Hz]
//
//    fvco= fxtal*(a+b/c)  ( a:15 -- 90,   b:0 -- 1048575, c:1 -- 1048575 )
//    freq= fvco /(a+b/c)  ( a:4, 6--1800, b:0 -- 1048575, c:1 -- 1048575 )
//
//    P1= 128*a +   floor(128*b/c) - 512
//    P2= 128*b - c*floor(128*b/c)
//    P3= c
//

  int k;
  unsigned long M;
  unsigned int R;

  if(freq<1500) freq=1500; else if(freq>280000000) freq=280000000;

  if(     freq> 150000000){M=4; R=0;}
  else if(freq>=63000000){M=6; R=0;}
  else if(freq>=27500000){M=14; R=0;}
  else if(freq>=13000000){M=30; R=0;}
  else if(freq>= 6500000){M=62; R=0;}
  else if(freq>= 3000000){M=126; R=0;}
  else if(freq>= 1500000){M=280; R=0;}
  else if(freq>=  700000){M=600; R=0;}
  else if(freq>=  330000){M=1280; R=0;}
  else if(freq>=  150000){M=1300; R=1;}
  else if(freq>=   67000){M=1500; R=2;}
  else if(freq>=   30300){M=1600; R=3;}
  else if(freq>=   14000){M=1800; R=4;}
  else if(freq>=    7000){M=1800; R=5;}
  else if(freq>=    3500){M=1800; R=6;}
  else{M=1800; R=7;}

  freq*=M;
  freq<<=R;

  unsigned long c=0xFFFFF;
  unsigned long a=freq/XtalFreq;
  unsigned long b=(long)((double)(freq-a*XtalFreq)*(double)c/(double)XtalFreq);
  unsigned long dd=(128*b)/c;
  unsigned long P1=128*a+dd-512;
  unsigned long P2=128*b-c*dd;
  unsigned long P3=c;


  //Set fvco of PLL_A
    cmd_si5351(MSNA_ADDR+0,(P3>>8)&0xFF);        //MSNA_P3[15:8]
    cmd_si5351(MSNA_ADDR+1,P3&0xFF);             //MSNA_P3[7:0]
    cmd_si5351(MSNA_ADDR+2,(P1>>16)&0x03);       //MSNA_P1[17:16]
    cmd_si5351(MSNA_ADDR+3,(P1>>8)&0xFF);        //MSNA_P1[15:8]
    cmd_si5351(MSNA_ADDR+4,P1&0xFF);              //MSNA_P1[7:0]
    cmd_si5351(MSNA_ADDR+5,(P3>>12)&0xF0|(P2>>16)&0x0F);//MSNA_P3[19:16], MSNA_P2[19:16]
    cmd_si5351(MSNA_ADDR+6,(P2>>8)&0xFF);        //MSNA_P2[15:8]
    cmd_si5351(MSNA_ADDR+7,P2&0xFF);             //MSNA_P2[7:0]

  // Set MS0, MS1
  // a=M, b=0, c=1 ---> P1=128*M-512, P2=0, P3=1
  if(M==4){
    P1=0;
    cmd_si5351(MS0_ADDR+0,0);                   //MS0_P3[15:8]
    cmd_si5351(MS0_ADDR+1,1);                   //MS0_P3[7:0]
    cmd_si5351(MS0_ADDR+2,0b00001100);          //0,R0_DIV[2:0],MS0_DIVBY4[1:0],MS0_P1[17:16]
    cmd_si5351(MS0_ADDR+3,0);                   //MS0_P1[15:8]
    cmd_si5351(MS0_ADDR+4,0);                   //MS0_P1[7:0]
    cmd_si5351(MS0_ADDR+5,0);                   //MS0_P3[19:16], MS0_P2[19:16]
    cmd_si5351(MS0_ADDR+6,0);                   //MS0_P2[15:8]
    cmd_si5351(MS0_ADDR+7,0);                   //MS0_P2[7:0]
 
    cmd_si5351(MS1_ADDR+0,0);                   //MS1_P3[15:8]
    cmd_si5351(MS1_ADDR+1,1);                   //MS1_P3[7:0]
    cmd_si5351(MS1_ADDR+2,0b00001100);          //0,R1_DIV[2:0],MS1_DIVBY4[1:0],MS1_P1[17:16]
    cmd_si5351(MS1_ADDR+3,0);                   //MS1_P1[15:8]
    cmd_si5351(MS1_ADDR+4,0);                   //MS1_P1[7:0]
    cmd_si5351(MS1_ADDR+5,0);                   //MS1_P3[19:16], MS0_P2[19:16]
    cmd_si5351(MS1_ADDR+6,0);                   //MS1_P2[15:8]
    cmd_si5351(MS1_ADDR+7,0);                   //MS1_P2[7:0]
  }else{
    P1=128*M-512;
    cmd_si5351(MS0_ADDR+0,0);                    //MS0_P3[15:8]
    cmd_si5351(MS0_ADDR+1,1);                    //MS0_P3[7:0]
    cmd_si5351(MS0_ADDR+2,(R<<4)&0x70|(P1>>16)&0x03);//0,R0_DIV[2:0],MS0_DIVBY4[1:0],MS0_P1[17:16]
    cmd_si5351(MS0_ADDR+3,(P1>>8)&0xFF);        //MS0_P1[15:8]
    cmd_si5351(MS0_ADDR+4,P1&0xFF);              //MS0_P1[7:0]
    cmd_si5351(MS0_ADDR+5,0);                    //MS0_P3[19:16], MS0_P2[19:16]
    cmd_si5351(MS0_ADDR+6,0);                    //MS0_P2[15:8]
    cmd_si5351(MS0_ADDR+7,0);                    //MS0_P2[7:0]
 
    cmd_si5351(MS1_ADDR+0,0);                    //MS1_P3[15:8]
    cmd_si5351(MS1_ADDR+1,1);                    //MS1_P3[7:0]
    cmd_si5351(MS1_ADDR+2,(R<<4)&0x70|(P1>>16)&0x03);//0,R1_DIV[2:0],MS1_DIVBY4[1:0],MS1_P1[17:16]
    cmd_si5351(MS1_ADDR+3,(P1>>8)&0xFF);        //MS1_P1[15:8]
    cmd_si5351(MS1_ADDR+4,P1&0xFF);              //MS1_P1[7:0]
    cmd_si5351(MS1_ADDR+5,0);                    //MS1_P3[19:16], MS0_P2[19:16]
    cmd_si5351(MS1_ADDR+6,0);                    //MS1_P2[15:8]
    cmd_si5351(MS1_ADDR+7,0);                    //MS1_P2[7:0]
  }
  cmd_si5351(CLK0_PHOFF,0);
  cmd_si5351(CLK1_PHOFF,M);

  cmd_si5351(PLL_RESET,0xA0);                 // Reset PLL_A.
}





            

2017年4月15日土曜日

RF Analyzer PCB

RF Analyzer安定動作の為、PCB化を行った。回路を少し変更したが、オリジナルのスケッチを変更する事無く使える。ケース(YM-150)に収納できる様、PCB(90 x 100)とした。ノイズフロア改善用に電源入力、AD8307電源入力、AD8307GNDの各所に対策用FB(フェライトビーズ)が挿入可能。




部品実装


AD9850モジュールの下側に、LPFを配置し、最短でSMAコネクタに繋いだ。AD8307 SOPを使ったので、パターン面に配置してある。ノイズフロア改善用にFB(抵抗より大きい、黒色部品)を3か所入れてあるが、効果が有ったのは、AD8307GNDとコモンGND間のみ。電源側の2か所は、気休め程度であった。







ノイズ対策


ケース収納しない状態で、フロアノイズ-73dBm(ケーブルなし)であったが、アルミケースに収納した所、約10dBm悪化した。その為、AD8307部分を鉄板を使ってシールドを施した。対策後をアルミケースに収納した完成品-74dBmである。







外観


 ケースは、タカチYM-150を使い、2.8"TFT組込んだ。電池駆動が可能なスペース(UM4 x 6本位)がある。













回路図



AD8307周辺部は、チップ部品を使った。












基板



サイズ 90 x 102   

              

2017年3月21日火曜日

RF Analyzer

何時もお世話になっている松浦OMのRF Analyzerを作った。このAnalyzerは、2.8"TFT(オリジナルは、2.2"TFT)を使用し、スタンドアーロンでSG、パワーメータ、周波数応答、アンテナアナライザなどの機能がある。今回、1ボードのユニバーサル基板で作り、ジャンクのHubケースに納めた。シールド対策を施した結果、ノイズフロアレベル-70dB(測定用ケーブルなしでの裸特性)となった。




            

AD8350とLPFを含めた回路、および、AD8307回路部に個別シールドを施した。更に、基板裏側もコネクタ部までシールドを行った。当初、アルミケースに組み込んだが、ノイズ対策後、蓋を閉めると状況が悪化した為、樹脂ケースを使う事にした。








Hub(ジャンク)のケースを流用し、余分な穴を塞いで見栄えを向上させた。







     
一部修正した回路である。オリジナル回路では、TL431が発振による動作不良の為、REF側にコンデンサを追加した。








  





2017年2月28日火曜日

スイッチング電源

2017年度クラブ製作講習会に当たり、色々検討した結果、スイッチング電源装置の試作を行う事にした。この電源は、半田付けが殆どなく、市販モジュール配線と板金加工で完成する。仕様は、固定出力13.8V(max10A)と可変出力2V~11V(max1A)を切替え、電圧・電流を表示。大きさ100x50x230、質量620g。 
固定出力(max10A)の写真。AJDスイッチをoffすると、固定出力(13.8V)となる。表示器の最大電流は10Aである為、スイッチング電源の能力に余裕が有っても、最大10A表示となる。 
可変出力(max1A)の写真。AJDスイッチをonすると、可変出力となる。可変範囲は2V~11V。
上から見た写真。小型に作った為、配線が窮屈となった。

 回路図。  

2017年1月24日火曜日

stm32duino

最近、海外サイトでstm32f103c8t6(左側)が多くなってきた。Arduino nano(右側)と比較して、少し大きい位のボードである。何故、海外で人気が有るかの理由は、性能とコストパフォーマンスの高さである。Arduino nanoが$3に対し、$2で高性能なボードが入手できるからだ。stm32f103c8t6のBlue Pill(青色基板)のスペックがFlashの公称値64kBだが、128kB(保証している訳でない)と魅力的。入手したBlue Pillの他、Red Pill(赤色基板)Black Pill(黒色基板)がある。更に、使い慣れたArduino IDEから開発が出来るstm32duinoである。



H/Wインストール(USBを使う場合)


USB規格ではD +に1.5kのプルアップ抵抗が必要だが、このボードは誤った値(R10 10kまたは、4.7k)となっている事が知られている。R10を1.5kまたは、1.8kに交換する事が必要である。但し、PCとのマージンの問題なので、通信が行えない場合のみ、改造すれば良い。



stm32duinoインストール


  • Arduino IDE 1.6.9をここでダウンロードしてインストールする。
  • IDEを実行し、ツールメニューでボードマネージャを選択し、使用可能なボードのリストからArduino Zeroを検索し、ARM CortexーM0+をインストールする。
  • STM32のZIPファイルを含むファイルをダウンロード。
  • 解凍してArduino_STM32フォルダを作成する。但し、フォルダ名は変更しない事。
  • Arduino_STM32フォルダをMy Documents / Arduino / hardwareにコピーする。     (hardwareフォルダが存在しない場合は、作成する必要がある)
インストール手順は、wikiから引用した。
Arduino IDE 1.6.9を使う様に書いて有るが、IDE 1.8.1を 使っても問題は起きてない。(但し、全ての機能を試した訳でない)

Bootloader(書込みしない)


Bootloaderとは、スケッチをマイコンボードに書込み、ロードなどを行うstm32f103c8t6のF/Wである。PCからシリアルまたは、ST-LINKを使う場合、Bootloader書込みは不要。USBを使う場合、Bootloader書込みが必要となるが、Power onまたはReset後、スケッチがロードされる迄に数秒待たなければプログラムが動作しない為、USBは使えない。
stm32f103c8t6に書き込まれたオリジナルのF/Wを使えば良い。


BOOTスイッチ(基板上のDIP SW)

 

ST-LINK V2

  BOOT0  0側
  BOOT1  0側

 書込み/Power onまたはRESET時とも同じ設定でOK。但し、シリアルモニタ機能は使えない。

シリアル

書込み時
  BOOT0 1側
  BOOT1 0側

 Power onまたはRESET時
  BOOT0 0側
  BOOT1 0側

 シリアルモニタ機能が使える。


USBアダプタ

ST-LINK V2

アダプタ               stm32f103c8t6
 2pin SWDIO           SWDIO
 4pin GND              GND
 6pin SWCLK          SWCLK
 8pin 3.3V               3.3V









シリアル
左側(CH340G)    stm32f103c8t6   
 TX                         A9     
 RX                         A10
 3.3V                       3.3V
 GND                      GND

右側(FT232RL)    stm32f103c8t6
  RX                         A9  
  TX                         A10
  3.3V                       3.3V
  GND                      GND


   

スケッチ(Lチカ)

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(PC13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(PC13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(PC13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}












2016年12月9日金曜日

バリキャップ容量測定治具

近頃バリキャップの入手が難しくなってきている。そこで、バリキャップの代替をする為に、測定治具を作った。LC meterにアダプタを付加する方式で、既存のLC meterの改造を行わない事にした。ツマミが付いた部分が、バリキャップ測定治具である。
 
測定治具は、アダプタ方式にしたので、取付/取外しが容易な構造にした。













回路図










バリキャップ代替
手持品の代替として使えそうな物の、特性を測った。