Categories
Statistics
Flag Counter
Since 08.08.2014
Counts only, if "DNT = disabled".

Your IP is 54.242.75.224
ec2-54-242-75-224.compute-1.
Info
Valid HTML 4.01 Transitional Creative Commons Lizenzvertrag
rss
เราจะทำแบบวิศวกรผู้ยิ่งใหญ่
We love the King
19. March 2024
ช้างเผือกรักในหลวง
Your valuable opinion :
4 stars

Avg. 4.33 from 18 votes.



March 2024 Tea Time :-)
Si570.php    42580 Bytes    31-05-2023 10:28:02


The Si-570 (SiLabs) • Micromod RF Synthesizer


A 19.9 - 199.999 MHz (CMOS) I2C programmeable XO : ไมโครมด





Si570 Test Board

The Si570 on the Shield, CMOS version (only pin 4, CLK+, in use)





✈ Motivation • Circuit Description




This integrated circuit is widespread and does it's job in various DIY Applications. Still on the search for "the perfect oscillator" we decided to give this candidate a try - and see by ourselves, what this device is capeable of. In order to have a universal circuit, we also packed a lowpass, a 0-50 dB attenuator, a connection for an lcd as well as for a rotary encoder on the Arduino/Genuino (UNO) shaped board. The sketch does not care if the "new" frequency is within this ±3500 ppm range. We used the NOKIA 5110 display in order to see how it works. Don't forget to solder the bridge on the adapter board. The contrast may be set in software or by the potentiometer on the shield. We used the one from Adafruit. But not the library they offer. If you have the file font.h in the same directory as the arduino sketch, it will show up as another tab in your development environment.




✈ Si570 - What's inside ?




SiLabs says : "The Si570 XO/Si571 VCXO utilizes Silicon Laboratories’ advanced DSPLL® circuitry to provide a low-jitter clock at any frequency." - Great one mayst think, but the Si570 comes in several variants. And all have a different "low-jitter" value. At this time, only the cmos version was available.


Si570-What's inside ?
What SiLabs claims to be inside
Si570-What's inside ?
and what really is inside (NO decoupling cap :-)




✈ Si570 - The Spectrum




The Spectrum of the Si-570 looks very nice. This is - of course - due to the large divider at the output. Our device obviously outputs 100 MHz (initial settings).


Spectrum of an Si570
Center = 100 MHz, Span = 2 kHz, RBW = 10 Hz.




✈ This calibration thing




The vco is locked to an internal crystal oscillator with a nominal frequency of 114.285 MHz and a maximum error of ±2000 ppm. This is ±0.002 * 114.285 = ±228.570 kHz. A calibration process therefore measures the output frequency while reading all divider values (Reg 07 - 12) and calculates the "real" crystal frequency. Our Arduino/Genuino sketch reads those values and displays them on startup. You mayst note those values and feed them into the javascript below. The "real" crystal frequency is then calculated and shown for future use in the sketch. This is particularly appropriate when you do it after the warm-up sequence.


Si570 Calibration
The registers needed. (07-12, here)
Si570 Calibration
and the measured frequency


The input values are assumed to be in HEXadecimal format. Use 0x.


Reg 07/13

Reg 08/14

Reg 09/15

Reg 10/16

Reg 11/17

Reg 12/18

True Output [MHz]


RFREQ

HS_DIV

N1

DCO [MHz]

True XTAL [MHz]

Deviation [ppm]


The output values are in DECimal format.







✈ Arduino Sketch - The Code



Double click on code to select ...


/* ////////////////////////////////////////////////////////////////// 
ARDUINO/Genuino (UNO) Si570 Evaluation Board - "Micromod Synthesizer"
https://www.changpuak.ch/electronics/Si570.php
Software Version 2.0, USES TIMER INTERRUPT
29.09.2016 by JOËL STEINEMANN AND ALEXANDER FRANK

HELPFUL WEBSITES/LINKS:
http://playground.arduino.cc/Main/PinChangeInterrupt
http://gammon.com.au/interrupts
https://www.youtube.com/watch?v=cwsCxUhHbQM
http://hastebin.com/cufoxazoxo.coffee

Si570 PROGRAMMING HELP:
http://cbjohn.com/aa0zz/PPLL/Article.pdf

DATA SHEETS:
https://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf
https://cdn.macom.com/datasheets/MAAD-007086.pdf

////////////////////////////////////////////////////////////////// */

// LCD PINS (NOKIA5110)
#define RST 13
#define CE  12
#define DC  9
#define DIN  11
#define CLK  10
char string[8];

