Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

myMem.begin() returns False if called immediately after a Write operation? #31

Closed
RemyDavies opened this issue Dec 7, 2023 · 5 comments

Comments

@RemyDavies
Copy link

Hi all, I'm hoping to quosh another issue I've been experiencing since v3.1.0 (or thereabouts).

I'm running the SparkFun Qwiic EEPROM Breakout - 512Kbit (https://www.sparkfun.com/products/18355).

With library versions prior to v3.1.0, if you called myMem.begin() immediately after completing a write operation it would always return True.

Now with the more recent releases (including the latest v3.2.2) if you call myMem.begin() immediately after completing a write operation, it continues to return false for about 2-3ms... after which it then finally returns True.

Below is an example sketch which reproduces the issue:

#include <Wire.h>                      // Wire library (I2C).
#include <SPI.h>                       // SPI library.
#include <SparkFun_External_EEPROM.h>  // EEPROM library.

ExternalEEPROM myMem;

unsigned int data_1[] = { 893, 277, 999, 126 };
unsigned int data_2[] = { 643, 425, 824, 954 };
unsigned int data_3[] = { 324, 943, 879, 321 };
unsigned int data_4[] = { 438, 478, 243, 986 };
unsigned int data_5 = 10000;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  myMem.setMemoryType(512); // SparkFun Qwiic EEPROM Breakout - 512Kbit (https://www.sparkfun.com/products/18355).
  delay(800);
}

void loop()
{
  if (myMem.begin() == true)
  {
    bool data_is_present = false;

    myMem.get(10, data_is_present);  // read flag from EEPROM.

    if (data_is_present == true)  // If the flag is true, erase data stored in EEPROM.
    {
      for (uint_fast8_t index = 100; index <= 100 + 80; index++)
      {
        myMem.write(index, '\0');
      }
      myMem.put(10, false);
    }
    char data_buffer[63] = "\0";

    snprintf(data_buffer, sizeof(data_buffer), "%u.%u.%u.%u,%u.%u.%u.%u,%u.%u.%u.%u,%u.%u.%u.%u,%u,",
             data_1[0], data_1[1], data_1[2], data_1[3],
             data_2[0], data_2[1], data_2[2], data_2[3],
             data_3[0], data_3[1], data_3[2], data_3[3],
             data_4[0], data_4[1], data_4[2], data_4[3],
             data_5);

    Serial.println("  Writing to EEPROM...");
    Serial.println();

    for (uint_fast8_t index = 0; index < sizeof(data_buffer); index++)
    {
      myMem.write(100 + index, data_buffer[index]);
    }
    myMem.put(10, true);
    Serial.println("  EEPROM write complete.");
    Serial.println();
  }
  else
  {
    Serial.println("  Cannot write to EEPROM...");
  }

  // Now that we've finished our EEPROM write operation, let's see how long it takes for myMem.begin() to return true...

  unsigned long timer_start = micros();

  while (myMem.begin() == false)
  {
    Serial.println("  No EEPROM memory detected...");
  }

  if (myMem.begin() == true)
  {
    unsigned long timer_end = micros();
    unsigned long duration = timer_end - timer_start;

    Serial.println("  EEPROM memory detected!");
    Serial.print("  Duration: ");
    Serial.print(duration);
    Serial.println("micros");
  }
 
  while (true)
  {
    // Done.
  }
}

Serial output:
Clipboard01

Any ideas on why this may be happening with the more recent releases?

@nseidle
Copy link
Member

nseidle commented Dec 7, 2023

This is expected behavior. begin() will return false when isConnected() is false. isConnected will return false when the device does not ack an I2C query. The device does not ack I2C queries when it is busy. The device is busy when it's writing to EEPROM. Therefore, begin() will return false for a few ms while the write completes.

This is by design. Writes take time. Rather than block during the write, we initiate the write and pass control back to the main code. When another write is initiated, the library checks to see if a write is in process. If it is, we block until the previous write is complete before starting another.

begin() only needs to be called once at the start of your sketch. You can call isBusy() instead to test if a write is complete.

@nseidle nseidle closed this as completed Dec 7, 2023
@RemyDavies
Copy link
Author

Thank you for the explanation, this makes sense.

I'm just not sure why I never experienced this behaviour before in previous releases? (nothing has changed in my projects since then).

As for only calling begin() once at the start of my sketch: -
I'm calling begin() every loop cycle to confirm the EEPROM is connected and responsive. If the EEPROM does not respond then this activates an 'Alarm' condition in my sketch.... is calling begin() the best way to 'pole' the EEPROM or should I be calling some other library function for this instead?

@nseidle
Copy link
Member

nseidle commented Dec 8, 2023

You can call isBusy() instead to test if a write is complete. You can call isConnected() to see if the device acks (isBusy calls isConnected).

@RemyDavies
Copy link
Author

RemyDavies commented Dec 22, 2023

Hi mate, can you please clarify the following?

  1. isBusy() returns TRUE if the eeprom is performing a Write operation.
    Should isBusy() also return TRUE if busy performing Read operations?

  2. If begin() calls isConnected() - then what exactly does begin() do which isConnected() does not do?

  3. During a Write operation - isBusy() returns TRUE and isConnected() will return FALSE.
    Strangely, if the eeprom is physically disconnected from the Arduino, the same function calls return the same values... isBusy() returns TRUE and isConnected() returns FALSE.
    Is this expected behavior? or are these function calls returning something other than True/False which I'm just not evaluating correctly?

@nseidle
Copy link
Member

nseidle commented Dec 22, 2023

Should isBusy() also return TRUE if busy performing Read operations?

I can't really answer this. read() is blocking and very fast. I can't think of a way that you could run the isBusy() during a read() without running your own low-level I2C operations.

If begin() calls isConnected() - then what exactly does begin() do which isConnected() does not do?

Have a look. Two library variables are set, then isConnected is tested. While begin() doesn't do much more than isConnected(), I consider it bad practice to instruct users to run begin() multiple times.

Strangely, if the eeprom is physically disconnected from the Arduino, the same function calls return the same values... isBusy() returns TRUE and isConnected() returns FALSE. Is this expected behavior?

Yes. Don't shy away from reading the manual my friend.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants