Tuesday, 20 March 2018

Homebrew SSB SDR Rig

Part 1. Quadrature Oscillator. See my ZL2CTM YouTube channel for accompanying video.



Code. This will be updated as additional SDR DSP functions are added.

#include <Wire.h>                          // I2C comms
#include <si5351.h>                        // Si5351 library
#include <LiquidCrystal_I2C.h>             // LCD library


// Define Constants and Vaviables
static const long bandStart = 1000000;     // start of HF band
static const long bandEnd =   30000000;    // end of HF band
static const long bandInit =  3690000;     // where to initially set the frequency
volatile long oldfreq = 0;
volatile long freq = bandInit ;
volatile long radix = 1000;                // how much to change the frequency by, clicking the rotary encoder will change this.
volatile int updatedisplay = 0;

// Rotary Encoder
static const int pushPin = 39;
static const int rotBPin = 36;
static const int rotAPin = 35;
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;
volatile int rotAcc = 0;

// Instantiate the Objects
LiquidCrystal_I2C lcd(0x3F, 16, 2);       // set the LCD address to either 0x27 or 0x3F for a 16 chars and 2 line display
Si5351 si5351;


void setup()
{
  // Set up input switches
  pinMode(rotAPin, INPUT);
  pinMode(rotBPin, INPUT);
  pinMode(pushPin, INPUT);
  digitalWrite(rotAPin, HIGH);
  digitalWrite(rotBPin, HIGH);
  digitalWrite(pushPin, HIGH);

  // Set up interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Initialise the lcd
  lcd.begin();
  lcd.backlight();

  // Initialise the DDS
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.set_freq((freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);

  UpdateDisplay();
}


void loop()
{
  if (freq != oldfreq)
  {
    UpdateDisplay();
    SendFrequency();
    oldfreq = freq;
  }

  if (digitalRead(pushPin) == LOW)
  {
    delay(10);
    while (digitalRead(pushPin) == LOW)
    {
      if (updatedisplay == 1)
      {
        UpdateDisplay();
        updatedisplay = 0;
      }
    }
    delay(50);
  }
}


// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


void UpdateRot()
{
  switch (rotState)
  {

    case 0:                                         // Idle state, look for direction
      if (!rotBval)
        rotState = 1;                               // CW 1
      if (!rotAval)
        rotState = 11;                              // CCW 1
      break;

    case 1:                                         // CW, wait for A low while B is low
      if (!rotBval)
      {
        if (!rotAval)
        {
          // either increment radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            updatedisplay = 1;
            if (radix == 1000000)
              radix = 100000;
            else if (radix == 100000)
              radix = 10000;
            else if (radix == 10000)
              radix = 1000;
            else if (radix == 1000)
              radix = 100;
            else if (radix == 100)
              radix = 10;
            else if (radix == 10)
              radix = 1;
            else
              radix = 1000000;
          }
          else
          {
            freq = (freq + radix);
            if (freq > bandEnd)
              freq = bandEnd;
          }
          rotState = 2;                             // CW 2
        }
      }
      else if (rotAval)
        rotState = 0;                               // It was just a glitch on B, go back to start
      break;

    case 2:                                         // CW, wait for B high
      if (rotBval)
        rotState = 3;                               // CW 3
      break;

    case 3:                                         // CW, wait for A high
      if (rotAval)
        rotState = 0;                               // back to idle (detent) state
      break;

    case 11:                                        // CCW, wait for B low while A is low
      if (!rotAval)
      {
        if (!rotBval)
        {
          // either decrement radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            updatedisplay = 1;
            if (radix == 1)
              radix = 10;
            else if (radix == 10)
              radix = 100;
            else if (radix == 100)
              radix = 1000;
            else if (radix == 1000)
              radix = 10000;
            else if (radix == 10000)
              radix = 100000;
            else if (radix == 100000)
              radix = 1000000;
            else
              radix = 1;
          }
          else
          {
            freq = (freq - radix);
            if (freq < bandStart)
              freq = bandStart;
          }
          rotState = 12;                            // CCW 2
        }
      }
      else if (rotBval)
        rotState = 0;                               // It was just a glitch on A, go back to start
      break;

    case 12:                                        // CCW, wait for A high
      if (rotAval)
        rotState = 13;                              // CCW 3
      break;

    case 13:                                        // CCW, wait for B high
      if (rotBval)
        rotState = 0;                               // back to idle (detent) state
      break;
  }
}


void UpdateDisplay()
{
  lcd.cursor();                                     // Turn on the cursor
  lcd.setCursor(0, 0);
  lcd.print("        ");
  lcd.setCursor(0, 0);
  lcd.print(freq);
  lcd.setCursor(10, 0);
  lcd.print("ZL2CTM");

  lcd.setCursor(0, 1);
  lcd.print("        ");
  lcd.setCursor(0, 1);

  if (freq > 9999999)
  {
    if (radix == 1)
      lcd.setCursor(7, 0);
    if (radix == 10)
      lcd.setCursor(6, 0);
    if (radix == 100)
      lcd.setCursor(5, 0);
    if (radix == 1000)
      lcd.setCursor(4, 0);
    if (radix == 10000)
      lcd.setCursor(3, 0);
    if (radix == 100000)
      lcd.setCursor(2, 0);
    if (radix == 1000000)
      lcd.setCursor(1, 0);

  }
  if (freq <= 9999999)
  {
    if (radix == 1)
      lcd.setCursor(6, 0);
    if (radix == 10)
      lcd.setCursor(5, 0);
    if (radix == 100)
      lcd.setCursor(4, 0);
    if (radix == 1000)
      lcd.setCursor(3, 0);
    if (radix == 10000)
      lcd.setCursor(2, 0);
    if (radix == 100000)
      lcd.setCursor(1, 0);
    if (radix == 1000000)
      lcd.setCursor(0, 0);
  }
}