#include <EEPROM.h>
#include <Wire.h>
#include <stdlib.h>
#include "font.h";
#include "TimerOne.h"


// ///////////////////////////////////////////////////////////// 

// CONSTANTS FOR THE Si570
const int Si570ADDRESS = 0x55 ;
const float MaxFreq = 199.999 ;
const float MinFreq = 19.999 ;
const float Crystal = 114.285046732392 ;
const float MaxVCO = 5670.0 ;
const float MinVCO = 4850.0 ;
float Frequency = 99.999 ;
// ARRAYS FOR THE LOOKUP TABLE
float VCO_Freq[7] = {125,140,155,170,202,236};
unsigned int HSDIV[7] = {11,5,9,4,7,4};
unsigned int HS[13] = {0,0,0,0,0,1,0,3,0,5,0,7};
unsigned int N1[7] = {4,8,4,8,4,6};
unsigned int Block ;
// VARIABLES FOR PROGRAMMING THE Si570
float RFREQ;
unsigned int RF_DIVIDER_INTEGER ;
long RF_DIVIDER_FRACTIONAL ;
unsigned int HS_DIVIDER;
unsigned int N_DIVIDER;
float FR;
// Si570 REGISTER VARIABLES
byte SiR7,SiR8,SiR9,SiR10,SiR11,SiR12;
byte R7,R8,R9,R10,R11,R12;
// ///////////////////////////////////////////////////////////// 

//VARIABLES AND PIN DEFINITION FOR THE ATTENUATOR
const float LevelMin = -35 ;
const float LevelMax = 15 ;
int Level = 15 ;
const int ATT32 = 2;
const int ATT16 = 3;
const int ATT08 = 4;
const int ATT04 = 5;
const int ATT02 = 6;
const int ATT01 = 7;
// ///////////////////////////////////////////////////////////// 

unsigned int CursorPosition = 2;
unsigned int CursorOFFtime = 0;
unsigned int AuxKnobEval = 0x00;

float EncoderValue;
boolean EncoderState;
unsigned long currentmillis;
unsigned long LcdMillis;
unsigned long lastchange;
boolean laststate = true;
boolean LcdState = true;
int x=12,y=2;
boolean Frequency_Level = true;
float Max, Min, Addition = 1,maxNr,minNr;
// ///////////////////////////////////////////////////////////// 

// INTERRUPT VARIABLES
volatile unsigned int RotaryEncoderStatus = 0;
volatile unsigned int RotaryEncoderStatusOld = 0;
volatile unsigned int RotaryEncoderActivity = 1 ;
// ///////////////////////////////////////////////////////////// 

// serial data input
char inputcmd[100];  
int cmdindex=0;
// ///////////////////////////////////////////////////////////// 

void LcdWriteString(char *characters)     
{
  while(*characters) LcdWriteCharacter(*characters++);
}

void LcdWriteData(byte data)  
{
digitalWrite(DC, HIGH);  
digitalWrite(CE, LOW);
shiftOut(DIN, CLK, MSBFIRST, data);  
digitalWrite(CE, HIGH);
}

void LcdWriteCmd(byte cmd)
{
digitalWrite(DC, LOW);  
digitalWrite(CE, LOW);
shiftOut(DIN, CLK, MSBFIRST, cmd);  
digitalWrite(CE, HIGH);
}

void LcdWriteCharacter(byte character)
{
  for(int i=0; i<5; i++) LcdWriteData(ASCII[character - 0x20][i]);
  LcdWriteData(0x00);   // 1 pixel distance
}

void LcdDisplay(byte data) 
{
  byte UpperNibble = (data & 0xF0) >> 4 ;
  byte LowerNibble = data & 0x0F ;
  if (UpperNibble < 0x0A) LcdWriteCharacter(UpperNibble + 0x30);  
  if (UpperNibble >= 0x0A) LcdWriteCharacter(UpperNibble + 0x41 - 0x0A);  
  if (LowerNibble < 0x0A) LcdWriteCharacter(LowerNibble + 0x30);  
  if (LowerNibble >= 0x0A) LcdWriteCharacter(LowerNibble + 0x41 - 0x0A);  
}

void LcdClearScreen()
{
for (int i=0; i<504; i++) LcdWriteData(0x00) ;
}

void LcdGoToXY(int x, int y)
{
LcdWriteCmd(0x80 | x);  // COL
LcdWriteCmd(0x40 | y);  // ROW
}

void LcdBlink(int x, int y)
{
  if(RotaryEncoderActivity == 0x00) // Encoder pressed or rotated
  {
    if(millis() - LcdMillis >= 1000) 
    {
      LcdMillis = millis();
      if(LcdState)                 
      {
        LcdState = !LcdState;
        LcdGoToXY(x,y);
        LcdWriteString(" ");
      }
      else
      {
        if(Frequency_Level) UpDateFreqLCD();
        else UpDateLevelLCD();
        LcdState = !LcdState;
      }
    }
  }
}

void UpDateFreqLCD() {
  LcdGoToXY(0,0);
  LcdWriteString("FREQUENCY");
  LcdGoToXY(0,2);
  // 3 integers + 1 decimal point + 3 fractionals = 7 characters
  LcdWriteString(dtostrf(Frequency,7,3,string));
  LcdWriteString(" MHz ");
}

void UpDateLevelLCD() {
  LcdGoToXY(0,4);
  LcdWriteString("LEVEL ");
  if (Level > 0) LcdWriteString("+");
  if ((Level <= 0)&& (Level > -10)) LcdWriteString(" ");
  // 1 sign + 2 integers + 0 decimal point + 0 fractionals = 1+2 characters
  LcdWriteString(dtostrf(Level,2,0,string));
  LcdWriteString(" dBm ");
}

void UpDateCursorPosition() 
{
  // CHANGE THE CURSORPOSITION 
   if (Frequency_Level)// CHECK WHERE IT STANDS NOW(FREQUENCY OR LEVEL)
    {
        CursorPosition = CursorPosition + 1;  // INCREASE CURSORPOSITION   
        if ( CursorPosition > 5 ) CursorPosition = 0 ;
    }
   else CursorPosition = 2;
      
   switch(CursorPosition)
      {
        case 0:
          Addition = 100.0; // SET TENS OF MAGNITUDE(10^2)
          x = 0; y = 2; // COORDINATES FOR THE BLINKING FUNCTION
          break;
        case 1:
          Addition = 10.0; 
          x = 6; y = 2; // 
          break;
        case 2:
          Addition = 1;
          if(Frequency_Level){x = 12; y = 2;} 
          else{x = 47; y = 4;}
          break;
        case 3:
          Addition = 0.1;
          x = 24; y = 2; 
          break;
        case 4:
          Addition = 0.01;
          x = 30; y = 2; 
          break;
        case 5:
          Addition = 0.001;
          x = 36; y = 2; 
          break;
      }
}
void UpdateEncoder()
{
  /*
      ¦   A   ¦   B   ¦
      -----------------
      ¦   0   ¦   0   ¦  
      -----------------    
 ¦¦   ¦   0   ¦   1   ¦  -1
 ¦¦   -----------------  /\
 \/   ¦   1   ¦   1   ¦  ¦¦
 +1   -----------------  ¦¦
      ¦   1   ¦   0   ¦
      -----------------
      ¦   0   ¦   0   ¦
      -----------------
 WHEN AB IS HIGH AND BY THE NEXT ROTATION B GOES HIGH, 
 THEN THE ENCODER TURNED LEFT.
 IF B GOES LOW, THEN IT TURNED RIGTH.
 EXACTLY THE OPPOSITE IS TRUE, WHEN AB IS LOW.
 */ 
 
 //DETECT THE ROTATION OF THE ENCODER AND SET SOME CONSTANTS 
  switch(RotaryEncoderStatusOld)
      {
        // AB WERE LOW
        case 4:
          if ((RotaryEncoderStatus & B0000010) == 0x00) 
          	EncoderValue = EncoderValue + Addition;
          else EncoderValue = EncoderValue - Addition;
          // STOPS COUNTING IF THE VALUE IS > MAX OR < MIN
          if (EncoderValue > Max) EncoderValue = maxNr;
          if (EncoderValue < Min) EncoderValue = minNr;
          break;
        // AB WERE HIGH
        case 14:
          if ((RotaryEncoderStatus & B0000010) == 0x00) 
          	EncoderValue = EncoderValue - Addition;
          else EncoderValue = EncoderValue + Addition;
          // STOPS COUNTING IF THE VALUE IS > MAX OR < MIN
          if (EncoderValue > Max) EncoderValue = maxNr;
          if (EncoderValue < Min) EncoderValue = minNr;
          break;
      }
  if (Frequency_Level)
  	{
  	Frequency = EncoderValue; 
  	maxNr = Frequency; 
  	minNr = Frequency;
  	}
  else {Level = EncoderValue; maxNr = Level; minNr = Level; }
}

