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

Your IP is 18.221.146.223
ec2-18-221-146-223.us-east-2
Info
Valid HTML 4.01 Transitional Creative Commons Lizenzvertrag
rss
เราจะทำแบบวิศวกรผู้ยิ่งใหญ่
We love the King
26. April 2024
Your valuable opinion :
5 stars

Avg. 5.24 from 34 votes.



Arduino-Shield-SUPERMOD.php    41503 Bytes    13-06-2019 19:29:51


Arduino / Genuino UHF Synthesiser "SUPERMOD"


With the MAX2871 (MAX2870) from Maxim



This is a shield to generate an UHF carrier, phaselocked to an internal or external 10 MHz Reference. Channel spacing is 12.5 kHz (exact), spanning -19.5 up to + 10 dBm in 0.5 dB steps. This is partly an IPA work, done in 2019 by my apprentice, Mr. Christoph Gisler. IPA means "Individuelle Persönliche Arbeit" (Individual Personal Work, ≈ final thesis)



Arduino Shield SUPERMOD





✈ Functional Description • Block Diagram




Arduino Shield Supermod (Schematics)


The mastermind of this design is of course the Arduino Due. It handles the user input from the rotary encoder and displays the status on the 128 x 64 px oled display. The Due also programs the MAX2871 (VCO/PLL), which is the workhorse of this uhf synthesiser, as well as the two attenuators.

The devices has an onboard 10 MHz crystal oscillator, generating 50 MHz (NB3N502) to serve as a reference clock for the MAX 2871. If an external 10 MHz is present, it will override the internal clock.

The signal synthesised by the MAX 2871 is then fed into an attenuator (HMC424ALP3E), passes an equaliser (EQY-5-63+), followed by an amplifier (GVA-123+) and a final attenuator (HMC424ALP3E).

The two attenuators shall allow a frequency dependent loss compensation as well as the attenuation itself. The equaliser shall help to reduce the amplitude drop at higher frequencies. (FR4 behaves evil above 2 GHz). And yes, if you attenuate a lot, an amplifier is a nice thing - if you have one (or two).

We even used an external afterburner (ZX60-43-S+, not shown here) which is specified up to 4 GHz, but goes much higher (MiniCircuits specifies very conservative) - and runs at 5 V - and last but not least, delivers + 12 dBm up to approx. 5800 MHz into a 50 Ω load.




✈ The workhorse : MAX 2871




Inside the MAX 2871 PLL

Inside the chip, courtesy of maxim integrated

"The MAX2871 is an ultra-wideband phase-locked loop (PLL) with integrated voltage control oscillators (VCOs) capable of operating in both integer-N and fractional-N modes. When combined with an external reference oscillator and loop filter, the MAX2871 is a high-performance frequency synthesizer capable of synthesizing frequencies from 23.5 MHz to 6.0 GHz while maintaining superior phase noise and spurious performance.

The ultra-wide frequency range is achieved with the help of multiple integrated VCOs covering 3 GHz to 6 GHz, and output dividers ranging from 1 to 128." says the datasheet of the MAX2871 by maxim integrated.

As you mayst have seen, there are (digital) frequency dividers involved. Do not pretend to be surprised, that there are harmonics in the output spectrum. Instead, use a suiteable lowpass filter if necessary.


MAX 2870 vs. MAX 2871

Maxim integrated offers two similar devices, the MAX2870 as well as the MAX2871. They have slightly different specifications. As the price is identical, we have no idea, why one should use the MAX2870.

The table below shows the different specifications.

Specification Condition MAX2870 MAX2871
Reference Input Frequency (MHz) Max. 200 210
Maximum PFD Frequency (MHz) INT mode
FRAC mode
105
50
140
125
3.0 GHZ VCO Open Loop Phase Noise (dBc/Hz) 10MHz offs. -155.0 -158.0
4.5 GHz VCO Open Loop Phase Noise (dBc/Hz) 10MHz offs. -151.0 -153.0
6.0 GHz VCO Open Loop Phase Noise (dBc/Hz) 10 MHz offs. -150.0 -151.0
Integrated RMS Jitter (ps)   0.250 0.200
Normalized In-Band Noise Floor (dBc/Hz)   -266 int -230 int
1/f Noise (dBc/Hz)   -95.0 -122.0
2nd Harmonics (VCO/2) dBc   -20 -25
Temperature Sensor & ADC   go go
Temp. Compensation from -40C to +85C   go go
Phase Synchronization   go go
Cycle-Slip Reduction and Fast Lock   go go
Mute Until Lock   go go
Muted Output Power   -31.0 -40.0
Total Supply Current at 6 GHz (mA)   162 182
Price / 2500 in CHF (digi-key, 5/2019)   6.912 6.912

Compilation courtesy of Maxim Semiconductor.




✈ 10 MHz Reference




This shield is equipped with a 10 MHz Oscillator (NB3N502) with a times 5 multiplier. By that, we generate a 50 MHz low jitter reference clock for the MAX 2871.

The input of the oscillator is connected to a bnc connector on the rearpanel. It is always possible to connect an external reference, there. This signal will override the crystal oscillator.

The display says "INTERN REFERENCE" - this is hard-coded in the sketch and therefore a static information, depending on the assembly of the crystal oscillator.


Arduino Shield Supermod

Locked to external 10 MHz standard ... Swiss Precision :-)




✈ EE-Sim by Maxim Semiconductor and this Loop-Filter stuff




Maxim Semiconductor offers a free and very helpful tool called EE-Sim. You mayst access it here. It is extremely helpful when designing a loop-filter with challenging requirements and beeing built with real world components.

For this design, we demanded a loop-filter with a 1 kHz cut-off frequency (minimum). The EE-Sim tool tells you, that for this, the minimum charge pump current of 0.32 mA is mandatory. It suggests a loop filter with the following components :

Arduino Shield Supermod LoopFilter

The calculated Gain and Phase of the loop is as follows :


Open Loop Gain / Phase
Closed Loop Gain / Phase




Arduino Shield Supermod

Spectrum at 300 MHz with the above loopfilter using internal reference (uncalibrated)




✈ Downloads








✈ Arduino Sketch - The Code



Double click on code to select ...


/* ///////////////////////////////////////////////////////////////////// 
ARDUINO/Genuino (DUE) Sketch for Shield "SUPERMOD"
https://www.changpuak.ch/electronics/Arduino-Shield-SUPERMOD.php
Software Version 1.0, 
21.05.2019 by Christoph Gisler (IPA)
using routines by Joël Steinemann (IPA) 
and Alexander Sse Frank (Fachvorgesetzter)
using libraries from Adafruit
Final Version as of 13.06.2019
//////////////////////////////////////////////////////////////////////*/


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>

 
 // PINS MAX2871
#define CLOCKPIN A0
#define DATAPIN A1
#define LE A2
#define CE A3


//composition of MAX2871 Registers
//Register 0
unsigned long INT = 0x0; //Enables fractional-N mode
unsigned long NDIV; // Integer part from N-Divider
unsigned long FRAC; 
unsigned long ADDR0 = 0x0;

//Register 1
unsigned long CPL = 0x3; //Charge pump liniarity 30%
unsigned long CPT = 0x00; //Charge pump test mode = normal mode
unsigned long PHASE = 0x1; //Phase Value (recomened)
unsigned long MODULUS = 0xFA0; //4000 for max resolution
unsigned long ADDR1 = 0x1;

//Register 2
unsigned long LDS = 0x1;  
// 1 if fPFD > 32 MHz
unsigned long SDN = 0x0;  
//noise mode = Low-noise mode
unsigned long MUX = 0x6;  
//MUX pin configuration = Digital lock detect
unsigned long DBR = 0x0;  
//reference doubler is disabled
unsigned long RDIV2 = 0x0; 
//reference divide-by-2 is disabled
unsigned long RCNT = 0x0; 
// reference divide Value is unused
unsigned long REG4DB = 0x0; 
//double buffer mode disabled
unsigned long CP = 0x00; 
//charge pump current = 0.32 mA (1.36/RSET * (1 + CP[3:0]) RSET = 5k1)
unsigned long LDF = 0x0;  
// lock dtect function = Frac-N lock detect
unsigned long LDP = 0x0;  
// lock detect precision = 10ns
unsigned long PDP = 0x1;  
//phase detector polarity set poitive
unsigned long SHDN = 0x0; 
//power down mode = normal mode
unsigned long TRI = 0x0;  
//charge pump output high-impedance mode disabled
unsigned long RST = 0x0;  
// counter reset mode = normal operation
unsigned long ADDR2 = 0x2; 

//Register 3
unsigned long VCO_MS = 0x0;  
// VCO maual selction: unused
unsigned long VAS_SHDN = 0x0;  
//VAS enabled
unsigned long VAS_TEMP = 0x1;  
//VAS temperature compensation enabled
unsigned long CSM = 0x0; 
//Cycle slip mode disabled
unsigned long MUTEDEL = 0x0; 
//mute delay mode disabled
unsigned long CDM = 0x1; 
// Fast-lock mode enabled
unsigned long CDIV = 0x0;  
// clock divider value unused
unsigned long ADDR3 = 0x3; 

//Register 4
unsigned long RES = 0x3; 
//Reserved
unsigned long SDLDO = 0x0; 
//LDO endabled
unsigned long SDDIV = 0x0; 
//VCO Divider enabled
unsigned long SDREF = 0x0; 
//Reference input enabled
unsigned long FB = 0x1; 
//VCO to N counter mode is NOT divided
unsigned long DIVA;
unsigned long BS = 0x30FF; 
//shoud be choosen so that fPFD/BS = 50kH or less
unsigned long SDVCO = 0x0; 
//VCO enabled
unsigned long MTLD = 0x0; 
//RFOUT Mute until Lock detet mode disabled
unsigned long BDIV = 0x0; 
//RFOUTB is divided (so it's the same as RFOUTA)
unsigned long RFB_EN = 0x1; 
//RFOUTB enabled
unsigned long BPWR = 0x3; 
//RFOUTB = 5 dBm
unsigned long RFA_EN = 0x1; 
//RFOUTA enabled
unsigned long APWR = 0x3; 
//RFOUTA = 5dBm
unsigned long ADDR4 = 0x4; 

//Register 5
unsigned long VAS_DLY = 0x3; 
//0x0 if VAS_TEMP = 0, 0x3 if VAS_TEMP = 1
unsigned long SDPLL = 0x0; 
// PLL enabled
unsigned long F01 = 0x1; 
// if F = 0 then int
unsigned long LD = 0x3; 
//Lock-Detect pin function = HIGH
unsigned long MUX_MSB = 0x0; 
//MSB of MUX
unsigned long ADCS = 0x0; 
//ADC normal operation (ADC isn't used)
unsigned long ADCM = 0x0; 
//ADC disabled
unsigned long ADDR5 = 0x5;


float AC[56];

unsigned long long FreqOUT = 0;
unsigned long long FreqOUTold = 0;
unsigned long long FMIN = 23499999;
unsigned long long FMAX = 6000000001;

unsigned long composedRegisterValue; 
float  EEPROM_float;

float LMAX = 12;
float LMIN = LMAX - 31.5;
float LACT = 12.0;
float ATT = 0.0;
float CAL = 0.0;

// OLED 128x64 with SH1106 Controller
// E.G. DM-OLED13-625
#define OLED_MOSI  29
#define OLED_CLK   27
#define OLED_DC    35
#define OLED_CS    37
#define OLED_RESET 31
Adafruit_SH1106 display(OLED_MOSI,OLED_CLK,OLED_DC,OLED_RESET,OLED_CS);
 
#if (SH1106_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SH1106.h!");
#endif

unsigned int ActiveDisplay = 1 ;  // AMPLITUDE
boolean ShowCursor = true ;
unsigned int CursorPosition = 2 ;

// Menue Intem to be displayed
unsigned int MenueItem = 0 ;

// STATE OF THE ROTARY ENCODER
const int RE2 = 49 ;  // PRESSED
const int RE1 = 47 ;
const int RE0 = 45 ;
unsigned long StartMilli ;
unsigned long DurationMilli ;
boolean PressedLong = false ;

// "INTERRUPT" VARIABLES
unsigned int RE_now = 0;
unsigned int RE_old = 0;
unsigned int RE_xor = 0 ;
unsigned int RE_one = 0 ;
unsigned int RE_two = 0 ;
unsigned int RE_eval = 0x0 ;  // 0 = LEFT(-), 1=RIGHT(+), 2=PRESSED
unsigned long RE_time0 = 0 ;
unsigned long RE_time1 = 0 ;
unsigned long RE_time2 = 0 ;

const int MCPADR = 0x27;
const int ATTREGADR = 0x12;    // ATTENUATOR, MCP REG A
const int CALREGADR = 0x13;    // CALIBRATION, MCP REG B
unsigned int CALBYTE;
unsigned int ATTBYTE;

const int EEPROM_ADR = 0x50;

void setup() {

  delay(5000);
 
  Serial.begin(9600);
  Wire.begin();
 
  pinMode(CLOCKPIN, OUTPUT);
  pinMode(DATAPIN, OUTPUT);
  pinMode(LE, OUTPUT);
  pinMode(CE, OUTPUT);
 
  digitalWrite(CLOCKPIN, LOW);
  digitalWrite(DATAPIN, LOW);
  digitalWrite(LE, HIGH);
  digitalWrite(CE, HIGH);
 
  // INIT OLED
  display.begin(SH1106_SWITCHCAPVCC);
  // SHOW STARTUP SCREEN
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Supermod");
  display.setTextSize(1);
  display.setCursor(0,21);
  display.println("AN UHF SYNTHESISER");
  display.setCursor(0,33);
  display.println("BASED ON THE MAX 2871");
  display.setCursor(0,45);
  display.println("(C) ETH QUANTUMOPTICS");
  display.setCursor(0,57);
  display.println("BUILT 29.04.2019");
  display.display();
  delay(2000);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Supermod");
  display.setTextSize(1);
  display.setCursor(0,21);
  display.println("FIRMWARE WRITTEN BY");
  display.setCursor(0,33);
  display.println("MR. JOEL STEINEMANN");
  display.setCursor(0,45);
  display.println("MR. CHRISTOPH GISLER");
  display.setCursor(0,57);
  display.println("MR. ALEXANDER FRANK");
  display.display();
  delay(2000);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Supermod");
  display.setTextSize(1);
  display.setCursor(0,21);
  display.println("HARDWARE DESIGNED BY");
  display.setCursor(0,33);
  display.println("MR. CHRISTOPH GISLER");
  display.setCursor(0,45);
  display.println("MR. ALEXANDER FRANK");
  display.setCursor(0,57);
  display.println("MR. TILMAN ESSLINGER");
  display.display();
  delay(2000);

  // KNOB - ROTARY ENCODER
  pinMode(RE2, INPUT_PULLUP);
  pinMode(RE1, INPUT_PULLUP);
  pinMode(RE0, INPUT_PULLUP);

  RE_now = (digitalRead(RE2)<<2)|(digitalRead(RE1)<<1)|digitalRead(RE0);
  RE_old = RE_now ;


  //request 8 Bytes from EEPROM
  Wire.beginTransmission(EEPROM_ADR);
  Wire.write(0x0);  //Addres of EEPROM where first byte of FreqOUT is saved
  delay(10);
  Wire.endTransmission();      
  Wire.requestFrom(EEPROM_ADR,8);

  FreqOUT = 0;
  //combines FreqOUT value from the 8 bytes
  for(int i = 7; i >= 0; i--)
  {
    FreqOUT |= ((unsigned long long)Wire.read() << (i * 8));
    delay(10);
  }

  //request 2 bytes from Eprom
  Wire.beginTransmission(EEPROM_ADR);
  Wire.write(0x8);
  delay(10);
  Wire.endTransmission();      
  Wire.requestFrom(EEPROM_ADR,2);

  //combines LACT valie from the 2 bytes
  LACT = Wire.read();
  delay(10);
  LACT += Wire.read()/2.;
  delay(10);

  if (FreqOUT == -1)
  {
    FreqOUT = 4000000000;
    LACT = 12;
  }
  
  //LACT = 12;
  //FreqOUT = 4000000000;
  //Wire.endTransmission();  
           
  delay(2000);

  CalculateRegisterValues(); 


  //init MAX2871 2* (see datasheet)
  for(int i = 0; i < 2; i++)
  {
      composedRegisterValue = VAS_DLY << 29|SDPLL << 25
	  |F01 << 24| LD <<22
      |MUX << 18|ADCS << 6
	  |ADCM << 3|ADDR5;
                              
      WriteMAX2871(composedRegisterValue);
      delay(20);
      //Serial.println(composedRegisterValue, BIN);

      composedRegisterValue = RES << 29|SDLDO << 28
	  |SDDIV << 27| SDREF << 26|FB << 23
	  |DIVA << 20|BS << 12|SDVCO << 11|MTLD << 10
	  |BDIV << 9| RFB_EN << 8|BPWR << 6|RFA_EN << 5
	  |APWR << 3|ADDR4;
                              
      WriteMAX2871(composedRegisterValue);
      //Serial.println(composedRegisterValue, BIN);

      composedRegisterValue = VCO_MS << 26|VAS_SHDN << 25
	  |VAS_TEMP << 24|CSM << 18
      |MUTEDEL << 17|CDM << 15|CDIV << 3|ADDR3;
                              
      WriteMAX2871(composedRegisterValue);
      //Serial.println(composedRegisterValue, BIN);

      composedRegisterValue = LDS << 31|SDN << 29|MUX << 26
	  |DBR <<25|RDIV2 <<24|RCNT <<14
	  |REG4DB <<13|CP << 9|LDF << 8|LDP << 7
	  |PDP << 6|SHDN << 5|TRI << 4|RST <<3|ADDR2;
                              
      WriteMAX2871(composedRegisterValue);
      //Serial.println(composedRegisterValue, BIN);  

      composedRegisterValue = CPL << 29|CPT << 27
	  |PHASE <<15|MODULUS << 3|ADDR1;
      
      WriteMAX2871(composedRegisterValue);
      //Serial.println(composedRegisterValue, BIN);
      
      composedRegisterValue = INT << 31|NDIV << 15
	  |FRAC << 3|ADDR0;
      
      WriteMAX2871(composedRegisterValue);
      //Serial.println(composedRegisterValue, BIN);
  }
  

   // ATTENUATION NEEDED FOR LMAX OUTPUT - CHECK THAT
  AC[0] = 19 ; //  100 MHz
  AC[1] = 19 ; //  300 MHz 
  AC[2] = 20 ; //  500 MHz
  AC[3] = 18.5 ; //  700 MHz 
  AC[4] = 18.5 ; //  900 MHz 
  AC[5] = 18.5 ; // 1100 MHz 
  AC[6] = 18.5 ; // 1300 MHz 
  AC[7] = 17 ; // 1500 MHz
  AC[8] = 17 ; // 1700 MHz
  AC[9] = 16.5 ; // 1900 MHz
  AC[10] = 16 ; // 2100 MHz
  AC[11] = 15 ; // 2300 MHz
  AC[12] = 13 ; // 2500 MHz
  AC[13] = 13 ; // 2700 MHz
  AC[14] = 11 ; // 2900 MHz
  AC[15] = 9.5 ; // 3100 MHz
  AC[16] = 10 ; // 3300 MHz
  AC[17] = 9 ; // 3500 MHz
  AC[18] = 8.5 ; // 3700 MHz
  AC[19] = 7 ; // 3900 MHz
  AC[20] = 6 ; // 4100 MHz
  AC[21] = 4 ; //4300 MHz
  AC[22] = 5.5 ; //4500 MHz
  AC[23] = 5 ;  //4700 MHz
  AC[24] = 2 ;  //4900 MHz
  AC[25] = 0 ;  //5100 MHz
  AC[26] = 0 ;  //5300 MHz
  AC[27] = 0 ;  //5500 MHz
  AC[28] = 0 ;  //5700 MHz
  AC[29] = 0 ;  //5900 MHz
  AC[30] = 0 ;  //6100 MHz

  


  // INIT MCP23017, ALL OUTPUT, A0,A1,A2 = HIGH
  Wire.beginTransmission(MCPADR);
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // set all of port A to outputs
  Wire.endTransmission();
  Wire.beginTransmission(MCPADR);
  Wire.write(0x01); // IODIRB register
  Wire.write(0x00); // set all of port B to outputs
  Wire.endTransmission();

}


 

void loop() {

  
  
   switch (MenueItem)
  {
    case 0:
      ShowFrequencyMenue() ;
      ActiveDisplay = 0 ;
      MenueItem = 2 ;
      ProgramMAX2871();
      SetRFLevel();
      break;
 
    case 1:
      ShowAmplitudeMenue() ;
      ActiveDisplay = 1 ;
      MenueItem = 2 ;
      SetRFLevel();
      break;
 
    case 2:
      // //////////////////////////////////////////////////////////////
      // READ THE ROTARY ENCODER EVERY 1 ms
      // Timer Interrupt does not work here
      // //////////////////////////////////////////////////////////////
      RE_xor = 0x00 ;
      while (RE_xor == 0x00)
      {
        CheckRE() ;
        delay(1) ;
        // saves LACT and FreqOUT to EEPROM if FreqOUT changed and the 
		// incrementer is not moved for 5 sechonds
        if((FreqOUTold != FreqOUT) && ((millis() - RE_time1) > 5000))
        {
            
         //save FreqOut to EEPROM
          Wire.beginTransmission(EEPROM_ADR);
          Wire.write(0x00);
          delay(10);

          for(int i = 7; i >= 0; i--)
          {
            Wire.write((int)(FreqOUT >> ((i * 8) & 0xFF)));
            delay(10);
          }
          Wire.endTransmission();
          
          //svaes LACT to EEPROM
          Wire.beginTransmission(EEPROM_ADR);
          Wire.write(0x08);
          delay(10);
          
          EEPROM_float = (int)LACT;
          Wire.write((int)LACT);
          delay(10);
          EEPROM_float =(LACT-EEPROM_float)*2.;
          Wire.write((int)EEPROM_float);
          delay(10);
          Wire.endTransmission();
          FreqOUTold = FreqOUT;
        }
      }
      RE_time0 = millis();
      RE_one = RE_xor ;
      delay(1);
      // NOW WAIT FOR THE SECOND TRANSITION ...
      RE_xor = 0x00 ;
      while (RE_xor == 0x00)
      {
        CheckRE() ;
        delay(1) ;
      }
      RE_time1 = millis();
      RE_two = RE_xor ;
      // TIME DURATION
      RE_time2 = RE_time1 - RE_time0 ;
      PressedLong = false ;
      if (RE_time2 > 999 ) PressedLong = true ;
      // NOW EVALUATE
      //Serial.print("RE_old: "); Serial.println(RE_old,BIN);
      //Serial.print("RE_now: "); Serial.println(RE_now,BIN);
      //Serial.print("RE_xor: "); Serial.println(RE_xor,BIN);
      //Serial.print("RE_one : ");Serial.println(RE_one,BIN);
      //Serial.print("RE_two : ");Serial.println(RE_two,BIN);
      //Serial.print("RE_time2 : ");Serial.println(RE_time2);
      //Serial.println(" ");
      RE_eval = 0xFF ;
      
      if ((RE_one == 0x1) & (RE_two == 0x2)) RE_eval = 0x0;  // LEFT
      if ((RE_one == 0x2) & (RE_two == 0x1)) RE_eval = 0x1;  // RIGHT
      if ((RE_one == 0x4) & (RE_two == 0x4)) RE_eval = 0x2;  // PRESSED
 
      // //////////////////////////////////////////////////////////////
      // ROTATION = LEFT = -
      // //////////////////////////////////////////////////////////////
      if ((RE_eval == 0x0) && (ActiveDisplay == 0))
        {
          switch (CursorPosition)
          {
            case 0: // -1 GHZ
              if (FreqOUT > (FMIN + 1E9)) FreqOUT -= 1E9 ;
              break;
            case 1: // -100 MHz
              if (FreqOUT > (FMIN + 1E8)) FreqOUT -= 1E8 ;
              break;
            case 2: // -10 MHz
              if (FreqOUT > (FMIN + 1E7)) FreqOUT -= 1E7 ;
              break;
            case 3: // -1 MHz
              if (FreqOUT > (FMIN + 1E6)) FreqOUT -= 1E6 ;
              break;
            case 4: // -100 kHz
              if (FreqOUT > (FMIN + 1E5)) FreqOUT -= 1E5 ;
              break;
            case 5: // -12.5 kHz
              if (FreqOUT > (FMIN + 12500)) FreqOUT -= 12500 ;
              break;
          }
          MenueItem = ActiveDisplay ;
        }
      // //////////////////////////////////////////////////////////////
      // ROTATION = LEFT = -
      // //////////////////////////////////////////////////////////////
      if ((RE_eval == 0x0) && (ActiveDisplay == 1))
        {
          // DECREASE LEVEL
          LACT -= 0.5 ;
          if (LACT < LMIN) LACT = LMIN ;
          MenueItem = ActiveDisplay ;
        }
      // //////////////////////////////////////////////////////////////
      // ROTATION = RIGHT = +
      // //////////////////////////////////////////////////////////////
      if ((RE_eval == 0x1) && (ActiveDisplay == 0))
        {
          switch (CursorPosition)
          {
            case 0: // +1 GHZ
              if (FreqOUT < (FMAX - 1E9)) FreqOUT += 1E9 ;
              break;
            case 1: // +100 MHz
              if (FreqOUT < (FMAX - 1E8)) FreqOUT += 1E8 ;
              break;
            case 2: // +10 MHz
              if (FreqOUT < (FMAX - 1E7)) FreqOUT += 1E7 ;
              break;
            case 3: // +1 MHz
              if (FreqOUT < (FMAX - 1E6)) FreqOUT += 1E6 ;
              break;
            case 4: // +100 kHz
              if (FreqOUT < (FMAX - 1E5)) FreqOUT += 1E5 ;
              break;
            case 5: // +12.5 kHz
              if (FreqOUT < (FMAX - 12500)) FreqOUT += 12500 ;
              break;
          }
          MenueItem = ActiveDisplay ;
        }
      // //////////////////////////////////////////////////////////////
      // ROTATION = RIGHT = +
      // //////////////////////////////////////////////////////////////
      if ((RE_eval == 0x1) && (ActiveDisplay == 1))
        {
          // INCREASE LEVEL
          LACT += 0.5 ;
          if (LACT > LMAX) LACT = LMAX ;
          MenueItem = ActiveDisplay ;
        }
      // //////////////////////////////////////////////////////////////
      // ROTARY ENCODER WAS PRESSED
      // //////////////////////////////////////////////////////////////
      if (RE_eval == 0x2)
        {
          // CASE 1 : FREQUENCY MODE AND SHORT PRESS
          if ((ActiveDisplay == 0) && !PressedLong)
          {
            // MOVE CURSOR ONE POSITION RIGHT
            CursorPosition += 1;
            if (CursorPosition > 5) CursorPosition = 0 ;
            MenueItem = ActiveDisplay ;
          }
          // CASE 2 : FREQUENCY MODE AND LONG PRESS
          else if ((ActiveDisplay == 0) && PressedLong)
          {
            // SWITCH TO AMPLITUDE MODE
            ActiveDisplay = 1 ;
            MenueItem = ActiveDisplay ;
          }
          // CASE 3 : AMPLITUDE MODE AND SHORT PRESS
          else if ((ActiveDisplay == 1) && !PressedLong)
          {
            // NOTHING TO DO HERE
            delay(1);
          }
          // CASE 4 : AMPLITUDE MODE AND LONG PRESS
          else if ((ActiveDisplay == 1) && PressedLong)
          {
            // SWITCH TO FREQUENCY MODE
            ActiveDisplay = 0 ;
            MenueItem = ActiveDisplay ;
          }
        }
      break;
 
    default:
      ShowErrorMenue() ;
      MenueItem = 2 ;
      delay(999);
      ActiveDisplay = 0 ;
      MenueItem = ActiveDisplay ;
      break;
  }


}
 
// /////////////////////////////////////////////////////////////////////
// SUBROUTINES FOR THE MAX2871.
// /////////////////////////////////////////////////////////////////////


void WriteMAX2871( unsigned long data )       
//Writes 32 Bit value to register of MAX2871
{
  digitalWrite(LE, LOW);
  
  shiftOut(DATAPIN, CLOCKPIN, MSBFIRST, ((data & 0xFF000000) >> 24));
  shiftOut(DATAPIN, CLOCKPIN, MSBFIRST, ((data & 0x00FF0000) >> 16));
  shiftOut(DATAPIN, CLOCKPIN, MSBFIRST, ((data & 0x0000FF00) >> 8));
  shiftOut(DATAPIN, CLOCKPIN, MSBFIRST, (data & 0x000000FF));

  digitalWrite(LE, HIGH);
  //delay(50);

}



void ProgramMAX2871()       // compose register value of register 0 and 4 
{
  CalculateRegisterValues();
  
  composedRegisterValue = INT << 31|NDIV << 15|FRAC << 3|ADDR0;
  
  WriteMAX2871(composedRegisterValue);
  //Serial.println(composedRegisterValue, BIN);

  composedRegisterValue = RES << 29|SDLDO << 28|SDDIV << 27
  | SDREF << 26|FB << 23|DIVA << 20|BS << 12
  |SDVCO << 11|MTLD << 10|BDIV << 9|RFB_EN << 8
  |BPWR << 6|RFA_EN << 5|APWR << 3|ADDR4;
                         
  WriteMAX2871(composedRegisterValue);
  //Serial.println(composedRegisterValue, BIN);
  
}


void CalculateRegisterValues()    //calculates values of NDIV, FRAC & DIVA
{
  double rest;
  
  if(FreqOUT >= 3000000000)
  {
    DIVA = 0;
    NDIV = FreqOUT / 50000000;
    rest = FreqOUT % 50000000;
    FRAC = rest / 50000000.0 * 4000.0; 
  }
  else if((FreqOUT < 3000000000) && (FreqOUT >= 1500000000))
  {
    DIVA = 1;
    NDIV = FreqOUT * 2 / 50000000;
    rest = FreqOUT * 2 % 50000000;
    FRAC = rest / 50000000.0 * 4000.0;
  }
  else if((FreqOUT < 1500000000) && (FreqOUT >= 750000000))
  {
    DIVA = 2;
    NDIV = FreqOUT * 4 / 50000000;
    rest = FreqOUT * 4 % 50000000;
    FRAC = rest / 50000000.0 * 4000.0;
  }
  else if((FreqOUT < 750000000) && (FreqOUT >= 375000000))
  {
    DIVA = 3;
    NDIV = FreqOUT * 8 / 50000000;
    rest = FreqOUT * 8 % 50000000;
    FRAC = rest / 50000000.0 * 4000.0;
  }
  else if((FreqOUT < 375000000) && (FreqOUT >= 187500000))
  {
    DIVA = 4;
    NDIV = FreqOUT * 16 / 50000000;
    rest = FreqOUT * 16 % 50000000;
    FRAC = rest / 50000000.0 * 4000.0;
  }
  else if((FreqOUT < 187500000) && (FreqOUT >= 93750000))
  {
    DIVA = 5;
    NDIV = FreqOUT * 32 / 50000000;
    rest = FreqOUT * 32 % 50000000;
    FRAC = rest / 50000000.0 * 4000.0;
  }
  else if((FreqOUT < 93750000) && (FreqOUT >= 46875000))
  {
    DIVA = 6;
    NDIV = FreqOUT * 64 / 50000000;
    rest = FreqOUT * 64 % 50000000;
    FRAC = rest / 50000000.0 * 4000.0;
  }
  else
  {
    DIVA = 7;
    NDIV = FreqOUT * 128 / 50000000;
    rest = FreqOUT * 128 % 50000000;
    FRAC = rest / 50000000.0 * 4000.0;
  }
  

  //Serial.println(NDIV);
  //Serial.println(FRAC);
}

 
 
// /////////////////////////////////////////////////////////////////////
// SUBROUTINES DISPLAY.
// /////////////////////////////////////////////////////////////////////
 
 
void ShowFrequencyMenue ()
{
  char str[20];
  sprintf(str, "%10lld", FreqOUT);
  int len=strlen(str);
  int offset = 0;
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(0,0);
  display.println("FREQUENCY");
  for (int i=0; i<10; i++)
  {
    if (i>=0) offset = 0;
    if (i>=1) offset = 5;
    if (i>=4) offset = 10;
    if (i>=7) offset = 15;
    display.setTextColor(WHITE);
    display.setCursor(i*11+offset,20);
    if (i<10-len) display.print(" ");
    else display.print(str[i]);
    if ((ShowCursor) && (CursorPosition == i))
    {
      display.setCursor(i*11+offset,26);
      display.print("_");
    }
  }
  ShowInfo();
  display.display();
}
 
void ShowAmplitudeMenue ()
{
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(0,0);
  display.println("AMPLITUDE");
  display.setCursor(0,20);
  if (LACT > 0.0) display.print("+");
  if (LACT == 0.0) display.print(" ");
  display.print(LACT,1);
  display.print(" dBm ");
  ShowInfo();
  display.display();
}
 
 
 
void ShowErrorMenue ()
{
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(0,0);
  display.println("ERROR 0x89");
  display.setCursor(0,20);
  //display.print("UNLOCKED");
  ShowInfo();
  display.display();
}
 
void ShowInfo()
{
  display.drawLine(0, 40, 128, 40, WHITE);
  display.setTextSize(1);
  display.setCursor(0,46);
  display.println("PRESS ->  ROTATE +/-");
  display.setCursor(0,57);
  display.print("INTERN REFERENCE ");
  //if (digitalRead(Locked)) display.print("LOCKED ");
  //else display.print("UNLOCKED ");
}
 
// CHECK ROTARY ENCODER
void CheckRE()
{
RE_old = RE_now ;
RE_now = (digitalRead(RE2)<<2)|(digitalRead(RE1)<<1)|digitalRead(RE0);
RE_xor = RE_now ^ RE_old ;
}
 
 
// /////////////////////////////////////////////////////////////////////
// SUBROUTINES ATTENUATOR.
// /////////////////////////////////////////////////////////////////////
 
 
// SET RF LEVEL / BOTH ATTENUATORS
void SetRFLevel()
{
  ATT = LMAX - LACT ;
  unsigned int IndexCalValue = (int)(FreqOUT / 200000000); // FLOOR
  CAL = AC[IndexCalValue] ;
  //MCP23017 SWITCH

  // /////////////////////////////////////
  // REVERSE THE ORDER TO MATCH MCP23017 LAYOUT
  // CALBYTE:
  CALBYTE = 0xFF;

  if ( CAL >= 16 )    
  {
    CALBYTE -= 0x01;
    CAL -= 16;
  }
  if ( CAL >=   8 )
  {
    CALBYTE -= 0x02;
    CAL -=   8;
  }
  if ( CAL >=   4 )
  {
    CALBYTE -= 0x04;
    CAL -=   4;
  }
  if ( CAL >=   2 )
  {
    CALBYTE -= 0x08;
    CAL -=   2;
  }
  if ( CAL >=   1 )
  {
    CALBYTE -= 0x10;
    CAL -=   1;
  }
  if ( CAL >= 0.5 )
  {
    CALBYTE -= 0x20;
    CAL -= 0.5;
  }
  

  // ATTBYTE:
  ATTBYTE = 0xFF;
  if ( ATT >=  16 )
  {
    ATTBYTE -= 0x01;
    ATT -=  16;
  }
  if ( ATT >=   8 )
  {
    ATTBYTE -= 0x02;
    ATT -=   8;
  }
  if ( ATT >=   4 )
  {
    ATTBYTE -= 0x04;
    ATT -=   4;
  }
  if ( ATT >=   2 )
  {
    ATTBYTE -= 0x08;
    ATT -=   2;
  }
  if ( ATT >=   1 )
  {
    ATTBYTE -= 0x10;
    ATT -=   1;
  }
  if ( ATT >= 0.5 )
  {
    ATTBYTE -= 0x20;
    ATT -= 0.5;
  }
  //Serial.print("ATT: "); Serial.println(ATT, BIN);
  //Serial.print("CALBYTE: "); Serial.println(CALBYTE,BIN);
  //Serial.print("ATTBYTE: "); Serial.println(ATTBYTE,BIN);
   
  // WRITE NEW REGISTERS
  Wire.beginTransmission(MCPADR);
  Wire.write(ATTREGADR); // address port A
  Wire.write(ATTBYTE);  // value to send
  Wire.endTransmission();
   
  Wire.beginTransmission(MCPADR);
  Wire.write(CALREGADR); // address port B
  Wire.write(CALBYTE);  // value to send
  Wire.endTransmission();
}
  
 

 
// /////////////////////////////////////////////////////////////////////
// END OF FILE.
// /////////////////////////////////////////////////////////////////////







Arduino Shield Supermod

Inside View, A ZX60-43-S+ from MCL gives some extra power ...




✈ 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 = 6497 d

t2 = 260 ms

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

Impressum