nobcha a
Published © MIT

To change Arduino from ATmehga328P to ESP32-C3

To widen the memory size and CPU power, I replaced the ATmega328P to ESP32-C3 for R909-VFO PCB. And also porting the sketches related.

IntermediateProtip12 hours190
To change Arduino from ATmehga328P to ESP32-C3

Things used in this project

Hardware components

ESP32-C3 super mini
×1

Hand tools and fabrication machines

Arduino IDE

Story

Read more

Schematics

The schematics of 909-VFO-ESP

ESP32-C3 super mini dev kit is following Arduino function by ATmega328P

Code

The reedited sketch of JCR's VFO

Arduino
I reedited JCR's sketch for the new PCB with ESP32-C3 super mini
// 2025.04.02
// Changed to R909-VFO-ESP  BAND A1->4, rx_tx A2->D5, AGC A0, TUNE-SW D1
//  INT,
// To reduce memory consumption, change code to array reference 20230729
//  freq_band[21], bargraph function, 
//  There are some bugs on startup display and serial message
/**********************************************************************************************************
  10kHz to 225MHz VFO / RF Generator with Si5351 and Arduino Nano, with Intermediate
  Frequency (IF) offset
  (+ or -), RX/TX Selector for QRP Transceivers, Band Presets
  and Bargraph S-Meter. See the schematics for
  wiring and README.txt for details.
  By J. CesarSound - ver 2.0 - Feb/2021.
***********************************************************************************************************/

//Libraries
#include <Wire.h>                 //IDE Standard
#include <Rotary.h>               //Ben  Buxton https://github.com/brianlow/Rotary
#include <si5351.h>               //Etherkit  https://github.com/etherkit/Si5351Arduino
#include <Adafruit_GFX.h>         //Adafruit  GFX https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_SSD1306.h>     //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306

//User  preferences
//------------------------------------------------------------------------------------------------------------
#define IF         0         //Enter your IF frequency, ex: 455 = 455kHz, 10700 = 10.7MHz,  
                             // 0 = to direct convert receiver or RF generator, + will add and - will subtract IF  offfset.
#define BAND_INIT  8         //Enter your initial Band (1-21) at startup,  8:10MHz
                             //  ex: 1 = Freq Generator, 2 = 800kHz (MW), 7 = 7.2MHz (40m), 11 = 14.1MHz (20m). 
#define XT_CAL_F   147600    //Si5351 calibration factor, adjust to get exatcly 10MHz. Increasing
                             //  this value will decreases the frequency and vice versa.
#define S_GAIN     1010      //Adjust the sensitivity of Signal Meter A/D input: 101 = 500mv; 202 = 1v;
                             //  303 = 1.5v; 404 = 2v; 505 = 2.5v; 1010 = 5v (max).
#define TUNE_SW    1         //  ** The   pin used by tune step push button.
#define BAND_SW    4         //  ** The pin used   by band selector push button. CHANGE A1->A2
#define RXTX_SW    5         //  ** The pin used by   RX / TX selector switch, RX = switch open, A2->D4
                             //  TX = switch closed to GND. When in TX,  the IF value is not considered.
#define AGC        A0        //  ** The pin used by   Signal Meter A/D input.
#define REA        2         //
#define REB        3         //
#define LED_PORT   21
//------------------------------------------------------------------------------------------------------------

//    stp = 4;   // Frequency step 4:1kHz

Rotary r = Rotary(REA, REB);
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
Si5351  si5351(0x60); //Si5351 I2C Address 0x60

unsigned long freq, freqold, fstep;
long   interfreq = IF, interfreqold = 0;
long cal5351 = XT_CAL_F;
unsigned int smval;
byte   encoder = 1;  // RE active or inactive
byte fstep_no, tu_ind = 1;     // Frequency step 4:1kHz, tu_ind: tune pointer position
unsigned int band_no=1;  // band_no: band number
unsigned int s_value, s_value_old;
bool rxtx_sts = 0;
unsigned int period = 100;
unsigned long time_now = 0;

static unsigned long freq_band[21] = {100000, 800000, 1800000, 3650000, 4985000, 
6180000, 7200000, 10000000, 11780000, 13630000, 14100000, 15000000, 17655000, 
21525000, 27015000, 28400000, 50000000, 100000000, 118000000, 144000000, 220000000} ;
static unsigned long fstep_list[6] = {1,1000,10000,100000,1000000,25000};
static unsigned char fstep_name[6][7] = { " 25kHz"," 1Hz "," 1kHz ", " 10kHz", "100kHz", " 1MHz "};
static unsigned char band_name[21][5] = { "GEN","MW","160m","80m","60m","49m","40m","31m","25m"
  ,"22m","20m","19m","16m","13m","11m","10m","6m","WFM","AIR","2m","1m"};

void rotary_encoder(){
  char re_result = r.process();
  if (re_result == DIR_CW) set_frequency(1);
  else if (re_result == DIR_CCW) set_frequency(-1);
}

void set_frequency(int dir) {
  if (encoder == 1) {                         //Up/Down frequency
    if (dir == 1) freq = freq + fstep;
    if (freq >= 225000000) freq = 225000000;
    if (dir == -1) freq = freq - fstep;
    if (fstep == 1000000 && freq <= 1000000) freq = 1000000;
    else if (freq < 10000) freq = 10000;
  }
  if (encoder  == 1) {                       //Up/Down graph tune pointer
    if (dir == 1)  tu_ind = tu_ind + 1;
    if (tu_ind > 42) tu_ind = 1;
    if (dir == -1) tu_ind = tu_ind - 1;
    if (tu_ind < 1) tu_ind = 42;
  }
}

void setup() {
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.display();

  pinMode(REA, INPUT_PULLUP);
  pinMode(REB, INPUT_PULLUP);
  pinMode(TUNE_SW, INPUT_PULLUP);
  pinMode(BAND_SW, INPUT_PULLUP);
  pinMode(RXTX_SW, INPUT_PULLUP);
  pinMode(LED_PORT, OUTPUT);
  digitalWrite(LED_PORT,LOW);

  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(cal5351, SI5351_PLL_INPUT_XO);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.output_enable(SI5351_CLK0, 1);                  //1 - Enable / 0 - Disable CLK
  si5351.output_enable(SI5351_CLK1, 0);
  si5351.output_enable(SI5351_CLK2, 0);

  attachInterrupt(REA,rotary_encoder,CHANGE);
  attachInterrupt(REB,rotary_encoder,CHANGE);

  sei();

  band_no = BAND_INIT;
  bandpresets(band_no);
  fstep_no = 1;          // Frequency step 4:1kHz
  setstep();
  
  statup_text();         //If you hang on startup, comment
  delay(500); 

//  Serial.begin(9600); //If you hang on startup, comment
//  Serial.println(F("\nJA3KPA VFO V1.0")); //If you hang on startup, comment

  delay(500); 
     
}

void loop() {

  if (freqold != freq) {
    time_set();             // time_now = mullis()
    tunegen();              // Set 5351 CLK0 as freq
    freqold = freq;
  }

  if (interfreqold != interfreq) {
    time_set();
    tunegen();
    interfreqold = interfreq;
  }

  if (s_value_old != s_value) {
    time_set();
    s_value_old = s_value;
  }

  if (digitalRead(TUNE_SW) == LOW) {
    time_delay_set();             // time_now = mullis()+300
    setstep();
    delay(300);
  }

  if (digitalRead(BAND_SW) == LOW) {
    time_delay_set();
    inc_preset();
    delay(300);
  }
  if (digitalRead(RXTX_SW) == LOW){
    time_delay_set();
    rxtx_sts = 1;
  } else rxtx_sts = 0;


  if ((time_now + period) > millis()) {
    displayfreq();
    layout();              // Display edited buffer
  }
  sgnalread();
}

void time_set(void){
  time_now = millis();
}

void time_delay_set(void){
  time_now = ( millis()+ 300 );
}

void tunegen() {
  si5351.set_freq((freq + (interfreq * 1000ULL)) * 100ULL, SI5351_CLK0);
}

void displayfreq() {
  unsigned int m = freq / 1000000;
  unsigned int k = (freq % 1000000) / 1000;
  unsigned int h = (freq % 1000) / 1;

  display.clearDisplay();
  display.setTextSize(2);

  char buffer[15] = "";
  if (m < 1) {
    display.setCursor(41, 1); 
    sprintf(buffer, "%003d.%003d", k, h);
  }
  else if (m < 100) {
    display.setCursor(5, 1); 
    sprintf(buffer, "%2d.%003d.%003d", m, k, h);
  }
  else if (m >= 100)
  {
    unsigned int h = (freq % 1000) / 10;
    display.setCursor(5, 1); 
    sprintf(buffer, "%2d.%003d.%02d", m, k, h);
  }
  display.print(buffer);
}

void  setstep() {
//  fstep = fstep_list[fstep_no-1];
  switch (fstep_no) {
    case 1: fstep = fstep_list[0]; break;
    case 2: fstep = fstep_list[1]; break;
    case 3: fstep = fstep_list[2]; break;
    case 4: fstep = fstep_list[3]; break;
    case 5: fstep = fstep_list[4]; break;
    case 6: fstep = fstep_list[5]; break;
  }
  fstep_no++;
  if(fstep_no>=7) fstep_no=1;
}

void inc_preset() {
  band_no++;
  if (band_no > 21) band_no = 1;
  bandpresets(band_no);
  delay(50);
}

void  bandpresets(unsigned int band_count) {
//  freq = freq_band[band_count-1];  
  switch (band_count){
    case 1: freq = freq_band[0]; tunegen(); break;
    case 2: freq = freq_band[1]; break;
    case 3: freq = freq_band[2]; break;
    case 4: freq = freq_band[3]; break;
    case 5: freq = freq_band[4]; break;
    case 6: freq = freq_band[5]; break;
    case 7: freq = freq_band[6]; break;
    case 8: freq = freq_band[7]; break;
    case 9: freq = freq_band[8]; break;
    case 10: freq = freq_band[9]; break;
    case 11: freq = freq_band[10]; break;
    case 12: freq = freq_band[11]; break;
    case 13: freq = freq_band[12]; break;
    case 14: freq = freq_band[13]; break;
    case 15: freq = freq_band[14]; break;
    case 16: freq = freq_band[15]; break;
    case 17: freq = freq_band[16]; break;
    case 18: freq = freq_band[17]; break;
    case 19: freq = freq_band[18]; break;
    case 20: freq = freq_band[19]; break;
    case 21: freq = freq_band[20]; break;
    
  }
  si5351.pll_reset(SI5351_PLLA);
  fstep_no = 4;     // Frequency step 4:1kHz n: tune pointer position
  setstep();
}

void layout() {
  display.setTextColor(WHITE);
  display.drawLine(0, 20, 127, 20, WHITE);
  display.drawLine(0, 43, 127, 43, WHITE);
  display.drawLine(105, 24, 105, 39, WHITE);
  display.drawLine(87, 24, 87, 39, WHITE);
  display.drawLine(87, 48, 87, 63, WHITE);
  display.drawLine(15, 55, 82, 55, WHITE);
  display.setTextSize(1);
  display.setCursor(59, 23);
  display.print("STEP");
  display.setCursor(54, 33);
  //char disp_buff[7];
  //strcpy(disp_buff,fstep_name[fstep_no-1]);
  //display.print(disp_buff);
  // /*  
  if (fstep_no == 2) display.print(" 1Hz"); 
  if (fstep_no == 3) display.print(" 1kHz"); 
  if (fstep_no == 4) display.print(" 10kHz");
  if (fstep_no == 5) display.print("100kHz"); 
  if (fstep_no == 6) display.print(" 1MHz");
  if (fstep_no == 1) display.print("25kHz");
  // */
  display.setTextSize(1);
  display.setCursor(92, 48);
  display.print("IF:");
  display.setCursor(92, 57);
  display.print(interfreq);
  display.print("k");
  display.setTextSize(1);
  display.setCursor(110, 23);
  if (freq < 1000000) display.print("kHz");
  if (freq >= 1000000) display.print("MHz");
  display.setCursor(110, 33);
  if (interfreq == 0) display.print("VFO");
  if (interfreq != 0) display.print("L O"); 
  display.setCursor(91, 28);
  if (!rxtx_sts) display.print("RX"); 
  if (!rxtx_sts) interfreq = IF;
  if (rxtx_sts) display.print("TX"); 
  if (rxtx_sts) interfreq = 0;  
  bandlist(); 
  drawbargraph();

  display.display();
}

void bandlist() {
  display.setTextSize(2);
  display.setCursor(0, 25);
  
//  char disp_buff[4];
//  strcpy(disp_buff,band_name[band_no-1]);
//  display.print(disp_buff);
  
  if (band_no == 1) display.print("GEN"); 
  if (band_no == 2) display.print("MW"); 
  if (band_no == 3) display.print("160m"); 
  if (band_no == 4) display.print("80m");
  if (band_no == 5) display.print("60m"); 
  if (band_no == 6) display.print("49m"); 
  if (band_no == 7) display.print("40m"); 
  if (band_no == 8) display.print("31m");
  if (band_no == 9) display.print("25m"); 
  if (band_no == 10) display.print("22m"); 
  if (band_no == 11) display.print("20m"); 
  if (band_no == 12) display.print("19m");
  if (band_no == 13) display.print("16m"); 
  if (band_no == 14) display.print("13m"); 
  if (band_no == 15) display.print("11m"); 
  if (band_no == 16) display.print("10m");
  if (band_no == 17) display.print("6m");
  if (band_no == 18) display.print("WFM"); 
  if (band_no == 19) display.print("AIR");
  if (band_no == 20) display.print("2m");
  if (band_no == 21) display.print("1m");

  
  if (band_no == 1) interfreq = 0; 
  else if (!rxtx_sts) interfreq = IF;
}

void sgnalread() {
    smval = analogRead(AGC); 
    s_value = map(smval, 0, S_GAIN, 1, 14); 
    if (s_value > 14) s_value = 14;
  }

void drawbargraph() {
  byte tu_pos = map(tu_ind, 1, 42, 1, 14);
  display.setTextSize(1);

  //Tune indicator pointer
  display.setCursor(0, 48);
  display.print("TU");
  byte t_pos = 15+5*(tu_pos-1);
  display.fillRect(t_pos, 48, 2, 6, WHITE);
 
  // S-meter displaying 
  display.setCursor(0, 57);
  display.print("SM");
  
  for ( int xx = s_value; xx >= 0; xx--){ 
    byte s_pos = 15+5*(xx-1);
    display.fillRect(s_pos, 58, 2, 6, WHITE);
  }
}

void statup_text() {
  display.clearDisplay();
  display.setTextSize(1); 
  display.setCursor(13, 18);
  display.print(F("Si5351 VFO/RF GEN"));
  display.setCursor(13, 40);
  display.print(F("KPA lab. V1.1 @JCR"));
  display.display(); 
  delay(4000);
}

The diagnostic sketch for R909-VFO-ESP

Arduino
This one is useful for checking after assembling the PCB. The sketch reports the i2c address chained and the switches status.
// 2025.03.30 i2c scan, RE
//  Report the connected i2c address. 
//  If sw turning on, reporting SW name and ADC value or RE count.
// For R909-VFO ESP32-C3 mini
// To test the OLED display and SW1 responce
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include<Rotary.h>                      // Mr Ben buxton's INT 
#define ENC_A 2                         // R909-VFO-ESP Rotary encoder A port
#define ENC_B 3
Rotary r = Rotary(ENC_A,ENC_B);

#define RE_SW 4                         // R909-VFO-ESP RE-SW port
#define PIN_SDA 8                       // ESP32-C3 mini SDA
#define PIN_SCL 9                       // ESP32-C3 mini SCL
#define ADC_port 1                      // R909-VFO-ESP SW port
#define led_port 21                     // R909-VFO-ESP LED port

  int onoff = 0;
  byte error, address;
  int nDevices;
  boolean led_status;
  char charbuf[6];
  int re_cnt = 0;                       // RE +/- counter
  int cnt = 0;

#define SCREEN_WIDTH 128                // SSD1306 resolution
#define SCREEN_HEIGHT 64                // SSD1306 resolution
#define OLED_RESET     -1               // Set -1 for no use
#define SCREEN_ADDRESS 0x3C             // 0x3C

Adafruit_SSD1306 display = Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);     //
                                        
void setup()
{
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    for(;;);                            // If no responce , wait for ever
  }

  r.begin();

  attachInterrupt(ENC_A,rotary_encoder,CHANGE);
  attachInterrupt(ENC_B,rotary_encoder,CHANGE);
  Serial.begin(9600);

  display.clearDisplay();               // Display clear at first
  display.display();                    // To kick displaying
  pinMode(led_port, OUTPUT);
  pinMode(RE_SW, INPUT);

  display.setTextSize(1);               // select second size of font
  display.setTextColor(SSD1306_WHITE);  // default
  display.setCursor(5, 0);              // the starting point of character of bit position
  display.print("R909-VFO");            // the banner
  display.print(" i2c TEST");
 
  delay(2000);
}

void loop()
{
  Serial.println("i2c Scanning start");
  digitalWrite(led_port, led_status);  
  led_status = !led_status;
  delay(1000);   

  display.setCursor(0, 15);
  display.print("i2c scan");  
  display.display();
  
  display.setCursor(0, 32);
  display.print(" AD:"); 
  display.display();
    
  nDevices = 0;
  cnt = 0;
  for(address = 1; address < 127; address++ )
  {
    // Check WIRE function return back result
    // The value of Write.endTransmisstion
    // Is there ACK response (yes:0 or no
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)         // Got response
    {
      Serial.print("i2c device found at address 0x");
      if (address<16) Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      sprintf(charbuf, "%02X", address );
 
      cnt++;
      display.setCursor(cnt*36, 32);
      display.print(charbuf); 
      display.print(",");
      display.display(); 
      
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16) Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  
  if (nDevices == 0)
  {
    Serial.println("No i2c devices found\n");   
    display.setCursor(0, 49);
    display.print("No devices"); 
    display.display();
  }
  else{
    Serial.println("done\n");    
    display.setCursor(cnt*15, 49);
    display.print("Done"); 
    display.display();
  } 

  delay(2000);                  // Wait 2 sec
  display.clearDisplay(); 
 
  display.display();                    // To kick displaying

  digitalWrite(led_port, onoff++%2);
  delay(500);
  int sw_adc;
  if ( (sw_adc = analogRead( ADC_port)) < 4000) {
    display.clearDisplay();
    display.setCursor(0, 0);            // the starting point of character of bit position
    if(sw_adc < 50) display.print("SW1 on");  
    else display.print("SW2 on");       // SW2   
    display.print(sw_adc); 
    display.display();                  // To display
    delay(1000);
  }
  if( digitalRead(RE_SW) == 0){
    display.clearDisplay();
    display.setCursor(0, 0);            // the starting point of character of bit position
    display.print("RE SW on  ");  
    display.print(re_cnt); 
    display.display();                  // To display
    delay(1000);
  }
}

void rotary_encoder(){
  unsigned char result = r.process();
  if(result){
    if(result == DIR_CW){
      re_cnt++;
      Serial.println("Right");
    }
    else{
      re_cnt--;
      Serial.println("Left");
    }
  }
}

The original functions of R909-VFO

Arduino
R909-VFO is providing 10kHz-220MHz signal with the rotary encoder operation. The 50 channel memories are available.
// 2025.04.06 releases 10kHz-220MHz V3 for ESP-C3 mini dev kit
//  Changed INT, EEPROM, RE,and SW for ESP-C3 super mini dev kit
// 2025.03.03 temporary releases 100kHz-200MHz V2
//    Initilising as 10MHz for memory channels
//    No LO mode,   F-COR @ STEP  50ch memories 79%/28%
//  Step coverage 1,10,100,1kHz,10kHz,100kHz,1MHz,25kHz
//  F_COR step 1,10,100,1kHz for 25MHz OSC
// 
// --=----=----=----=----=----=----=----=----=----=----=----=----
// R909-VFO V1.0 20240531
// --=----=----=----=----=----=----=----=----=----=----=----=----
// R909-SDR-OLED  Ver3.2 20240204
//  Rotary switch:INT(D2,D3), RE-SW:A2, Function switch1,2: A0, 
//  Si4732: 0x11, Reset: D17, PU2CLR LIB, Si5351a: 0x60, TJ lab 
//  OLED: 0x3C, ADA fruits, ATmega328P with bootloader
//  
// si5351a ARDUINO LO  Ver3.0 (LCD&KEY, i2c SSD1306 LCD, Timer
// Rotary switch:INT(D2,D3), Function switch: D4 port, Squelch:A3
// Si5351_ADDR = 0x60, CPU:Arduino PRO mini, LCD: SSD1306:
// --=----=----=----=----=----=----=----=----=----=----=----=----

//Libraries definition
#include <EEPROM.h>
#include <Wire.h>
#include <si5351.h>                             
// https://github.com/etherkit/Si5351Arduino/tree/master/src/si5351.h
// #define SI5351_FREQ_MULT                100ULL
Si5351 si5351;

//////// OLED SSD1306 //// 
// Thanks Adafruit for providing the library of OLED SSD1306
//Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library
//Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306
#include <Adafruit_GFX.h>     
#include <Adafruit_SSD1306.h> 
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);




// --=----=----=----=----=----=----=----=----=----=----=----=----
// PORTs assign
#define REA 2          // D2 2 Rotary encode A
#define REB 3          // D3 3 B
#define RESW 4         // Rotary encoder push switch 4 
#define FUNC_SW 1      // SW1:<80, SW2:<250, (SW3:<430, SW4:<600)  
#define AGC_PORT A0 

#define SQLMUTE  4     // digital output for SQUELCH 
                       // to mute LM386 AMP when no signal 

#define led_pin 21     // Orange LED on panel 
// --=----=----=----=----=----=----=----=----=----=----=----=----

unsigned long int startF = 78000000;     // Japanese FM starting F
unsigned long int interfreq1 = 21400000; // 21.40Mhz
unsigned long int interfreq = 0; // 0Mhz
unsigned long int interfreq3 =  455000;  // 455khz

int freq_correction = 0;                 // Correction Hz for 25MHz 

//  Rotary encoder handler for arduino. v1.1
//  Copyright 2011 Ben Buxton. 
//  Licenced under the GNU GPL Version 3. Contact: bb@cactii.net  
//  http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
//  Rotary encoder test debug sketch
//  PWM/3: Rotary A --> D2
//  PWM/2: Rotary B --> D3
//  GND: C
#include <Rotary.h>
#define HALF  // better 
Rotary r = Rotary(REA, REB);
// --=----=----=----=----=----=----=----=----=----=----=----=----
// Assign function number 1-9 for short pushing at FUNCTION mode
// long pushing at 1:FREQ -> 11:FREQSET, 2:STEP-> 12:STEPSET
// 3:MEMORY-> 13:MMEMORYPUT, 4:SCAN->14:SCANAUTO, 
// 5:VOLUME&6:SQUELCH&7:BAND&8:BAND_W&9:F_COR->11:FREQSET
//
// 14 modes defined 0:NONE,1:FREQ,2:STEP,3:MEMORY,4:SCAN,5:VOLUME,
//  6:SQUELCH,7:BAND,8:BAND_W,9:F_COR,10:FUNCTION,11:FREQSET,
//  12:STEPPUT,13:MEMORYPUT,14:SCANAUTO,
// STATE 1:FR,2:ST,3:ME,4:SC,5:vol,6:squ,7:band,8:band_w,9:F_COR,10:func
// STATE+RE -> parameter increase/decrease
#define NONE 0          //
#define FREQ 1
#define STEP 2
#define MEMORY 3
#define SCAN 4
#define VOLUME 5
#define SQUELCH 6
#define BAND 7          // AM/FM SELECTION 
#define FUNCTION 10
#define FREQSET 11      // double push for FREQ set
#define STEPPUT 12      // double push for STEP set
#define MEMORYPUT 13    // double push for memory F set
#define SCANAUTO 14     // double push for Automatic SCAN set
#define BAND_W 8        // band width select
#define F_COR 9         // frequency error correction value inc/dec

// EEPROM Address
#define FREQ_AD 0       // EEPROM address for FREQ data as long
#define FSTEP_AD 4      // EEPROM address for FSTEP data as long 
#define MCHAN0 8        // MCHAN start ADD, MCHAN0 + 4 * chan  chan: 0- 50 

#define VOL_AD 400      // EEPROM ADDRESS for stored volume 
#define SQU_AD 404      // EEPROM address for squelch setting 
#define BAND_AD 408     // EEPROM ADDRESS for band 
#define previous_freqAM_AD 412 // EEPROM ADDRESS for previous_freqAM
#define BAND_W_AD 418   // EEPROM ADDRESS for BAND width 
#define F_COR_AD 422    // frequency error correction value
// --=----=----=----=----=----=----=----=----=----=----=----=----
//
#define Time_elapsedRSSI 300  // RSSI check period mS

// Band AM or FM at Si4732
// #define AM_FUNCTION 1
// #define FM_FUNCTION 0

// --=----=----=----=----=----=----=----=----=----=----=----=----
// functions
  void FUNC_Disp ( char*);              //  cursor(0,23)
  void Step_Disp(void);
  void Freq_Disp(void);

  void s_meter_Disp(void);
  void clearLCDLine (int, int, int);
 
  void layout(); 
  void drawbargraph(void);

  void startup_text(void);
  void sprintfreq(char*, int, int, int);
  
  void LongToStr(long , char*);
  void Fdds_Space(char *);
  
  void send_frequency(long, int);
  void set_freq(unsigned long);         // Call ETHERKIT ribrary
  void setstep();
  
  int function_key(void);
  int mode_define(unsigned char) ;
  void rotary_event(uint8_t);
  
  void TimerCount(void);
  void blink(long, long);
  
  void putFirstSettings(void) ;
  void ShowSettings(void);
  void getSettings(void);

  void freqEEPROMput(int, long*);  //EEPROM
  void freqEEPROMget(int, long);   //EEPROM
  

// --=----=----=----=----=----=----=----=----=----=----=----=----
// variables
boolean if_mode = 1;             // 1LO mode FREQ being LO above 
volatile int mode = FUNCTION;    // current mode 
// When mode is FUNCTION, mode_temp is candidate to be selected 
// by click. Blinking FUNC & mode_temp candidate.
volatile char mode_last = FREQ;  //  last time mode as FREQ
volatile char mode_temp = FREQ;  //  candidate
volatile int memo_ad = 0;        //  select  memory address
unsigned char set_sw = 1;        //  set freq on memory, or step to freq

volatile unsigned long int freq1, freq0, freq_0, freq_last;


// volatile unsigned long int previous_freqFM = 80200000;  // FM802 in OSAKA
volatile unsigned long int previous_freqAM = 118100000; // ITM TOWER


volatile unsigned long int fstep ;
int fstep_idx=5;                   // 1-6
int bandAM_idx=0;                  // 0-6
volatile unsigned long int_time = 0 ;
volatile unsigned long time0 = 0;
volatile unsigned long time1 = 0;
volatile long  Last_millis;
int Timer_LED = 1000;
int Timer_mash_i = 500;
int Timer_mash = 0;
int Timer_RESW_i = 50;
int Timer_RESW = -1;
int Timer_scan = -1;
int Timer_DISP_REF = 50;
int Timer_Mem_Write = 500;
int Timer_Mem_Write1 = 500;
volatile boolean Mem_Write1=0;

volatile boolean j, k;                   // led/LCD blinking status
volatile int ADCdata;
volatile int scan_ad = 0, scan_ad_last=0;   //  scanning address counter
volatile int i = 0;
volatile unsigned int re_result = 0;    // Rotary switch activated
                                         //result 0x10:right,0x20:left
volatile unsigned int result;
// --=----=----=----=----=----=----=----=----=----=----=----=----
// 0:no,1:FR,2:ST,3:ME,4:SC,5:vol,6:squelch,7:band,8:band_w,9:F_cor,10:func
char freqdisp[5] = { 0x46, 0x52, 0x45, 0x51, 0 };        // To display FRQ mode = 1
char stepdisp[5] = {0x53, 0x54, 0x45, 0x50, 0 };         // To display STP mode = 2
char mdisp[6] = {0x4d, 0x45, 0x4d, 0x30, 0x30 ,0};       // To display MEM number as mode = 3
char scandisp[6] = { 0x53, 0x43, 0x4e, 0x30 , 0x30 , 0 };// To display SCA channel mode = 4
char ascandisp[6] = {0x41, 0x53, 0x41, 0x30, 0x30 , 0 }; // To display ASA(Automatic scanning) mode = 14
char voldisp[6] = {0x56, 0x4f, 0x4c, 0x30 ,0x30 , 0};    // To display VOL mode = 5
char squdisp[6] = {0x53, 0x51, 0x55, 0x30 ,0x30 , 0};    // To display SQU SQUELCH LEVEL mode = 6
char banddisp[5] = {0x42, 0x41, 0x4e, 0x44, 0 };         // To display BAND mode = 7
char funcdisp[5] = { 0x46, 0x55, 0x4e, 0x43, 0 };        // To display FUNC mode = 10
char b_wdisp[6] = {0x42, 0x20, 0x57, 0x30 ,0x30 , 0};    // To display band width = 8
char f_erdisp[6] = {"F_COR"};   // To display Si5351a freq error correction  = 9

char spdisp[6] = { 0x20, 0x20, 0x20, 0x20, 0x20, 0 };    // SPACE

char eachdisp[8] = { 0, 0, 0, 0, 0, 0,0,0 };

// const char *bandwidthAM[]={"6","4","3","2","1","1.8","2.5"};

boolean RESW_last = 1;
boolean RESW_value_last = 1;
boolean RESW_pending = 0;
int RESW_result_p;
volatile unsigned int SW_result = 0;   // no:0, one click:2, double click:3
volatile unsigned int SW_result0 = 0;
volatile unsigned int sw_value, sw_stat;
int func_sw_value;

// int VolumeLevel = 15, last_VolumeLevel = 15;   // 
// uint8_t vl_pos, vl_ind;
// uint8_t sq_pos, sq_ind;
 
// int SquelchLevel = 0, last_SquelchLevel = 0;    // 

 boolean BandSelect = true, BandSelect_last= true; // am/fm:false
 boolean last_BandSelect = true;     // am:true/fm:false

// LCD SECOND LINE DOUBLE USE
boolean valid = false;
unsigned long previousMillis = 0;
const long interval = 5000;         //5 seconds
unsigned long elapsedRSSI;


// for squelch audio detection
int val = 0;
int timer = 0;
int maxi = 0;
unsigned int s_value;
boolean  s_dot_disp = 0;
unsigned int rssi, snr;
int ascan_hold = 0;

int debug=0,state1=0, state2=0;    // Debug counter

void rotary_encoder(){
  re_result = r.process();
}


// --=----=----=----=----=----=----=----=----=----=----=----=----
// --------------------------------------------------------------
// Power up setting section
void setup() {
// setup EEPROM handling
  EEPROM.begin(430);                    // For ESP32 EEPROM service  
// to configure a mode of the pins
  pinMode(led_pin, OUTPUT);             // monitor LED
  digitalWrite( led_pin, 1 );           // LED on
 
  pinMode(REA, INPUT_PULLUP);           // Rotary encoder port  
  pinMode(REB, INPUT_PULLUP);           // 
  pinMode(RESW, INPUT_PULLUP);          // Rotary encoder push SW

  delay(200);
// i2c starts up and SSD1306 sets up
  Wire.begin();  
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);

  attachInterrupt(REA,rotary_encoder,CHANGE);
  attachInterrupt(REB,rotary_encoder,CHANGE);


// Opening message
  display.setTextSize(2);
  display.setCursor(0, 25);
  display.print(F("R909-VFOV2"));
  display.setCursor(92, 48);
  display.print(F("kpa "));
  display.display();
  delay(200);
  
  /////// Switch sence ////////////////////////////////////////////////////////
  SW_result0 = function_key();         // Freq mode set on power start
  if (SW_result0 == 0) if_mode = 1;    // When no action, set IF_mode for LO

  r.begin(true);                       // rotary encoder initialise
  Last_millis = millis();
 
  delay(50);
  
// EEPROM data recover for clock frequency data
// There are FREQ, FSTEP, and MCHAN0-9
  freqEEPROMget( FREQ_AD, freq1);      // FREQ data  recover from EPROM
  freq_0 = freq1;
// *************************************
  
  EEPROM.get( FSTEP_AD, fstep_idx);        // fstep data from EEPROM Read   EEPROM
  setstep();

  EEPROM.get( BAND_AD, BandSelect);    // band data  recover from EPROM EEPROM

  EEPROM.get( previous_freqAM_AD, previous_freqAM );    //     EEPROM

  EEPROM.get( F_COR_AD,freq_correction);
  
  int d = digitalRead(RESW);           // If RESW is ON at starting up, 
  if (d == 0) {                        // EEPROM initialised
    putFirstSettings();
  }

//  getSettings();
  Freq_Disp();                        // display freq
  freq_0 = freq1 + interfreq;

//  si5351_init();                     // initialise the si5351

  if (freq1 < 100000 || freq1 > 200000000) { //100kHz-200MHz
    freq1 = 10000000;
    putFirstSettings();
    EEPROM.put( FREQ_AD, freq1);      // FREQ data  10MHz for EPROM EEPROM
    EEPROM.commit();                  // Fro ESP32 EEPROM service
    freq_0 =  118100000;              // changed 118.1MHz AM
    for ( memo_ad = 0 ; memo_ad < 50; memo_ad++ ) {
      EEPROM.put( FREQ_AD + 8 + memo_ad * 4, freq_0); // FREQ data  118.1MHz for eEPROM  EEPROM
      EEPROM.commit();                  // Fro ESP32 EEPROM service
    }
  }

  delay(500);
  
  // Set CLK0 
  si5351.set_ms_source(SI5351_CLK1, SI5351_PLLA);
  si5351.set_ms_source(SI5351_CLK0, SI5351_PLLB);
  si5351.set_ms_source(SI5351_CLK2, SI5351_PLLB);
//  correct_si5351a();
  si5351.update_status();
 // The calibration method is called below:
  si5351.set_correction(freq_correction, SI5351_PLL_INPUT_XO);
  
  si5351.set_freq(freq1 * SI5351_FREQ_MULT, SI5351_CLK0);


  if(fstep_idx<1 | fstep_idx>8){
    display.setTextSize(2);
    display.setCursor(0, 0);
    display.print(F("STP Err")) ;
    
    display.display();
    delay(1000);
    fstep = 100000;
    EEPROM.put( FSTEP_AD, fstep_idx );   // fstep data 100kHz for EEPROM
    EEPROM.commit();                  // Fro ESP32 EEPROM service

    EEPROM.put( F_COR_AD,0);
    EEPROM.commit();                  // Fro ESP32 EEPROM service
    delay(200);
  }
  
  digitalWrite( led_pin,0 );         // off
  
  // Set up INT function for RE
  re_result = 0;

  layout();

  if (if_mode == 1) freq_0 = freq1 + interfreq ; // On IF mode FREQ must be 
  else freq_0 = freq1;                           // upper than RX FREQ

//  starting VFO
  SI_setfreq( freq_0 );
// *************************************


  // debug print out
  /*    Serial.print("j: ");        // LCD blinking status
      Serial.println(j);
      Serial.print("mode: ");
      Serial.println(mode);
      Serial.print("mode_temp: ");
      Serial.println(mode_temp);
      Serial.print("SW_result: ");
      Serial.println(SW_result);
      Serial.print("SW_result0: ");
      Serial.println(SW_result0);
      
      Serial.print("freq1: ");
      Serial.println(freq1);  
       */
       
  // To inform the end of starting up
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.print(F("START"));

  display.display();

  delay(2000);   
// Once erase screen
  display.clearDisplay();
}
// End of setup

// --=----=----=----=----=----=----=----=----=----=----=----=----
//==========================MAIN=================================
void loop() {
  TimerCount();                 // To manage timer counter
 // digitalWrite(led_pin, 0);     // To turn off LED
 
  // Basic function for timer control led on_off & LCD blink
  blink(800, 500);      // Blinking for monitor LED and FUNC display on OLED

  // Check SW action
  SW_result = function_key();           // Get RESW result(on:50mS push) SW_result == 1
  SW_result0 = mode_define(SW_result);  // Define SW status 0:no, 1:single, 2:double

  //  RE push switch to FUNC mode, push switch again to each mode
  if (SW_result0 == 1) {
    if (mode != FUNCTION)  {    //  Go into FUNC mode
      mode_last = mode;
      mode = FUNCTION;  //  0:no,1:FR,2:ST,3:ME,4:SC,5:vol,6:squelch,7:Band,
                        //  8:band width,9:Frequency correction,
                        //  10:func,11:FSet,12:STSet,13:MWrite,14:AScan,
                        //  15:band w set, 16:F COR set
    }
    else { //  If FUNC, every click goes each FUNC defined
      mode_last = mode;
      mode = mode_temp;
    }
  }
  if ( SW_result0 == 2 ) {      //  select double click
    mode_last = mode_temp;      // double push

// To define mode by RE double push switching **********
// long pushing at 1:FREQ -> 11:FREQSET, 2:STEP-> 12:STEPSET
// 3:MEMORY-> 13:MMEMORYPUT, 4:SCAN->14:SCANAUTO, 
// 5:VOLUME&6:SQUELCH&7:BAND&8:BAND_W,9:F_COR->11:FREQSET
    switch (mode) {
      case FREQ:{
        mode = FREQSET;         // freq, vol, squ and band set
        break;
      }
      case STEP:{
        mode = STEPPUT;         // STP set
        break; 
      }
      case MEMORY:{
        mode = MEMORYPUT;       // Memory set
        break;
      }
      case SCAN:{
        mode = SCANAUTO;        // Automatic scanning
        break;    
      }
      case VOLUME:{
        mode = FREQSET;         // freq, vol, squ and band set
        break;    
      } 
      case SQUELCH:{
        mode = FREQSET;         // freq, vol, squ and band set
        break;    
      }            
      case BAND:{
        mode = FREQSET;         // freq, vol, squ and band set
        break;    
      }     

      case BAND_W:{
        mode = FREQSET;         // freq, vol, squ and band set
        break;    
      } 
      case F_COR:{
        mode = FREQSET;         // freq, vol, squ and band set
        break;    
      }       
      default:
        mode = FUNCTION;        // Go back to FUNC
    }
  }
// end of sw action

// Rotary encoder service
  if (re_result != 0) {         // If CW, re_result is 0x10, if CCW, 0x20.
    rotary_event(re_result);    // To start the concerning process
    re_result = 0;
  }
   
  
// process depended on mode
  switch ( mode ) {
    
    case FUNCTION: {                     // function mode is 12 
        if (j == 0) {                    // boolean j led blink state
          switch ( mode_temp ) {    
            case FREQ: {                 //  FREQ determining mode 1
                sprintf(eachdisp, freqdisp);
                break;
              }
            case STEP: {                 //  STEP select mode 2
                sprintf(eachdisp, stepdisp);     
                break;
              }
            case VOLUME: {               //  volume select mode 9 !corrupsed
                sprintf(eachdisp, freqdisp);   // voldisp->freqdisp
                break;
              }
            case SQUELCH: {              //  squelch select mode 10  !corrupsed
                sprintf(eachdisp, freqdisp);    // squdisp->freqdisp          
                break;
              }
            case BAND: {                 //  band select mode 11
                sprintf(eachdisp, freqdisp);    // squdisp->freqdisp                     
                break;
              }
            case MEMORY: {               //  MEMORY ch select mode 3
                sprintf(eachdisp, mdisp);
                break;
              }
            case SCAN: {                 //  SCAN select mode 4
                sprintf(eachdisp, scandisp) ;
                break;
              }
            case BAND_W: {               //  BAND width select mode 8
                sprintf(eachdisp, freqdisp) ;    // b_wdisp->freqdisp 
                break;
              }
            case F_COR: {                //  VFO error correction value 9
                sprintf(eachdisp, f_erdisp) ;
                break;
              }
              
            // next were added later
            default: sprintf(eachdisp, funcdisp);  // Function select mode 10
          }
        }    
          if (j == 1) sprintf(eachdisp, funcdisp); // LCD display alternated
      }                                  // end of process for FUNCTION
      break;
      
    case FREQ: {                         //  FREQ determining mode 1
        sprintf(eachdisp,  freqdisp ) ;   
        break;
      }
    case STEP: {                         //  STEP select mode 2
        sprintf(eachdisp,  stepdisp ) ;
        break;
      }

    case VOLUME: {                       //  volume select mode 5

        break;
      }
    case SQUELCH: {                      //  squelch select mode 6

        break;
      }
    // band
    case BAND: {                         //  band select mode 7

        break;
      }
    case MEMORY: {                       //  MEMORY ch select mode 3
        mdisp[3] = 0x30 | (memo_ad / 10) ;
        mdisp[4] = 0x30 | (memo_ad % 10) ;
        sprintf(eachdisp, mdisp) ;       // 
        break;
      }

    case SCAN: {                         //  Manual step SCAN mode 4
      //  fm mode to be added
        scandisp[3] = 0x30 | (scan_ad / 10) ;     //  display scan chan
        scandisp[4] = 0x30 | (scan_ad % 10) ;
        sprintf(eachdisp,  scandisp ) ;        
        freqEEPROMget( MCHAN0 + scan_ad * 4, freq1); // read out MEM frequency
        
        if (freq_last == freq1)  break;

        
     //   Freq_Disp();
        freq_0 = freq1  ;
        // FREQ is more than IF above IF frequency for RX FREQ
        if (if_mode == 1) freq_0 = freq1  + interfreq  ; 
 
        freq_last = freq1 ;
        if(BandSelect == false) {    // If FM mode, 

        }
        else {
          send_frequency(freq_0, 0); //send it to si5351

        }
        break;
      }
      case BAND_W: {               //  BAND width select mode 8
        break;
      }
      case F_COR: {                //  VFO error correction value 9
        
        sprintf(eachdisp, "%5d", freq_correction) ;
        break;
      }


    case FREQSET: {                      //  FREQ button long push 
        sprintf(eachdisp, freqdisp) ;    //  freq display
        
        freq0 = freq1;
        if(BandSelect == false) freq0 = -freq1;  // If FM, convert to negative
        EEPROM.put( FREQ_AD, freq0 );    // freq data into EEPROM
        EEPROM.commit();                  // Fro ESP32 EEPROM service
        EEPROM.put( F_COR_AD,freq_correction);// Frequency error correction value
        EEPROM.commit();                  // Fro ESP32 EEPROM service
        EEPROM.put( previous_freqAM_AD, previous_freqAM );    // 
        EEPROM.commit();                  // Fro ESP32 EEPROM service
        mode = FREQ;
        break;
      }
    case STEPPUT: {                 //  STEP written 
       sprintf(eachdisp, stepdisp) ; 
       if(Timer_Mem_Write<=0 && Mem_Write1==0){
         sprintf(eachdisp, spdisp) ;    // 
         EEPROM.put( FSTEP_AD, fstep_idx ); // fstep data of 100kHz unit in EEPROM  
         EEPROM.commit();                  // Fro ESP32 EEPROM service
         Timer_Mem_Write=800;   
         Mem_Write1=1;     
       }
       if(Timer_Mem_Write>0 && j==1){       
         sprintf(eachdisp, spdisp) ;    // 2nd line 1st character step display
       }
       if(Timer_Mem_Write<=0){
         mode = FREQ;
         Mem_Write1=0;
       }
       break;
      }
    case MEMORYPUT: {                    //  MEMORY write  
        sprintf(eachdisp, mdisp) ;       //  
        
        freq0 = freq1;
        if( BandSelect == false) freq0 = -(freq1);
        EEPROM.put( MCHAN0 + memo_ad * 4, freq0); // Write FREQ on defined EEPROM
        EEPROM.commit();                  // Fro ESP32 EEPROM service
        display.clearDisplay(); 
  
        sprintf(eachdisp, spdisp) ;       //  line 2 first column is space
        layout();
        display.clearDisplay();  
 
        sprintf(eachdisp, mdisp) ;        //  line 2 first column is m
        layout();
        display.clearDisplay();  
        mode = FREQ;
        break;
      }
    case SCANAUTO: {                       //  AUTO SCAN mode from M-chan
        if (Timer_scan <= 0) {             //  If timer up
          scan_ad++;           
          Timer_scan = 1000;
          ascandisp[3] = 0x30 | (scan_ad / 10) ;   //  display scan chan
          ascandisp[4] = 0x30 | (scan_ad % 10) ;   //  display scan chan
          sprintf(eachdisp, ascandisp ) ;
         
          freqEEPROMget( MCHAN0 + scan_ad * 4, freq1); // read out MEM frequency

                      //Changed 20201013
          if (scan_ad > 49) scan_ad = 0;
                    
          if(BandSelect == false ){         // If FM, skip FM freq
            BandSelect = true;
            Timer_scan = 0;
            break;  
          }  
          
          Freq_Disp();
          
//          Band_setting();      

          if (if_mode == 1) freq_0 = freq1 + interfreq  ; // 
          send_frequency(freq_0, 0);        //send it to si5351

          state2 = s_value;
          s_meter_Disp();                   // Get AGC voltage & change S-meter

        }
        break;
      }
  }
  
  
  // S METER & squelch
  // CHECK TIMER FOR TIMEOUT
  if (( millis() - elapsedRSSI ) > Time_elapsedRSSI ){  // 300ms
    s_meter_Disp();
    elapsedRSSI = millis();
    
   
  }

  // SW1:<320, SW2:<1000, (SW3:<1720, SW4:<2400 )
  // actual 
  // This set keeps 2 keys of SW1 & SW2
  
  func_sw_value = analogRead(FUNC_SW);
  if (func_sw_value < 900) {

    sw_stat = 1;
    if (func_sw_value>320) sw_stat = 2; 
     
    switch ( sw_stat){
      case 1:
        mode = FREQ;          // freq mode 0
        break; 
      case 2:   
        mode = SCAN;          // SCAN mode 4
        break;      
    }
  }

// display  
  if(Timer_DISP_REF<=0){      // Periodic display timer expired
    digitalWrite(led_pin, k=!k);    

    Freq_Disp();
   
    layout();
    display.clearDisplay();    
    Timer_DISP_REF = 500;    // Display every 500mS
  }


}
//end of loop
// --=----=----=----=----=----=----=----=----=----=----=----=----
// **************************************************************

//  ************************************
//   FUNCTIONs
//  ************************************

//
void getSettings() {

  freqEEPROMget( FREQ_AD, freq1);   // freq1:FREQ data recover from EPROM 
                                    // freq0:as AM:+, FM:- freq1:absolute
                                    // When freq0 is minus, Bandselect becomes false:FM 
  EEPROM.get( FSTEP_AD, fstep_idx);     // fstep data from EEPROM Read
  setstep();
//  EEPROM.get( VOL_AD, VolumeLevel); // volume data  recover from EPROM
//  EEPROM.get( SQU_AD, SquelchLevel);// squelch data from EEPROM Read
  EEPROM.get( BAND_AD, BandSelect); // band data  recover from EPROM
  EEPROM.get( F_COR_AD,freq_correction); 
//  EEPROM.get( BAND_W_AD, bandAM_idx);   // band with index recover from EPROM

//  EEPROM.get( previous_freqFM_AD, previous_freqFM );    // 
  EEPROM.get( previous_freqAM_AD, previous_freqAM );    // 
}

// 
void putFirstSettings() {

  freq0 = freq1;  
  if( BandSelect == false) freq0 = -(freq1);
  EEPROM.put( FREQ_AD, freq0);            // FREQ data  100MHz for EPROM
  EEPROM.commit();                  // Fro ESP32 EEPROM service
//  freqEEPROMput(FREQ_AD, freq1);        // Put freq1 + BAND on EEPROM
  EEPROM.put( FSTEP_AD, fstep_idx);           // fstep data from EEPROM Read
  EEPROM.commit();                  // Fro ESP32 EEPROM service
//  EEPROM.put( VOL_AD, VolumeLevel);       // volume data  recover from EPROM
//  EEPROM.put( SQU_AD, SquelchLevel);      // squelch data from EEPROM Read
  EEPROM.put( BAND_AD, BandSelect);       // band data  recover from EPROM
  EEPROM.commit();                  // Fro ESP32 EEPROM service
  EEPROM.put( F_COR_AD,freq_correction); 
  EEPROM.commit();                  // Fro ESP32 EEPROM service
//  EEPROM.put( BAND_W_AD, bandAM_idx);     // band with index recover from EPROM
   
//  EEPROM.put( previous_freqFM_AD, previous_freqFM );    // 
  EEPROM.put( previous_freqAM_AD, previous_freqAM );    // 
  EEPROM.commit();                  // Fro ESP32 EEPROM service
  freq_0 =  10000000;
  
  for ( memo_ad = 0 ; memo_ad < 50; memo_ad++ ) {
    EEPROM.put( FREQ_AD + 8 + memo_ad * 4, freq_0); // FREQ data  AM 10MHz for EEPROM
    EEPROM.commit();                  // Fro ESP32 EEPROM service
  }
  freq_0 =  10000000;
  EEPROM.put( FREQ_AD + 8 , freq_0); // FREQ data  AM 10MHz for EEPROM #0
  EEPROM.commit();                  // Fro ESP32 EEPROM service
//  freq_0 =  -80200000;
//  EEPROM.put( FREQ_AD + 8 + 49 * 4, freq_0); // FREQ data  FM 80.2MHz for EEPROM #49
//  freq_0 =  -85100000;
//  EEPROM.put( FREQ_AD + 8 + 48 * 4, freq_0); // FREQ data  FM 85.1MHz for EEPROM #48

}

// Long FREQ data changes to 10 digit numerics
void LongToStr(long dat, char *fm) {
  long fmdat;
  int i;
  fmdat = dat;  
  for (i = 0; i < 11; i++) {
    fm[10 - i] = ( fmdat % 10 ) | 0x30;
    fmdat = fmdat / 10;
  }
}

// Reducing preceding zero into space
void  Fdds_Space(char *fm) {
  int i;
  for (i = 0; i < 10; i++) {
    if ( fm[i] == 0x30) {
      fm[i] = 0x20;
    }
    else i = 11;
  }
}

// Function SEL determining  A4 port: RE push SW
// result 0:no key, 1:off-> on
int function_key() {
  result = 0;
  //  SW sensing to avoid chattering
  if (Timer_RESW <= 0) {
    boolean RESW_value = digitalRead(RESW);
    if ((RESW_value == 0) && (RESW_value_last == 1)) {
      Timer_RESW = Timer_RESW_i;
      RESW_value_last = 0;
      result = 1;
    }     if ((RESW_value == 1) && (RESW_value_last == 0)) {
      Timer_RESW = Timer_RESW_i;
      RESW_value_last = 1;
      result = 0;
    }
    RESW_value_last = RESW_value;
  }
  return result ;                 // Switch not settled 
}

// After key result(RESW_click), wait timer_mash. Then decide single/double
// result 0:no key, off-> on pending, 1:single click, 2:double click
int mode_define(unsigned char keyresult) {
  char result = 0;
  // To detect double click  Detect double within a cirtain second
  // After keyresult = 1;
  // waiting double click  (Timer_mash > 0): mash pending
  if ((Timer_mash > 0) && (keyresult == 1)) {  // Double RESW pushed
    RESW_result_p = 2;
  }
  else if ((Timer_mash <= 0) && (keyresult == 1)) { // Firstly RESW pushed
    Timer_mash = Timer_mash_i;             // Mash timer set
    RESW_result_p = 1;            // Once set single click
  }
  // waiting timer end
  else if (( Timer_mash <= 0 ) && (RESW_result_p >= 1)) {
    result = RESW_result_p;  // Stop to wait & report result
    RESW_result_p = 0;
  }
  return result;
}


// Timing managing function: When Time_value <= 0, timer expired
void TimerCount(void) {
  long Current_millis = millis();
  long time_dif = Current_millis - Last_millis;   // Calculate how many millis after last call
  Last_millis = Current_millis;                   // Remember current time
  if (Timer_mash > 0) Timer_mash = Timer_mash - time_dif; // To wait double click timing
  if (Timer_RESW > 0) Timer_RESW = Timer_RESW - time_dif; // To avoid chattering
  if (Timer_LED > 0) Timer_LED = Timer_LED - time_dif;    // To turn on/off for #13 LED
  if (Timer_scan > 0) Timer_scan = Timer_scan - time_dif;
  if (Timer_DISP_REF > 0) Timer_DISP_REF = Timer_DISP_REF - time_dif;    // Display refresh timing
  if (Timer_Mem_Write > 0) Timer_Mem_Write = Timer_Mem_Write - time_dif; // EEPROM put blink timing
}

//  LED on/off & OLED FUNCTION blink:j
void blink(long on_time, long off_time) {  // LED on_off, j effects FUNC on/off
  if ((Timer_LED <= 0) && (j == 1)) {
    digitalWrite(led_pin, 0 );       // Monitor Led off
    j = 0;                           // bit j off  j:LCD blink
    Timer_LED = off_time;
  }
  else if ((Timer_LED <= 0) && (j == 0)) {
    digitalWrite(led_pin, 1 );       // Mon Led on
    j = 1;                           // bit j off  j:LCD blink
    Timer_LED = on_time;
  }
}


void FUNC_Disp ( char* func){        // Display FUNC of #2 size on X:0,Y:25 
  display.setTextSize(2);
  display.setCursor(0, 25);
  display.print(func);
  display.print("TEST");
}


//********* display frequency *********
// Assemble the format of frequency value and display it on the OLED
void Freq_Disp() {              // Format freq data for display & display
  unsigned int m = freq1 / 1000000;
  unsigned int k = (freq1 % 1000000) / 1000;
  unsigned int h = (freq1 % 1000) / 1;

  display.clearDisplay();
  display.setTextSize(2);

  char buffer[15] = "";
  if (m < 1) {                   // In he case of less than MHz, kkk.hhh kHz
    display.setCursor(5, 24); 
    sprintf(buffer, "%003d.%003d", k, h);
  
  }
  else if (m < 100) {            // In the case of more than MHz and 
                                 // less than 100MHz, mm.kkk hhh MHz
    display.setCursor(5, 24); 
    sprintf(buffer, "%2d.%003d,%003d", m, k, h);
  }
  else if (m >= 100){            // In the case of more than 100MHz, mmm.kkk hh MHz
    unsigned int h = (freq1 % 1000) / 10;
    display.setCursor(5, 24); 
    sprintf(buffer, "%3d.%003d,%002d", m, k, h);
   }
  display.print(buffer);
}

// Serial.ino   
// show in serial the eeprom settings
void  ShowSettings() {
/*
  Serial.println("Stored EEPROM Settings");
  Serial.print("\nFreq = ");
  Serial.println(freq1);
  Serial.print("\nFstep = ");
  Serial.println(fstep);
  Serial.print("\nVolume = ");
  Serial.println(VolumeLevel);
  Serial.print("\nSquelch = ");
  Serial.println( SquelchLevel);
  Serial.print("\nBand = ");
  Serial.println(BandSelect);
  Serial.println("----------------------");
  Serial.print("\nfreq_0 = ");
  Serial.println(freq_0);
  Serial.print("\nSfreq1= ");
  Serial.println( freq1);
  Serial.print("\nif_mode = ");
  Serial.println(if_mode);
 */
}


// CHANGE! No change no setting
int32_t last_ffrequency0 = 0;
int32_t last_ffrequency1 = 0;
int32_t last_ffrequency2 = 0;

// calculate and send frequency code to Si5351...
//   si5351.set_freq(freq1 * SI5351_FREQ_MULT, SI5351_CLK0);

void send_frequency(int32_t ffrequency, int fcontext) {
  ffrequency = ffrequency * 100 ;
  switch (fcontext) {        // no use fcontext  only CLK0
    case 0:                                     // Port 1
      if ( ffrequency != last_ffrequency0 ){
        si5351.set_freq((uint64_t)ffrequency, SI5351_CLK0 );        // Set the frequency on the Si5351a.
        last_ffrequency0 = ffrequency;
      }
      break;
    case 1:                                     // Port 2
      if ( ffrequency != last_ffrequency1 ){
        si5351.set_freq((uint64_t)ffrequency, SI5351_CLK1 );
        last_ffrequency1 = ffrequency;
      }
      break;
    case 2:                                     // Port 3
      if ( ffrequency != last_ffrequency2 ){
        si5351.set_freq((uint64_t)ffrequency, SI5351_CLK2 );
        last_ffrequency2 = ffrequency;
      }
      break;
  }
}


//
unsigned long int last_freq = 0;
unsigned long int last_ifclk = 0;
//
void SI_setfreq( unsigned long int freq) {
...

This file has been truncated, please download it to see its full contents.

Credits

nobcha a
9 projects • 3 followers
I'm interested in designing a radio with Si4732 and Si5351a.

Comments