Alteración de la eeprom a la hora de subir un sketch

Hola a todos.

Estoy empezando a jugar con la eeprom de arduino y estoy teniendo un pequeño problema con ella. Quiero utilizar la eeprom para guardar el valor por defecto de una variable y que cuando este se reinicie, ya sea que pulse reset o se vaya la luz) vuelva a cargar ese valor por defecto.

Decir que no uso la libreria EEPROM, si no que directamente uso las funciones básicas para ello.

El código tiene la siguiente pinta:

int  address;   // La dirección donde guardar.
byte variable;  // Variable a guardar.

void setup()
{

    // La primera vez grabo la variable para iniciar
    // la eeprom. 
    // Lo ejecuto una vez, apago, comento estas 
    // líneas y vuelvo a subir el sketch.
    variable = 1; 
    eeprom_byte_write((byte*)address, variable);
    
    
    // Aquí leo la variable de la memoria.
    variable = eeprom_byte_read((byte*)address);
}

void loop()
{
   // Todo el código del programa donde hay un menu que
   // me permite guardar el valor de la variable si la
   // he modificado, usando update para escribir.
   eeprom_update_byte((byte*)address, variable);
}

Como veis una primera vez, incializo las variables a un valor que yo quiero, lo escribo y apago el arduino, antes de que ejecutar nada dentro del loop que me grabe nada en la memoria. Luego borro esas líneas (o las comento) y vuelvo a subir el sketch sin que inicialize la memoria.

El problema es que cada vez subo el primer sketch, funciona. Cuando vuelvo a subir el sketch con las lineas comentadas, no tiene el valor por defecto, que se supone que he leido de la eeprom. Lo grabo
desde el mismo menu del arduino y lo apago y al encender si ha grabado los datos.

Estoy usando un chip atmega328p usando un arduino como ISP, usando la opcion "subir usando programador" del ide.

¿Puede ser que al grabar el nuevo sketch se haga un borrado de la eeprom y por eso no tengo los
valores inicializados?

Soy 100 % ignorante en el tema de las eeprom pero, ¿por qué no usas la librería?

Efectivamente, victorjam, creo que así es. No estoy seguro al 100% pero sí en gran medida.

La solución pasa por, utilizar una dirección de eeprom "testigo", que leerás en setup. Con un simple if, si está limpia (creo que inicialmente están con valor 0xFF) entonces escribes el valor inicial y el byte testigo. Si la dirección testigo no está limpia, te vas a leer dicho valor inicial.

También puedes trabajar de una forma alternativa con la eeprom, definir variables con el modificador EEMEM de forma similar a como se hace con PROGMEM para almacenar constantes en flash, y se puede hacer que al subir programa, también suba a eeprom dichas variables, con lo que te ahorras el if y asignación anteriores.

Aquí un hilo interesante, en el que conseguimos eso.

Recomiendo leer el hilo completo, mirando fechas. Aunque peque de inmodestia, lo veo como un buen ejemplo de investigación por mi parte. Lo que viene siendo "autosacarse las habichuelas del fuego". 8) 8) 8)

yo veo que

int  address;   // La dirección donde guardar.
byte variable;  // Variable a guardar.

void setup()
{

    // La primera vez grabo la variable para iniciar
    // la eeprom. 
    // Lo ejecuto una vez, apago, comento estas 
    // líneas y vuelvo a subir el sketch.
    variable = 1; 
    eeprom_byte_write((byte*)address, variable);

No tiene un address para tu primera vez, entonces donde guarda ese dato?

Para surbyte:

Es un código más o menos simple. Se me ha olvidado poner la inicilización de la variable; de hecho escribo varios valores: dos enteros y 3 float e incremento las dirección según voy leyendo/escribiendo (2,2,4,4, respectivamente). El código funciona perfecto, es solo que cuando subo el sketch se borra la eeprom

Para noter:

Considerando que no estoy seguro tampoco al 100%, creo que SI, que la borra cada vez que cargo el programa. Teniendo en cuenta eso he usado otro método y he solucionado el problema. Y mira por donde si había visto la directiva EEMEN por algún sitio, pero no se me había ocurrido investigarla. Gracias por el enlace al hilo, todos los días se aprende algo nuevo.

Para cefere0:

No uso EEPROM por dos motivos. El primero por mania. El segundo, siempre que veo una libreria, con intenciones de usarla, lo primero que hago es leermela, intentar comprenderla y entonces la uso. Así me evito muchos dolores de cabeza y venir al foro pidiendo socorro. En el caso de EEPROM, miré el código y me encontré esto:

uint8_t EEPROMClass::read(int address)
{
	return eeprom_read_byte((unsigned char *) address);
}

¿Qué simple no? Pensé. Entonces busque información sobre la función eeprom_read_byte, vi que estaba definida en el propio entorno de avrgcc. Es más descubrí que existe el equivalente eeprom_read_XXXX, donde XXXX lo sustituyes por BYTE, WORD, FLOAT y BLOCK. Esto te permite leer/escribir varios tipos de datos, como float y bloques (estructuras, etc), y no está limitado solo a byte como en la libreria. Además, tenemos que aparte de read y write, existe otra opción que es update que sólo escribe en la memoria si el valor es distinto, lo cual puede alargar la vida util de la eeprom. También si piensas un poco, usar un objeto (que ocupa memoria), que llamas a una función (que ocupa memoria de pila y tiempo de ejecución) para luego llamar a la última función... pues me ahorro el intermediario.

No sé, quizás sean manias mias...

En cuanto a la forma que se borra sigue siendo un misterio, y supongo que será alguna opción del IDE a la hora de grabar los micros.

No tengo el arduino a mano, pero si haces una subida de programa activando el modo verbose al cargar al arduino, luego puedes analizar los distintos parámetros que se envían a avrdude. Seguramente que entre ellos veas algún modificador tipo -uueprom o similar, que realiza el borrado o carga de un archivo.eep.
Con ello ya tendrías tu 100% de certeza; pero ahora mismo, al 99% te podría confirmar que así es.

¿Qué solución tomaste/tomarás finalmente?

Tengo activado el modo verbose, aunque no leo todo lo que me dice, pero en alguna parte indica que la opción X ha sido usada y se ha hecho un ciclo de borrado, pero parece indicar que solo lo hace en la flash... De todas formas, lo veré bien esta tarde que lo tendré más a mano.

La solución por la que opté fue la siguiente:

int address;
int v1, v2;
float f1, f2, f3;

void setup()
{
   // Otro código...
   
   address = 0;
   v1 = eeprom_read_word((int*)address); address+=2;
   v2 = eeprom_read_word((int*)address); address+=2;
   f1 = eeprom_read_float((float*)address); address+=4;
   f2 = eeprom_read_float((float*)address); address+=4;
   f3 = eeprom_read_float((float*)address);

   // Comprobamos que lo que ha leido es válido. Teniendo en cuenta
   // que si se ha borrado la eeprom el contenido de toda ella es 
   // FF.
   
   // 0xFFFF es el valor -1.
   if ( v1==-1 ) v1=24;
   if ( v2==-1 ) v2=34;
   
   // 0xFFFFFFFF es el valor NAN.
   if ( isnan(f1) ) f1=0.00;
   if ( isnan(f2) ) f2=0.00;
   if ( isnan(f3) ) f3=0.00;
}

void loop()
{
    //...
}

.

Al borrarse la eeprom, esta se pone en todos los bytes de memoria al valor 0xFF. Ese valor no es el que me interesa ya que o es un -1 o el valor NAN y mis variables suelen tener un rango de valor definido; en el caso de los enteros es de 0..200 (un valor porcentual) y en caso de los float entre 0.00 y 1.00 (los cuales varian dentro del programa en incrementos de 0.01)

Ok, ya entiendo....