Memoria no volátil en proyecto

Hola a todos, saludos desde Chile.

Desde ya les agradezco, ojalá me puedan ayudar. Es mi primer Post.

Estoy diseñando un controlador para utilizar con efectos de guitarra muy similar al de imagen.

En cuanto a sus capacidades, estoy considerando ofrecer 32 "presets" en total, los cuales estarán agrupados en 4 grupos de 8 preset.

Declaré una estructura la cual define y contiene los datos asociados a cada preset. Entre byte asociados al control de relés, encentido de leds, envío de mensajes MIDI (tipo PC y CC), strings para mostrar en LCD 16x2, entre otros, cada nueva variable del tipo struct ya definido, tiene una longitud de 30 bytes en total.

Luego, si considero mis 32 preset, requiero de un total de 960 bytes y como esta información debe permanecer y ser modificada al vuelo por el usuario, pretendo almacenarla en la EEPROM del Nano la cual ofrece 1024 bytes.

Como verán, estoy al limite. :confused:

La premisa es que al momento en que el usuario presione un botón, se lean 30 bytes lo suficientemente rápido como para que inmediatamente se hagan las tareas asociados a cada uno de ellos. (activar reles, display LCD, envío mensajes MIDI, etc).

Sobre ello, requiero definir si la memoria interna es suficiente o utilizar una memoria externa y así puedo aumentar las capacidades ofrecidas. He visto sobre EEPROM externas, Módulos micro SD y las famosas FRAM.

Requiero de sus consejos y experiencia. En cuanto a velocidad de lectura, con la EEPROM interna no he tenido problemas pero me preocupa si estaré trabajando muy al limite en cuanto a capacidad y sobre todo, el límite de escritura (Aún cuando los 100mil ciclos son suficientes)

Por otra parte, que modulo externo me recomiendan o mas bien, que opción tomar?... Me llama la mucho la atención, los modulos FRAM i2c.

Desde ya, muchas gracias!!

El problema no es si estas al límite o no. El problema es si 960 son suficientes o luego necesitaras algunas mas tal que no tengas mas lugar?

No se como almacenas la información pero al no compartirla tampoco sabemos si lo has hecho de la manera mas adecuada, hay maneras de aprovechar todo de tal forma que ahorras mucho espacio.

Ejemplo: todo el mundo para guardar un SI-NO usa un entero y un entero ocupa 2 bytes. Imagina 20 memorias de 2 bytes son 40 bytes pero si te digo que con una variable bool haces lo mismo y ocupa un bit al final solo necesitas 40 bits o 40/8 = 5 bytes o sea son 35 bytes ahorrados. Lo mismo con otras cosas.

Asi que podrias plantear como armaste esa estructura y tal vez este bien hecha y no haya nada para optimizar o tal vez si.

Si 1K no son suficientes puedes usar una EEPROM externa y llevarla a 64K como minimo. Hay modulos y memorias de todo tamaño hasta de 1M y mas.

Ahora que leo el final de tu mensaje has investigado y ya sabias de las memorias externas e incluso de otras tecnologías. Bien... tienes un abanico de posiblidades, pero para mi gusto uso lo que tengo a mano, será porque no vivo en New York o Europa y no todo esta a mi alcance rápidamente.

Wau! Muchas gracias por tu pronta respuesta!

La verdad, como comentaba, la estructura que he definido va mas o menos así.

 struct preset{

byte relay;    // Usando bitRead leo los bit y puedo activar 8 relés.
byte control; // usando bitRead puedo controlar otras salidas control o leds.

//MIDI CC 1
byte canal1; // Solo utilizaré 4 bits.
byte data1;  // Mensaje midi considera el uso de los 8 bit.
byte value1; // Mensaje midi considera el uso de los 8 bit.

//... Repito la secuencia para no extenderme. Son 4 mensajes MIDI CC asignables a cada preset
//...
//MIDI CC 4
byte canal4;
byte data4;
byte value4;

// MIDI PC 1
byte canal_a; // Solo utilizaré 4 bits.
byte LSB_a;   // tipo mensaje MIDI considera el uso de los 8 bit.
byte MSB_a;  // tipo mensaje MIDI considera el uso de los 8 bit.
byte Value_a; // tipo mensaje MIDI considera el uso de los 8 bit.
//...Repito la secuencia para no extenderme. Son 4 mensajes MIDI PC asignable a cada preset
//...

// MIDI PC 4
byte canal_d; 
byte LSB_d;
byte MSB_d;
byte Value_d;

}

