Skip to content

Latest commit

 

History

History
902 lines (535 loc) · 36.4 KB

README.md

File metadata and controls

902 lines (535 loc) · 36.4 KB

This section presents several prototypes and circuits with different displays and controller boards. The source codes for each prototype are stored in the examples folder of this repository. Please, check the comments at the beginning of each sketch example available in this library. You will find the SI473X, button, encoder, display and Arduino settings. There are more than 30 projects that can help you to build your own receiver based on the SI47XX IC family.

THE CIRCUIT DESIGNS CREATED BY THE AUTHOR ARE NOT INTEND TO BE A FINAL PRODUCT. SOME IMPORTANT ASPECTS OF A GOOD RECEIVER ARE OUTSIDE THE SCOPE OF THESE EXAMPLES. THE CIRCUITS MADE BY THE AUTHOR ARE A PROOF OF CONCEPT OF THE FUNCTIONS IMPLEMENTED IN THE ARDUINO LIBRARY. SO, COMPONENTS LIKE RF FRONT-END, BAND PASS FILTER, ESD, ANTENNA DESIGN ARE NOT THE MAIN PART OF THIS PROJECT.

This project is about a library to control the SI47XX devices and the focus of this project is the library and its functionalities. Please, don't ask the author to assist you with displays, encoders, buttons or something else outside of the "PU2CLR SI4735 Arduino Library" scope. Thanks.

Use the following groups to guide you in your projects

  • Facebook group called Si47XX for Radio Experimenters. The purpose is exchanging experiences with projects based on Silicon Labs SI47XX IC family.
  • group.io SI47XX for hobbyists. This group is formed by people with experience in electronics and firmware development.

Donate

If you find this project useful, consider making a donation so that the author of this library can purchase components and modules for improvements and testing of this library. Click here to donate or use the QR code below.

Donate

SI4735 and SI4732 pinout

If a schematic uses the SI4735 device but you have the SI4732 device or vice-versa, then reference the table below to correct the pinout for your specific IC model. See pictures and the table SI4735-D60 and SI4732-A10 replacement below.

The picture below shows the SI4735-D60/SI4730-D60 pinout (SSOP)

Si4735-D60 pinout

The picture below shows the SI4732-A10 pinout (16L SOIC Package)

Si4732-A10 pinout

SI4735-D60 and SI4732-A10 replacement

SI4735-D60 PIN SI4732-A10 PIN Note
#3 (GP03/[DCLK]) #2 (GP03/[DCLK])
#8 (FMI) #6 (FMI)
#9 (RFGND) #7 (RFGND) Depending on your design, you can use this pin connected to GND
#10 and #11 (NC) Not applicable Connected to GND if you have the SI4735
#12 (AMI) #8 (AMI)
#13 and #14 (GND) #15 (GND)
#15 (RST) #9 (RST)
#16 (SEN) #10 (SENB) (*1 ) See the text ATTENTION below
#17 (SCLK) #11 (SCLK)
#18 (SDIO) #12 (SDIO)
#19 (RCLK) #13 (RCLK)
#20 and #21 (VD VA) #14 (VDD) Connected to +VCC (between 2.8V and 3.7V)
#22 (DBYP) Not applicable
#23 (ROUT/DOUT) #16 (ROUT/DOUT)
#24 (LOUT/DFS) #1 (LOUT/DFS)

(*1) ATTENTION:

While the Si4735 device provides the 0x11 I²C bus address when the SEN pin is connected to ground, the SI4732-A10 provides the same address when the SENB pin is connected to +VCC. The SI4735 Arduino Library provides the function getDeviceI2CAddress to detect the I²C bus address automatically. The library will detect and use the correct address if you use this function. See getDeviceI2CAddress(). By default, connect SEN/SENB pin to the GND. See schematics below.


Basic Schematic (Atmega328 based board)

The two schematics below show the basic setup. The first schematic uses the SI4735-D60 and the secound schematic uses the SI4732-A10. These schematics will help you to replace the SI4735-D60 with the SI4732-A10 or vice versa.

SI4735-D60 Version

The schematic below shows how to connect the SI473X (SSOP24 package) circuit with Arduino Pro Mini 3.3V/8MHz.

Basic Schematic

All Sketches on SI47XX_01_SERIAL_MONITOR folder

Part Description
C1 22nF Monolithic Multilayer Chip Ceramic non polarized capacitor (Place it close to VA pin)
C2 1nF Monolithic Multilayer Chip Ceramic non polarized capacitor
C3 470nF Monolithic Multilayer Chip Ceramic non polarized capacitor
C4 100nF Monolithic Multilayer Chip Ceramic non polarized capacitor (Place it close to VD pin)
C5 and C6 22pF (Crystal load capacitors)
C7 and C8 *1 4.7uF Monolithic Multilayer Chip Ceramic non polarized capacitor
R3 2.2K
(R4 and R5) *2 2.2K to 10K (pull-up resistors)
L1 Ferrite loop stick (about 500 μH)
X1 32.768 kHz crystal
SI4735 digital CMOS AM(LW, MW and SW)/FM radio receiver IC

SI4732-A10 Version

The schematic below shows how to connect the SI4732-A10 circuit with Arduino Pro Mini 3.3V/8MHz.

Basic Schematic

All Sketches on SI47XX_01_SERIAL_MONITOR folder



Atmega328 based board and OLED

Atmega328 based board and OLED

Sketche SI47XX_02_ALL_IN_ONE_OLED


ESP32 based board

The schematic below guides you to build a SI473X based receiver using the ESP32 device.

ESP32 basic setup

ESP32 Basic schematic

ESP32 DEVKIT with OLED and Encoder setup

Esp32 based board schematic

All Sketches on SI47XX_06_ESP32 folder

{% include esp32_mega2560.html %}

ESP8266

ESP8266 basic schematic

ESP8266 Basic schematic

ESP8266 OLED

ESP8266-12-F with OLED

ESP8266_12_F Basic schematic

Generic ESP8266 with OLED

ESP32 Basic schematic

All Seeeduino sketches on /examples/SI47XX_06_ESP8266 folder

Seeeduino XIAO

ESP32 Basic schematic

Youtube

All Seeeduino sketches on examples/SI47XX_15_SEEEDUINOX_06_ESP32 folder


Standalone ATmega328 with or without external Crystal (SI4735-D60 and LCD 16x2).

The schematic below can be also used with a regular Arduino Board based on ATmega328. It is almost the same circuit posted by Mirko Pavleski on his Arduino Project repository. If you use an SI4735-D60 or SI4732-A10, you can have an All band receiver with FM, AM and SSB modes.

Standalone ATmega328 with or without external Crystal (LCD 16x2 version)

Sketch SI47XX_02_for_Mirko_Pavleski_radio.

Please, use the MiniCore setup on your Arduino IDE to deal with standalone Atmega328.

See video:

{% include atmega328_standalone.html %}


Basic schematic with TFT

The schematic below demonstrates how to build your own receiver based on the SI473X with TFT display. The sketches are available on examples/SI47XX_04_TFT/ folder decribe the wire up used by the TFT selected by the author. Please, read the comments at the beginning of each sketch example.

Basic schematic with TFT

Sketches on examples/SI47XX_04_TFT/

See video: Si4735 All in One Receiver running on Arduino Pro Mini 3.3V (8MHz) and TFT Display

{% include videoSSB.html %}


Arduino DUE/MEGA and touch TFT display.

The schematic below shows just the Arduino DUE and SI473X connections. The touch TFT used by this circuit is a shield that can be connected to the Arduino DUE directly. If you intent to use Arduino Mega, you have to add a bidirectional logic level converter.

Basic schematic with TFT

Sketches on SI47XX_10_RDS

See videos:

{% include shcematic_due_mega.html %}


Attiny85 basic circuit

You can use the Si4735 Arduino Library on the very small ATtiny85 or Attiny84. The schematic below can guide you to build a receiver based on attiny85 device.

Attiny85 Basic schematic

Attiny85 with external eeprom

Attiny85 Basic schematic

Sketches on examples/SI47XX_05_ATTINY85

See videos:

{% include schematic_attiny85.html %}


Bluepill - STM32F103C8 basic schematic

STM32F1 and SI4735-D60 or SI4732-A10 wire up

Si4735 SI4732 DESC. ESP32
pin 15 pin 9 RESET PA12
pin 18 pin 12 SDIO B7
pin 17 pin 11 SCLK B6

The schematic below guides you to build a SI473X based receiver using the STM32 device.

The schematics below guide you to build a SI473X based receiver using the STM32 device.

Bluepill Basic schematic V1

This version uses a Encoder with Push Button, and 7 push button.

Bluepill Basic schematic V1

OLED, Encoder and Buttons connections

Device name Device Pin / Description STM32F1
OLED
SDA/SDIO B7
SCL/SCLK B6
Encoder
A PA0
B PA1
PUSH BUTTON (BFO/VFO) PA15
Buttons
MODE_SWITCH Switch MODE (Am/LSB/USB) PA2
BANDWIDTH Bandwidth PA3
VOL Volume Up PA4
VOL_DOWN Volume Down PA5
BAND_UP Next Band PA6
BAND_DOWN Previous band PA7
AGC_SWITCH Switch AGC PA8
STEP_SWITCH Step Switch PA11

Bluepill Basic schematic V2

This version uses only a Encoder with Push Button

Bluepill Basic schematic V2

OLED and Encoder connections

STM32F1 and components wire up.

Device name Device Pin / Description STM32F1
OLED
SDA/SDIO B7
SCL/SCLK B6
Encoder
A PA9
B PA10
PUSH BUTTON (encoder) PA11

Sketches on SI47XX_07_STM32

See video:

{% include schematic_basic_stm32.html %}


Teensy 3.X and 4.X

The setup bellow works on Teensy 3.X and Teensy 4.X board family.

Teensy and components wire up.

OLED and Encoder

Device name Device Pin / Description Teensy
OLED
SDA/SDIO A4
SCL/SCLK A5
Encoder
A 9
B 10
PUSH BUTTON (encoder) 11

SI4735-D60 or SI4732-A10 wire up

Si4735 SI4732 DESC. Teensy
pin 15 pin 9 RESET 12
pin 18 pin 12 SDIO A4
pin 17 pin 11 SCLK A5

Teensy Basic schematic with OLED and Encoder

Teensy 3.X or 4.X Basic schematic with OLED

Sketches on SI47XX_14_TEENSY

Arduino Pro Mini 3.3V and 7SEG Display based on TM1638

It is a receiver prototype based on SI4735 controlled by TM1638 based devices with buttons, LEDs and 7 segment display. This receiver covers AM and SSB (LW, MW and SW) and FM from 64 to 108 MHz.

The photo below shows the TM1638 based device.

TM1638 photo

SI4735, Arduino Pro Mini 3.3V, encoder and TM1638

Arduino and TM1638 schematic

Sketches on SI47XX_08_TM1638

See video:

{% include schematic_basic_tm1638.html %}

Arduino / ATmega328 with Nokia 5110

Example One encoder and 7 push buttons to control the receiver

This example uses the Adafruit libraries Adafruit_GFX and Adafruit_PCD8544. The receiver works on VFH/FM (broadcast stations), and LW,MW and SW on AM and SSB modes.

FM MW/AM SW/AM 40M/LSB 10M/USB
N701 N702 N703 N704 N705

The schematic below shows the Arduino board based on ATmega 328 and the Nokia 5110 display

Nokia 5110 schematic

Sketches on SI47XX_08_TM1638

Example one encoder with push button to control the receiver

This example uses the Adafruit librarie LCD5110_Graph to control the Nokia 5110. It is not available on Arduino IDE. To install LCD5110_Graph library, download that library on Rinky-Dink Eletronics site, unzip the file and move the folder unzipped to your Arduino Libraries folder.

The receiver works on VFH/FM (broadcast stations), and LW,MW and SW on AM and SSB modes.

FM MW/AM SW/AM 40M/LSB 10M/USB
N101 N102 N103 N104 N105

The schematic below shows the Arduino board based on ATmega 328 and the Nokia 5110 display controlled just by one encoder and one push button.

Nokia 5110 schematic

Video

{% include nokia5110.html %}

The schematic below is a simple example that shows a way to use your smartphone as a remote control via Bluetooth. You will find more details here.

Mobile device remote control Schematic

See Android and iOS Remote Control for PU2CLR Arduino Library DSP receivers.

See video

{% include ble_remote_control.html %}


External Mute Circuit

The SI47XX devices have about 0,7V DC bias component in the analog audio output pins (SI4735-D60 pins 23 and 24). When the device goes to power down mode, the voltage on the audio pins drops to 0V. The devices do it internally so there is not a way to avoid that. When the device goes to power up, the audio pins suddenly go to high DC again. This transition causes the loud pop in the speaker. It is possible to solve this problem by adding an extra mute circuit and control it by the MCU (Atmega, ESP32, STM32, ATtiny85 etc).

External Mute Circuit

Considering that you are using a MCU based on Atmega328, when the D14 is HIGH the Si47XX output audio will be drained to the ground. At this condition, no audio will be transferred to the amplifier input and, consequently, to the speaker. So, no loud click in the speaker.

When the D14 is LOW, the most of signal audio output from the Si47XX will be transfered to the input of the amplifier.

The code below shows all you have to do in your sketch to implement this resource.

#include <SI4735.h>
#define AUDIO_MUTE 14      // Pin A0 - Switch AGC ON/OF

Si4735 r;

void setup() {
  .

  // It is all you have to do to control a external audio mute circuit if you have one.
  r.setAudioMuteMcuPin(AUDIO_MUTE); // Tells the system to control an external audio mute circuit.

  r.setup(RESET_PIN, -1, 1, SI473X_ANALOG_AUDIO); // Starts on FM mode and ANALOG audio mode.
  .
  .
  .

}

Some low power audio amplifiers IC also implement mute circuit that can be controlled externally. You can find this resource on LM4906, LM4863, KA8602B, MC34119, PAM8403 and HT82V739 devices.

See Video:

Removing the loud click in the speaker during power down and power up

{% include audiomute.html %}


SI473X and external active crystal oscillator or signal generator

You can use a signal generator or a active crystal oscillator instead the passive 32768kHz crystal with Si473X devices. This setup can be useful to improve the receiver performance or deal with digital audio output. The schematic below shows this setup.

SI473X and external active crystal oscillator or signal generator

If you have an active crystal or other signal generator that oscillates at Z Hz, where Z is a value greater than 31130Hz, do the follow steps:

  • Choosing a reference clock value between 31130Hz and 34406 Hz that multiplied by N (prescaler) is equal or very close to Z.
  • call the setRefClock(R). Where R (reference clock) have to be a value between 31130Hz and 34406;
  • call the setRefClockPrescaler(N). Where N (prescaler) is a value that multiplied by R is equal to the frequency of your active crystal or signal renerator;
  • call the setup() function with the parameter XOSCEN_RCLK

For example: If you have an active crystal that oscillates at 32500Hz (32.5kHz), the N must be equal to 1. So, the right setup for this case is:

si4735.setRefClock(32500); // Reference clock = 32500 si4735.setRefClockPrescaler(1); // Prescaler = 1 si4735.setup(RESET_PIN, -1, POWER_UP_FM, SI473X_ANALOG_AUDIO, XOSCEN_RCLK);

As you may notice, some active crystals or some frequencies will not work properly, as the product of R and N will result in values far from the oscillation frequency provided by the source. For example: A signal generator running at 40kHz.

Check the PU2CLR SI4735 Arduino Library API documentation to deal with external clock reference. The code below shows how to setup 32.768kHz external clock.

The example below shows the setup to an active crystal that oscillate at 32768Hz.

void setup(void)
{
  .
  .
  .
  si4735.setRefClock(32768);        // Ref = 32768Hz
  si4735.setRefClockPrescaler(1);   // prescaler = 150 =>  32768 x 1 = 32768

  si4735.setup(RESET_PIN, -1, POWER_UP_FM, SI473X_ANALOG_AUDIO, XOSCEN_RCLK); // XOSCEN_RCLK means: external clock source setup
  .
  .
  .
}

IMPORTANT: use a reference clock between 31130Hz to 34406Hz;

Some examples below

100kHz

if you have an active 100kHz crystal, you must select the reference clock of 33333Hz (33kHz) and a prescaler of 3 (3 x 33333 = ~100000Hz). Example:

rx.setRefClock(33333);
rx.setRefClockPrescaler(3);
rx.setup(RESET_PIN, 0, POWER_UP_AM, SI473X_ANALOG_AUDIO, XOSCEN_RCLK);

It is important to note the setup function and the parameter XOSCEN_RCLK.

4.9152MHz
rx.setRefClock(32768);        // Ref = 32768Hz
rx.setRefClockPrescaler(150); // prescaler = 150 ==> 32768 x 150 = 4915200Hz (4.9152MHz)
rx.setup(RESET_PIN, 0, POWER_UP_AM, SI473X_ANALOG_AUDIO, XOSCEN_RCLK);
13MHz
si4735.setRefClock(32500);          // Ref = 32.5kHz
si4735.setRefClockPrescaler(400);   // prescaler = 400 ==> 32500 x 400 = 13000000 (13MHz)
rx.setup(RESET_PIN, 0, POWER_UP_AM, SI473X_ANALOG_AUDIO, XOSCEN_RCLK);
13.107200MHz:
rx.setRefClock(32768);        // Ref = 32768Hz
rx.setRefClockPrescaler(400); // prescaler = 400 ==> 32768 x 400 = 13.107200MHz
rx.setup(RESET_PIN, 0, POWER_UP_AM, SI473X_ANALOG_AUDIO, XOSCEN_RCLK);

See the sketch example: I47XX_02_RDS_TOUCH_SHIELD_REF_CLOCK

Video:

SI4735-D60 and external reference clock test

{% include external_crystal.html %}

Digital Audio (I2S) setup

To use I2S with SI473X device family, you must use the external clock or active crystal setup (see previous section). The schematic below shows the Digital Audio setup using an SI4735-D60 with an ESP32 Devkit.

SI473X and external active crystal oscillator or signal generator

ESP32 and SI4735-D60 Digital Audio setup (I2S) with LCD 16x2

ESP32 and SI4735-D60 Digital Audio setup

ESP32 Wire up with LCD, encoder/pushbutton and SI4735-D60

Device name Device Pin / Description ESP32
LCD 16x2 or 20x4
D4 GPIO18
D5 GPIO17
D6 GPIO16
D7 GPIO15
RS GPIO19
E/ENA GPIO23
RW & VSS & K (16) GND
A (15) & VDD +Vcc
VO (see 20K tripot connection) ------------
SS473X
RESET (pin 15) GPIO12
SDIO (pin 18) GPIO21
SCLK (pin 17) GPIO22
(*1)SEN (pin 16) +Vcc or GND
Encoder
A CPIO13
B GPIO14
PUSH BUTTON (encoder) GPIO27

The table below shows the SI4735, DAC MAX98357A and ESP32 wireup

Si4735 Function DAC MAX98357A ESP32
pin 1 DOUT DIN SerialData / GPIO32
pin 2 DFS RC WordSelect / GPIO25
pin 3 DCLK BCLK ContinuousSerialClock / GPIO33

The table below shows the SI4735, DAC CJMCU and ESP32 wireup

Si4735 Function DAC MAX98357A ESP32
pin 1 DOUT DIN SerialData / GPIO32
pin 2 DFS WSEL WordSelect / GPIO25
pin 3 DCLK BCLK ContinuousSerialClock / GPIO33

Band Pass Filter controlled by Arduino

It is a HF band pass filter controlled by Arduino. It is designed for HF receivers. With this project, you can use a set of up to four HF bandpass filters that can be selected by Arduino. To do that you will need just two digital Arduino pins. All about this project on here.

Band Pass Filter controlled by Arduino

See videos:

{% include bpf.html %}

Storing data into the internal EEPROM before shutdowning

This example uses the Arduino Pro Mini 3.3V (8MHz), the SI4735 and OLED.

The EEPROM has a lifetime around 100,000 write/erase cycles. On "Atmel, ATmega328P, 8-bit AVR Microcontroller with 32K Bytes In-System Programmable Flash". The DATASHEET, page 19, you will find: "The Atmel® ATmega328P contains 1Kbyte of data EEPROM memory. It is organized as a separate data space, in which single bytes can be read and written. The EEPROM has an endurance of at least 100,000 write/erase cycles". Therefore, writing data to eeprom with each system status change could give an application a very short life. To mitigate this problem, some approaches can be used to save recordings on the EEPROM.

The following circuit illustrates a way to configure an Arduino based on Atmega328 to record useful information on its internal EEPROM. The idea of this approach is to obtain the last status of the system after turning it on. Observe in the circuit that a 1000uF electrolytic capacitor has been added. Depending on the arduino board, the time needed to record the information and the shutdown check time, the capacitor value may be different. This capacitor is powered by the battery voltage or external power supply while the system is working. When the user turns the system off, the capacitor will still keep the arduino running for a few seconds. Observe also that the Arduino pin 16 (A2), is connected to the power supply. That setup works as a shutdown detector. I mean, the pin 16 status will keep HIGH while the power supply is on. However, when the user turns the system off (no power supply), the pin 16 status will be LOW. In this condition, a few lines of code have to be added to the loop function to check the pin 16 status frequently. If the pin 16 is LOW, the Arduino will have few seconds to save data into the internal EEPROM. Be aware the capacitance of the capacitor must be high enough to allow the arduino to record all needed data. Increase the capacitance value if 1000uF does not provide enough time for your setup. Actually, the best way to save data immediately is using the interrupt approaching via digital pins 2 or 3 of Atmega328 . However, this example uses with success the pulling approach.

Due to the voltage drop caused by the diode D1, it is important to raise the input voltage to 3.7V. This way the Arduino will continue operating steadily with about 3V. The SI4735 and OLED are powered with 3.7V, a safe voltage for both devices. Only the arduino will keep running for a few seconds after system shutdown. See circuit and sketch reference below.


Storing data into the internal EEPROM before shutdowning


Arduino sketch setup


#include <SI4735.h>
#include <EEPROM.h>

#define SHUTDOWN_DETECTOR 16 // A2 - Arduino pin 16 configured as digital

const uint8_t app_id =  35; // Useful to check the EEPROM content before processing useful data
const int eeprom_address = 0;

void setup() {
  pinMode(SHUTDOWN_DETECTOR, INPUT); // If HIGH power supply detected; else, no power supply detected
  pinMode(VOLUME_DOWN, INPUT_PULLUP);
  pinMode(VOLUME_UP, INPUT_PULLUP);
  .
  .
  // If you want to reset (erase) the eeprom, keep the VOLUME_UP button pressed during startup
  if (digitalRead(VOLUME_UP) == LOW)
  {
    EEPROM.write(eeprom_address, 0); // In our case, just the app_id is enough.
    oled.print("EEPROM RESETED");
    delay(2000);
  }

  // Checking the EEPROM content
  if (EEPROM.read(eeprom_address) == app_id) { // There are useful data stored to rescue
    volume = EEPROM.read(eeprom_address + 1); // Gets the stored volume;
    freqByteHigh = EEPROM.read(eeprom_address + 2); // Gets the frequency high byte
    freqByteLow = EEPROM.read(eeprom_address + 3);  // Gets the frequency low  byte
    currentFrequency = (freqByteHigh << 8) | freqByteLow; // Converts the stored frequency to SI473X frequency.
  } else { // No data found
    volume = 45;
    currentFrequency = 10390; // 103.9MHz
  }
  .
  .
  .
  rx.setup(RESET_PIN, FM_FUNCTION);
  rx.setFM(8400, 10800, currentFrequency, 10);
  rx.setVolume(volume);
  .
  .
  .
}

/**
 *  Saves the current volume and frequency into the internal EEPROM
 */