void SendFrequency()
{
  si5351.set_freq((freq * 4) * 100ULL, SI5351_PLL_FIXED, SI5351_CLK0);
}


*****************************************************************************

Dual Quadrature NE612 Direct Conversion Front End



Antenna RF Amplifier




80m/20m Bandpass Filter



Audio Pass-through Test Code

#include <Wire.h>                          // I2C comms
#include <si5351.h>                        // Si5351 library
#include <LiquidCrystal_I2C.h>             // LCD library
#include <Audio.h>                         // Teensy audio library

// Define Constants and Vaviables
static const long bandStart = 1000000;     // start of HF band
static const long bandEnd =   30000000;    // end of HF band
static const long bandInit =  3690000;     // where to initially set the frequency
volatile long oldfreq = 0;
volatile long freq = bandInit ;
volatile long radix = 1000;                // how much to change the frequency by, clicking the rotary encoder will change this.
volatile int updatedisplay = 0;

// Rotary Encoder
static const int pushPin = 39;
static const int rotBPin = 36;
static const int rotAPin = 35;
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;
volatile int rotAcc = 0;

// Instantiate the Objects
LiquidCrystal_I2C lcd(0x3F, 16, 2);       // Set the LCD address to either 0x27 or 0x3F for a 16 chars and 2 line display
Si5351 si5351;                            // The Si5351 DDS
AudioControlSGTL5000    audioShield;      // The Teensy audio CODEC on the audio shield


// Audio shield
AudioInputI2S           audioInput;                                   // What we call the input to the audio shield
AudioOutputI2S          audioOutput;                                  // What we call the output of the audio shield
AudioConnection         patchCord5(audioInput, 0, audioOutput, 0);    // Left channel in to left channel out
AudioConnection         patchCord10(audioInput, 1, audioOutput, 1);   // Right channel in to right channel out

void setup()
{
  // Setup input switches
  pinMode(rotAPin, INPUT);
  pinMode(rotBPin, INPUT);
  pinMode(pushPin, INPUT);
  digitalWrite(rotAPin, HIGH);
  digitalWrite(rotBPin, HIGH);
  digitalWrite(pushPin, HIGH);

  // Setup interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Setup the lcd
  lcd.begin();
  lcd.backlight();

  // Setup the DDS
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.set_freq((freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);

  // Setup the audio shield
  AudioNoInterrupts();
  AudioMemory(16);
  audioShield.enable();
  audioShield.inputSelect(AUDIO_INPUT_LINEIN);
  audioShield.volume(0.7);
  audioShield.unmuteLineout();
  AudioInterrupts();

  UpdateDisplay();
}


void loop()
{
  if (freq != oldfreq)
  {
    UpdateDisplay();
    SendFrequency();
    oldfreq = freq;
  }

  if (digitalRead(pushPin) == LOW)
  {
    delay(10);
    while (digitalRead(pushPin) == LOW)
    {
      if (updatedisplay == 1)
      {
        UpdateDisplay();
        updatedisplay = 0;
      }
    }
    delay(50);
  }
}


// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


void UpdateRot()
{
  switch (rotState)
  {

    case 0:                                         // Idle state, look for direction
      if (!rotBval)
        rotState = 1;                               // CW 1
      if (!rotAval)
        rotState = 11;                              // CCW 1
      break;

    case 1:                                         // CW, wait for A low while B is low
      if (!rotBval)
      {
        if (!rotAval)
        {
          // either increment radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            updatedisplay = 1;
            if (radix == 1000000)
              radix = 100000;
            else if (radix == 100000)
              radix = 10000;
            else if (radix == 10000)
              radix = 1000;
            else if (radix == 1000)
              radix = 100;
            else if (radix == 100)
              radix = 10;
            else if (radix == 10)
              radix = 1;
            else
              radix = 1000000;
          }
          else
          {
            freq = (freq + radix);
            if (freq > bandEnd)
              freq = bandEnd;
          }
          rotState = 2;                             // CW 2
        }
      }
      else if (rotAval)
        rotState = 0;                               // It was just a glitch on B, go back to start
      break;

    case 2:                                         // CW, wait for B high
      if (rotBval)
        rotState = 3;                               // CW 3
      break;

    case 3:                                         // CW, wait for A high
      if (rotAval)
        rotState = 0;                               // back to idle (detent) state
      break;

    case 11:                                        // CCW, wait for B low while A is low
      if (!rotAval)
      {
        if (!rotBval)
        {
          // either decrement radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            updatedisplay = 1;
            if (radix == 1)
              radix = 10;
            else if (radix == 10)
              radix = 100;
            else if (radix == 100)
              radix = 1000;
            else if (radix == 1000)
              radix = 10000;
            else if (radix == 10000)
              radix = 100000;
            else if (radix == 100000)
              radix = 1000000;
            else
              radix = 1;
          }
          else
          {
            freq = (freq - radix);
            if (freq < bandStart)
              freq = bandStart;
          }
          rotState = 12;                            // CCW 2
        }
      }
      else if (rotBval)
        rotState = 0;                               // It was just a glitch on A, go back to start
      break;

    case 12:                                        // CCW, wait for A high
      if (rotAval)
        rotState = 13;                              // CCW 3
      break;

    case 13:                                        // CCW, wait for B high
      if (rotBval)
        rotState = 0;                               // back to idle (detent) state
      break;
  }
}


