I am building an AM/FM receiver based upon the SI4730 family and I am experiencing issues with my control interface. After some random amount of hitting attached buttons, it simply hangs up and will no longer respond. Hitting the reset on the MC clears the issue ... until it happens again. I hit the buttons in random order and random amount of times.
I am using two MCP23008 with interrupts tied and feeding the D2 pin on a 5Volt mini. Momentary switches to ground are the inputs. 10K resistors in the I2C lines. I am also using a 20X4 LCD display for troubleshooting as I will be using that in the final project. No issues with the display.
I have considered isolating the expanders for individual testing but wanted to see what other ideas might be out there.
Here is the code for the interface functionality stripped of other stuff. This version is not written for efficiency. Also, for anyone testing it, feel free to strip out the LCD stuff for the serial line interface.
#include <pu2clr_mcp23008.h>
#include <LiquidCrystal_I2C.h>
#define ARDUINO_INTERRUPT_PIN 2
#define IO_RESET_PIN 3
#define DISPLAY_ADDRESS 0x27
#define DISPLAY_COLUMNS 20
#define DISPLAY_ROWS 4
#define MCP0_ADDRESS 0X20
#define MCP1_ADDRESS 0X21
MCP mcp0, mcp1;
uint8_t intcap0, intcap1;
int button;
bool isBank0 = true;
volatile bool button_event = LOW;
LiquidCrystal_I2C lcd(DISPLAY_ADDRESS, DISPLAY_COLUMNS, DISPLAY_ROWS);
void setMCP()
{
button_event = true;
}
void initializeButtons(){
// Ensure that the I/O chips are reset upon powerup/reset
digitalWrite(IO_RESET_PIN, HIGH);
delay(10);
digitalWrite(IO_RESET_PIN, LOW);
delay(10);
digitalWrite(IO_RESET_PIN, HIGH);
delay(10);
mcp0.setup(MCP0_ADDRESS, 0B01111111);
mcp1.setup(MCP1_ADDRESS, 0B01111111);
mcp0.setInterrupt(INTERRUPT_INTPOL_ACTIVE_HIGH, INTERRUPT_ODR_OPEN_DRAIN); // Defines the behaviour of the interrupt
mcp1.setInterrupt(INTERRUPT_INTPOL_ACTIVE_HIGH, INTERRUPT_ODR_OPEN_DRAIN);
for(int i = 0; i < 8; i++){
mcp0.pullUpGpioOn(i); // Enables internal pullup resistor on gpio pin 1
mcp0.interruptGpioOn(i, HIGH); // Sets the GPIO pin 1 to deal with interrupt. The pin 1 will be compared with the value 1 (HIGH). It will be launch an interrupt if the pin 1 goes to level 0 (LOW).
}
for(int i = 0; i < 8; i++){
mcp1.pullUpGpioOn(i);
mcp1.interruptGpioOn(i, HIGH);
}
pinMode(ARDUINO_INTERRUPT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ARDUINO_INTERRUPT_PIN), setMCP, CHANGE);
}
// Button functions
bool checkInput(int mcp0, int mcp1){
if(mcp0 == 127 && mcp1 == 127) // Initial value - not wanted
return false;
if(mcp0 == 255 && mcp1 == 255) // After register reset - not wanted
return false;
return true;
}
int getButton(int intcap){
for(int i = 0; i < 8; i++){
if(!bitRead(intcap, i)){
return i;
}
}
return -1;
}
void checkButtons(){
// Get I/O registers. Also resets registers and interrupt pin.
intcap0 = mcp0.getRegister(REG_INTCAP);
intcap1 = mcp1.getRegister(REG_INTCAP);
if(checkInput(intcap0, intcap1)){
if(intcap0 != 255){
isBank0 = true;
button = getButton(intcap0);
}else{
isBank0 = false;
button = getButton(intcap1);
}
lcd.clear();
lcd.setCursor(0,0);
if(isBank0){
switch(button){
case 0:
lcd.print("volumeDown");
break;
case 1:
lcd.print("volumeUp");
break;
case 2:
lcd.print("increaseSweepRate");
break;
case 3:
lcd.print("changeSweepDirection");
break;
case 4:
lcd.print("OPEN");
break;
case 5:
lcd.print("saveSettings");
break;
case -1:
lcd.print("ERROR!");
break;
}
}else{
switch(button){
case 0:
lcd.print("decreaseSweepRate");
break;
case 1:
lcd.print("bandChange");
break;
case 2:
lcd.print("indexBacklight");
break;
case 3:
lcd.print("setScanPause");
break;
case -1:
lcd.print("ERROR!");
break;
}
}
}
button_event = false;
}
void setup() {
pinMode(IO_RESET_PIN, OUTPUT);
/* Initialize display */
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("INITIALIZING...");
initializeButtons();
}
void loop() {
if (button_event){
checkButtons();
}
}
Again, any assistance would be greatly appreciated.
Thanks.
PS: I can also provide a (somewhat messy) image of the schematic upon request.