//SWITCH BETWEEN FREQUENCY AND LEVEL VALUE
void SwitchFreqLevel()
{
  // CHECK WHERE IT STANDS NOW
  Frequency_Level = !Frequency_Level; 
      if (Frequency_Level)
      {
        //SET THE CONSTANTS FOR THE FREQUENCY
        EncoderValue = Frequency;
        Max = MaxFreq;
        Min = MinFreq;
        Addition = 1.0;
        CursorPosition = 1;
        UpDateCursorPosition(); 
        UpDateLevelLCD();
      }
      else
      {
        //SET THE CONSTANTS FOR THE ATTENTUATOR LEVEL
        EncoderValue = Level;
        Max = LevelMax;
        Min = LevelMin;
        Addition = 1.0;
        UpDateCursorPosition();
        UpDateFreqLCD();
      }
}




// CHECK ROTARY ENCODER (A1...A3)
void CheckRotaryEncoder() 
{
RotaryEncoderStatusOld = RotaryEncoderStatus ;
RotaryEncoderStatus = PINC & B00001110 ; 
// PORT MANIPULATION FOR FAST READ
RotaryEncoderActivity = RotaryEncoderActivity | (
	RotaryEncoderStatus ^ RotaryEncoderStatusOld) ;
}  

void Si570SetFrequency(float Freq)
{
  // VCO_MIN = 4850 MHz, VCO_MAX = 5670 MHz
  /*
     HSDIV  ¦    N1   ¦ DIVIDER  ¦ VCO_MIN  ¦ VCO_MAX  ¦ 
  ------------------------------------------------------
       4    ¦    6    ¦    24    ¦  202.08  ¦  236.25  ¦
  ------------------------------------------------------
       7    ¦    4    ¦    28    ¦  173.21  ¦  202.50  ¦
  ------------------------------------------------------
       4    ¦    8    ¦    32    ¦  151.56  ¦  172.18  ¦
  ------------------------------------------------------
       9    ¦    4    ¦    36    ¦  134.72  ¦  157.50  ¦
  ------------------------------------------------------
       5    ¦    8    ¦    40    ¦  121.25  ¦  141.75  ¦
  ------------------------------------------------------
       11   ¦    4    ¦    44    ¦  110.23  ¦  128.87  ¦
  ------------------------------------------------------ // :1
       4    ¦    12   ¦    48    ¦  101.04  ¦  118.12  ¦
  ------------------------------------------------------
       7    ¦    8    ¦    56    ¦  86.61   ¦  101.25  ¦
  ------------------------------------------------------
       4    ¦    16   ¦    64    ¦  75.78   ¦  88.59   ¦
  ------------------------------------------------------
       9    ¦    8    ¦    72    ¦  67.36   ¦  78.75   ¦
  ------------------------------------------------------
       5    ¦    16   ¦    80    ¦  60.63   ¦  70.875  ¦
  ------------------------------------------------------
       11   ¦    8    ¦    88    ¦  55.11   ¦  64.43   ¦
  ------------------------------------------------------ // :2
       4    ¦    24   ¦    96    ¦  50.52   ¦  59.06   ¦
  ------------------------------------------------------
       7    ¦    16   ¦    112   ¦  43.30   ¦  50.625  ¦
  ------------------------------------------------------
       4    ¦    32   ¦    128   ¦  37.89   ¦  44.29   ¦
  ------------------------------------------------------
       9    ¦    16   ¦    144   ¦  33.68   ¦  39.375  ¦
  ------------------------------------------------------
       5    ¦    32   ¦    160   ¦  30.31   ¦  35.43   ¦
  ------------------------------------------------------
       11   ¦    16   ¦    176   ¦  27.56   ¦  32.21   ¦
  ------------------------------------------------------ // :4
       4    ¦    48   ¦    192   ¦  25.26   ¦  29.53   ¦
  ------------------------------------------------------
       7    ¦    32   ¦    224   ¦  21.65   ¦  25.31   ¦
  ------------------------------------------------------
       4    ¦    64   ¦    256   ¦  18.95   ¦  22.14   ¦
  ------------------------------------------------------
       9    ¦    32   ¦    288   ¦  16.84   ¦  19.68   ¦
  ------------------------------------------------------
       5    ¦    64   ¦    320   ¦  15.16   ¦  17.71   ¦
  ------------------------------------------------------
       11   ¦    32   ¦    352   ¦  13.78   ¦  16.10   ¦
  ------------------------------------------------------ // :8
       4    ¦    96   ¦    384   ¦  12.63   ¦  14.76   ¦
  ------------------------------------------------------
       7    ¦    64   ¦    448   ¦  10.83   ¦  12.65   ¦
  ------------------------------------------------------
       4    ¦    128  ¦    512   ¦  9.47    ¦  11.07   ¦
  ------------------------------------------------------
       9    ¦    64   ¦    576   ¦  8.42    ¦  9.84    ¦
  ------------------------------------------------------
       5    ¦    128  ¦    640   ¦  7.58    ¦  8.85    ¦
  ------------------------------------------------------
       11   ¦    64   ¦    704   ¦  6.89    ¦  8.05    ¦  
  ------------------------------------------------------ // :16

  THE VALUES IN THE TABLE ABOVE REPEAT ITSELF(236.25/2=118.12, 
  236.25/4=59.06 AND SO ON). THEREFOR WE JUST SAVED THE FIRST 
  SIX HSDIV, N1 AND VCO_MAX VALUES IN AN ARRAY. FIRST, SET THE 
  BLOCK(DIVIDER) AND THEN WE CAN CALCULATE HS_DIV AND N1 BY 
  DIVIDING THE SAVED VALUES IN THE ARRAY BY THE BLOCK. 
  */
  
  int i=-1;
  Block = 1;
  if(Freq <= 115.0)Block = 2;
  if(Freq <= 58.0)Block = 4;
  if(Freq <= 28.0)Block = 8;
  if(Freq <= 14.0)Block = 16;
  
  do
  {
    i++; 
    HS_DIVIDER = HSDIV[i];
    N_DIVIDER = ((N1[i]*Block));  
  }while((VCO_Freq[i]/Block/Freq) <= 1.0);
  
  // BASIC FORMULA: Fout = (Fxtal * RFREQ) / (HS_DIV * N1), 
  WHERE (Fxtal * RFREQ) MUST BE BETWEEN 4.85 AND 5.67 GHz
  RFREQ = Freq* HS_DIVIDER * N_DIVIDER / Crystal;
  // SPLIT RFREQ IN INTEGER(10BIT) AND FRACTIONAL(28BIT) PART
  RF_DIVIDER_INTEGER = int(RFREQ);
  RF_DIVIDER_FRACTIONAL = long(pow(2,28)*(RFREQ-RF_DIVIDER_INTEGER));
  // CALCULATE N1, DATA SHEET : 
  // The value for the N1 register can be calculated by taking the divider 
  // ratio minus one. For example, to divide by 10,write 0001001 (9 decimal) 
  // to the N1 registers.
  N_DIVIDER = N_DIVIDER - 1;
  Si570CommandToByte();
  Si570sendData(); 
}

void Si570CommandToByte()
{
  /*
        ¦   7   ¦   6   ¦   5   ¦   4   ¦   3   ¦   2   ¦   1   ¦   0   ¦
  -----------------------------------------------------------------------      
  SiR7  ¦  HS_DIV_INDEX[2:0]    ¦              (N1-1)[6:2]
  -----------------------------------------------------------------------
  SiR8  ¦  (N1-1)[1:0]  ¦            RFREQ(INTEGER)[37:32]
  -----------------------------------------------------------------------
  SiR9  ¦     RFREQ(INTEGER)[31:28]     ¦    RFREQ(FRACTIONAL)[27:24]
  -----------------------------------------------------------------------
  SiR10 ¦                    RFREQ(FRACTIONAL)[23:16]
  -----------------------------------------------------------------------
  SiR11 ¦                    RFREQ(FRACTIONAL)[15:8]
  -----------------------------------------------------------------------
  SiR12 ¦                    RFREQ(FRACTIONAL)[7:0]
  -----------------------------------------------------------------------
  SiReg ¦RST_REG¦  NEW  ¦ FREEZ ¦       ¦       ¦       ¦       ¦RECALL ¦
   137  ¦       ¦  Freq ¦   M   ¦       ¦       ¦       ¦       ¦       ¦
  -----------------------------------------------------------------------
  SiReg ¦       ¦       ¦       ¦ FREEZ ¦       ¦       ¦       ¦       ¦
   137  ¦       ¦       ¦       ¦  DCO  ¦       ¦       ¦       ¦       ¦
  -----------------------------------------------------------------------
  */
  // SET BYTES AS SEEN ABOVE
  
  SiR7 = (HS[HS_DIVIDER]<<5) + (N_DIVIDER>>2);
  SiR8 = (N_DIVIDER<<6) + (RF_DIVIDER_INTEGER>>4);
  SiR9 = (RF_DIVIDER_INTEGER<<4) + (RF_DIVIDER_FRACTIONAL>>24);
  SiR10 = (RF_DIVIDER_FRACTIONAL>>16);
  SiR11 = (RF_DIVIDER_FRACTIONAL>>8);
  SiR12 = (RF_DIVIDER_FRACTIONAL);
}