void UpdateDisplay()
{
  lcd.cursor();                                     // Turn on the cursor
  lcd.setCursor(0, 0);
  lcd.print("        ");
  lcd.setCursor(0, 0);
  lcd.print(freq);
  lcd.setCursor(10, 0);
  lcd.print("ZL2CTM");

  lcd.setCursor(0, 1);
  lcd.print("        ");
  lcd.setCursor(0, 1);

  if (freq > 9999999)
  {
    if (radix == 1)
      lcd.setCursor(7, 0);
    if (radix == 10)
      lcd.setCursor(6, 0);
    if (radix == 100)
      lcd.setCursor(5, 0);
    if (radix == 1000)
      lcd.setCursor(4, 0);
    if (radix == 10000)
      lcd.setCursor(3, 0);
    if (radix == 100000)
      lcd.setCursor(2, 0);
    if (radix == 1000000)
      lcd.setCursor(1, 0);

  }
  if (freq <= 9999999)
  {
    if (radix == 1)
      lcd.setCursor(6, 0);
    if (radix == 10)
      lcd.setCursor(5, 0);
    if (radix == 100)
      lcd.setCursor(4, 0);
    if (radix == 1000)
      lcd.setCursor(3, 0);
    if (radix == 10000)
      lcd.setCursor(2, 0);
    if (radix == 100000)
      lcd.setCursor(1, 0);
    if (radix == 1000000)
      lcd.setCursor(0, 0);
  }
}



void SendFrequency()
{
  si5351.set_freq((freq * 4) * 100ULL, SI5351_PLL_FIXED, SI5351_CLK0);
}

************************************************************************

AF Amp.

















Saturday, 10 March 2018

Si5351 DDS VFO/BFO Example Software

#include <Wire.h>                         // I2C comms
#include <LiquidCrystal_I2C.h>
#include <si5351.h>

// Define Constants and Vaviables
static const long bandStart = 1000000;     // start of 80m
static const long bandEnd =   30000000;    // end of 80m
static const long bandInit =  3690000;     // where to initially set the frequency
static const long LSB_IF_freq = 9001500;   // filter centre freq + 1500Hz
static const long LSB_BFO_freq = 9001500;  // filter centre freq + 1500Hz
volatile long oldfreq = 0;
volatile long freq = bandInit ;           
volatile long radix = 1000;                // how much to change the frequency by, clicking the rotary encoder will change this.
volatile int updatedisplay = 0;

// Rotary encoder pins and other inputs
static const int pushPin = 4;
static const int rotBPin = 3;
static const int rotAPin = 2;

// Rotary encoder variables, used by interrupt routines
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;

// Instantiate the Objects
LiquidCrystal_I2C lcd(0x3F, 16, 2);
Si5351 si5351;

void setup()
{
  // Set up frequency and radix switches
  pinMode(rotAPin, INPUT);
  pinMode(rotBPin, INPUT);
  pinMode(pushPin, INPUT);

  // Set up pull-up resistors on inputs
  digitalWrite(rotAPin, HIGH);
  digitalWrite(rotBPin, HIGH);
  digitalWrite(pushPin, HIGH);

  // Set up interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Initialize the display
  lcd.begin();
  lcd.backlight();
  UpdateDisplay();
  delay(1000);

  // Initialize the DDS
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);
  si5351.set_freq((freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);
  si5351.set_freq((LSB_BFO_freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK2);
}


void loop()
{
  if (freq != oldfreq)
  {
    UpdateDisplay();
    SendFrequency();
    oldfreq = freq;
  }

  if (digitalRead(pushPin) == LOW)
  {
    delay(10);
    while (digitalRead(pushPin) == LOW)
    {
      if (updatedisplay == 1)
      {
        UpdateDisplay();
        updatedisplay = 0;
      }
    }
    delay(50);
  }
}


// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


void UpdateRot()
{
  switch (rotState)
  {

    case 0:                                         // Idle state, look for direction
      if (!rotBval)
        rotState = 1;                               // CW 1
      if (!rotAval)
        rotState = 11;                              // CCW 1
      break;

    case 1:                                         // CW, wait for A low while B is low
      if (!rotBval)
      {
        if (!rotAval)
        {
          // either increment radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            updatedisplay = 1;
            if (radix == 1000000)
              radix = 100000;
            else if (radix == 100000)
              radix = 10000;
            else if (radix == 10000)
              radix = 1000;
            else if (radix == 1000)
              radix = 100;
            else if (radix == 100)
              radix = 10;
            else if (radix == 10)
              radix = 1;
            else
              radix = 1000000;
          }
          else
          {
            freq = (freq + radix);
            if (freq > bandEnd)
              freq = bandEnd;
          }
          rotState = 2;                             // CW 2
        }
      }
      else if (rotAval)
        rotState = 0;                               // It was just a glitch on B, go back to start
      break;

    case 2:                                         // CW, wait for B high
      if (rotBval)
        rotState = 3;                               // CW 3
      break;

    case 3:                                         // CW, wait for A high
      if (rotAval)
        rotState = 0;                               // back to idle (detent) state
      break;

    case 11:                                        // CCW, wait for B low while A is low
      if (!rotAval)
      {
        if (!rotBval)
        {
          // either decrement radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            updatedisplay = 1;
            if (radix == 1)
              radix = 10;
            else if (radix == 10)
              radix = 100;
            else if (radix == 100)
              radix = 1000;
            else if (radix == 1000)
              radix = 10000;
            else if (radix == 10000)
              radix = 100000;
            else if (radix == 100000)
              radix = 1000000;
            else
              radix = 1;
          }
          else
          {
            freq = (freq - radix);
            if (freq < bandStart)
              freq = bandStart;
          }
          rotState = 12;                            // CCW 2
        }
      }
      else if (rotBval)
        rotState = 0;                               // It was just a glitch on A, go back to start
      break;

    case 12:                                        // CCW, wait for A high
      if (rotAval)
        rotState = 13;                              // CCW 3
      break;

    case 13:                                        // CCW, wait for B high
      if (rotBval)
        rotState = 0;                               // back to idle (detent) state
      break;
  }
}


void UpdateDisplay()
{
  lcd.setCursor(0, 0);
  lcd.print("        ");
  lcd.setCursor(0, 0);
  lcd.print(freq);
  lcd.setCursor(10, 0);
  lcd.print("ZL2CTM");
  lcd.setCursor(10, 1);
  lcd.print("80m");

  lcd.setCursor(0, 1);
  lcd.print("        ");
  lcd.setCursor(0, 1);
  if (freq > 9999999)
  {
    if (radix == 1)
      lcd.print("       -");
    if (radix == 10)
      lcd.print("      -");
    if (radix == 100)
      lcd.print("     -");
    if (radix == 1000)
      lcd.print("    -");
    if (radix == 10000)
      lcd.print("   -");
    if (radix == 100000)
      lcd.print("  -");
    if (radix == 1000000)
      lcd.print(" -");
  }
  if (freq <= 9999999)
  {
    if (radix == 1)
      lcd.print("      -");
    if (radix == 10)
      lcd.print("     -");
    if (radix == 100)
      lcd.print("    -");
    if (radix == 1000)
      lcd.print("   -");
    if (radix == 10000)
      lcd.print("  -");
    if (radix == 100000)
      lcd.print(" -");
    if (radix == 1000000)
      lcd.print("-");
  }
}


void SendFrequency()
{
  // VFO
  si5351.set_freq(((LSB_IF_freq - freq - 70) * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);

  // BFO
  si5351.set_freq((LSB_BFO_freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK2);
}

Monday, 29 January 2018

80/40/20m Base Rig Notes



Current notes for the 80/40/20m SSB rig.













VFO/BFO Test Code

#include <UTFT.h>
#include <si5351.h>

extern uint8_t SmallFont[];

volatile int updatedisplay = 0;
volatile long freq = 6200000;
volatile long currentfreq = 0;
volatile long oldfreq = 0;
volatile long remainder = 0;
const uint32_t bandStart = 1000000;
const uint32_t bandEnd =   30000000;

volatile long BFOfreq = 8000000;
volatile long BFOcurrentfreq = 0;
volatile long BFOoldfreq = 0;
volatile long BFOremainder = 0;

float OnesHz = 0;
float TensHz = 0;
float HundredsHz = 0;
float OneskHz = 0;
float TenskHz = 0;
float HundredskHz = 0;
float OnesMHz = 0;
float TensMhz = 0;

float BFOOnesHz = 0;
float BFOTensHz = 0;
float BFOHundredsHz = 0;
float BFOOneskHz = 0;
float BFOTenskHz = 0;
float BFOHundredskHz = 0;
float BFOOnesMHz = 0;
float BFOTensMhz = 0;

volatile long radix = 100;
volatile long oldradix = 100;

volatile long BFOradix = 100;
volatile long BFOoldradix = 100;

int mode = 1;
int button_delay = 100;

volatile uint32_t LSB_IF_freq = 8011500;    // Crystal filter centre freq
volatile uint32_t LSB_BFO_freq = 8013000;   // Crystal filter centre freq

// Rotary encoder pins and other inputs
static const int pushPin = 4;
static const int rotBPin = 3;
static const int rotAPin = 2;

// Rotary encoder variables, used by interrupt routines
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;


// Usage: TFT(<model code>, SDA, SCL, CS, RST, RS/A0);
UTFT TFT(ITDB18SP, 11, 10, 9, 12, 8);   // Remember to change the model parameter to suit your display module!
Si5351 si5351;


void setup()
{
  // Set up frequency and radix switches
  pinMode(rotAPin, INPUT);
  pinMode(rotBPin, INPUT);
  pinMode(pushPin, INPUT);
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);


  // Set up pull-up resistors on inputs
  digitalWrite(rotAPin, HIGH);
  digitalWrite(rotBPin, HIGH);
  digitalWrite(pushPin, HIGH);
  digitalWrite(A0, HIGH);
  digitalWrite(A1, HIGH);
  digitalWrite(A2, HIGH);
  digitalWrite(A3, HIGH);

  // Set up interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Setup the LCD
  TFT.InitLCD();
  TFT.clrScr();
  TFT.setFont(SmallFont);
  SetupScreen();

  // Initialize the DDS
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);
}


void loop()
{
  currentfreq = getfreq();                // Interrupt safe method to get the current frequency

  if (currentfreq != oldfreq)
  {
    UpdateFreq();
    SendFrequency();
    oldfreq = currentfreq;
  }


  BFOcurrentfreq = BFOgetfreq();                // Interrupt safe method to get the current frequency

  if (BFOcurrentfreq != BFOoldfreq)
  {
    UpdateFreq();
    SendFrequency();
    BFOoldfreq = BFOcurrentfreq;
  }


  if (digitalRead(A3) == LOW)
  {
    delay(10);
    if (digitalRead(A3) == LOW)
    {
      if (mode == 1)            // VFO
      {
        if (radix == 1000000)
          radix = 100000;
        else if (radix == 100000)
          radix = 10000;
        else if (radix == 10000)
          radix = 1000;
        else if (radix == 1000)
          radix = 100;
        else if (radix == 100)
          radix = 10;
        else if (radix == 10)
          radix = 1;
        else
          radix = 1000000;
      }
      if (mode == 2)              // BFO
      {
        if (BFOradix == 1000000)
          BFOradix = 100000;
        else if (BFOradix == 100000)
          BFOradix = 10000;
        else if (BFOradix == 10000)
          BFOradix = 1000;
        else if (BFOradix == 1000)
          BFOradix = 100;
        else if (BFOradix == 100)
          BFOradix = 10;
        else if (BFOradix == 10)
          BFOradix = 1;
        else
          BFOradix = 1000000;
      }
    }
    delay(button_delay);
    UpdateFreq();
  }

  if (digitalRead(A1) == LOW)
  {
    delay(10);
    if (digitalRead(A1) == LOW)
    {
      if (mode == 1)            // VFO
      {
        if (radix == 1)
          radix = 10;
        else if (radix == 10)
          radix = 100;
        else if (radix == 100)
          radix = 1000;
        else if (radix == 1000)
          radix = 10000;
        else if (radix == 10000)
          radix = 100000;
        else if (radix == 100000)
          radix = 1000000;
        else
          radix = 1;
      }
      if (mode == 2)              // BFO
      {
        if (BFOradix == 1)
          BFOradix = 10;
        else if (BFOradix == 10)
          BFOradix = 100;
        else if (BFOradix == 100)
          BFOradix = 1000;
        else if (BFOradix == 1000)
          BFOradix = 10000;
        else if (BFOradix == 10000)
          BFOradix = 100000;
        else if (BFOradix == 100000)
          BFOradix = 1000000;
        else
          BFOradix = 1;
      }
    }
    UpdateFreq();
    delay(button_delay);
  }

  if (digitalRead(A0) == LOW)
  {
    delay(10);
    if (digitalRead(A0) == LOW)
    {
      mode++;
      if (mode == 3)
        mode = 1;
    }
    delay(button_delay);
    UpdateFreq();
  }


  if (digitalRead(A2) == LOW)
  {
    delay(10);
    if (digitalRead(A2) == LOW)
    {
      mode--;
      if (mode == 0)
        mode = 2;
    }
    delay(button_delay);
    UpdateFreq();
  }
}