Así, es como llego a tener 30 bytes para cada uno de los 32 preset.

Fuera de eso, no requiero almacenar otras variables en la EEPROM. En cada inicio, todo parte de cero, es decir, cargo por defecto el preset 1.

Tengo en la mira el adquirir otros módulos externos, precisamente para poder almacenar mas variables (y poder trabajar con mas de 32 presets o ampliar la cantidad de mensajes MIDI) pero como bien mencionas, en Chile no se pueden conseguir estos módulos y debo importarlos. por eso la consulta antes de comprar para ver por cual debería ir.

Ahora, sobre esta misma materia. De que forma debo abordar el desarrollo de mi programa? Creo que hay dos caminos:

Opcion1: Al inicio de mi programa leer "toda" la EEPROM (los 960 bytes) y almacenarlo en la SRAM para luego leer desde ahí? almacenar 960 byte implica de inmediato utilizar el 50% de la SRAM disponible (Arduino nano son 2kbyte) pero podría ser mas "rapido".

Opcion2: Trabajar solo con variables que almacenen "direcciones" y constantemente leer la EEPROM. No utilizaría tanta SRAM pero podría ser mas lento? (esto mismo puedo pensarlo de los módulos externos). He leído que las FRAM son muy rapidas!

En relación a cuanto mas rápido o lento debiera ser, solo busco que el usuario no perciba un retraso entre que presiona el botón y que se enciendan leds, se activen/desactiven los relés o los equipos reciban los mensajes MIDI.

Creo que eso ayudaría a entender un poco mas lo que estoy desarrollando. Son mis primeras publicaciones en el foro asi que si se requiere que suba mas información con gusto puedo hacerlo.

Les agradezco desde ya por su ayuda!

Me parece que el NANO te quedará corto pero continua porque esta justo pero no da problemas x ahora.

La estructura creo que merece algunas consideraciones.

Veo que repites secuencias para cada canal entonces no entiendo porque no usas una structure para un canal general optimizada y luego creas un vector o array de dicha estructura.

strucutre datos {
//MIDI CC
byte canal; // Solo utilizaré 4 bits.
byte data;  // Mensaje midi considera el uso de los 8 bit.
byte value; // Mensaje midi considera el uso de los 8 bit.

// MIDI PC
byte canal; // Solo utilizaré 4 bits.
int msg;   // tipo mensaje MIDI considera el uso de los 16 bits incluye LSB y MSB
byte Value; // tipo mensaje MIDI considera el uso de los 8 bit.
}

Luego la usas asi

datos memoria[CANTIDAD];

Algo mejor donde aprovechas los 4 bits de uno y otra variable en 1 sola es asi

union conversion
{
  struct
  {
    byte canal_CC: 4;
    byte canal_PC: 4;
  } partes;
  byte todo;
};

Entonces para trabajar lo usas asi

union conversion data;
data.partes.canal_CC=1;
data.partes.canal_PC=15;
byte result=data.todo;

canal_CC/canal_PC ahora ocupan 1 byte
Será algo menor pero si sigo con mi ejemplo de 30 datos distintos, te ahorras 15 bytes. Algo es algo.

Genial! Creo haber entendido lo que me planteas... Sin duda ayudara a tener un mejor orden.

Gracias!

La segunda parte es mas elaborada pero la primera sobre una estructura general te permitiría manejar todo de forma mas comoda.

La segunda parte si la integras quedaría asi es decir ahorrando 1 byte para los dos nibles o medios bytes

union conversion {
  struct   {
    byte canal_CC: 4;
    byte canal_PC: 4;
  } partes;
  byte todo;
};


struct datos {
  //MIDI CC
  union conversion canal; // con esto ya defines los dos
  byte data;  // Mensaje midi considera el uso de los 8 bit.
  byte value; // Mensaje midi considera el uso de los 8 bit.

  // MIDI PC
  int msg;   // tipo mensaje MIDI considera el uso de los 16 bits incluye LSB y MSB
  byte Value; // tipo mensaje MIDI considera el uso de los 8 bit.
};

y luego defines por ejemplo

#define CANTIDAD 100

datos memoria[CANTIDAD];

cuando quieras asignar un canal será

memoria[0].canal.partes.canal_CC = 1;
memoria[20].canal.partes.canal_PC = 25;

He hecho un pequeño ejemplo que muestra como funciona todo

union conversion {
  struct   {
    byte canal_CC: 4;
    byte canal_PC: 4;
  } partes;
  byte todo;
};

struct datos {
  //MIDI CC
  union conversion canal; // con esto ya defines los dos
  byte data;  // Mensaje midi considera el uso de los 8 bit.
  byte value; // Mensaje midi considera el uso de los 8 bit.

  // MIDI PC
  int msg;   // tipo mensaje MIDI considera el uso de los 16 bits incluye LSB y MSB
  byte Value; // tipo mensaje MIDI considera el uso de los 8 bit.
};

#define CANTIDAD 20

datos memoria[CANTIDAD];

void setup() {
  Serial.begin(9600);
  Serial.println("Prueba de structure con union de bytes.");
}

void loop() {
  char buffer[30];

  for (int i = 0; i<CANTIDAD; i++) {
      memoria[i].canal.partes.canal_CC = i;
      memoria[i].canal.partes.canal_PC = i+2;
      memoria[i].data = i;
      memoria[i].Value = i;
      sprintf(buffer, "Canal_CC[%d]= %d Canal PC[%d]= %d", i, memoria[i].canal.partes.canal_CC, i, memoria[i].canal.partes.canal_PC);
      Serial.println(buffer);
      sprintf(buffer, "data        [%d]= %d Value    [%d]= %d", i, memoria[i].data, i, memoria[i].Value);
      Serial.println(buffer);
  }
}

Estimado moderador,

Agradezco la gentileza y el tiempo para orientarme en el diseño. Estoy aun estudiando lo que me propones.

Ahora, según entiendo los alcances que me haces nacen para:

1.- Orden
2.- Ahorro de memoria.

Si pienso en agregar un módulo de memoria externa, el 2 punto no seria crítico. Aun cuando considero que la mayor justificación es el primero.

Sobre esto, habrá diferencias perceptibles en cuanto a la velocidad de lectura de una EEPROM Externa vs la interna?

El día de ayer hice pruebas utilizando funciones como millis() y sizeof () y al menos en lo que refiere a la velocidad de lectura de la EEPROM interna, para leer los 30 bytes, al hacer un print de la variable utilizada par medir el tiempo me indica que esa lectura se hace en 0ms.

Creo que un eventual retraso se produciría en como desarrollo la información leída.

Me atrae bastante la idea de utilizar una EEPROM externa, hay mas libertad, podría ampliar el sistema y tengo mucha mas vida útil.

Gracias!

Eso fue lo que te comenté incialmente respecto de la memoria externa, incluso si miras pueds usar un RTC DS3231 que tiene ademas una EEPROM y no tendiras que cablear nada y ya tienes RTC si es que lo necesitaras.
Algunas librerías disponen del manejo de dicha memoria EEPROm ademas que dispone tambien de no se que cantidad de memoria NVRAM.

He estado leyendo que ese reloj me serviría para implementar un tap tempo via MIDI.

Pero ahi tengo muchas dudas, no se si usted podria ayudarme.

Pero me parece genial, no sabia que ese módulo integraba EEPROM.

Para sustentar lo que mencioné agrego por ejemplo este sitio en Banggood

Ahora mira la imagen

Tiene una EEPROM AT24C32.

Acá una guia (Using a $1 DS3231 Real-time Clock Module with Arduino )bastante completa que cubre varios aspectos.