attachInterrupt() + i2c eeprom + oled problem

I wrote a code for an application which uses OLED display in SPI mode to illustrate some measurements and some calculations. When using the internal eeprom of the microcontroller everything is working properly :).
If I use external eeprom in I2C mode and interrupt arrives, the system freezes :blush:. If no interrupt arrives its OK.
Do you have any suggestions for that?

Thanks...

Do you have any suggestions for that?

Yes. Read the sticky at the top of this forum. Do what it says.

dimigav:
I wrote a code ...

What code would that be?

Read this before posting a programming question

How to use this forum

#include <Wire.h>
#include <SPI.h>
#include <Denjay_fonts.h>
#include <Denjay_OLED.h>

OLED OLED;

#define eeprom_id 0x50          //Address of Microchip 24LC025 eeprom chip

unsigned int pulses;
unsigned int KWh_counter;
float cost_800;
float cost_2000;
float cost_2000_plus;
float total_cost;
char str_KWh_counter[5];
char str_pulses[3];
char str_total_cost[10];

int rst_btn_state;
int last_rst_btn_state = LOW;

const int rst_btn = 4;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 5000;    // the debounce time; increase if the output flickers

unsigned int addr_pulses = 0;
unsigned int addr_KWh = 16;
  
void setup()
{
  Serial.begin(9600);
  Wire.begin();

  pinMode(rst_btn, INPUT);      // sets the digital pin 8 as input
  pinMode(7, OUTPUT);
  
  pulses = readEEPROM(eeprom_id, addr_pulses);

  if (pulses < 0 || pulses > 100)
  {
    pulses = 0;
  }
  
  KWh_counter = readEEPROM(eeprom_id, addr_KWh);
  
  if (KWh_counter < 0)
  {
    KWh_counter = 0;
  }
  
  OLED.OLED_INIT(10, 13, 12, 9, 11, SOFT);           //OLED.OLED_INIT(int cs_pin, int sck_pin, int data_pin, int dc_pin, int reset_pin, SPI_mode mode);
  OLED.OLED_ClearScreen();                           //OLED.OLED_ClearScreen(Void);

  if (KWh_counter <= 800)
  {
    OLED.OLED_FILL(OLED_GREEN);                      //OLED.OLED_FILL(word color);
    OLED.OLED_SetBackColor(OLED_GREEN);              //OLED.OLED_SetBackColor(word Color);
    OLED.OLED_SetTextColor(OLED_BLACK);              //OLED.OLED_SetTextColor(word Color);
  }

  if (KWh_counter >= 801 && KWh_counter <= 2000)
  {
    OLED.OLED_FILL(OLED_YELLOW);                     //OLED.OLED_FILL(word color);
    OLED.OLED_SetBackColor(OLED_YELLOW);             //OLED.OLED_SetBackColor(word Color);
    OLED.OLED_SetTextColor(OLED_BLACK);              //OLED.OLED_SetTextColor(word Color);
  }

  if (KWh_counter >= 2001)
  {
    OLED.OLED_FILL(OLED_RED);                        //OLED.OLED_FILL(word color);
    OLED.OLED_SetBackColor(OLED_RED);                //OLED.OLED_SetBackColor(word Color);
    OLED.OLED_SetTextColor(OLED_BLACK);              //OLED.OLED_SetTextColor(word Color);
  }

  OLED.OLED_DisplayStringLine(9, 0, "Energy Cost");  //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
  OLED.OLED_DisplayStringLine(1, 16, "KWh   : ");    //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
  OLED.OLED_DisplayStringLine(1, 32, "Pulses: ");    //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
  OLED.OLED_DisplayStringLine(1, 48, "Cost: ");      //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
  attachInterrupt(0, count_KWh, FALLING);            //configure pin2 as an interrupt input
}
....

This is the code....

On Digital Pin 4 makes counters and memory reset, after some seconds, with PULL-DOWN resistor.
On Digital Pin 7 gives pulses for testing purposes.
On Digital Pin 2(interrupt0) takes the counting pulses with PULL-UP resistor.

.....
void loop()
{
  if (KWh_counter == 801 && pulses == 0)
  {
    OLED.OLED_FILL(OLED_YELLOW);                     //OLED.OLED_FILL(word color);
    OLED.OLED_SetBackColor(OLED_YELLOW);             //OLED.OLED_SetBackColor(word Color);
    OLED.OLED_SetTextColor(OLED_BLACK);              //OLED.OLED_SetTextColor(word Color);
    OLED.OLED_DisplayStringLine(9, 0, "Energy Cost");//OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
    OLED.OLED_DisplayStringLine(1, 16, "KWh   : ");  //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
    OLED.OLED_DisplayStringLine(1, 32, "Pulses: ");  //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
    OLED.OLED_DisplayStringLine(1, 48, "Cost: ");    //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
  }
  
  if (KWh_counter == 2001 && pulses == 0)
  {
    OLED.OLED_FILL(OLED_RED);                        //OLED.OLED_FILL(word color);
    OLED.OLED_SetBackColor(OLED_RED);                //OLED.OLED_SetBackColor(word Color);
    OLED.OLED_SetTextColor(OLED_BLACK);              //OLED.OLED_SetTextColor(word Color);
    OLED.OLED_DisplayStringLine(9, 0, "Energy Cost");//OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
    OLED.OLED_DisplayStringLine(1, 16, "KWh   : ");  //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
    OLED.OLED_DisplayStringLine(1, 32, "Pulses: ");  //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
    OLED.OLED_DisplayStringLine(1, 48, "Cost: ");    //OLED.OLED_DisplayStringLine(byte xpos, byte ypos, char *ptr);
  }

  itoa(KWh_counter, str_KWh_counter, 10);
  OLED.OLED_DisplayStringLine(56, 16, str_KWh_counter);
  
  itoa(pulses, str_pulses, 10);
  OLED.OLED_DisplayStringLine(56, 32, str_pulses);

  if (pulses == 0)                                   //Check if pulses variable is less that value 10
  {
    if (KWh_counter <= 800)
    {
      OLED.OLED_FillRect(64, 33, 7, 16, OLED_GREEN);
    }
    if (KWh_counter >= 801 && KWh_counter <= 2000)
    {
      OLED.OLED_FillRect(64, 33, 7, 16, OLED_YELLOW);
    }
    if (KWh_counter >= 2001)
    {
      OLED.OLED_FillRect(64, 33, 7, 16, OLED_RED);
    }
  }

  if (KWh_counter >= 2001)
  {
    total_cost = 62.344 + 113.520 + (KWh_counter - 2000) * 0.10252; //Summarize the previous costs.
  }
  
  if (KWh_counter >= 801 && KWh_counter <= 2000)
  {
    total_cost = 62.344 + (KWh_counter - 800) * 0.09460; //Summarize the previous costs.
  }

  if (KWh_counter <= 800)
  {
    total_cost = KWh_counter * 0.07793;                  //Summarize the previous costs.
  }

  dtostrf(total_cost, 6, 2, str_total_cost);
  OLED.OLED_DisplayStringLine(42, 48, str_total_cost);
  
  OLED.OLED_WritePixel(89, 53, OLED_BLACK);
  OLED.OLED_WritePixel(90, 53, OLED_BLACK);
  OLED.OLED_WritePixel(91, 53, OLED_BLACK);
  OLED.OLED_WritePixel(88, 54, OLED_BLACK);
  OLED.OLED_WritePixel(92, 54, OLED_BLACK);
  OLED.OLED_WritePixel(88, 55, OLED_BLACK);
  OLED.OLED_WritePixel(89, 55, OLED_BLACK);
  OLED.OLED_WritePixel(90, 55, OLED_BLACK);
  OLED.OLED_WritePixel(88, 56, OLED_BLACK);
  OLED.OLED_WritePixel(88, 57, OLED_BLACK);
  OLED.OLED_WritePixel(89, 57, OLED_BLACK);
  OLED.OLED_WritePixel(90, 57, OLED_BLACK);
  OLED.OLED_WritePixel(91, 57, OLED_BLACK);
  OLED.OLED_WritePixel(88, 58, OLED_BLACK);
  OLED.OLED_WritePixel(88, 59, OLED_BLACK);
  OLED.OLED_WritePixel(89, 59, OLED_BLACK);
  OLED.OLED_WritePixel(92, 59, OLED_BLACK);
  OLED.OLED_WritePixel(89, 60, OLED_BLACK);
  OLED.OLED_WritePixel(90, 60, OLED_BLACK);
  OLED.OLED_WritePixel(91, 60, OLED_BLACK);

  int reading = digitalRead(rst_btn);

  if (reading != last_rst_btn_state)
  {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay)
  {
    if (reading != rst_btn_state)                        // ?? ?? reading ????? ??????????? ??? ?? buttonState
    {
      rst_btn_state = reading;                           // ???? ??? buttonState ??? ???? ??? reading
      
      if (rst_btn_state == HIGH)                         // only toggle the LED if the new button state is HIGH
      {
        KWh_counter = 0;
        pulses = 0;
        writeEEPROM(eeprom_id, addr_pulses, pulses);
        writeEEPROM(eeprom_id, addr_KWh, KWh_counter);
        OLED.OLED_FILL(OLED_GREEN);                      //Fill the display with green color
        OLED.OLED_SetBackColor(OLED_GREEN);              //Set background color to green
        OLED.OLED_SetTextColor(OLED_BLACK);              //Set text color to black
        OLED.OLED_DisplayStringLine(9, 0, "Energy Cost");//print to display
        OLED.OLED_DisplayStringLine(1, 16, "KWh   : ");  //print to display
        OLED.OLED_DisplayStringLine(1, 32, "Pulses: ");  //print to display
        OLED.OLED_DisplayStringLine(1, 48, "Cost: ");    //print to display
      }
    }
  }
  last_rst_btn_state = reading;
  
  digitalWrite(7, HIGH);       // For testing purposes I give
  delay(100);                  // pulses from uController
  digitalWrite(7, LOW);        // and on rising edge of pulse
  delay(10000);                // interrupt activated.

}