long getfreq()
{
  long temp_freq;
  cli();
  temp_freq = freq;
  sei();
  return temp_freq;
}


long BFOgetfreq()
{
  long temp_freq;
  cli();
  temp_freq = BFOfreq;
  sei();
  return temp_freq;
}


// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


void UpdateRot()
{
  switch (rotState)
  {

    case 0:                                         // Idle state, look for direction
      if (!rotBval)
        rotState = 1;                               // CW 1
      if (!rotAval)
        rotState = 11;                              // CCW 1
      break;

    case 1:                                         // CW, wait for A low while B is low
      if (!rotBval)
      {
        if (!rotAval)
        {
          if (mode == 1)
          {
            // either increment radixindex or freq
            freq = (freq + radix);
            if (freq > bandEnd)
              freq = bandEnd;
          }
          if (mode == 2)
          {
            BFOfreq = (BFOfreq + BFOradix);
            if (BFOfreq > bandEnd)
              BFOfreq = bandEnd;
          }
          rotState = 2;                             // CW 2
        }
      }
      else if (rotAval)
        rotState = 0;                             // It was just a glitch on B, go back to start
      break;

    case 2:                                         // CW, wait for B high
      if (rotBval)
        rotState = 3;                               // CW 3
      break;

    case 3:                                         // CW, wait for A high
      if (rotAval)
        rotState = 0;                               // back to idle (detent) state
      break;

    case 11:                                        // CCW, wait for B low while A is low
      if (!rotAval)
      {
        if (!rotBval)
        {
          // either decrement radixindex or freq
          if (mode == 1)
          {
            freq = (freq - radix);
            if (freq < bandStart)
              freq = bandStart;
          }
          if (mode == 2)
          {
            BFOfreq = (BFOfreq - BFOradix);
            if (BFOfreq < bandStart)
              BFOfreq = bandStart;
          }
          rotState = 12;                            // CCW 2
        }
      }
      else if (rotBval)
        rotState = 0;                             // It was just a glitch on A, go back to start
      break;

    case 12:                                        // CCW, wait for A high
      if (rotAval)
        rotState = 13;                              // CCW 3
      break;

    case 13:                                        // CCW, wait for B high
      if (rotBval)
        rotState = 0;                               // back to idle (detent) state
      break;
  }
}


void SetupScreen()
{
  TFT.setColor(VGA_BLUE);
  TFT.fillRect(0, 0, 159, 13);
  TFT.drawRect(0, 0, 159, 127);
  TFT.setColor(VGA_WHITE);
  TFT.setBackColor(VGA_BLUE);
  TFT.print("ZL2CTM Base Rig", CENTER, 1);
}


