Playing with Phasing - part 2a - VFO control code
Code for Quadrature VFO control. Credits to ZL2CTM and NT7S (and probably others..)
Use at your own risk - If your radio starts to glow green and explodes from running this code, it's not my (or anyone else's) fault. Target is Arduino Nano or Metro mini.
_______________________________________________________________________________________________
//
#include <Rotary.h>
#include <si5351.h>
#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define I2C_ADDRESS 0x3C
// Define proper RST_PIN if required.
#define RST_PIN -1
SSD1306AsciiWire oled;
#define ENCODER_A 3 // Encoder pin A
#define ENCODER_B 2 // Encoder pin B
#define ENCODER_BTN 11
#define RESET_BTN 12
#define TX_ON 6
#define OFFSET_ON 8
Si5351 si5351;
Rotary r = Rotary(ENCODER_A, ENCODER_B);
volatile uint32_t cw_offset = 0ULL;
volatile uint32_t cwo_old = 0ULL;
volatile uint32_t radix = 1000; //start step size - change to suit
boolean changed_f = 0;
String tbfo = "";
static const long long pll_min = 38000000000ULL;
static const long long pll_max = 90000000000ULL;
static const long long bandInit = 1410000000ULL;
volatile long long vfo = bandInit / SI5351_FREQ_MULT;
int multiple;
float pll_freq;
bool reset_pll;
bool tx_mode;
bool offset_mode;
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result == DIR_CW)
set_frequency(1);
else if (result == DIR_CCW)
set_frequency(-1);
}
/* Change the frequency */
/* dir = 1 Increment */
/* dir = -1 Decrement */
/**************************************/
void set_frequency(short dir) {
if (dir == 1)
vfo += radix;
if (dir == -1)
vfo -= radix;
changed_f = 1;
}
/**************************************/
/* Read the button with debouncing */
/**************************************/
boolean get_button() {
if (!digitalRead(ENCODER_BTN)) {
delay(20);
if (!digitalRead(ENCODER_BTN)) {
while (!digitalRead(ENCODER_BTN));
return 1;
}
}
return 0;
}
/**************************************/
/* Displays the frequency */
/**************************************/
void display_frequency() {
uint16_t f, g;
//oled.clear(PAGE);
oled.setCursor(0, 0);
f = vfo / 1000000; //variable is now vfo instead of 'frequency'
if (f < 10)
oled.print(' ');
oled.print(f);
oled.print('.');
f = (vfo % 1000000) / 1000;
if (f < 100)
oled.print('0');
if (f < 10)
oled.print('0');
oled.print(f);
//oled.print('.');
f = vfo % 1000;
if (f < 100)
oled.print('0');
if (f < 10)
oled.print('0');
oled.print(f);
oled.setCursor(60, 0);
oled.print("MHz");
oled.setCursor(0, 3);
oled.print(tbfo);
//Serial.println(vfo + bfo);
//Serial.println(tbfo);
}
/**************************************/
/* Displays the frequency change step */
/**************************************/
void display_radix() {
oled.setCursor(84, 0);
switch (radix) {
case 1:
oled.print(" 1");
break;
case 10:
oled.print(" 10");
break;
case 100:
oled.print(" 100");
break;
case 1000:
oled.print(" 1k");
break;
case 10000:
oled.print(" 10k");
break;
case 100000:
//oled.setCursor(10, 40);
oled.print(" 100k");
break;
case 1000000:
//oled.setCursor(0, 40);
oled.print("1000k"); //1MHz increments
break;
}
oled.print("Hz");
}
void GetPLLFreq()
{
if (vfo < 6850000) {
multiple = 126;
}
if ((vfo >= 6850000) && (vfo < 9500000)) {
multiple = 88;
}
if ((vfo >= 9500000) && (vfo < 13600000)) {
multiple = 64;
}
if ((vfo >= 13600000) && (vfo < 17500000)) {
multiple = 44;
}
if ((vfo >= 17500000) && (vfo < 25000000)) {
multiple = 34;
}
if ((vfo >= 25000000) && (vfo < 36000000)) {
multiple = 24;
}
if ((vfo >= 36000000) && (vfo < 45000000)) {
multiple = 18;
}
if ((vfo >= 45000000) && (vfo < 60000000)) {
multiple = 14;
}
if ((vfo >= 60000000) && (vfo < 80000000)) {
multiple = 10;
}
if ((vfo >= 80000000) && (vfo < 100000000)) {
multiple = 8;
}
if ((vfo >= 100000000) && (vfo < 146600000)) {
multiple = 6;
}
if ((vfo >= 150000000) && (vfo < 220000000)) {
multiple = 4;
}
pll_freq = multiple * (vfo * SI5351_FREQ_MULT);
}
void send_freq() {
int old_mult = multiple;
GetPLLFreq();
si5351.set_pll(pll_freq, SI5351_PLLA);
si5351.set_freq_manual(((vfo+cw_offset) * SI5351_FREQ_MULT), pll_freq, SI5351_CLK0);
si5351.set_freq_manual(((vfo+cw_offset) * SI5351_FREQ_MULT), pll_freq, SI5351_CLK2);
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK2, multiple);
if (multiple != old_mult) {
si5351.pll_reset(SI5351_PLLA);
}
tbfo = "QUAD";
}
void setup() {
// Serial.begin(9600);
Wire.begin();
pinMode(RESET_BTN, INPUT_PULLUP);
pinMode(TX_ON, INPUT_PULLUP);
pinMode(OFFSET_ON, INPUT_PULLUP);
#if RST_PIN >= 0
oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0
oled.setFont(Adafruit5x7);
oled.clear();
//initialize the Si5351
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 11000);
//Correction = 11000 for Adafruit board; 118500 for Chinese board
//si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA);
si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_2MA);
// Set CLK0 to output the starting "vfo" frequency as set above by vfo = ?
send_freq();
pinMode(ENCODER_BTN, INPUT_PULLUP);
PCICR |= (1 << PCIE2); // Enable pin change interrupt for the encoder
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();
display_frequency(); // Update the display
display_radix();
}
void loop() {
// Update the display if the frequency has been changed
if (changed_f) {
display_frequency();
send_freq();
changed_f = 0;
}
// Button press changes the frequency change step for 1 Hz steps
if (get_button()) {
switch (radix) {
case 1:
radix = 10;
break;
case 10:
radix = 100;
break;
case 100:
radix = 1000;
break;
case 1000:
radix = 10000;
break;
case 10000:
radix = 100000;
break;
case 100000:
radix = 1000000;
break;
case 1000000:
radix = 1;
break;
}
display_radix();
}
reset_pll = digitalRead(RESET_BTN);
if (reset_pll == 0)
{
si5351.pll_reset(SI5351_PLLA);
delay(1000);
}
cwo_old = cw_offset;
offset_mode = digitalRead(OFFSET_ON);
tx_mode = digitalRead(TX_ON);
if (!offset_mode && !tx_mode)
{
cw_offset = 800ULL;
if (cw_offset != cwo_old)
{
changed_f = 1;
cwo_old = cw_offset;
}
}
else
{
cw_offset = 0ULL;
if (cw_offset != cwo_old)
{
changed_f = 1;
cwo_old = cw_offset;
}
}
}
Comments
Post a Comment