void count_KWh()
{
  Serial.println("Here");
  pulses = pulses + 1;                                   //Increase pulses variable on every falling edge on pin 2

  writeEEPROM(eeprom_id, addr_pulses, pulses);           //Write to eeprom the current value of the pulses

  if (pulses == 100)                                     //Check if pulses variable achieve the value 100
  {
    KWh_counter = KWh_counter + 1;                       //If variable pulses achieved value 100 then increase KWh_counter variable
    pulses = 0;                                          //reset pulses variable
    writeEEPROM(eeprom_id, addr_KWh, KWh_counter);       //write to eeprom the current KWh value
  }
}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, word data) 
{
  byte lowByte = ((data >> 0) & 0xFF);
  byte highByte = ((data >> 8) & 0xFF);
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress));
  Wire.write(highByte);
  Wire.write(lowByte);
  Wire.endTransmission();
 
  delay(5);
}

word readEEPROM(int deviceaddress, unsigned int eeaddress) 
{
  word rdata = 0xFFFF;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress));
  Wire.endTransmission();
 
  Wire.requestFrom(deviceaddress,2);
 
  if (Wire.available())
  {
    rdata = (Wire.read() << 8) + Wire.read();
  }
  return rdata;
}
  attachInterrupt(0, count_KWh, FALLING);            //configure pin2 as an interrupt input

So, count_KWh is an interrupt service routine (ISR).

void count_KWh()
{
  Serial.println("Here");
  pulses = pulses + 1;                                   //Increase pulses variable on every falling edge on pin 2

  writeEEPROM(eeprom_id, addr_pulses, pulses);           //Write to eeprom the current value of the pulses

  if (pulses == 100)                                     //Check if pulses variable achieve the value 100
  {
    KWh_counter = KWh_counter + 1;                       //If variable pulses achieved value 100 then increase KWh_counter variable
    pulses = 0;                                          //reset pulses variable
    writeEEPROM(eeprom_id, addr_KWh, KWh_counter);       //write to eeprom the current KWh value
  }
}

You have a lot to learn about what can, and what can NOT be done in an ISR.

The clock ticking on the Arduino generates an interrupt. Can you imagine how much work the Arduino could do if that interrupt handler tried to print the time every time it fired?

You can not do other things that require that interrupts are enabled, like Serial.print(), because they are not enabled while your ISR is running.

You have a lot to learn about what can, and what can NOT be done in an ISR.

Thats the reason that I'm asking here.

So, if I put out all the others and keep only

void count_KWh()
{
  pulses++;                                   //Increase pulses variable on every falling edge on pin 2
}

this works fine for you.

I'll try it.

Thank you very much..

dimigav:
So, if I put out all the others and keep only

void count_KWh()

{
  pulses++;                                   //Increase pulses variable on every falling edge on pin 2
}



this works fine for you.
unsigned int pulses;

Make pulses volatile.