void UpdateFreq()
{
  TFT.setBackColor(VGA_BLACK);
  if (mode == 1)
    TFT.setColor(VGA_AQUA);
  else if (mode == 2)
    TFT.setColor(VGA_GRAY);
  TFT.print("VFO", 10, 20);

  if (mode == 2)
    TFT.setColor(VGA_AQUA);
  else if (mode == 1)
    TFT.setColor(VGA_GRAY);
  TFT.print("BFO", 10, 40);

  TensMhz = freq / 10000000;                                // TensMHz = 12345678 / 10000000 = 1
  remainder = freq - (TensMhz * 10000000);                  // remainder = 12345678 - 10000000 = 2345678
  OnesMHz = remainder / 1000000;                            // OnesMhz = 2345678 / 1000000 = 2
  remainder = remainder - (OnesMHz * 1000000);              // remainder = 2345678 - (2 * 1000000) = 345678
  HundredskHz = remainder / 100000;                         // HundredskHz = 345678 / 100000 = 3
  remainder = remainder - (HundredskHz * 100000);           // remainder = 345678 - (3 * 100000) = 45678
  TenskHz = remainder / 10000;                              // TenskHz = 45678 / 10000 = 4
  remainder = remainder - (TenskHz * 10000);                // remainder = 45678 - (4 * 10000) = 5678
  OneskHz = remainder / 1000;                               // OneskHz = 5678 / 1000 = 5
  remainder = remainder - (OneskHz * 1000);                 // remainder = 5678 - (5 * 1000) = 678
  HundredsHz = remainder / 100;                             // HundredsHz = 678 / 100 = 6
  remainder = remainder - (HundredsHz * 100);               // remainder = 678 - (6 * 100) = 78
  TensHz = remainder / 10;                                  // TensHz = 78 / 10 = 7
  remainder = remainder - (TensHz * 10);                    // remainder = 78 - (7 * 10) = 8
  OnesHz = remainder;                                       // OnesHz = 8

  BFOTensMhz = BFOfreq / 10000000;                                // TensMHz = 12345678 / 10000000 = 1
  BFOremainder = BFOfreq - (BFOTensMhz * 10000000);                  // remainder = 12345678 - 10000000 = 2345678
  BFOOnesMHz = BFOremainder / 1000000;                            // OnesMhz = 2345678 / 1000000 = 2
  BFOremainder = BFOremainder - (BFOOnesMHz * 1000000);              // remainder = 2345678 - (2 * 1000000) = 345678
  BFOHundredskHz = BFOremainder / 100000;                         // HundredskHz = 345678 / 100000 = 3
  BFOremainder = BFOremainder - (BFOHundredskHz * 100000);           // remainder = 345678 - (3 * 100000) = 45678
  BFOTenskHz = BFOremainder / 10000;                              // TenskHz = 45678 / 10000 = 4
  BFOremainder = BFOremainder - (BFOTenskHz * 10000);                // remainder = 45678 - (4 * 10000) = 5678
  BFOOneskHz = BFOremainder / 1000;                               // OneskHz = 5678 / 1000 = 5
  BFOremainder = BFOremainder - (BFOOneskHz * 1000);                 // remainder = 5678 - (5 * 1000) = 678
  BFOHundredsHz = BFOremainder / 100;                             // HundredsHz = 678 / 100 = 6
  BFOremainder = BFOremainder - (BFOHundredsHz * 100);               // remainder = 678 - (6 * 100) = 78
  BFOTensHz = BFOremainder / 10;                                  // TensHz = 78 / 10 = 7
  BFOremainder = BFOremainder - (BFOTensHz * 10);                    // remainder = 78 - (7 * 10) = 8
  BFOOnesHz = BFOremainder;                                       // OnesHz = 8


  // VFO
  if (TensMhz == 0)
  {
    TFT.setColor(VGA_BLACK);
    TFT.printNumI(TensMhz, 75, 20);
  }
  if (TensMhz > 0)
  {
    if (mode == 1)
      TFT.setColor(VGA_AQUA);
    else if (mode == 2)
      TFT.setColor(VGA_GRAY);
    TFT.printNumI(TensMhz, 75, 20);
  }
  if (mode == 1)
    TFT.setColor(VGA_AQUA);
  else if (mode == 2)
    TFT.setColor(VGA_GRAY);
  TFT.printNumI(OnesMHz, 84, 20);
  TFT.print(".", 93, 20);
  TFT.printNumI(HundredskHz, 102, 20);
  TFT.printNumI(TenskHz, 111, 20);
  TFT.printNumI(OneskHz, 120, 20);
  TFT.printNumI(HundredsHz, 129, 20);
  TFT.printNumI(TensHz, 138, 20);
  TFT.printNumI(OnesHz, 147, 20);



  // BFO
  if (BFOTensMhz == 0)
  {
    TFT.setColor(VGA_BLACK);
    TFT.printNumI(BFOTensMhz, 75, 40);
  }
  if (BFOTensMhz > 0)
  {
    if (mode == 2)
      TFT.setColor(VGA_AQUA);
    else if (mode == 1)
      TFT.setColor(VGA_GRAY);
    TFT.printNumI(BFOTensMhz, 75, 40);
  }
  if (mode == 2)
    TFT.setColor(VGA_AQUA);
  else if (mode == 1)
    TFT.setColor(VGA_GRAY);
  TFT.printNumI(BFOOnesMHz, 84, 40);
  TFT.print(".", 93, 40);
  TFT.printNumI(BFOHundredskHz, 102, 40);
  TFT.printNumI(BFOTenskHz, 111, 40);
  TFT.printNumI(BFOOneskHz, 120, 40);
  TFT.printNumI(BFOHundredsHz, 129, 40);
  TFT.printNumI(BFOTensHz, 138, 40);
  TFT.printNumI(BFOOnesHz, 147, 40);

  if (mode == 1)
  {
    //Radix
    TFT.setColor(VGA_BLACK);
    if (oldradix == 1)
      TFT.drawLine(147, 31, 151, 31);
    else if (oldradix == 10)
      TFT.drawLine(138, 31, 142, 31);
    else if (oldradix == 100)
      TFT.drawLine(129, 31, 133, 31);
    else if (oldradix == 1000)
      TFT.drawLine(120, 31, 124, 31);
    else if (oldradix == 10000)
      TFT.drawLine(111, 31, 115, 31);
    else if (oldradix == 100000)
      TFT.drawLine(102, 31, 106, 31);
    else if (oldradix == 1000000)
      TFT.drawLine(84, 31, 88, 31);

    TFT.setColor(VGA_AQUA);
    //TFT.setFont(SmallFont);
    if (radix == 1)
      TFT.drawLine(147, 31, 151, 31);
    else if (radix == 10)
      TFT.drawLine(138, 31, 142, 31);
    else if (radix == 100)
      TFT.drawLine(129, 31, 133, 31);
    else if (radix == 1000)
      TFT.drawLine(120, 31, 124, 31);
    else if (radix == 10000)
      TFT.drawLine(111, 31, 115, 31);
    else if (radix == 100000)
      TFT.drawLine(102, 31, 106, 31);
    else if (radix == 1000000)
      TFT.drawLine(84, 31, 88, 31);

    oldradix = radix;
  }

  if (mode == 2)
  {
    //Radix
    TFT.setColor(VGA_BLACK);
    if (BFOoldradix == 1)
      TFT.drawLine(147, 51, 151, 51);
    else if (BFOoldradix == 10)
      TFT.drawLine(138, 51, 142, 51);
    else if (BFOoldradix == 100)
      TFT.drawLine(129, 51, 133, 51);
    else if (BFOoldradix == 1000)
      TFT.drawLine(120, 51, 124, 51);
    else if (BFOoldradix == 10000)
      TFT.drawLine(111, 51, 115, 51);
    else if (BFOoldradix == 100000)
      TFT.drawLine(102, 51, 106, 51);
    else if (BFOoldradix == 1000000)
      TFT.drawLine(84, 51, 88, 51);

    TFT.setColor(VGA_AQUA);
    //TFT.setFont(SmallFont);
    if (BFOradix == 1)
      TFT.drawLine(147, 51, 151, 51);
    else if (BFOradix == 10)
      TFT.drawLine(138, 51, 142, 51);
    else if (BFOradix == 100)
      TFT.drawLine(129, 51, 133, 51);
    else if (BFOradix == 1000)
      TFT.drawLine(120, 51, 124, 51);
    else if (BFOradix == 10000)
      TFT.drawLine(111, 51, 115, 51);
    else if (BFOradix == 100000)
      TFT.drawLine(102, 51, 106, 51);
    else if (BFOradix == 1000000)
      TFT.drawLine(84, 51, 88, 51);

    BFOoldradix = BFOradix;
  }
}


void SendFrequency()
{
  //si5351.set_freq(((freq - BFOfreq) * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);
  si5351.set_freq((freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);
  si5351.set_freq((BFOfreq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK2);
}




Rig Code (not finished)

#include <UTFT.h>
#include <si5351.h>

extern uint8_t SmallFont[];

volatile int updatedisplay = 0;
volatile long freq = 14200000;
volatile long currentfreq = 0;
volatile long oldfreq = 0;
volatile long remainder = 0;
const uint32_t bandStart = 3000000;
const uint32_t bandEnd =   15000000;


float OnesHz = 0;
float TensHz = 0;
float HundredsHz = 0;
float OneskHz = 0;
float TenskHz = 0;
float HundredskHz = 0;
float OnesMHz = 0;
float TensMhz = 0;

volatile long radix = 1000;
volatile long oldradix = 1000;
int button_delay = 150;

volatile uint32_t LSB_BFO_freq = 8000000;    // Crystal filter centre freq
volatile uint32_t USB_BFO_freq = 8000000;   // Crystal filter centre freq

// Rotary encoder pins and other inputs
static const int pushPin = 4;
static const int rotBPin = 3;
static const int rotAPin = 2;

// Rotary encoder variables, used by interrupt routines
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;


// Usage: TFT(<model code>, SDA, SCL, CS, RST, RS/A0);
UTFT TFT(ITDB18SP, 11, 10, 9, 12, 8);   // Remember to change the model parameter to suit your display module!
Si5351 si5351;


void setup()
{
  // Set up frequency and radix switches
  pinMode(rotAPin, INPUT);
  pinMode(rotBPin, INPUT);
  pinMode(pushPin, INPUT);
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);

  // Set up pull-up resistors on inputs
  digitalWrite(rotAPin, HIGH);
  digitalWrite(rotBPin, HIGH);
  digitalWrite(pushPin, HIGH);
  digitalWrite(A0, HIGH);
  digitalWrite(A1, HIGH);
  digitalWrite(A2, HIGH);
  digitalWrite(A3, HIGH);

  // Set up interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Setup the LCD
  TFT.InitLCD();
  TFT.clrScr();
  TFT.setFont(SmallFont);
  SetupScreen();

  // Initialize the DDS
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);
}

void loop()
{
  currentfreq = getfreq();                // Interrupt safe method to get the current frequency

  if (currentfreq != oldfreq)
  {
    UpdateFreq();
    SendFrequency();
    oldfreq = currentfreq;
  }


  if (digitalRead(A3) == LOW)
  {
    delay(10);
    if (digitalRead(A3) == LOW)
    {
      if (radix == 1000000)
        radix = 100000;
      else if (radix == 100000)
        radix = 10000;
      else if (radix == 10000)
        radix = 1000;
      else if (radix == 1000)
        radix = 100;
      else if (radix == 100)
        radix = 10;
      else if (radix == 10)
        radix = 1;
      else
        radix = 1000000;
    }
    delay(button_delay);
    UpdateFreq();
  }


  if (digitalRead(A1) == LOW)
  {
    delay(10);
    if (digitalRead(A1) == LOW)
    {
      if (radix == 1)
        radix = 10;
      else if (radix == 10)
        radix = 100;
      else if (radix == 100)
        radix = 1000;
      else if (radix == 1000)
        radix = 10000;
      else if (radix == 10000)
        radix = 100000;
      else if (radix == 100000)
        radix = 1000000;
      else
        radix = 1;
    }
    delay(button_delay);
    UpdateFreq();
  }
}


long getfreq()
{
  long temp_freq;
  cli();
  temp_freq = freq;
  sei();
  return temp_freq;
}


// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


void UpdateRot()
{
  switch (rotState)
  {

    case 0:                                         // Idle state, look for direction
      if (!rotBval)
        rotState = 1;                               // CW 1
      if (!rotAval)
        rotState = 11;                              // CCW 1
      break;

    case 1:                                         // CW, wait for A low while B is low
      if (!rotBval)
      {
        if (!rotAval)
        {
          freq = (freq + radix);
          if (freq > bandEnd)
            freq = bandEnd;
          rotState = 2;                             // CW 2
        }
      }
      else if (rotAval)
        rotState = 0;                             // It was just a glitch on B, go back to start
      break;

    case 2:                                         // CW, wait for B high
      if (rotBval)
        rotState = 3;                               // CW 3
      break;

    case 3:                                         // CW, wait for A high
      if (rotAval)
        rotState = 0;                               // back to idle (detent) state
      break;

    case 11:                                        // CCW, wait for B low while A is low
      if (!rotAval)
      {
        if (!rotBval)
        {
          freq = (freq - radix);
          if (freq < bandStart)
            freq = bandStart;
          rotState = 12;                            // CCW 2
        }
      }
      else if (rotBval)
        rotState = 0;                             // It was just a glitch on A, go back to start
      break;

    case 12:                                        // CCW, wait for A high
      if (rotAval)
        rotState = 13;                              // CCW 3
      break;

    case 13:                                        // CCW, wait for B high
      if (rotBval)
        rotState = 0;                               // back to idle (detent) state
      break;
  }
}


void SetupScreen()
{
  TFT.setColor(VGA_BLUE);
  TFT.fillRect(0, 0, 159, 13);
  TFT.drawRect(0, 0, 159, 127);
  TFT.setColor(VGA_WHITE);
  TFT.setBackColor(VGA_BLUE);
  TFT.print("ZL2CTM Base Rig", CENTER, 1);

  TFT.setBackColor(VGA_BLACK);
  TFT.setColor(VGA_AQUA);
  TFT.print("VFO-A", 10, 20);
  TFT.setColor(VGA_GRAY);
  TFT.print("VFO-B", 10, 40);
  TFT.setColor(VGA_GRAY);
  TFT.print("MEM-10", 10, 60);
  TFT.setColor(VGA_GRAY);
  TFT.print("SCAN-12", 10, 80);
}

void UpdateFreq()
{
  TensMhz = freq / 10000000;                                // TensMHz = 12345678 / 10000000 = 1
  remainder = freq - (TensMhz * 10000000);                  // remainder = 12345678 - 10000000 = 2345678
  OnesMHz = remainder / 1000000;                            // OnesMhz = 2345678 / 1000000 = 2
  remainder = remainder - (OnesMHz * 1000000);              // remainder = 2345678 - (2 * 1000000) = 345678
  HundredskHz = remainder / 100000;                         // HundredskHz = 345678 / 100000 = 3
  remainder = remainder - (HundredskHz * 100000);           // remainder = 345678 - (3 * 100000) = 45678
  TenskHz = remainder / 10000;                              // TenskHz = 45678 / 10000 = 4
  remainder = remainder - (TenskHz * 10000);                // remainder = 45678 - (4 * 10000) = 5678
  OneskHz = remainder / 1000;                               // OneskHz = 5678 / 1000 = 5
  remainder = remainder - (OneskHz * 1000);                 // remainder = 5678 - (5 * 1000) = 678
  HundredsHz = remainder / 100;                             // HundredsHz = 678 / 100 = 6
  remainder = remainder - (HundredsHz * 100);               // remainder = 678 - (6 * 100) = 78
  TensHz = remainder / 10;                                  // TensHz = 78 / 10 = 7
  remainder = remainder - (TensHz * 10);                    // remainder = 78 - (7 * 10) = 8
  OnesHz = remainder;                                       // OnesHz = 8

  if (TensMhz == 0)
  {
    TFT.setColor(VGA_BLACK);
    TFT.printNumI(TensMhz, 75, 20);
  }
  if (TensMhz > 0)
  {
    TFT.setColor(VGA_AQUA);
    TFT.printNumI(TensMhz, 75, 20);
  }

  TFT.setColor(VGA_AQUA);
  TFT.printNumI(OnesMHz, 84, 20);
  TFT.print(".", 93, 20);
  TFT.printNumI(HundredskHz, 102, 20);
  TFT.printNumI(TenskHz, 111, 20);
  TFT.printNumI(OneskHz, 120, 20);
  TFT.printNumI(HundredsHz, 129, 20);
  TFT.printNumI(TensHz, 138, 20);
  TFT.printNumI(OnesHz, 147, 20);

  //Radix
  TFT.setColor(VGA_BLACK);
  //TFT.setFont(SmallFont);
  if (oldradix == 1)
    TFT.drawLine(147, 31, 151, 31);
  else if (oldradix == 10)
    TFT.drawLine(138, 31, 142, 31);
  else if (oldradix == 100)
    TFT.drawLine(129, 31, 133, 31);
  else if (oldradix == 1000)
    TFT.drawLine(120, 31, 124, 31);
  else if (oldradix == 10000)
    TFT.drawLine(111, 31, 115, 31);
  else if (oldradix == 100000)
    TFT.drawLine(102, 31, 106, 31);
  else if (oldradix == 1000000)
    TFT.drawLine(84, 31, 88, 31);

  TFT.setColor(VGA_AQUA);
  //TFT.setFont(SmallFont);
  if (radix == 1)
    TFT.drawLine(147, 31, 151, 31);
  else if (radix == 10)
    TFT.drawLine(138, 31, 142, 31);
  else if (radix == 100)
    TFT.drawLine(129, 31, 133, 31);
  else if (radix == 1000)
    TFT.drawLine(120, 31, 124, 31);
  else if (radix == 10000)
    TFT.drawLine(111, 31, 115, 31);
  else if (radix == 100000)
    TFT.drawLine(102, 31, 106, 31);
  else if (radix == 1000000)
    TFT.drawLine(84, 31, 88, 31);

  oldradix = radix;
}

void SendFrequency()
{
  if (freq <= 8000000)
  {
    // VFO
    si5351.set_freq(((freq + LSB_BFO_freq) * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);
    // BFO
    si5351.set_freq((LSB_BFO_freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK2);
  }
  
  if (freq > 8000000)
  {
    // VFO
    si5351.set_freq(((freq - USB_BFO_freq) * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);
    // BFO
    si5351.set_freq((USB_BFO_freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK2);
  }
}