Arduino is freezing after running function twice

Hello, everyone, I wrote a couple of functions to read and write strings to EEPROM. The code works perfectly but the problem is when I run it a second time by either pressing the reset button on the Arduino or re-upload the code it is freezing after just calling the function once or twice (I know because I made it print messages in different sections of the function). It was supposed to run 5 times. What is this problem? Why does it work the first time only? I have run the code on multiple Arduino’s with the same result. A couple of times it worked even after the first time but then it stops suddenly. What is the problem :frowning: ? Please help. Thank you in advance.

Here’s the code:

#include<EEPROM.h>

String EEPROM_stringread(int addr) {
  int address = 0, eeprom_value;
  String eeprom_data = "";

  while (1)
  {
    eeprom_value = EEPROM.read(address);

    if (eeprom_value == addr)
    {
      break;
    }
    eeprom_value = EEPROM.read(address + 1);
    address = address + eeprom_value + 2;
  }
  eeprom_value = EEPROM.read(address + 1);

  for (int i = address + 2; i <= address + eeprom_value + 1; i++)
  {
    char char_value;
    EEPROM.get(i, char_value);
    eeprom_data = eeprom_data + char_value;
  }
  return eeprom_data;
}

String EEPROM_stringwrite(int addr, String data) {
  int len = data.length(), address = 0, counter = 0, eeprom_value;
  //data = data + " ";
  ++len;
  char char_array[len];
  data.toCharArray(char_array, len);
  --len;

  do
  {
    eeprom_value = EEPROM.read(address);
    Serial.println("yass");
    if (eeprom_value == addr)
    {
      Serial.println("match");
      ++address;
      eeprom_value = EEPROM.read(address);

      if (eeprom_value > len)
      {
        Serial.println("small");
        int current_address = address + eeprom_value + 1, new_address = address + len + 1, data_length, temp_value;
        //new_address = current_address - eeprom_value + len;

        while (EEPROM.read(current_address + 1) != 0)
        {
          EEPROM.put(new_address, EEPROM.read(current_address));
          ++new_address;
          ++current_address;
          data_length = EEPROM.read(current_address);
          EEPROM.put(new_address, data_length);
          ++new_address;
          ++current_address;
          temp_value = current_address;

          for (current_address; current_address <= temp_value + data_length - 1; current_address++)
          {
            char char_value;
            EEPROM.get(current_address, char_value);
            EEPROM.put(new_address, char_value);
            ++new_address;
          }
        }
      }

      else if (eeprom_value < len)
      {
        Serial.println("large");
        int current_address, new_address = address + eeprom_value + 2, previous_address, data_length;
        previous_address = new_address;

        while (1)
        {
          data_length = EEPROM.read(new_address);

          if (data_length == 0)
          {
            new_address = new_address + len - eeprom_value - 2;

            if (new_address > EEPROM.length())
            {
              return "String too large";
            }

            else
            {
              break;
            }
          }
          previous_address = new_address;
          new_address = new_address + data_length + 2;
        }

        do
        {
          data_length = EEPROM.read(previous_address);
          current_address = previous_address + data_length;

          for (current_address; current_address >= previous_address + 1; current_address--)
          {
            char char_value;
            EEPROM.get(current_address, char_value);
            EEPROM.put(new_address, char_value);
            --new_address;
          }

          EEPROM.put(new_address, EEPROM.read(current_address));
          --new_address;
          --current_address;
          EEPROM.put(new_address, EEPROM.read(current_address));
          int address_value = address + eeprom_value + 2, temp_value = previous_address;

          while (address_value != temp_value)
          {
            data_length = EEPROM.read(address_value);
            previous_address = address_value;
            address_value = address_value + data_length + 2;
          }
          --new_address;
        } while (current_address != address + eeprom_value + 1);
      }
      EEPROM.put(address, len);

      for (int i = address + 1; i <= address + len; i++)
      {
        EEPROM.put(i, char_array[counter]);
        ++counter;
      }
     Serial.println("cmon");
      return "Sucess";
    }
    eeprom_value = EEPROM.read(address + 1);
    address = address + eeprom_value + 2;
  } while (eeprom_value != 0);
Serial.println("normal");
  address = 1;
  while (1)
  {
    eeprom_value = EEPROM.read(address);

    if (eeprom_value == 0)
    {
      break;
    }
    address = address + eeprom_value + 2;
  }

  if (address + len < EEPROM.length())
  {
    EEPROM.put(address - 1, addr);
    EEPROM.put(address, len);

    for (int i = address + 1; i <= address + len; i++)
    {
      EEPROM.put(i, char_array[counter]);
      ++counter;
    }
  }
  else
  {
    return "String too large";
  }
Serial.println("cmon!");
}


void setup() {
  Serial.begin(9600);


  for (int i = 0 ; i < EEPROM.length() ; i++) {
    EEPROM.write(i, 0);
  }
  Serial.println("done!");

  EEPROM_stringwrite(11, "hello");
  EEPROM_stringwrite(15, "world");
  
 EEPROM_stringwrite(9, "monster");
  
  EEPROM_stringwrite(23, "saiyan");
  
  EEPROM_stringwrite(30, "goku");
  
  String a;
  a = EEPROM_stringread(11);
  Serial.println(a);
  a = EEPROM_stringread(15);
  Serial.println(a);
  a = EEPROM_stringread(9);
  Serial.println(a);
  a = EEPROM_stringread(23);
  Serial.println(a);
  a = EEPROM_stringread(30);
  Serial.println(a);
  EEPROM_stringwrite(9, " ");
  a = EEPROM_stringread(23);
  Serial.println(a);
  a = EEPROM_stringread(30);
  Serial.println(a);




}

void loop() {

}

Given these statements:

  • EEPROM_stringwrite(11, "hello");*
  • EEPROM_stringwrite(15, "world");*

Won't you end up with "hellworld"? Also, dump the String class, it wastes memory and the EEPROM routines actually become easier.

No, I won't end up with "hellworld", I have also tested it and it works. How can I do it without String? Please elaborate.Thanks

suersaiyangod:
No, I won't end up with "hellworld"

Sure you will. You write "hello" at address 11. So 11 has the h, 12 has the e, 13 is the l, 14 is also an l and 15 is the o.

Then you write "world" at address 15, where the o from "hello" is located. So you get a w at position 15, o at 16, r at 17, etc. As you can see, you're overwriting the o in "hello" with the w in "world".

Then you write "monster" at address 9, so you overwrite all the rest of hello. Let's see now you've got

9 m
10 o
11 n
12 s
13 t
14 e
15 r
16 o
17 r
18 l
19 d

At that point.

suersaiyangod:
No, I won't end up with "hellworld", I have also tested it and it works. How can I do it without String? Please elaborate.Thanks

Check out this site for using C strings (note lowercase 's') instead of the String class.

++len;
  char char_array[len];
  data.toCharArray(char_array, len);
  --len;

Instead of adding one and then subtracting one why don't you write this way so it is clear what you're doing

  char char_array[len + 1];
  data.toCharArray(char_array, len + 1);

What is all this convoluted stuff you're doing with the address? You're reading the EEPROM address from the EEPROM itself? How do you know which address to read then? You're going to have to explain how this is supposed to work before I'm going to dig into it too deep to figure out why it doesn't. For now I'll just chalk it up to using the String class. Use char arrays instead. It will make everything easier to work with.

econjack:
Given these statements:

  • EEPROM_stringwrite(11, "hello");*
  • EEPROM_stringwrite(15, "world");*

Won't you end up with "hellworld"? Also, dump the String class, it wastes memory and the EEPROM routines actually become easier.

Delta_G:
Sure you will. You write "hello" at address 11. So 11 has the h, 12 has the e, 13 is the l, 14 is also an l and 15 is the o.

Then you write "world" at address 15, where the o from "hello" is located. So you get a w at position 15, o at 16, r at 17, etc. As you can see, you're overwriting the o in "hello" with the w in "world".

Then you write "monster" at address 9, so you overwrite all the rest of hello. Let's see now you've got

9 m
10 o
11 n
12 s
13 t
14 e
15 r
16 o
17 r
18 l
19 d

At that point.

Oh no, 11 isn't the actual address that I'm storing it in EEPROM, its the address i'm assigning it to them, more like an identification number. Thanks econjack for the link :slight_smile:

Okay, so I store each string in a pattern. The first address(relative to the string i'm storing) is the address that i'm assigning to the string, it's like an identification number. The second address(let's call this the length address) will store the length of the string continued by the individual characters of the string. So this pattern is followed for storing all the strings. Now if there is a 0 in the length address then it means that the address(of the EEPROM) hasn't been written to, so I will start storing the new string in the address before the length address( to store the identification number). So now if the address declared in the function(EEPROM_stringwrite(23, "saiyan"); 23 in that) matches with an already existing address then it over-writes that particular string currently stored in that address. The strings stored after that address are then adjusted to accommodate the new string. There is no problem if the new string is the same size as the previous string but if it's is bigger then the next address( of the EEPROM) are moved to farther and if the length of the new string is lesser than the current string stored in that address then the next string(s) are "pulled" closer to accommodate the size of the new string. So yeah that's how it works. Thanks for mentioning that inefficient part "++len" will change it. I'm still an amateur(15 yrs) so can you put it in simpler terms, not too simple but not too complex. Thanks

suersaiyangod:
...Now if there is a 0 in the length address then it means that the address(of the EEPROM) hasn't been written to, so I will start storing the new string in the address before the length address( to store the identification number). So now if the address declared in the function(EEPROM_stringwrite(23, "saiyan"); 23 in that) matches with an already existing address then it over-writes that particular string currently stored in that address....

:o yikes. :o

instead of coming up with this kludge, why not just ask "hey world, how best to store some Strings in EEPROM?"

suersaiyangod:
The code works perfectly but the problem is when I run it a second time by either pressing the reset button on the Arduino or re-upload the code it is freezing

some new definition of "perfect" I guess...

If the process of reproduction was perfect to this standard, we'd be extinct.

Okay so I fixed it( the function for writing), i used a char array at the start instead of String but the problem now is that the function for reading isn’t EVEN getting called.

#include<EEPROM.h>

String EEPROM_stringread(int addr) {
Serial.println("heckyeh");
  int address = 0, eeprom_value;
Serial.println("heckyeh");
  String eeprom_data = "";

  while (1)
  {
  Serial.println("arduino");
    eeprom_value = EEPROM.read(address);

    if (eeprom_value == addr)
    {
      break;
    }
    eeprom_value = EEPROM.read(address + 1);
    address = address + eeprom_value + 2;
  }
  eeprom_value = EEPROM.read(address + 1);
  Serial.println(eeprom_value);
  for (int i = address + 2; i <= address + eeprom_value + 1; i++)
  {
  Serial.println("yup");
    char char_value;
    EEPROM.get(i, char_value);
   Serial.println(char_value);
    eeprom_data = eeprom_data + char_value;
  }
  Serial.println("yes it works");
  return eeprom_data;
}

String EEPROM_stringwrite(int addr, char char_array[]) {
  int len = strlen(char_array), address = 0, counter = 0, eeprom_value;
  //data = data + " ";
  //++len;
  //char char_array[len];
  //data.toCharArray(char_array, len);
  //--len;

  do
  {
    eeprom_value = EEPROM.read(address);
    Serial.println("yass");
    if (eeprom_value == addr)
    {
      Serial.println("match");
      ++address;
      eeprom_value = EEPROM.read(address);

      if (eeprom_value > len)
      {
        Serial.println("small");
        int current_address = address + eeprom_value + 1, new_address = address + len + 1, data_length, temp_value;
        //new_address = current_address - eeprom_value + len;

        while (EEPROM.read(current_address + 1) != 0)
        {
          EEPROM.put(new_address, EEPROM.read(current_address));
          ++new_address;
          ++current_address;
          data_length = EEPROM.read(current_address);
          EEPROM.put(new_address, data_length);
          ++new_address;
          ++current_address;
          temp_value = current_address;

          for (current_address; current_address <= temp_value + data_length - 1; current_address++)
          {
            char char_value;
            EEPROM.get(current_address, char_value);
            EEPROM.put(new_address, char_value);
            ++new_address;
          }
        }
      }

      else if (eeprom_value < len)
      {
        Serial.println("large");
        int current_address, new_address = address + eeprom_value + 2, previous_address, data_length;
        previous_address = new_address;

        while (1)
        {
          data_length = EEPROM.read(new_address);

          if (data_length == 0)
          {
            new_address = new_address + len - eeprom_value - 2;

            if (new_address > EEPROM.length())
            {
              return "String too large";
            }

            else
            {
              break;
            }
          }
          previous_address = new_address;
          new_address = new_address + data_length + 2;
        }

        do
        {
          data_length = EEPROM.read(previous_address);
          current_address = previous_address + data_length;

          for (current_address; current_address >= previous_address + 1; current_address--)
          {
            char char_value;
            EEPROM.get(current_address, char_value);
            EEPROM.put(new_address, char_value);
            --new_address;
          }

          EEPROM.put(new_address, EEPROM.read(current_address));
          --new_address;
          --current_address;
          EEPROM.put(new_address, EEPROM.read(current_address));
          int address_value = address + eeprom_value + 2, temp_value = previous_address;

          while (address_value != temp_value)
          {
            data_length = EEPROM.read(address_value);
            previous_address = address_value;
            address_value = address_value + data_length + 2;
          }
          --new_address;
        } while (current_address != address + eeprom_value + 1);
      }
      EEPROM.put(address, len);

      for (int i = address + 1; i <= address + len; i++)
      {
        EEPROM.put(i, char_array[counter]);
        ++counter;
      }
     Serial.println("cmon");
      return "Sucess";
    }
    eeprom_value = EEPROM.read(address + 1);
    address = address + eeprom_value + 2;
  } while (eeprom_value != 0);
Serial.println("normal");
  address = 1;
  while (1)
  {
    eeprom_value = EEPROM.read(address);

    if (eeprom_value == 0)
    {
      break;
    }
    address = address + eeprom_value + 2;
  }

  if (address + len < EEPROM.length())
  {
    EEPROM.put(address - 1, addr);
    EEPROM.put(address, len);

    for (int i = address + 1; i <= address + len; i++)
    {
      EEPROM.write(i, char_array[counter]);
      Serial.println(char_array[counter]);
      ++counter;
    }
  }
  else
  {
    return "String too large";
  }
Serial.println("cmon!");
}


void setup() {
  Serial.begin(9600);


  for (int i = 0 ; i < EEPROM.length() ; i++) {
    EEPROM.write(i, 0);
  }
  Serial.println("done!");

  EEPROM_stringwrite(11, "hello");
  EEPROM_stringwrite(15, "world");
  Serial.println("h");
 EEPROM_stringwrite(9, "monster");
  
  EEPROM_stringwrite(23, "saiyan");
  
  EEPROM_stringwrite(30, "goku");
  Serial.println("kami");
  Serial.println(EEPROM.read(0));
  char x;
  EEPROM.get(2, x);
  Serial.println(x);
  
  String a;
  /*EEPROM.get(2, a);
  Serial.println(a);
  */
  a = EEPROM_stringread(11);
  Serial.println(a);
  a = EEPROM_stringread(15);
  Serial.println(a);
  a = EEPROM_stringread(9);
  Serial.println(a);
  a = EEPROM_stringread(23);
  Serial.println(a);
  a = EEPROM_stringread(30);
  Serial.println(a);
  EEPROM_stringwrite(9, " ");
  a = EEPROM_stringread(23);
  Serial.println(a);
  a = EEPROM_stringread(30);
  Serial.println(a);

Serial.println("wat?!");


}

void loop() {

}

It’s not even printing Serial.println("heckyeh"); (the read function) in Serial montior. What is this new error? Thanks

Okay, so I found out the problem and have corrected it. I can't use strings in my program anymore, even outside the function like even if i declare a string in setup it crashes so i have completely ditched strings and am using only char arrays. Even though it is solved i want to know why i cant even declare 1 string. Thanks guys

Okay so the problem was that my write function itself was a String and my messages were too big. So changed it to an int type and am outputting either 1 or 0 to indicate that the string has been successfully written or not.

here’s the code just in case any of you need it.

Write function:

int EEPROM_stringwrite(int addr, const char *char_array) {
  int address = 0, counter = 0, eeprom_value;
  size_t len = strlen(char_array);
  
  do
  {
    eeprom_value = EEPROM.read(address);

    if (eeprom_value == addr)
    {
      ++address;
      eeprom_value = EEPROM.read(address);

      if (eeprom_value > len)
      {
        int current_address = address + eeprom_value + 1, new_address = address + len + 1, data_length, temp_value;
        //new_address = current_address - eeprom_value + len;

        while (EEPROM.read(current_address + 1) != 0)
        {
          EEPROM.put(new_address, EEPROM.read(current_address));
          ++new_address;
          ++current_address;
          data_length = EEPROM.read(current_address);
          EEPROM.put(new_address, data_length);
          ++new_address;
          ++current_address;
          temp_value = current_address;

          for (current_address; current_address <= temp_value + data_length - 1; current_address++)
          {
            char char_value;
            EEPROM.get(current_address, char_value);
            EEPROM.put(new_address, char_value);
            ++new_address;
          }
        }
      }

      else if (eeprom_value < len)
      {
        int current_address, new_address = address + eeprom_value + 2, previous_address, data_length;
        previous_address = new_address;

        while (1)
        {
          data_length = EEPROM.read(new_address);

          if (data_length == 0)
          {
            new_address = new_address + len - eeprom_value - 2;

            if (new_address > EEPROM.length())
            {
              return 1;
            }

            else
            {
              break;
            }
          }
          previous_address = new_address;
          new_address = new_address + data_length + 2;
        }

        do
        {
          data_length = EEPROM.read(previous_address);
          current_address = previous_address + data_length;

          for (current_address; current_address >= previous_address + 1; current_address--)
          {
            char char_value;
            EEPROM.get(current_address, char_value);
            EEPROM.put(new_address, char_value);
            --new_address;
          }

          EEPROM.put(new_address, EEPROM.read(current_address));
          --new_address;
          --current_address;
          EEPROM.put(new_address, EEPROM.read(current_address));
          int address_value = address + eeprom_value + 2, temp_value = previous_address;

          while (address_value != temp_value)
          {
            data_length = EEPROM.read(address_value);
            previous_address = address_value;
            address_value = address_value + data_length + 2;
          }
          --new_address;
        } while (current_address != address + eeprom_value + 1);
      }
      EEPROM.put(address, len);

      for (int i = address + 1; i <= address + len; i++)
      {
        EEPROM.put(i, char_array[counter]);
        ++counter;
      }
      return 0;
    }
    eeprom_value = EEPROM.read(address + 1);
    address = address + eeprom_value + 2;
  } while (eeprom_value != 0);

  address = 1;
  while (1)
  {
    eeprom_value = EEPROM.read(address);

    if (eeprom_value == 0)
    {
      break;
    }
    address = address + eeprom_value + 2;
  }

  if (address + len < EEPROM.length())
  {
    EEPROM.put(address - 1, addr);
    EEPROM.put(address, len);

    for (int i = address + 1; i <= address + len; i++)
    {
      EEPROM.put(i, char_array[counter]);
      ++counter;
    }
  
    return 0;
  }
  else
  {
    return 1;
  }
}

returns 0 if string was successfully written. returns 1 if there is no space in EEPROM to fit string.

Read function using string:

String EEPROM_stringread(int addr) {
  int address = 0, eeprom_value, counter = 0;
  
  while (address <= EEPROM.length())
  {
    eeprom_value = EEPROM.read(address);

    if (eeprom_value == addr)
    {
      break;
    }
    eeprom_value = EEPROM.read(address + 1);
    address = address + eeprom_value + 2;
  }
 
 if(address > EEPROM.length())
 {
   return;
 }
 
  eeprom_value = EEPROM.read(address + 1);
  String eeprom_data = "";
  for (int i = address + 2; i <= address + eeprom_value + 1; i++)
  {
    char char_value;
    EEPROM.get(i, char_value);
    eeprom_data = eeprom_data + char_value;
  }
  return eeprom_data;
}

Reading an address that wasn’t written to will give you no value. I have learned that using strings is not good so if you can work with char arrays(which i will also be using) here’s the code:

char* EEPROM_stringread(int addr) {
  int address = 0, eeprom_value, counter = 0;
  
  while (address <= EEPROM.length())
  {
    eeprom_value = EEPROM.read(address);

    if (eeprom_value == addr)
    {
      break;
    }
    eeprom_value = EEPROM.read(address + 1);
    address = address + eeprom_value + 2;
  }
 
 if(address > EEPROM.length())
 {
   return;
 }
 
  eeprom_value = EEPROM.read(address + 1);
  char eeprom_data[eeprom_value + 1];
  for (int i = address + 2; i <= address + eeprom_value + 1; i++)
  {
    char char_value;
    EEPROM.get(i, char_value);
    eeprom_data[counter] = char_value;
    ++counter;   
  }
  eeprom_data[counter] = '\0';
  return eeprom_data;
}

Thanks for all the help :slight_smile: :slight_smile:

Okay so the problem was that my write function itself was a String

Rubbish. Functions and classes are completely different beasts. The return type of the function was a String, and you WERE told to get rid of ALL Strings.