void writeReceiverData() {
  EEPROM.write(eeprom_address, app_id); // stores the app id;
  EEPROM.write(eeprom_address + 1, rx.getVolume()); // stores the current Volume
  EEPROM.write(eeprom_address + 2, (currentFrequency >> 8) );   // stores the current Frequency HIGH byte
  EEPROM.write(eeprom_address + 3, (currentFrequency & 0xFF));  // stores the current Frequency LOW byte
}


void loop {
  .
  .
  .
  // Checks the shutdown status
  if (digitalRead(SHUTDOWN_DETECTOR) == LOW ) {
    writeReceiverData();
    while(1); // Stop working
  }
}

See the complete sketches on examples/TOOLS/SI47XX_02_STORE_EEPROM_BEFORE_SHUTDOWN

See video:

{% include eeprom_receiver_status.html %}

Back to the main page

Another method to store data into the EEPROM

You also can store useful data without a special circuit. This approach will store data every time some important status changes. The idea is store data only if it is necessary.

Steps:

  • Select the data you want to keep into the EEPROM;
  • Add the code to monitor the data in your sketch;
  • Add code to save the data. In this case, you need to define the criteria that will be used to perform a recording on the EEPROM. In general, a good criteria is: any change of useful data AND elapsed time. It will depend on your application.
  • Consider using the method EEPROM.update instead EEPROM.write. It will not write information if it is the same stored before;
  • Add the code to restore data from EEPROM;
  • Add the code to check if exist useful data stored into EEPROM. It can be a single byte indicating that exist valid information for the system. Use an identification number (ID) that will be understood as valid data by the system.
  • Add code to erase the information in EEPROM. All you have to do is erasing the identification number. Actually just change the ID value. In other words, you do not need erease all data stored into EEPROM to reset the data to the system.
  • Add code to RESET the system. At system start up check if a given button is pressed and then erase the ID;

Example

#define STORE_TIME 10000      // Time of inactivity to make the current receiver status writable (10 seconds).

const uint8_t app_id = 35;     // Application ID. Any value from 1 to 255.  It will be useful to check the EEPROM content before processing useful data
const int eeprom_address = 0;  // Address where the data will be stored into EEPROM
long storeTime = millis();     // elapsed time control


void setup() {

  .
  .
  .

  // If you want to reset the eeprom, keep the  button pressed during statup
  if (digitalRead(GIVEN_BUTTON) == LOW)
  {
    EEPROM.write(eeprom_address, 0); // Changes the application ID. It invalidates all stotred information. 
    delay(2000);
  }

  .
  .
  .

  // Checking the EEPROM content and read if it has valid information
  if (EEPROM.read(eeprom_address) == app_id)
  {
    readAllReceiverInformation();
  }

  .
  .
  .

}


void saveAllReceiverInformation()
{
  EEPROM.update(eeprom_address, app_id);                      // stores the app id;
  EEPROM.update(eeprom_address + 1, si4735.getVolume());      // stores the current Volume
  EEPROM.update(eeprom_address + 2, currentMode);             // Stores the current Mode (FM / AM / SSB)
  EEPROM.update(eeprom_address + 3, currentFrequency >> 8);   // Store the current frequency
  EEPROM.update(eeprom_address + 4, currentFrequency & 0XFF);
  .
  .
  .

}


void readAllReceiverInformation()
{
  volume = EEPROM.read(eeprom_address + 1);                 // Gets the stored volume;
  currentMode = EEPROM.read(eeprom_address + 2);            // Gets the stored mode
  currentFrequency = EEPROM.read(eeprom_address + 3) << 8;  // Gets the stored frequency
  currentFrequency |= EEPROM.read(eeprom_address + 4);
  .
  .
  .
}


void loop() {
  .
  .
  .
  // Monitor your data and set statusChanged variable to true if any useful data has changed.
  .
  .
  .

  // check if some status was changed
  if ( statusChanged )
  {
    // If the status has changed and the elapsed time is less than minimal time, wait a bit more for saving new data.
    if ((millis() - storeTime) > STORE_TIME)
    {
      saveAllReceiverInformation();
      storeTime = millis();
      statusChanged = false;
    }
  }

}

See this approach working on: