Arduino UNO AF/FM Radio Si4844-B20 I2C Issues

Status
Not open for further replies.

djsfantasi

Joined Apr 11, 2010
9,237
I know the analogread() function gives values between 0 and 1023 (0 to 5V) for an analog potentiometer. If I can somehow scale this to be 0 to 64, shouldn’t it work with the chip?
The Arduino variant of C includes a “map” function if you have trouble with the algebra. Instead of using the map function, divide the value returned by analogRead() by 16 and you’ll have a value in the range of 0-64. Or you can use the map() function. It’s up to you!
 
I must confess that I did not read your initial post about the pot correctly. I carelessly and immediately thought that you wanted to use pots to directly attenuate the LOUT and ROUT signals rather than use the digital VOL commands.

Using an analog input pin and a MAP, as suggested, might work.

Below are the Vol_up() and Vol_down() commands from the program. In the project article, I chose to track a current volume setting and execute changes. You can see from the code that you do not have to do that at all. That is, you can send the chip a volume value straight away.


C:
void Vol_up()
{
  // we operate in the audio default Mixed Mode 2
  // assume that current_vol is accurate
  if (current_vol <63)
  {
  current_vol++;
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(SET_PROPERTY);  
  Wire.write(0x00);  // ARG1
  Wire.write(RX_VOLUME);  // ARG2 RX_VOLUME 0x40
  Wire.write(0x00);  // ARG3
  Wire.write(0x00);  // ARG4
  Wire.write(current_vol);  // ARG5 is actual volume 0-63
  Wire.endTransmission();
  display_vol();
  }
}

void Vol_down()
{
  // we operate in the default Mixed Mode 2
  // assume that current_vol is accurate
  if (current_vol >0)
  {
  current_vol--;
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(SET_PROPERTY);  
  Wire.write(0x00);  // ARG1
  Wire.write(RX_VOLUME);  // ARG2 RX_VOLUME 0x40
  Wire.write(0x00);  // ARG3
  Wire.write(0x00);  // ARG4
  Wire.write(current_vol);  // ARG5 is actual volume 0-63
  Wire.endTransmission();
  display_vol();
  }
}
At the point you appear to be at now, I would suggest that you build a block diagram of all the controls that you want - if you have not already done so. This will save you some time in the long run.

I also have to admit that this thread sort of teases me to build a second project. I am very happy the project, still use it regularly, and...as I find myself stating repeatedly, it is still on the breadboard.:)
 

Thread Starter

talexander

Joined Feb 5, 2019
33
I must confess that I did not read your initial post about the pot correctly. I carelessly and immediately thought that you wanted to use pots to directly attenuate the LOUT and ROUT signals rather than use the digital VOL commands.

Using an analog input pin and a MAP, as suggested, might work.

Below are the Vol_up() and Vol_down() commands from the program. In the project article, I chose to track a current volume setting and execute changes. You can see from the code that you do not have to do that at all. That is, you can send the chip a volume value straight away.


C:
void Vol_up()
{
  // we operate in the audio default Mixed Mode 2
  // assume that current_vol is accurate
  if (current_vol <63)
  {
  current_vol++;
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(SET_PROPERTY);
  Wire.write(0x00);  // ARG1
  Wire.write(RX_VOLUME);  // ARG2 RX_VOLUME 0x40
  Wire.write(0x00);  // ARG3
  Wire.write(0x00);  // ARG4
  Wire.write(current_vol);  // ARG5 is actual volume 0-63
  Wire.endTransmission();
  display_vol();
  }
}

void Vol_down()
{
  // we operate in the default Mixed Mode 2
  // assume that current_vol is accurate
  if (current_vol >0)
  {
  current_vol--;
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(SET_PROPERTY);
  Wire.write(0x00);  // ARG1
  Wire.write(RX_VOLUME);  // ARG2 RX_VOLUME 0x40
  Wire.write(0x00);  // ARG3
  Wire.write(0x00);  // ARG4
  Wire.write(current_vol);  // ARG5 is actual volume 0-63
  Wire.endTransmission();
  display_vol();
  }
}
At the point you appear to be at now, I would suggest that you build a block diagram of all the controls that you want - if you have not already done so. This will save you some time in the long run.

I also have to admit that this thread sort of teases me to build a second project. I am very happy the project, still use it regularly, and...as I find myself stating repeatedly, it is still on the breadboard.:)
I'm near the end of my project and have everything finished except some last minute programming. I designed a circuit board and will be posting the project at a later date. I included all of my modified code. I am trying to use potentiometers instead of the keypad and I'm not quite having success with the input selecting (executed in void(loop) lines 78-94). The band is changed from a high signal sent from another Arduino to one of three pins (A0-A2 for AM, FM, SW) because this potentiometer is hooked up to the other Arduino. The volume potentiometer will be hooked up directly to an analog pin on the Arduino controlling the AM/FM/SW radio. I know that it's probably a small change to my current code and after getting the input selection the volume will be easy. To be clear, the only variables that I want to change are the volume and band. Still no luck with the volume either (none of the code below is different than the original for volume control - so far just input). Please help!