void Si570sendData()
{
  Wire.beginTransmission(Si570ADDRESS);
  Wire.write(137); // WRITE THE BYTE ADRESS (REGISTER 137)
  Wire.write(0x10); // 0x10, FREEZ DCO
  Wire.endTransmission();
  
  Wire.beginTransmission(Si570ADDRESS); 
  Wire.write(7); // WRITE THE BYTE ADRESS (REGISTER 7)
  Wire.write(SiR7); // WRITE THE REGISTER 7-12
  Wire.write(SiR8); 
  Wire.write(SiR9); 
  Wire.write(SiR10); 
  Wire.write(SiR11); 
  Wire.write(SiR12); 
  Wire.endTransmission(); 

  Wire.beginTransmission(Si570ADDRESS);
  Wire.write(137); // WRITE THE BYTE ADRESS (REGISTER 137)
  Wire.write(0x00); // 0x00, UNFREEZ DCO
  Wire.endTransmission();  
  
  Wire.beginTransmission(Si570ADDRESS);
  Wire.write(135); // WRITE THE BYTE ADRESS (REGISTER 135)
  Wire.write(0x40); //0x40, INFORM THE Si570 THAT THERE IS A NEW FREQUENCY
  Wire.endTransmission(); 
}

void Si570readData()
{
  Wire.beginTransmission(Si570ADDRESS);
  Wire.write(0x07); // WRITE THE BYTE ADRESS (REGISTER 7)
  Wire.endTransmission(); 
  Wire.requestFrom(Si570ADDRESS,6);
  R7 = Wire.read();      // 0x07
  R8 = Wire.read();      // 0x08
  R9 = Wire.read();      // 0x09
  R10 = Wire.read();     // 0x0A
  R11 = Wire.read();     // 0x0B
  R12 = Wire.read();     // 0x0C
}

void SetAttentuator(byte b)
{
  /*
  ATTENTUATION  ¦ C32   ¦  C16  ¦  C8   ¦  C4   ¦  C2   ¦  C1   ¦
  ---------------------------------------------------------------
  LOSS,REFERENCE¦   0   ¦   0   ¦   0   ¦   0   ¦   0   ¦   0   ¦
  ---------------------------------------------------------------
       1 dB     ¦   0   ¦   0   ¦   0   ¦   0   ¦   0   ¦   1   ¦
  ---------------------------------------------------------------
       2 dB     ¦   0   ¦   0   ¦   0   ¦   0   ¦   1   ¦   0   ¦
  ---------------------------------------------------------------
       4 dB     ¦   0   ¦   0   ¦   0   ¦   1   ¦   0   ¦   0   ¦
  ---------------------------------------------------------------
       8 dB     ¦   0   ¦   0   ¦   1   ¦   0   ¦   0   ¦   0   ¦
  ---------------------------------------------------------------
       16 dB    ¦   0   ¦   1   ¦   0   ¦   0   ¦   0   ¦   0   ¦
  ---------------------------------------------------------------
       32 dB    ¦   1   ¦   0   ¦   0   ¦   0   ¦   0   ¦   0   ¦
  ---------------------------------------------------------------
       50 dB    ¦   1   ¦   1   ¦   0   ¦   0   ¦   1   ¦   0   ¦
  ---------------------------------------------------------------
  */
  
  // CHECK IF WE ARE IN THE LEVEL MENU
  if(!Frequency_Level) 
  {
    // CHANGE ATTENTUATER LEVEL FROM (-35 -> +15) TO (0 -> +50) 
    b = ((-b)+15);
    // REVERSE THE BYTE AND SET ATTENTUATOR(PORT MANIPULATION)
    PORTD=((b*0x0802LU&0x22110LU)|(b*0x8020LU&0x88440LU))*0x10101LU>>16; 
    // Do not change pin 0 and 1(TX,RX) 
  }
}

void SaveValues()
{
  // CHECK FOR CHANGE OF ROTARY ENCODER  
  if ( RotaryEncoderActivity > 0x00 ) 
  {
    lastchange = millis();
    laststate = true;
  }
  // CHECK IF LAST CHANGE OF ROTARY ENCODER > 20 SECONDS
  if(((millis()-lastchange)>20000)&& laststate)
    {
      // SAVE THE VALUES IN THE EEPROM
      if( EEPROM.get(0,FR) != Frequency )EEPROM.put(0,Frequency);
      if( EEPROM.get(10,FR) != Level )EEPROM.put(10,Level);
      laststate = false;
    }    
      
}

/*
void SerialProgramming()
{
  char ch;
  long int temp;
  while (Serial.available()) 
  {
    ch=(char)Serial.read();
    if (((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'Z'))) 
    	inputcmd[cmdindex++]=ch; 
    if (ch == '\n') 
    {    // parse command if its a newline
      inputcmd[cmdindex]=0; // terminate the string
      if ((temp=atol(inputcmd)) > 0) 
       {
        if ((temp<MaxFreq)&&(temp>MinFreq))
         Si570SetFrequency(temp);
       }
      cmdindex=0; // reset command line      
    }
  }
}
*/

void setup() {
  
  // LCD NOKIA 5110
  pinMode(RST, OUTPUT);
  pinMode(CE, OUTPUT);
  pinMode(DC, OUTPUT);
  pinMode(DIN, OUTPUT);
  pinMode(CLK, OUTPUT);
  digitalWrite(RST, LOW);
  digitalWrite(RST, HIGH); 
  LcdWriteCmd(0x21); // LCD extended commands
  LcdWriteCmd(0xB8); // set LCD Vop (contrast)
  LcdWriteCmd(0x04); // set temp coefficent
  LcdWriteCmd(0x14); // LCD bias mode 1:40
  LcdWriteCmd(0x20); // LCD basic commands
  LcdWriteCmd(0x0C); // LCD normal video
  LcdClearScreen();
  
  // Startup display
  LcdGoToXY(0,0); LcdWriteString("MICROMOD UNO");
  LcdGoToXY(0,2); LcdWriteString("SOFTWARE V1.1"); 
  LcdGoToXY(0,3); LcdWriteString("HARDWARE V1.0"); 
  LcdGoToXY(0,4); LcdWriteString("29.09.2016");  
  delay(5000);
  
  // CHIP USED : SiLabs 570 CAC000121G
  // C: 3.3V CMOS
  // A: 50ppm TempStability
  // C: 10-160 MHz
  // We need to refer to register 07 - 12
  Wire.begin(); // join i2c bus (address optional for master)
  Si570readData(); // Read the Register
  LcdClearScreen();
  LcdGoToXY(0,0); LcdWriteString("REG. 07 : 0x"); LcdDisplay(R7);
  LcdGoToXY(0,1); LcdWriteString("REG. 08 : 0x"); LcdDisplay(R8);
  LcdGoToXY(0,2); LcdWriteString("REG. 09 : 0x"); LcdDisplay(R9);
  LcdGoToXY(0,3); LcdWriteString("REG. 10 : 0x"); LcdDisplay(R10);
  LcdGoToXY(0,4); LcdWriteString("REG. 11 : 0x"); LcdDisplay(R11);
  LcdGoToXY(0,5); LcdWriteString("REG. 12 : 0x"); LcdDisplay(R12);

  delay(10000);
  
  LcdClearScreen();
  
  // ATENUATOR, SET ATTENUATOR TO MAX 
  pinMode(ATT32, OUTPUT); digitalWrite(ATT32, LOW);
  pinMode(ATT16, OUTPUT); digitalWrite(ATT16, LOW);
  pinMode(ATT08, OUTPUT); digitalWrite(ATT08, LOW);
  pinMode(ATT04, OUTPUT); digitalWrite(ATT04, LOW);
  pinMode(ATT02, OUTPUT); digitalWrite(ATT02, LOW);
  pinMode(ATT01, OUTPUT); digitalWrite(ATT01, LOW);
 
  // THE ROTARY ENCODER: A1, A2, A3
  pinMode(A1, INPUT); digitalWrite(A1,HIGH); // PULLUP
  pinMode(A2, INPUT); digitalWrite(A2,HIGH);  
  pinMode(A3, INPUT); digitalWrite(A3,HIGH); 

  // ENABLE INTERRUPT FOR PIN ...
  Timer1.initialize(1000);  // EVERY 1 ms
  Timer1.attachInterrupt(CheckRotaryEncoder);
  RotaryEncoderStatus = PINC ;
  RotaryEncoderStatusOld = RotaryEncoderStatus ;
  RotaryEncoderActivity = 0x00;  
  
  // Read EEPROM
  if(EEPROM.read(15) != 0) // Clear all by the first upload
  {
    for (int i = 0 ; i < EEPROM.length() ; i++) 
    {
    EEPROM.write(i, 0);
    }
    EEPROM.put(0,Frequency);
    EEPROM.put(10,Level);   
  }
  else
  {
    EEPROM.get(0,Frequency);
    EEPROM.get(10,Level);
  }
  
  Max = MaxFreq;
  Min = MinFreq;
  EncoderValue = Frequency;
  Addition = 0;
  
  // Set to saved values
  Si570SetFrequency(Frequency);
  SetAttentuator(Level);
  UpDateFreqLCD();
  UpDateLevelLCD();
  Serial.begin(9600);

}
 
void loop() 
{
  // EVALUATE KNOB PRESSED, BIT 3, TOGGLE
  if (RotaryEncoderActivity == 0x04)
    {
    // FALLING EDGE ONLY
      if (( RotaryEncoderStatus & B00000100 ) == 0x00)
        {
          currentmillis = millis(); 
          EncoderState = true;
        }
     }

  // CHECK IF THE KNOB WAS PRESSED AND HOLDED FOR longER 
  // THAN 1.5 SECONDS.(PRESS AND HOLD)
  if ((( RotaryEncoderStatus & B00000100 ) == 0x00)&&(millis() 
  	- currentmillis >= 1500)&&EncoderState)// FALLING EDGE ONLY
    {
      // CHANGE BETWEEN FREQUENCY AND ATTENTUATOR LEVEL
      SwitchFreqLevel();
      EncoderState = false;
    }
    
  //CHECK IF THE KNOB WAS PRESSED longER THAN 0.1 SECONDS.(SINGLE PRESS)
  if ((( RotaryEncoderStatus & B00000100 ) != 0x00)&&(millis() 
  	- currentmillis >= 0.1)&&EncoderState)// RISING EDGE ONLY
    {
      UpDateCursorPosition(); 
      EncoderState = false;
    }
    
  // CHECK FOR CHANGE OF ROTARY ENCODER  
  if ( RotaryEncoderActivity > 0x00 ) 
  {
    // EVALUATE KNOB NOT PRESSED
    if (( RotaryEncoderStatus & B00000100 ) != 0x00)
    {
      UpdateEncoder();
      UpDateFreqLCD();
      UpDateLevelLCD();     
      Si570SetFrequency(Frequency); 
      SetAttentuator(Level);
    }
  }
  
  SaveValues();
  LcdBlink(x,y);
  RotaryEncoderActivity = 0 ;
  if(Addition == 0)Addition = 1;
 //SerialProgramming();
  delay(1);
        
}
// ///////////////////////////////////////////////////////////// 
// END OF FILE.
// ///////////////////////////////////////////////////////////// 




✈ Downloads









✈ The Rotary Encoder




The Rotary Encoder is connected at A1,A2 and A3. We used pull-up resistors of 2.2 kΩ in connection with 47 nF capacitors for debouncing. From the waveforms below, we see that setting the timer interrupt to 1 ms should be far more than necessary to detect the slopes. Pressing the knob will move the "cursor" to the next (right) digit. Pressing it even longer and you can change the power level. The actual digit will blink.


Rotary Encoder and the Si570
Waveform when turning "moderate"
Rotary Encoder and the Si570
here the horiz. scale is 1 ms / DIV




✈ The Attenuator




We used an MAAD-007086-000100 (RF Attenuator 50dB ±0.5dB 0 ~ 2GHz 50 Ohm 24-SOIC ) here, because of it's DIY-Formfactor. (everything else seems to use TQFP or similiar cases). This luxury of easy soldering and easy "programming" has it's price. Check it out, we got it from Digi-Key for a bargain price of €49.-




✈ Micromod RF Synthesizer • ไมโครมด ความถี่วิทยุ สังเคราะห์




In order to have a student proof, lab suiteable device, we addded a measurement amplifier and a case. The name "Micromod" was chosen to underline it's usefulness (despite it's small size) and to pay respect to one of the greatest engineers of our time.


Frontpanel
The Frontpanel
Measurement Amplifier
The measurement amplifier


-
in a KOH4 case with a NOKIA 5110 display
-
The final unit, ready to be shipped to our labs



Si570 RF Synthesizer




✈ Share your thoughts



The webmaster does not read these comments regularely. Urgent questions should be send via email. Ads or links to completely uncorrelated things will be removed.


Your Browser says that you allow tracking. Mayst we suggest that you check that DNT thing ?

 
t1 = 6459 d

t2 = 248 ms

★ ★ ★  Copyright © 2006 - 2024 by changpuak.ch  ★ ★ ★

PRchecker.info Impressum