RECEPTOR FM/OM/SW(AM SSB e CW) com SI4735 protótipo
RECEIVER FM/MW/SW(AM SSB and CW) with SI4735 prototype


Tela inicial
Home screen

No youtube tem um video deste prototipo recebendo LSB
On youtube there is a video of this prototype receiving LSB


Quando  tivemos a noticia que o Ricardo PU2CLR havia desenvolvido uma biblioteca, compativel com Arduino, para o SI4735 e que esta biblioteca permitiria receber SSB, resolvemos adquirir o integrado.
When we got the news that Ricardo PU2CLR had developed a library, compatible with Arduino, for the SI4735 and that this library would allow receiving SSB, we decided to buy the integrated one.

Depois de longa espera, recebemos o integrado e partimos para a montagem de um prototipo, para avaliar o funcionamento do integrado recebendo SSB.
O repositorio do Ricardo  GitHub -pu2clr , tem praticamente tudo que precisamos para montar o receptor.
After a long wait, we received the integrated and started to assemble a prototype, to evaluate the functioning of the integrated receiving SSB.
Ricardo's GitHub repository -pu2clr , has practically everything we need to assemble the receiver.

Resolvi montar o "All in one"
I build the
"All in one"

As caracteristicas do circuito são estas :

1. FM, OM e OC recebendo AM, LSB, USB.
2. Filtro de audio com largura de 0,5  1,0  1,2  2,2  3,0 e 4,0kHz.
3. 22 bandas entre de radioamadores e comerciais pré-configuradas.
4. BFO ajustavel.
5. Passo de sintonia ajustavel de 1,0  5,0 e 10kHz

The characteristics of the circuit are these:

1. FM, OM and OC receiving AM, LSB, USB.
2. Audio filter with width of 0.5 1.0 1.2 2.2 3.0 and 4.0kHz.
3. 22 pre-configured commercial and amateur radio bands.
4. Adjustable BFO.
5. Adjustable tuning step from 1.0, 5.0 and 10kHz

O esquema basico sugerido é este :
The basic schema suggested is this:

 
Como podemos observar o esquema basico é bem simples e se refere a todas as montagens do Ricardo.
As we can see, the basic schema is very simple and refers to all Ricardo assemblies.

Vamos a nossa montagem
Let's go to our montage

Esquema :
Scheme:


O esquema ficou um pouco mais complicado pois acrescentamos tudo que foi preciso para funcionar a partir de 12V e com o Arduino Nano.
The scheme got a little more complicated because we added everything needed to work from 12V and with the Arduino Nano.

Prototipo montado esquerda para direita bobina de OM, SI4735 +fonte de 3,3V, amplificador de audio, conversor de nivel 5V para 3,3V junto com o arduino nano e fonte de 5V, conjunto de chaves. Embaixo o LCD.
Prototype mounted left to right OM coil, SI4735 +3.3V power supply, audio amplifier, 5V to 3.3V level converter along with Arduino nano and 5V power supply, set of switches. Underneath the LCD.

No lugar dos transistores Tr1 a Tr3 e R1 a R6 eu coloquei um conversor de nivel bidirecional comprado da China.
In place of transistors Tr1 to Tr3 and R1 to R6 I put a bidirectional level converter bought from China.

Onde HV é ligado os 5V , em LV os 3,3V, em HV1 a HV4 as conexões do Arduino nano, em LV1 a LV4 as conexões do SI4735. E ambos os GND ligados a terra. Usei sómente tres dos quatro conversores.
Where HV is connected to 5V, in LV the 3.3V, in HV1 to HV4 the Arduino nano connections, in LV1 to LV4 the SI4735 connections. And both GND connected to ground. I only used three of the four converters.


Foto : esquerda fonte de 5V, arduino nano com o conversor plugado e cabos para as chaves.
Photo: left 5V power supply, arduino nano with the converter plugged in and cables for the switches.


Foto:  outro detalhe do arduino, conversor de nivel e fonte de 5V
Photo: another detail of the arduino, level converter and 5V source

Para ler o endereço do I2C do LCD eu usei este sketch
To read the I2C address from the LCD I used
this sketch

Foto: SI4735 soldado manualmente

Soldagem do CI
Para soldar o SI4735 eu usei somente a pasta XG-50 (Sn63 Pb37) e uma placa adaptadora (como não tinha uma de 24 pinos usei uma de 28 pinos). Tanto a pasta de solda como a placa adaptadora foram comprados da China.
Para soldar o SI4735 na placa, eu costumo virar o CI com lides para cima (inseto morto) e colocar a pasta nos lides, deixando eles cobertos de pasta, mas o corpo de CI limpo.
Os lides do CI ficam então cobertos de pasta, e a pasta fica entre os pinos tambem.
Coloco o CI na posição de montagem, pino 1 com pino1,  cuidando para que fique bem dividido ou seja não fique muito de um lado e pouco de outro.
Soldo um pino da extremidade e verifico se o CI esta fixo e confiro se os pinos estão alinhados com a PCB adptadora.
Estando fixo, eu soldo os outros pinos, procurando derreter toda a pasta como soldador (uso um de 30W Hikari).
Passo a ponta do soldador entre os pinos eliminado o excesso.
Verifico a continuidade e os curtos com um Ohmimetro analogico escala x1.
Se não há continuidade eu repasso o soldador.
Tendo curtos circuitos, ai fica mais dificil, mas com o soldador simplesmente eu consigo eliminar a maioria os curtos. Os dificeis uso uma malha (shield de cabo) ou uma cordoalha para sugar o excesso de solda entre os pinos. É muito raro ter que dessoldar os CI para solda-lo novamente.
Não uso lupas de aumento e nem dispositivos eletronicos (lupas). Simplesmente tiro os oculos (tenho 3,5 graus de miopia em cada olho e sem oculos a distancia fica perfeita para enxergar e soldar).
A pasta de solda tem boa durabilidade se guardada na geladeira.

IC welding
To solder the SI4735 I used only the XG-50 paste (Sn63 Pb37) and an adapter plate (as I didn't have a 24-pin one, I used a 28-pin one). Both solder paste and adapter plate were purchased from China.
To solder the SI4735 to the board, I usually turn the IC with the leads up (dead insect) and put the paste on the leads, leaving them covered in paste, but the IC body clean.
The IC leads are then covered in paste, and the paste is between the pins as well.
I place the IC in the mounting position, pin 1 with pin1, taking care that it is well divided, that is, it is not too much on one side and not too much on the other.
Solder a pin from the end and check if the IC is fixed and check if the pins are aligned with the adapter PCB.
Being fixed, I solder the other pins, trying to melt all the paste as a welder (I use a 30W Hikari).
Pass the welder tip between the pins to eliminate excess.
I check continuity and shorts with an x1 scale analog ohmmeter.
If there's no continuity, I'll replace the welder.
Having short circuits, it becomes more difficult, but with the welder I can simply eliminate most of the shorts. The hard ones use a mesh (cable shield) or a strand to suck the excess solder between the pins. It is very rare to have to unsolder the IC to solder it again.
I do not use magnifying glasses or electronic devices (loupes). I simply take my glasses off (I have 3.5 degrees of myopia in each eye and without glasses the distance is perfect for seeing and soldering).
Solder paste has a good shelf life if stored in the refrigerator.

Foto : SI4735 soldado na placa de 28 pinos e plugado em uma PCB padrão, o cristal capacitores ealguns resistores estão soldados na pCB sob a placa adaptadora.

Nota :
Para quem mora no Brasil tem um vendedor, no mercado livre, que vende o CI montado (soldado) na placa, já com o cristal de 32,768kHz e os capacitores de 22pF soldados.

O cristal de 32,768kHz eu tinha de sucata. Este cristal é facilmente encontrado em placas de PC ou outras como clock, são pequenos e cilindricos.
O regulador 7805, 78L33, LCD, encoder e o adaptador para LCD I2C : comprei da China.

Photo: SI4735 soldered on the 28-pin board and plugged into a standard PCB, the crystal capacitors and some resistors are soldered on the pCB under the adapter board.

Note :
For those who live in Brazil, there is a seller, on the free market, who sells the IC mounted (soldered) on the board, already with the 32.768kHz crystal and the 22pF capacitors soldered.

The 32.768kHz crystal I had scrap. This crystal is easily found in PC boards or other like clock, they are small and cylindrical.
The 7805, 78L33, LCD, encoder and adapter for LCD I2C : I bought it from China.


Foto: modulo do amplificador de audio, montado em modulo (15x 15mm) inseto morto

O amplificador de audio pode ser eliminado se usar fones ou se utilisar mini falantes amplificados (estereo). Ou então usar um amplificador estereo de 3W (CI PAM8403 5V) que é vendido montado ou similar.
Como devo usar o radio para receber ondas curtas preferi montar um LM386 mono. A montagem foi feita em um pequeno modulo (15x15mm), montando o LM386 como inseto morto.

Photo: audio amplifier module, mounted on module (15x 15mm) dead insect

The audio amplifier can be eliminated if you use headphones or if you use mini amplified (stereo) speakers. Or use a 3W stereo amplifier (CI PAM8403 5V) that is sold assembled or similar.
As I should use the radio to receive short waves I preferred to mount a LM386 mono. The assembly was done in a small module (15x15mm), mounting the LM386 as a dead bug.


Foto Si4735 e a bobina de OM, usamos a derivação para ligar a antena. Para a banda LW abaixo de 500kHz recomendaoms colocar duas bobinas de OM em serie. Podendo uma ser jampeada para oucir OM (MW).
Photo Si4735 and the OM coil, we use the shunt to connect the antenna. For the LW band below 500kHz, we recommend placing two OM coils in series. One can be jammed to hear OM (MW).

A bobina de antena usei uma da sucata semelhante a que tinha usado na montagem do SI4825
The antenna coil I used a scrap similar to the one I had used in the assembly of the 
SI4825

Para carregar o sketch usei a IDE 1.8.9 copiada (e usada) a partir de um pendrive. Para não dar conflito com a IDE usada anteriormente eu renomeio a pasta Ardunio (ex. para xxArduino) que contem os sketches e livrarias anteriores. O uso da outra IDE criará uma nova pasta Arduino (não esqueça de voltar tudo ao que era).
To load the sketch I used the IDE 1.8.9 copied (and used) from a pendrive. In order not to conflict with the IDE used previously, I rename the Ardunio folder (eg for xxArduino) which contains the previous sketches and libraries. Using the other IDE will create a new Arduino folder (don't forget to reset everything to what it was).

Como o sketch do Ricardo tinha um conflito com o uso do pino D13, mudamos para A2 alterando o codigo correspondente e adicionamos um resistor para deixar o nivel de entrada em HI.
No software alteramos a linha 95 :
de :
As Ricardo's sketch had a conflict with the use of pin D13, we changed it to A2 changing the corresponding code and added a resistor to leave the input level at HI.
In the software we change line 95 :
in :

#define BFO_SWITCH 13      // Used to select the enconder control (BFO or VFO)
para :
#define BFO_SWITCH A2      // Used to select the enconder control (BFO or VFO)
e a linha 201
de :
pinMode(BFO_SWITCH, INPUT_PULLUP);
para:
pinMode(BFO_SWITCH, INPUT);//modificado para uno

Explicação :
No pino D13 (digital 13 ) do arduino nano tem um LED ligado do pino D13 ao terra,  qdo o resistor interno (pullup), é acionado por software o led acende, mas a tensão Hi não é muito alta pois tem a tesão que esta acionando o LED cerca de 2,1V.
Como foi usadas todos os pinos digitais (tipo D), usamos uma porta analogica como digital (A2) e necessitamos adicionar um resistor para deixar esta porta em Hi (nas portas A analogicas não tem a função que lga os resistores internos como nas portas digitais D) como era no sketch do Ricardo

Alteramos tambem o endereço do I2C do LCD obtido como descrito anteriormente. Este endereço foi 0x3F caso o endereço que voce obteve, no seu LCD +I2C , voce deve alterar na linha numero 187 :
este é a linha do Ricardo
LiquidCrystal_I2C display(0x27, 20, 4); // please check the address of your I2C device
a minha linha ficou assim :
LiquidCrystal_I2C display(0x3F, 20, 4); // please check the address of your I2C device

O software tem a possibilidade de carregar os arquivos patch_ini.h ou patch_full.h carregamos uma a cada vez e não observamos diferenças.

No hardware usamos o pino 16 ligado a terra (endereço 0x11).

O sketch modificado pode ser obtido neste arquivo

Gostariamos de agradecer ao PU2CLR Ricardo pelo excelente trabalho realizado !

Explanation :
On pin D13 (digital 13) of the arduino nano there is an LED connected from pin D13 to ground, when the internal resistor (pullup) is activated by software the led lights up, but the Hi voltage is not very high because it is horny driving the LED about 2.1V.
As all digital pins (D type) were used, we used an analog port as a digital one (A2) and we need to add a resistor to leave this port in Hi (on analog ports A does not have the function that connects the internal resistors as in digital ports D) as it was in Ricardo's sketch

We also changed the LCD I2C address obtained as described above. This address was 0x3F if the address you got, on your LCD +I2C , you must change it on line number 187:
this is Ricardo's line
LiquidCrystal_I2C display(0x27, 20, 4); // please check the address of your I2C device
my line looked like this:
LiquidCrystal_I2C display(0x3F, 20, 4); // please check the address of your I2C device

The software has the possibility to load the files patch_ini.h or patch_full.h we load them one at a time and we didn't notice any differences.

In hardware we use pin 16 connected to ground (address 0x11).

The modified sketch can be obtained from this 
File

We would like to thank PU2CLR Ricardo for the excellent work done!

73 de py2ohh miguel

Aqui esta o sketch :

/*
  SI4735 all in one with SSB Support

  This sketch has been successfully tested on:
  1) Pro Mini 3.3V;
  2) UNO (by using a voltage converter);
  3) Arduino Yún (by using a voltage converter);
  4) Arduino Micro (see the operating voltage of your Micro);
  5) Arduino Mega (by using a voltage converter); and
  6) Arduino DUE;

  This sketch uses I2C LiquidCrystal/LCD, buttons and  Encoder.

  This sketch uses the Rotary Encoder Class implementation from Ben Buxton (the source code is included
  together with this sketch) and LiquidCrystal I2C Library by Frank de Brabander (https://github.com/johnrickman/LiquidCrystal_I2C).
  Look for LiquidCrystal I2C on Manager Libraries.


  ABOUT DIGITAL pin 13 and INPUT PULL-UP on Arduino Pro Mini, UNO or similar:
  This pin has a LED and a resistor connected on the board. When this pin is set to HIGH the LED comes on. If you use the internal
  pull-up resistor of the pin 13, you might experiment problem due to the drop voltage caused by the LED circuit.
  If this occurs in your project, change the circuit to use external pull-up on pin 13.    


  ABOUT SSB PATCH: 
  This sketch will download a SSB patch to your SI4735 device (patch_init.h). It will take about 8KB of the Arduino memory.

  In this context, a patch is a piece of software used to change the behavior of the SI4735 device.
  There is little information available about patching the SI4735. The following information is the understanding of the author of
  this project and it is not necessarily correct. A patch is executed internally (run by internal MCU) of the device.
  Usually, patches are used to fixes bugs or add improvements and new features of the firmware installed in the internal ROM of the device.
  Patches to the SI4735 are distributed in binary form and have to be transferred to the internal RAM of the device by
  the host MCU (in this case Arduino). Since the RAM is volatile memory, the patch stored into the device gets lost when you turn off the system.
  Consequently, the content of the patch has to be transferred again to the device each time after turn on the system or reset the device.

  ATTENTION: The author of this project does not guarantee that procedures shown here will work in your development environment.
  Given this, it is at your own risk to continue with the procedures suggested here.
  This library works with the I2C communication protocol and it is designed to apply a SSB extension PATCH to CI SI4735-D60.
  Once again, the author disclaims any liability for any damage this procedure may cause to your SI4735 or other devices that you are using.

  Features of this sketch:

  1) FM, AM (MW and SW) and SSB (LSB and USB);
  2) Audio bandwidth filter 0.5, 1, 1.2, 2.2, 3 and 4Khz;
  3) 22 commercial and ham radio bands pre configured;
  4) BFO Control; and
  5) Frequency step switch (1, 5 and 10KHz);

  Main Parts:
  Encoder with push button;
  Seven bush buttons;
  LCD20x4 with I2C device;
  Arduino Pro mini 3.3V;

  Prototype documentation : https://pu2clr.github.io/SI4735/
  PU2CLR Si47XX API documentation: https://pu2clr.github.io/SI4735/extras/apidoc/html/

  By Ricardo Lima Caratti, Nov 2019.
*/

#include <SI4735.h>
#include <LiquidCrystal_I2C.h>
#include "Rotary.h"

// Test it with patch_init.h or patch_full.h. Do not try load both.
#include "patch_init.h" // SSB patch for whole SSBRX initialization string
//#include "patch_full.h"    // SSB patch for whole SSBRX full download

const uint16_t size_content = sizeof ssb_patch_content; // see ssb_patch_content in patch_full.h or patch_init.h

#define FM_BAND_TYPE 0
#define MW_BAND_TYPE 1
#define SW_BAND_TYPE 2
#define LW_BAND_TYPE 3

// OLED Diaplay constants
#define I2C_ADDRESS 0x3C
#define RST_PIN -1 // Define proper RST_PIN if required.

#define RESET_PIN 12

// Enconder PINs
#define ENCODER_PIN_A 3
#define ENCODER_PIN_B 2

// Buttons controllers
#define MODE_SWITCH 4      // Switch MODE (Am/LSB/USB)
#define BANDWIDTH_BUTTON 5 // Used to select the banddwith. Values: 1.2, 2.2, 3.0, 4.0, 0.5, 1.0 KHz
#define VOL_UP 6           // Volume Up
#define VOL_DOWN 7         // Volume Down
#define BAND_BUTTON_UP 8   // Next band
#define BAND_BUTTON_DOWN 9 // Previous band
#define AGC_SWITCH 11      // Switch AGC ON/OF
#define STEP_SWITCH 10     // Used to select the increment or decrement frequency step (1, 5 or 10 KHz)
#define BFO_SWITCH A2      // Used to select the enconder control (BFO or VFO)

#define MIN_ELAPSED_TIME 100
#define MIN_ELAPSED_RSSI_TIME 150

#define DEFAULT_VOLUME 15 // change it for your favorite sound volume

#define FM 0
#define LSB 1
#define USB 2
#define AM 3
#define LW 4

#define SSB 1

const char *bandModeDesc[] = {"FM ", "LSB", "USB", "AM "};
uint8_t currentMode = FM;

bool bfoOn = false;
bool disableAgc = true;
bool ssbLoaded = false;
bool fmStereo = true;

int currentBFO = 0;
int previousBFO = 0;

long elapsedRSSI = millis();
long elapsedButton = millis();
long elapsedFrequency = millis();

// Encoder control variables
volatile int encoderCount = 0;

// Some variables to check the SI4735 status
uint16_t currentFrequency;
uint16_t previousFrequency;
uint8_t currentStep = 1;
uint8_t currentBFOStep = 25;

uint8_t bwIdxSSB = 2;
const char *bandwitdthSSB[] = {"1.2", "2.2", "3.0", "4.0", "0.5", "1.0"};

uint8_t bwIdxAM = 1;
const char *bandwitdthAM[] = {"6", "4", "3", "2", "1", "1.8", "2.5"};

/*
   Band data structure
*/
typedef struct
{
  uint8_t bandType;     // Band type (FM, MW or SW)
  uint16_t minimumFreq; // Minimum frequency of the band
  uint16_t maximumFreq; // maximum frequency of the band
  uint16_t currentFreq; // Default frequency or current frequency
  uint16_t currentStep; // Defeult step (increment and decrement)
} Band;

/*
   Band table
*/
Band band[] = {
  {FM_BAND_TYPE, 8400, 10800, 10390, 10},
  {LW_BAND_TYPE, 100, 510, 300, 1},
  {MW_BAND_TYPE, 520, 1720, 810, 10},
  {SW_BAND_TYPE, 1800, 3500, 1900, 1}, // 160 meters
  {SW_BAND_TYPE, 3500, 4500, 3700, 1}, // 80 meters
  {SW_BAND_TYPE, 4500, 5500, 4850, 5},
  {SW_BAND_TYPE, 5600, 6300, 6000, 5},
  {SW_BAND_TYPE, 6800, 7800, 7200, 5}, // 40 meters
  {SW_BAND_TYPE, 9200, 10000, 9600, 5},
  {SW_BAND_TYPE, 10000, 11000, 10100, 1}, // 30 meters
  {SW_BAND_TYPE, 11200, 12500, 11940, 5},
  {SW_BAND_TYPE, 13400, 13900, 13600, 5},
  {SW_BAND_TYPE, 14000, 14500, 14200, 1}, // 20 meters
  {SW_BAND_TYPE, 15000, 15900, 15300, 5},
  {SW_BAND_TYPE, 17200, 17900, 17600, 5},
  {SW_BAND_TYPE, 18000, 18300, 18100, 1},  // 17 meters
  {SW_BAND_TYPE, 21000, 21900, 21200, 1},  // 15 mters
  {SW_BAND_TYPE, 24890, 26200, 24940, 1},  // 12 meters
  {SW_BAND_TYPE, 26200, 27900, 27500, 1},  // CB band (11 meters)
  {SW_BAND_TYPE, 28000, 30000, 28400, 1}
}; // 10 meters

const int lastBand = (sizeof band / sizeof(Band)) - 1;
int bandIdx = 0;

uint8_t rssi = 0;
uint8_t stereo = 1;
uint8_t volume = DEFAULT_VOLUME;

// Devices class declarations
Rotary encoder = Rotary(ENCODER_PIN_A, ENCODER_PIN_B);
LiquidCrystal_I2C display(0x3F, 20, 4); // please check the address of your I2C device
SI4735 si4735;

void setup()
{
  // Encoder pins
  pinMode(ENCODER_PIN_A, INPUT_PULLUP);
  pinMode(ENCODER_PIN_B, INPUT_PULLUP);

  pinMode(BANDWIDTH_BUTTON, INPUT_PULLUP);
  pinMode(BAND_BUTTON_UP, INPUT_PULLUP);
  pinMode(BAND_BUTTON_DOWN, INPUT_PULLUP);
  pinMode(VOL_UP, INPUT_PULLUP);
  pinMode(VOL_DOWN, INPUT_PULLUP);
  pinMode(BFO_SWITCH, INPUT);//modificado para uno
  pinMode(AGC_SWITCH, INPUT_PULLUP);
  pinMode(STEP_SWITCH, INPUT_PULLUP);
  pinMode(MODE_SWITCH, INPUT_PULLUP);

  display.init();

  delay(500);

  // Splash - Change it for your introduction text.
  display.backlight();
  display.setCursor(7, 0);
  display.print("SI4735");
  display.setCursor(2, 1);
  display.print("Arduino Library");
  delay(500);
  display.setCursor(1, 2);
  display.print("All in One Radio");
  delay(500);
  display.setCursor(0, 3);
  display.print("V1.1.5 - By PU2CLR");
  delay(2000);
  // end Splash

  // Encoder interrupt
  attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), rotaryEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_B), rotaryEncoder, CHANGE);

  si4735.setup(RESET_PIN, FM_BAND_TYPE);

  // Set up the radio for the current band (see index table variable bandIdx )
  useBand();
  delay(200);
  currentFrequency = previousFrequency = si4735.getFrequency();

  si4735.setVolume(volume);
  display.clear();
  showStatus();
}

// Use Rotary.h and  Rotary.cpp implementation to process encoder via interrupt
void rotaryEncoder()
{ // rotary encoder events
  uint8_t encoderStatus = encoder.process();
  if (encoderStatus)
  {
    if (encoderStatus == DIR_CW)
    {
      encoderCount = 1;
    }
    else
    {
      encoderCount = -1;
    }
  }
}


void clearLine4() {
  display.setCursor(0, 2);
  display.print("                    ");
}

// Show current frequency

void showFrequency()
{
  String freqDisplay;
  String unit;
  String bandMode;
  int divider = 1;
  int decimals = 3;
  if (band[bandIdx].bandType == FM_BAND_TYPE)
  {
    divider = 100;
    decimals = 1;
    unit = "MHz";
  }
  else if (band[bandIdx].bandType == MW_BAND_TYPE || band[bandIdx].bandType == LW_BAND_TYPE)
  {
    divider = 1;
    decimals = 0;
    unit = "KHz";
  }
  else
  {
    divider = 1000;
    decimals = 3;
    unit = "KHz";
  }

  if ( !bfoOn )
    freqDisplay = String((float)currentFrequency / divider, decimals);
  else
    freqDisplay = ">" + String((float)currentFrequency / divider, decimals) + "<";

  display.setCursor(7, 0);
  display.print("        ");
  display.setCursor(7, 0);
  display.print(freqDisplay);

  if (currentFrequency < 520 )
    bandMode = "LW  ";
  else
    bandMode = bandModeDesc[currentMode];

  display.setCursor(0, 0);
  display.print(bandMode);

  display.setCursor(17, 0);
  display.print(unit);
}

/*
    Show some basic information on display
*/
void showStatus()
{

  showFrequency();

  display.setCursor(13, 1);
  display.print("      ");
  display.setCursor(13, 1);
  display.print("St: ");
  display.print(currentStep);

  display.setCursor(0, 3);
  display.print("           ");
  display.setCursor(0, 3);

  if (currentMode == LSB || currentMode == USB)
  {
    display.print("BW:");
    display.print(String(bandwitdthSSB[bwIdxSSB]));
    display.print("KHz");
    showBFO();
  }
  else if (currentMode == AM)
  {
    display.print("BW:");
    display.print(String(bandwitdthAM[bwIdxAM]));
    display.print("KHz");
  }

  // Show AGC Information
  si4735.getAutomaticGainControl();
  display.setCursor(0, 1);
  display.print((si4735.isAgcEnabled()) ? "AGC ON " : "AGC OFF");

  showRSSI();
  showVolume();
}

/* *******************************
   Shows RSSI status
*/
void showRSSI()
{
  int bars = ((rssi / 10.0) / 2.0) + 1;

  display.setCursor(13, 3);
  display.print("       ");
  display.setCursor(13, 3);
  display.print("S:");
  if ( bars > 5 )  {
    bars = 5;
  }
  for (int i = 0; i < bars; i++)
    display.print(">");

  if ( currentMode == FM) {
    display.setCursor(0, 3);
    display.print((si4735.getCurrentPilot()) ? "STEREO   " : "MONO     ");
  }

}

/*
   Shows the volume level on LCD
*/
void showVolume()
{
  display.setCursor(10, 3);
  display.print("  ");
  display.setCursor(10, 3);
  display.print(si4735.getCurrentVolume());
}

/*
   Shows the BFO current status.
   Must be called only on SSB mode (LSB or USB)
*/
void showBFO()
{

  String bfo;

  if (currentBFO > 0)
    bfo = "+" + String(currentBFO);
  else
    bfo = String(currentBFO);

  display.setCursor(0, 2);
  display.print("         ");
  display.setCursor(0, 2);
  display.print("BFO:");
  display.print(bfo);
  display.print("Hz ");

  display.setCursor(13, 2);
  display.print("       ");
  display.setCursor(13, 2);
  display.print("St: ");
  display.print(currentBFOStep);
}

/*
   Goes to the next band (see Band table)
*/
void bandUp()
{
  // save the current frequency for the band
  band[bandIdx].currentFreq = currentFrequency;
  band[bandIdx].currentStep = currentStep;

  if (bandIdx < lastBand)
  {
    bandIdx++;
  }
  else
  {
    bandIdx = 0;
  }
  useBand();
}

/*
   Goes to the previous band (see Band table)
*/
void bandDown()
{
  // save the current frequency for the band
  band[bandIdx].currentFreq = currentFrequency;
  band[bandIdx].currentStep = currentStep;
  if (bandIdx > 0)
  {
    bandIdx--;
  }
  else
  {
    bandIdx = lastBand;
  }
  useBand();
}

/*
   This function loads the contents of the ssb_patch_content array into the CI (Si4735) and starts the radio on
   SSB mode.
*/
void loadSSB()
{
  display.setCursor(0, 2);
  display.print("  Switching to SSB  ");

  si4735.reset();
  si4735.queryLibraryId(); // Is it really necessary here?  Just powerDown() maigh work!
  si4735.patchPowerUp();
  delay(50);
  // si4735.setI2CFastMode(); // Recommended
  si4735.setI2CFastModeCustom(500000); // It is a test and may crash.
  si4735.downloadPatch(ssb_patch_content, size_content);
  si4735.setI2CStandardMode(); // goes back to default (100KHz)
  clearLine4();

  // delay(50);
  // Parameters
  // AUDIOBW - SSB Audio bandwidth; 0 = 1.2KHz (default); 1=2.2KHz; 2=3KHz; 3=4KHz; 4=500Hz; 5=1KHz;
  // SBCUTFLT SSB - side band cutoff filter for band passand low pass filter ( 0 or 1)
  // AVC_DIVIDER  - set 0 for SSB mode; set 3 for SYNC mode.
  // AVCEN - SSB Automatic Volume Control (AVC) enable; 0=disable; 1=enable (default).
  // SMUTESEL - SSB Soft-mute Based on RSSI or SNR (0 or 1).
  // DSP_AFCDIS - DSP AFC Disable or enable; 0=SYNC MODE, AFC enable; 1=SSB MODE, AFC disable.
  si4735.setSSBConfig(bwIdxSSB, 1, 0, 0, 0, 1);
  delay(25);
  ssbLoaded = true;
  display.clear();
}

/*
   Switch the radio to current band.
   The bandIdx variable points to the current band.
   This function change to the band referenced by bandIdx (see table band).
*/
void useBand()
{
  clearLine4();
  if (band[bandIdx].bandType == FM_BAND_TYPE)
  {
    currentMode = FM;
    si4735.setTuneFrequencyAntennaCapacitor(0);
    si4735.setFM(band[bandIdx].minimumFreq, band[bandIdx].maximumFreq, band[bandIdx].currentFreq, band[bandIdx].currentStep);
    bfoOn = ssbLoaded = false;

  }
  else
  {
    if (band[bandIdx].bandType == MW_BAND_TYPE || band[bandIdx].bandType == LW_BAND_TYPE)
      si4735.setTuneFrequencyAntennaCapacitor(0);
    else
      si4735.setTuneFrequencyAntennaCapacitor(1);

    if (ssbLoaded)
    {
      si4735.setSSB(band[bandIdx].minimumFreq, band[bandIdx].maximumFreq, band[bandIdx].currentFreq, band[bandIdx].currentStep, currentMode);
      si4735.setSSBAutomaticVolumeControl(1);
      si4735.setSsbSoftMuteMaxAttenuation(0); // Disable Soft Mute for SSB
    }
    else
    {
      currentMode = AM;
      si4735.setAM(band[bandIdx].minimumFreq, band[bandIdx].maximumFreq, band[bandIdx].currentFreq, band[bandIdx].currentStep);
      si4735.setAutomaticGainControl(1, 0);
      si4735.setAmSoftMuteMaxAttenuation(0); // // Disable Soft Mute for AM
      bfoOn = false;
    }

  }
  delay(100);
  currentFrequency = band[bandIdx].currentFreq;
  currentStep = band[bandIdx].currentStep;
  showStatus();
}


void loop()
{
  // Check if the encoder has moved.
  if (encoderCount != 0)
  {
    if (bfoOn)
    {
      currentBFO = (encoderCount == 1) ? (currentBFO + currentBFOStep) : (currentBFO - currentBFOStep);
    }
    else
    {
      if (encoderCount == 1)
        si4735.frequencyUp();
      else
        si4735.frequencyDown();

      // Show the current frequency only if it has changed
      currentFrequency = si4735.getFrequency();
    }
    encoderCount = 0;
  }

  // Check button commands
  if ((millis() - elapsedButton) > MIN_ELAPSED_TIME)
  {
    // check if some button is pressed
    if (digitalRead(BANDWIDTH_BUTTON) == LOW)
    {
      if (currentMode == LSB || currentMode == USB)
      {
        bwIdxSSB++;
        if (bwIdxSSB > 5)
          bwIdxSSB = 0;
        si4735.setSSBAudioBandwidth(bwIdxSSB);
        // If audio bandwidth selected is about 2 kHz or below, it is recommended to set Sideband Cutoff Filter to 0.
        if (bwIdxSSB == 0 || bwIdxSSB == 4 || bwIdxSSB == 5)
          si4735.setSBBSidebandCutoffFilter(0);
        else
          si4735.setSBBSidebandCutoffFilter(1);
      }
      else if (currentMode == AM)
      {
        bwIdxAM++;
        if (bwIdxAM > 6)
          bwIdxAM = 0;
        si4735.setBandwidth(bwIdxAM, 1);
      }
      showStatus();
      delay(MIN_ELAPSED_TIME); // waits a little more for releasing the button.
    }
    else if (digitalRead(BAND_BUTTON_UP) == LOW)
      bandUp();
    else if (digitalRead(BAND_BUTTON_DOWN) == LOW)
      bandDown();
    else if (digitalRead(VOL_UP) == LOW)
    {
      si4735.volumeUp();
      delay(MIN_ELAPSED_TIME); // waits a little more for releasing the button.
    }
    else if (digitalRead(VOL_DOWN) == LOW)
    {
      si4735.volumeDown();
      delay(MIN_ELAPSED_TIME); // waits a little more for releasing the button.
    }
    else if (digitalRead(BFO_SWITCH) == LOW)
    {
      if (currentMode == LSB || currentMode == USB) {
        bfoOn = !bfoOn;
        if (bfoOn)
          showBFO();
        showStatus();
      } else if (currentMode == FM) {
        si4735.seekStationUp();
        delay(30);
        currentFrequency = si4735.getFrequency();
      }
      delay(MIN_ELAPSED_TIME); // waits a little more for releasing the button.
    }
    else if (digitalRead(AGC_SWITCH) == LOW)
    {
      disableAgc = !disableAgc;
      // siwtch on/off ACG; AGC Index = 0. It means Minimum attenuation (max gain)
      si4735.setAutomaticGainControl(disableAgc, 1);
      showStatus();
    }
    else if (digitalRead(STEP_SWITCH) == LOW)
    {
      if ( currentMode == FM) {
        fmStereo = !fmStereo;
        if ( fmStereo )
          si4735.setFmStereoOn();
        else
          si4735.setFmStereoOff(); // It is not working so far.
      } else {

        // This command should work only for SSB mode
        if (bfoOn && (currentMode == LSB || currentMode == USB))
        {
          currentBFOStep = (currentBFOStep == 25) ? 10 : 25;
          showBFO();
        }
        else
        {
          if (currentStep == 1)
            currentStep = 5;
          else if (currentStep == 5)
            currentStep = 10;
          else
            currentStep = 1;
          si4735.setFrequencyStep(currentStep);
          band[bandIdx].currentStep = currentStep;
          showStatus();
        }
        delay(MIN_ELAPSED_TIME); // waits a little more for releasing the button.
      }
    }
    else if (digitalRead(MODE_SWITCH) == LOW)
    {
      if (currentMode != FM ) {
        if (currentMode == AM)
        {
          // If you were in AM mode, it is necessary to load SSB patch (avery time)
          loadSSB();
          currentMode = LSB;
        }
        else if (currentMode == LSB)
        {
          currentMode = USB;
        }
        else if (currentMode == USB)
        {
          currentMode = AM;
          ssbLoaded = false;
          bfoOn = false;
        }
        // Nothing to do if you are in FM mode
        band[bandIdx].currentFreq = currentFrequency;
        band[bandIdx].currentStep = currentStep;
        useBand();
      }
    }
    elapsedButton = millis();
  }

  // Show the current frequency only if it has changed
  if (currentFrequency != previousFrequency)
  {
    previousFrequency = currentFrequency;
    showFrequency();
  }

  // Show RSSI status only if this condition has changed
  if ((millis() - elapsedRSSI) > MIN_ELAPSED_RSSI_TIME * 12)
  {
    si4735.getCurrentReceivedSignalQuality();
    int aux = si4735.getCurrentRSSI();
    if (rssi != aux)
    {
      rssi = aux;
      showRSSI();
    }
    elapsedRSSI = millis();
  }

  // Show volume level only if this condition has changed
  if (si4735.getCurrentVolume() != volume)
  {
    volume = si4735.getCurrentVolume();
    showVolume();
  }

  if (currentMode == LSB || currentMode == USB)
  {
    if (currentBFO != previousBFO)
    {
      previousBFO = currentBFO;
      si4735.setSSBBfo(currentBFO);
      showBFO();
    }
  }
 
  delay(10);
}