Code:
#include <Wire.h>  // for the Arduino wire library (I2C)
#define Si_ADDRESS 0x11
#define ATDD_POWER_DOWN 0x11
#define ATDD_POWER_UP  0xE1
#define ATDD_XOWAIT  0x40
#define SET_PROPERTY  0x12
#define RX_VOLUME  0x40
#define ATDD_GET_STATUS 0xE0
// Globals
// Arduino Pins D2=IRQ D7=reset
const byte INTpin = 2;
const byte RESETpin = 7;
// for the ISR
volatile byte IRQflag;
// Default bands within FM/AM/SW - the band we start with when switching modes
byte d_FM_band = 8;
byte d_AM_band = 22;
byte d_SW_band = 31;
byte status_rsp[4];  // holds response bytes following commands
byte current_band = 0;  // 0=FM 1-AM 2=SW  if there has been no power down we will start with 0
byte current_bandix;  // current band index
byte current_mute = 0;  // 0=off 1=on (muted)
byte current_font;  // 0=small 1=medium
byte current_vol = 30;  // default boot up value is 63
byte current_BT = 4;  // default boot up value is 4 or 3 FM/AM
byte power_mode = 1;  // denotes if we are in power down mode (1=power on 0=power off (powered down))
byte mute_mode = 0;  // denotes mute mode (1=on 0=off)
char buf2[3];  // for itoa conversion up to two characters
int d1, d2, d3, d4;  // for an easy print
// Band Range strings to make display easy and fast
char * BandRange[] = {"  87-108  ", "  87-108  ", "  87-108  ", "  87-108  ", "  86.5-109 ", "  86.5-109 ", "  86.5-109 ", "  86.5-109 ",
  "87.3-108.25", "87.3-108.25", "87.3-108.25", "87.3-108.25", "  76-90  ", "  76-90  ", "  76-90  ", "  76-90  ", "  64-87  ", "  64-87  ",
  "  64-87  ", "  64-87  ", "  520-1710 ", "  522-1620 ", "  504-1665 ", "  520-1730 ", "  510-1750 ", "  5.6-6.4  ", "  5.95-6.2 ", "  6.8-7.6  ",
  "  7.1-7.6  ", "  9.2-10  ", "  9.2-9.9  ", "11.45-12.25", " 11.6-12.2 ", " 13.4-14.2 ", "13.57-13.87", "  15-15.9  ", " 15.1-15.8 ", "  17.1-18  ",
  " 17.48-17.9", "  21.2-22  ", "21.45-21.85"
  };
//input pins
const int FM_Input = A0;
const int AM_Input = A1;
const int SW_Input = A2;
int FM_State = 0;
int AM_State = 0;
int SW_State = 0;
void setup() {
  // set up pins and IRQ
  // interrupt active HIGH
  pinMode (INTpin, INPUT);
  // reset pin
  pinMode(RESETpin, OUTPUT);
  digitalWrite(RESETpin, HIGH);
  // ISR
  attachInterrupt(0, SiISR, RISING);
  // switch to the FM band with the default band_idx
  SiReset();
  current_bandix = d_FM_band;
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band = (status_rsp[1] >> 6);
  current_bandix = (status_rsp[1] & B00111111);
  go_current();  // will set up for default VOL BT and Mute
}
void loop() {
  // Check for tuning changes
  if (IRQflag)
  {
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(ATDD_GET_STATUS);
  Wire.endTransmission();
  Wire.requestFrom(Si_ADDRESS, 0x04);
  status_rsp[0] = Wire.read();
  status_rsp[1] = Wire.read();
  status_rsp[2] = Wire.read();
  status_rsp[3] = Wire.read();
  IRQflag = 0;
  }
  IRQflag = 0;
  FM_State = analogRead(FM_Input);
  AM_State = analogRead(AM_Input);
  SW_State = analogRead(SW_Input);
  if (FM_State == HIGH)
  {
  Go_FM();
  }
  if (AM_State == HIGH)
  {
  Go_AM();
  }
  if (SW_State == HIGH)
  {
  Go_SW();
  }
}
void SiReset()
{
  // reset Si4844 and back up
  // switch I2C to 10kHz
  I2C_10kHz();
  IRQflag = 0;
  digitalWrite(RESETpin, LOW);
  delayMicroseconds(200);
  digitalWrite(RESETpin, HIGH);
  delayMicroseconds(200);
  // wait for an IRQ rising edge
  while (!IRQflag);
  // wait for 2.5 ms
  delayMicroseconds(2500);
}
void SiGetStatus()
{
  // send a get status command and wait for 2 ms before testing response byte
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(ATDD_GET_STATUS);
  Wire.endTransmission();
  delayMicroseconds(2000);
  // test response byte
  Wire.requestFrom(Si_ADDRESS, 0x04);
  for (int x = 0; x < 4; x++)
  {
  status_rsp[x] = Wire.read();
  }
}
void SiSetBand()
{
  // assuming CTS is ok to send, assume current_band is set
  // will do a power up AND a get status setting status_rsp[0-4]
  byte cb;
  cb = current_bandix;
  bitSet(cb, 7);  // bit 7=1 for external crystal
  bitClear(cb, 6);  // bit 6=0 for normal crystal time
  // arg[2]-[7] are not used in this mode
  IRQflag = 0;
  // send it
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(ATDD_POWER_UP);
  Wire.write(cb);
  Wire.endTransmission();
  // wait for an IRQ for tune wheel frequency ready
  delayMicroseconds(2500);
  while (!IRQflag);
  // wait for 2.5 ms because our IRQ is rising edge
  delayMicroseconds(2500);
  I2C_50kHz();
  // send a get status and wait for 2 ms before testing response byte
  get_status();
}
void Vol_up()
{
  // we operate in the audio default Mixed Mode 2
  // assume that current_vol is accurate
  if (current_vol < 63)
  {
  current_vol++;
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(SET_PROPERTY);
  Wire.write(0x00);  // ARG1
  Wire.write(RX_VOLUME);  // ARG2 RX_VOLUME 0x40
  Wire.write(0x00);  // ARG3
  Wire.write(0x00);  // ARG4
  Wire.write(current_vol);  // ARG5 is actual volume 0-63
  Wire.endTransmission();
  }
}
void Vol_down()
{
  // we operate in the default Mixed Mode 2
  // assume that current_vol is accurate
  if (current_vol > 0)
  {
  current_vol--;
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(SET_PROPERTY);
  Wire.write(0x00);  // ARG1
  Wire.write(RX_VOLUME);  // ARG2 RX_VOLUME 0x40
  Wire.write(0x00);  // ARG3
  Wire.write(0x00);  // ARG4
  Wire.write(current_vol);  // ARG5 is actual volume 0-63
  Wire.endTransmission();
  }
}
void Go_FM()
{
  // switch to the FM band with the default band_idx
  SiReset();
  current_bandix = d_FM_band;
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band = (status_rsp[1] >> 6);
  current_bandix = (status_rsp[1] & B00111111);
  go_current();
}
void Go_AM()
{
  // switch to the AM band with the default band_idx
  SiReset();
  current_bandix = d_AM_band;
  SiSetBand();
  // in testing the this never loops
  get_status();
  // power up is completed so get the values from the chip
  current_band = (status_rsp[1] >> 6);
  current_bandix = (status_rsp[1] & B00111111);
  go_current();
}
void Go_SW()
{
  // switch to the SW band with the default band_idx
  SiReset();
  current_bandix = d_SW_band;
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band = (status_rsp[1] >> 6);
  current_bandix = (status_rsp[1] & B00111111);
  go_current();
}
void go_current()
{
  // restore current settings when we switch AM/FM/SW
  // set the Vol to whatever current_vol is
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(SET_PROPERTY);
  Wire.write(0x00);  // ARG1
  Wire.write(RX_VOLUME);  // ARG2 RX_VOLUME 0x40
  Wire.write(0x00);  // ARG3
  Wire.write(0x00);  // ARG4
  Wire.write(current_vol);  // ARG5 is actual volume 0-63
  Wire.endTransmission();
}

void Band_up()
{
  // increase the band index by 1
  // assume current_band and current_bandix are accurate
  switch (current_band)
  {
  case 0: // FM is 0 19
  if (current_bandix < 19)
  {
  current_bandix++;
  }
  break;
  case 1:  // AM is 20-24
  if (current_bandix < 24)
  {
  current_bandix++;
  }
  break;
  case 2:  //  SW is 25-40
  if (current_bandix < 40)
  {
  current_bandix++;
  }
  break;
  default:
  // error - take no action
  break;
  }
  SiReset();
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band = (status_rsp[1] >> 6);
  current_bandix = (status_rsp[1] & B00111111);
  go_current();
}
void Band_down()
{
  // decrease the band index by 1
  // assume current_band and current_bandix are accurate
  switch (current_band)
  {
  case 0: // FM is 0 19
  if (current_bandix > 0)
  {
  current_bandix--;
  }
  break;
  case 1:  // AM is 20-24
  if (current_bandix > 20)
  {
  current_bandix--;
  }
  break;
  case 2:  //  SW is 25-40
  if (current_bandix > 25)
  {
  current_bandix--;
  }
  break;
  default:
  // error - take no action
  break;
  }
  SiReset();
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band = (status_rsp[1] >> 6);
  current_bandix = (status_rsp[1] & B00111111);
  go_current();
}
void get_status()
{
  // do SiGetStatus until we have valid frequency info in status_rsp
  // note: in testing we don't loop but it is a good practice
  // also, an error out routine can be added here so it can escape
  // after a certain number of attempts
Waitforgo:
  SiGetStatus();
  if ( ((bitRead(status_rsp[0], 4) == 0) || ( (status_rsp[2] == 0) && (status_rsp[3] == 0))) )
  {
  goto Waitforgo;
  }
}
// NOTE: These speed routines for I2C are for an 8mhz, 3.3v Pro Mini
// They need to be changed for a 16 mHz UNO or other Arduinos
void I2C_10kHz()
{
  // set I2C speed to 10Khz on an 8mHz chip
  TWBR = 98;
  TWSR |= bit(TWPS0);
}
void I2C_50kHz()
{
  // set I2C speed to 50Khz on an 8mHz chip
  TWBR = 18;
  TWSR |= bit(TWPS0);
}
// The interrupt service routine
void SiISR()
{
  IRQflag = 1;
}
 
Last edited:
I'm near the end of my project and have everything finished except some last minute programming. I designed a circuit board and will be posting the project at a later date. I included all of my modified code. I am trying to use potentiometers instead of the keypad and I'm not quite having success with the input selecting (executed in void(loop) lines 78-94). The band is changed from a high signal sent from another Arduino to one of three pins (A0-A2 for AM, FM, SW) because this potentiometer is hooked up to the other Arduino. The volume potentiometer will be hooked up directly to an analog pin on the Arduino controlling the AM/FM/SW radio. I know that it's probably a small change to my current code and after getting the input selection the volume will be easy. To be clear, the only variables that I want to change are the volume and band. Still no luck with the volume either (none of the code below is different than the original for volume control - so far just input). Please help!
There is far too much in your condensed paragraph to wrap my head around all at once. So, maybe it would be helpful to look at and explain how I did it and then see how you want to modify it, how you have modified it, and what your way is doing or not doing. That much, I can try to do. Also, all that I am referencing here is in connection to the Si4844-A10 so you will need to reconcile any small differences between the chips.

First of all, I have three buttons (keys on the keypad) that set AM/FM/SW. Remember, however, that what I am really doing when I "set" AM/FM/SW is setting a band.

From the original article: https://www.allaboutcircuits.com/projects/build-an-arduino-controlled-am-fm-sw-radio/

Rather than simply setting an AM/FM/SW “register”, the radio chip can be set to one of 41 different frequency bands. Bands 0-19 are FM, 87-109 mHz; bands 20-24 are AM, 504-1750 kHz; bands 25-40 are SW, 5.6-22.0 mHz.

and

Keypad Function Definitions:

  • AM : Switch to AM mode, band 22
  • FM : Switch to FM mode, band 8
  • SW : Switch to SW mode, band 31
So, stop think about it as a discrete three position switch (would be a better way of doing it for you than potentiometers) and see that I am simply setting a band among all of the bands, to correspond to a default AM/FM/SW band. That is done in setup(). Notice also that I am keeping the band in a variable.
C:
  // switch to the FM band with the default band_idx
  SiReset();
  current_bandix=d_FM_band;
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band=(status_rsp[1]>>6);
  display_band();
  current_bandix=(status_rsp[1]&B00111111);
  display_band_index();
Once that default band has been set, ALL the functionality, is governed by the keypad in this routine:
C:
  // Get and process a keypress when present
  if(key=keypad.getKey())
  {
  switch(key)
  {
  case '1':
  Go_AM();
  break;
  case '2':
  Go_FM();
  break;
  case '3':
  Go_SW();
  break;
  case '4':
  Vol_up();
  break;
  case '7':
  Vol_down();
  break;
  case '5':
  Band_up();
  break;
  case '8':
  Band_down();
  break;
  case '6':
  BT_up();
  break; 
  case '9':
  BT_down();
  break;
  case '0':
  Mute();
  break;
  default:
  break;
  }
  }
Think about this, all I need to do is detect a keypad press - if there is none, then I don't make any changes. Consider how that changes with a potentiometer setting. You would have to read it and then decide whether it has been changed...see what I am getting at? It is a fundamentally different task and I am not sure that you are appreciating that.

You said:
The band is changed from a high signal sent from another Arduino to one of three pins (A0-A2 for AM, FM, SW) because this potentiometer is hooked up to the other Arduino.
Let's assume that you understand what I have said previously. The second Arduino is mapping the potentiometer setting into one of three ranges and setting the A0-A2 GPIO lines on the first Arduino. Note that you have three bits there (A0, A1 and A2) that would give you 8 possible values and you are only using 3. This is not the way to do it in my view, but that is your chosen approach and I am trying to help.

In that case, you would first read A0-A2 in setup and determine what default AM/FM/SW band to set and, once determined, set that band and a variable to hold the band value.

Then in the main loop, you would need to have a routine, let's call it Go_Band that examines A0-A2 and determines if it has been changed and acts accordingly. This actions takes the place of keypad presses case 1, case 2 and case 3, except for a notable difference is that you have to detect whether the pot has changed. All I need to do is detect if a keypad press is occurred.

Once you get to that point, the action taking is the same. That is, Go_FM gets called when there is a keypad press, case 2 for me and for you it is when A0-A2 has changed because the potentiometer on Arduino #2 has CHANGED to the analogous setting.

C:
void Go_FM()
{
  // switch to the FM band with the default band_idx
  SiReset();
  current_bandix=d_FM_band;
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band=(status_rsp[1]>>6);
  display_band();
  current_bandix=(status_rsp[1]&B00111111);
  display_band_index();
  display_frequency();
  go_current();
}
This making any sense?
 
BTW: It's going on 3 years and it is still on the breadboard (this was just taken). You might think that I would be embarrassed :). I just am woefully lacking in the ability and motivation to package projects.

 

Thread Starter

talexander

Joined Feb 5, 2019
33
BTW: It's going on 3 years and it is still on the breadboard (this was just taken). You might think that I would be embarrassed :). I just am woefully lacking in the ability and motivation to package projects.

There is far too much in your condensed paragraph to wrap my head around all at once. So, maybe it would be helpful to look at and explain how I did it and then see how you want to modify it, how you have modified it, and what your way is doing or not doing. That much, I can try to do. Also, all that I am referencing here is in connection to the Si4844-A10 so you will need to reconcile any small differences between the chips.

First of all, I have three buttons (keys on the keypad) that set AM/FM/SW. Remember, however, that what I am really doing when I "set" AM/FM/SW is setting a band.

From the original article: https://www.allaboutcircuits.com/projects/build-an-arduino-controlled-am-fm-sw-radio/

Rather than simply setting an AM/FM/SW “register”, the radio chip can be set to one of 41 different frequency bands. Bands 0-19 are FM, 87-109 mHz; bands 20-24 are AM, 504-1750 kHz; bands 25-40 are SW, 5.6-22.0 mHz.

and

Keypad Function Definitions:

  • AM : Switch to AM mode, band 22
  • FM : Switch to FM mode, band 8
  • SW : Switch to SW mode, band 31
So, stop think about it as a discrete three position switch (would be a better way of doing it for you than potentiometers) and see that I am simply setting a band among all of the bands, to correspond to a default AM/FM/SW band. That is done in setup(). Notice also that I am keeping the band in a variable.
C:
  // switch to the FM band with the default band_idx
  SiReset();
  current_bandix=d_FM_band;
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band=(status_rsp[1]>>6);
  display_band();
  current_bandix=(status_rsp[1]&B00111111);
  display_band_index();
Once that default band has been set, ALL the functionality, is governed by the keypad in this routine:
C:
  // Get and process a keypress when present
  if(key=keypad.getKey())
  {
  switch(key)
  {
  case '1':
  Go_AM();
  break;
  case '2':
  Go_FM();
  break;
  case '3':
  Go_SW();
  break;
  case '4':
  Vol_up();
  break;
  case '7':
  Vol_down();
  break;
  case '5':
  Band_up();
  break;
  case '8':
  Band_down();
  break;
  case '6':
  BT_up();
  break;
  case '9':
  BT_down();
  break;
  case '0':
  Mute();
  break;
  default:
  break;
  }
  }
Think about this, all I need to do is detect a keypad press - if there is none, then I don't make any changes. Consider how that changes with a potentiometer setting. You would have to read it and then decide whether it has been changed...see what I am getting at? It is a fundamentally different task and I am not sure that you are appreciating that.

You said:


Let's assume that you understand what I have said previously. The second Arduino is mapping the potentiometer setting into one of three ranges and setting the A0-A2 GPIO lines on the first Arduino. Note that you have three bits there (A0, A1 and A2) that would give you 8 possible values and you are only using 3. This is not the way to do it in my view, but that is your chosen approach and I am trying to help.

In that case, you would first read A0-A2 in setup and determine what default AM/FM/SW band to set and, once determined, set that band and a variable to hold the band value.

Then in the main loop, you would need to have a routine, let's call it Go_Band that examines A0-A2 and determines if it has been changed and acts accordingly. This actions takes the place of keypad presses case 1, case 2 and case 3, except for a notable difference is that you have to detect whether the pot has changed. All I need to do is detect if a keypad press is occurred.

Once you get to that point, the action taking is the same. That is, Go_FM gets called when there is a keypad press, case 2 for me and for you it is when A0-A2 has changed because the potentiometer on Arduino #2 has CHANGED to the analogous setting.

C:
void Go_FM()
{
  // switch to the FM band with the default band_idx
  SiReset();
  current_bandix=d_FM_band;
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band=(status_rsp[1]>>6);
  display_band();
  current_bandix=(status_rsp[1]&B00111111);
  display_band_index();
  display_frequency();
  go_current();
}
This making any sense?
Just to clarify I’m not trying to use a potentiometer for the input. I am using a rotary switch. The potentiometer is for volume control. Lines 78-94 show my code for this function. Sorry for being unclear and I don’t see any reason for this code not working unless it has something to do with me using if statements and you using a switch case statement. I am just calling Go_FM(), etc. when the corresponding pin is high if this makes sense!
 

Thread Starter

talexander

Joined Feb 5, 2019
33
BTW: It's going on 3 years and it is still on the breadboard (this was just taken). You might think that I would be embarrassed :). I just am woefully lacking in the ability and motivation to package projects.

I don’t blame you if it works why mess with it! Looks amazing and it’s good to hear that it still works!
 
Just to clarify I’m not trying to use a potentiometer for the input. I am using a rotary switch. The potentiometer is for volume control. Lines 78-94 show my code for this function. Sorry for being unclear and I don’t see any reason for this code not working unless it has something to do with me using if statements and you using a switch case statement. I am just calling Go_FM(), etc. when the corresponding pin is high if this makes sense!
C:
  FM_State = analogRead(FM_Input);
  AM_State = analogRead(AM_Input);
  SW_State = analogRead(SW_Input);
  if (FM_State == HIGH)
  {
  Go_FM();
  }
  if (AM_State == HIGH)
  {
  Go_AM();
  }
  if (SW_State == HIGH)
  {
  Go_SW();
  }
In your case if AM_State, FM_State and SW_State are all mutually exclusive in the sense that only ONE can be high, your code might work but it is nutty because it is going to set the band EVERY TIME THROUGH THE MAIN LOOP.

This is a completely different issue than why you are doing analog reads and deciding if they are HIGH or LOW. If you do AM_State = analogRead(AM_Input); and subsequently if (AM_State == HIGH), when will the latter evaluate to false? Only when the AM_State value=0.

Let me try to explain with pseudo code...

in the initialization code, set the band and a variable called lastband. The variable can be 0 for AM, 1-FM or 2 for SW - if you still want to use 3 bits, then do it that way. In any event, you should be reading digital inputs right? If not than where have you clearly explained that?

Read A0-A2 - return a number between 0 and 8 - call it bandsetting

if bandsetting does not equal lastband change the band (if the user hasn't messed with it do nothing

switch bandsetting

case 0 - do AM
case 1 - do FM
case 2 - do SW
default - error

lastly set lastband to bandsetting
 
Last edited:
I apologize if I seem a little frustrated but I feel like I have written more in this thread than the original article, but I suppose that is to be expected and nobody is forcing me to keep responding and I do want to see you get to where you want to go.

Please clearly illustrate how you have wired up the rotary switch. Also show me a short program that tests only the switch. That is, simply reads the switch and prints out the value(s).

On that subject, there are many ways to do this and it might depend on your specific switch, but look at this schematic:


and the accompanying article and code here http://learn.linksprite.com/project/3-way-switch-and-arduino/

Using this scheme, you would read just one analog input and decide whether the band setting should be 0, 1, or 2. From there, see my previous post (#48) for programming.
 

Thread Starter

talexander

Joined Feb 5, 2019
33
I apologize if I seem a little frustrated but I feel like I have written more in this thread than the original article, but I suppose that is to be expected and nobody is forcing me to keep responding and I do want to see you get to where you want to go.

Please clearly illustrate how you have wired up the rotary switch. Also show me a short program that tests only the switch. That is, simply reads the switch and prints out the value(s).

On that subject, there are many ways to do this and it might depend on your specific switch, but look at this schematic:


and the accompanying article and code here http://learn.linksprite.com/project/3-way-switch-and-arduino/

Using this scheme, you would read just one analog input and decide whether the band setting should be 0, 1, or 2. From there, see my previous post (#48) for programming.
After following your instructions here's where I'm at. Worrying about the switch setup aside, I should still be able to code the Arduino to switch inputs when a pin goes high. I used current_band instead of lastband if that works and I'm getting an error saying the SiIRQ is not defined. What do I need to change to make this work with the interrupt? If you can recommend any changes to the current code to make it do what you were describing I would appreciate it, otherwise I can keep trying and stop bugging you. I am in no way skilled at coding and have learned a lot from this project. I tried to simplify the code to make it shorter and easier to read.

Code:
byte current_band = 0;  // 0=FM 1-AM 2=SW  if there has been no power down we will start with 0

//input pins
const int FM_Input = A0;
const int AM_Input = A1;
const int SW_Input = A2;
int bandsetting = 0;
int FM;
int AM;
int SW;

void setup() {
  // set up pins and IRQ
  // interrupt active HIGH
  pinMode (INTpin, INPUT);
  // reset pin
  pinMode(RESETpin, OUTPUT);
  digitalWrite(RESETpin, HIGH);
  // ISR
  attachInterrupt(0, SiISR, RISING);
  // switch to the FM band with the default band_idx
  SiReset();
  current_bandix = d_FM_band;
  SiSetBand();
  get_status();
  // power up is completed so get the values from the chip
  current_band = (status_rsp[1] >> 6);
  current_bandix = (status_rsp[1] & B00111111);
  go_current();  // will set up for default VOL BT and Mute
}

void loop() {
  // Check for tuning changes
  if (IRQflag)
  {
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(ATDD_GET_STATUS);
  Wire.endTransmission();
  Wire.requestFrom(Si_ADDRESS, 0x04);
  status_rsp[0] = Wire.read();
  status_rsp[1] = Wire.read();
  status_rsp[2] = Wire.read();
  status_rsp[3] = Wire.read();
  IRQflag = 0;
  }

  FM = analogRead(FM_Input);
  AM = analogRead(AM_Input);
  SW = analogRead(SW_Input);
  if (FM = HIGH) {
  bandsetting = 0;
  }
  else if ( AM = HIGH) {
  bandsetting = 1;
  }
  else (SW = HIGH) {
  bandsetting = 2;
  }

  if (bandsetting != current_band) {
  switch (bandsetting) {
  case 0:
  Go_AM();
  break;
  case 1:
  Go_FM();
  break;
  case 2:
  Go_SW();
  break;
  default:
  break;
  }
  current_band = bandsetting;
  }
 
After following your instructions here's where I'm at. Worrying about the switch setup aside, I should still be able to code the Arduino to switch inputs when a pin goes high. I used current_band instead of lastband if that works and I'm getting an error saying the SiIRQ is not defined. What do I need to change to make this work with the interrupt? If you can recommend any changes to the current code to make it do what you were describing I would appreciate it, otherwise I can keep trying and stop bugging you. I am in no way skilled at coding and have learned a lot from this project. I tried to simplify the code to make it shorter and easier to read.
It is going to be very difficult to modify the code if you do not understand it, and there is no way around that. Such is the way it is.

The reason that you are getting an error saying the SiIRQ is not defined, is because the SiIRQ is not defined. This line of code, attachInterrupt(0, SiISR, RISING); Assigns an interrupt to the pin and assigns a routine that will be executed when an interrupt ocurrs. That is, when the pin goes from low to high, the interrupt will be asserted and control with be diverted to the defined routine (SiISR) and when that routine finishes, it will go back to doing what it was doing. You get the error because you assigned an interrupt service routine that does not exist - that is, you are not including that code as was included in the working program.

In the article, it is explained thusly:

We use INT0 on the Arduino and, basically, when that pin is set high by the Si4844-A10, the program will execute a simple routine that has been “attached” to the interrupt. All the routine will do is set a flag variable that can be examined and changed in other parts of the code. The Si4844-A10 will issue interrupts (i.e., bring the INT pin high) under certain conditions, most notably when the tuning potentiometer has been changed. Therefore, the Si4844-A10 tells the Arduino that you have moved the tuning knob and that the frequency display should be updated.


I get that you have some limitations on how much you can do on your own, there is no shame in that. On the other hand, you will be blindly staggering around with almost no chance of success, if you don't, at least, plan out an attack.

With the proper approach, you may be able to use the existing working code as a template of sorts. Then, in a step-wise fashion, work in your changes.

Back in post #42, I said...
At the point you appear to be at now, I would suggest that you build a block diagram of all the controls that you want - if you have not already done so. This will save you some time in the long run.
So, I encourage you to go ahead and build that block diagram and post it. Then, maybe, we can see how to add to and remove from the working code to accommodate. Make sense?
 

Thread Starter

talexander

Joined Feb 5, 2019
33
Here's my volume code:

Code:
byte current_vol = 30;  // default boot up value is 63

//volume potentiometer
int potVol = A3;
int vol = 0; 

  void (loop){
...
  vol = analogRead(vol_Pot);
  current_vol = map(vol, 1, 1023, 0, 63);
  go_current();
  }

  void go_current()
  {
  // restore current settings when we switch AM/FM/SW
  // set the Vol to whatever current_vol is
  Wire.beginTransmission(Si_ADDRESS);
  Wire.write(SET_PROPERTY);
  Wire.write(0x00);  // ARG1
  Wire.write(RX_VOLUME);  // ARG2 RX_VOLUME 0x40
  Wire.write(0x00);  // ARG3
  Wire.write(0x00);  // ARG4
  Wire.write(current_vol);  // ARG5 is actual volume 0-63
  Wire.endTransmission();
  }
 

Thread Starter

talexander

Joined Feb 5, 2019
33
I understand a block diagram would be helpful I was just wondering if you could suggest how to not include that code in the routine and add in my modified code. That is the only part that I am changing. If this isn't possible I'll go back and do that. The only problem is that time is just very limited so I was just looking for a quick fix. Thanks again.
 
In my experience, many a quick fix has taken a very long time, especially when you can't yet understand the code. I'm going to stick with the block diagram. I have absolutely no problem if anyone else wants to jump in and help though.
 

Thread Starter

talexander

Joined Feb 5, 2019
33
In my experience, many a quick fix has taken a very long time, especially when you can't yet understand the code. I'm going to stick with the block diagram. I have absolutely no problem if anyone else wants to jump in and help though.
I'll get to work on that can you please just explain what changes when I remove the "key press" code and add in my own for my understanding? That is the only part of the code that is confusing. If I could understand how to modify this part it would help me make a block diagram in reference to the interrupt command.
 

djsfantasi

Joined Apr 11, 2010
9,237
I'll get to work on that can you please just explain what changes when I remove the "key press" code and add in my own for my understanding? That is the only part of the code that is confusing. If I could understand how to modify this part it would help me make a block diagram in reference to the interrupt command.
First, if I understand your various posts which explain your problem a little differently each time, you have three switches connected to three analog pins and use analogRead() to check them.

You don’t want those pins to be analog; you want them to be digital!

You use analogRead(). That function returns a value from 0 to 1023. Then, you test the analog value against a digital constant (HIGH). It ain’t never going to work.

Note: on the Arduino, the analog pins can be used as analog OR digital pins. Not so much the other way around.

But if you use mechanical push buttons, you have to quickly learn about “switch bounce”. Download the BOUNCE2 library and install it in the Arduino IDE, and experiment with the sample code. There is also a sketch in the IDE called buttonPress. Experiment with it as well.

Until you understand the concepts and techniques of using a switch or push button on a microprocessor (and an Arduino is the best environment to learn), I’m sorry to say that you’re going to have a difficult time and a quick fix is going to be impossible.
 

Thread Starter

talexander

Joined Feb 5, 2019
33
First, if I understand your various posts which explain your problem a little differently each time, you have three switches connected to three analog pins and use analogRead() to check them.

You don’t want those pins to be analog; you want them to be digital!

You use analogRead(). That function returns a value from 0 to 1023. Then, you test the analog value against a digital constant (HIGH). It ain’t never going to work.

Note: on the Arduino, the analog pins can be used as analog OR digital pins. Not so much the other way around.

But if you use mechanical push buttons, you have to quickly learn about “switch bounce”. Download the BOUNCE2 library and install it in the Arduino IDE, and experiment with the sample code. There is also a sketch in the IDE called buttonPress. Experiment with it as well.

Until you understand the concepts and techniques of using a switch or push button on a microprocessor (and an Arduino is the best environment to learn), I’m sorry to say that you’re going to have a difficult time and a quick fix is going to be impossible.
Absolutely! I can easily fix the pin mistake and I should have known that. I already swapped those over to digital pins, changed the pins to input, and I'm just trying to understand the code as mentioned in 55. I'm sure it's frustrating reading this thread but everything is working except input selection and volume control. I'll continue working with the code (original shown in 43). My biggest problem is modifying the interrupt to work with my new code.
 

djsfantasi

Joined Apr 11, 2010
9,237
Absolutely! I can easily fix the pin mistake and I should have known that. I already swapped those over to digital pins, changed the pins to input, and I'm just trying to understand the code as mentioned in 55. I'm sure it's frustrating reading this thread but everything is working except input selection and volume control. I'll continue working with the code (original shown in 43). My biggest problem is modifying the interrupt to work with my new code.
Just curious? Why are you using an interrupt?

Have you read the Arduino reference pages on interrupts?

And it’s not clear to me what the original key press code was and what you replaced it with.

Did you find the buttonPress sample code and understand what it does? Walk before you can run. If you don’t understand the basic concepts (including debouncing), then no one here can explain it to you.

  • Teach yourself the basics by reading the sample code and running it on your Arduino. Otherwise, you won’t be able to understand what we’re telling you
  • Take small steps. Get one button working Toggle an LED with a button
  • Add buttons, one by one until they work with a test program
  • Learn what switch bounce us and write a couple of sketches, One without debouncing that counts the number of times a switch input toggled from high to low you might be surprised! The second switch uses the BOUNCE2 library. Count the number of times s switch input changed state with the bounce functions
  • By the time you’ve done this, you’ll know what’s wrong with this program.
BTW, your last comment implied that we haven’t seen your latest code. Isn’t it then reasonable to assume we have no chance to fix something we’ve never seen?
 
Last edited:
Please post a block diagram that illustrates the radio functions that you want to perform and that explains clearly what you have or want to have connected to the radio.

You have little more than a confusing jumble of posts. All of a sudden, you added a second Arduino. You designed the board (which you will post soon) and we have no idea what you did or are doing.

When I explain that it makes no sense to do an analog read and a digital compare...
This is a completely different issue than why you are doing analog reads and deciding if they are HIGH or LOW. If you do AM_State = analogRead(AM_Input); and subsequently if (AM_State == HIGH), when will the latter evaluate to false? Only when the AM_State value=0.
You respond that you are actually using a rotary switch. When someone else repeats the observation, you say that you changed all that. And again, we have no idea what you have over there.

When I ask you....
Please clearly illustrate how you have wired up the rotary switch.
You ignore that (we'll just set that aside) and post your volume routine.


When you say things like...
If I could understand how to modify this part it would help me make a block diagram in reference to the interrupt command.
I think that you have it backwards. if you would take the time to do some diagramming, you would understand what you are trying to do....and so might we. How freaking long would it take to draw out what you have connected and what functions that you want to perform - honestly, how long...I'm asking because it seems like you could have done that tonight..

My biggest problem is modifying the interrupt to work with my new code.
No, your biggest problem is that you are absolutely locked into going down a path that is unlikely to lead to success. You are sounding like a student who is working on a project that is panicking over the due date and mistakenly believes a few changes in a few lines is all you need.

I'm sure it's frustrating reading this thread but everything is working except input selection and volume control.
It is not so frustrating to me as you might think because my radio works.
 
Just curious? Why are you using an interrupt?

Have you read the Arduino reference pages on interrupts?
I would say the answers are no and no.

The interrupt is issued by the Si when a tuning change has been performed - when you turn the tuning pot. I use that so that the code can query the chip to find out what the new frequency is and then to display that information. This is all completely spelled out in the article. Do you have to use that? I suppose not, but then imagine tuning your radio and not knowing the frequencies you are tuning to? Of course, if there were a diagram illustrating the functions that the OP wants to implement, that part would come up....have I mentioned the need for some kind of diagram? :)

I don't feel like I am being harsh to ask someone to draw out what they have and what they want to do. If they don't want to do it, they don't have to.
 
Status
Not open for further replies.
Top