Go Down

Topic: Lector y grabador de EEPROM tipo 24LCxx (Read 14897 times) previous topic - next topic

Metaconta

Aug 18, 2017, 02:57 am Last Edit: Aug 18, 2017, 03:04 am by Metaconta
Hola:

Tengo dos EEPROM, la 24LC16 y la 24LC64. Puedes encontrar las de tipo 24LCxx en su Web oficial.

Mi idea por curiosidad y experimentación es lograr que Arduino se convierta en un grabador de EEPROM de la serie 24LCxx. Hay que hacer una interfaz para cargar el archivo hex o bin de la EEPROM y guardarlo en su interior, lo mismo para leer. No voy hacer un proyecto de guardar datos desde Arduino en la EEPROM como los LEd encendido la última vez que se apagó.

La interfaz que se usaba antes para otros microcontroladores es el famoso Ic-prog y el WinPic800.


La interfaz básica que he hecho hasta ahora es así, en fase alfa.


Quiero saber detalles, ideas de la gente y plasmarla aquí para hacerlo lo mejor posible.

¿Alguna sugerencia?

Saludos.

PD: Dejar claro que no es lo mismo archivo .hex que binario .bin.

Lucario448

Quiero saber detalles, ideas de la gente y plasmarla aquí para hacerlo lo mejor posible.
¿Con la interfaz o el programa en general?

Si no tienes nada hecho, se me ocurre que como la comunicación al PC siempre es por USART, dar las órdenes al Arduino mediante la técnica que yo llamo "petición y respuesta".
Para refrescarte la memoria, es el proceso de enviar un comando, que el Arduino lo interprete y accione como corresponda; y con base en el resultado devolver una respuesta. Ese flujo de datos PC-Arduino no necesariamente tiene que ser legible para un ser humano, por lo tanto sugiero que sea meramente binario (podría haber texto pero solo si es parte del contenido que va o viene de la EEPROM).

¿Esa serie 24LCxx es únicamente por I2C o también lo tienes que hacer compatible con los demás protocolos de comunicación serial?

Metaconta

#2
Aug 18, 2017, 04:42 pm Last Edit: Aug 18, 2017, 06:11 pm by Metaconta
Hola:

Esa serie es de I2C, es lo que tengo ahora físicamente y haré las cosas poco a poco. Cuando termine todo al 100 % con I2C ya me meteré con el SPI tipo 93LCxx. Leer y grabar EEPROM tipo 24LCxx, o lo que es lo mismo 24Cxx.

A buscar información por todas partes como se comunicar Arduino con I2C. Eso si, el hex se transfiere desde la Interfaz del ordenador o PC, pasa por Arduino UNO y lo graba en la EEPROM 24LCxx.

Web que he encontrado
:
http://hispavila.com/total/3ds/atmega/i2c-eeprom.html


La pregunta es.

¿Se puede hacer un grabador de EEPROM con Arduino UNO desde una interfaz con el PC?


La interfaz de prueba la tengo hecha en C#. (Versión Alfa).



Saludos.

PD: En este mismo momento, en paralelo estoy haciendo tutoriales en Java con Eclipse, luego paso a NetBeans sobre comunicación por el puerto serie. Ya he hecho tres medio rápido, con C++ Win32, Consola Visual Studio y Delphi que puedes ver en documentación.

PD2: No he olvidado lo que estábamos haciendo. Tengo claro que tendré la versión de Java sea como sea y su tutorial.

Lucario448

La pregunta es.

¿Se puede hacer un grabador de EEPROM con Arduino UNO desde una interfaz con el PC?
Mi pregunta sería: ¿y por qué no?

Si hasta los desarrolladores crearon Arduino que programa Arduino con el ejemplo ArduinoISP, ¿por cuál razón no sería posible programar un EEPROM?

La interfaz de prueba la tengo hecha en C#. (Versión Alfa).
Vaya que sí es alfa, la escritura lleva un 4864% de progreso.
Por cierto me gusta hasta lo simplificado que se ve utilizar el programa: escoges el archivo a grabar (o la ruta dónde guardar la lectura), y luego con el par de botones decides si "Leer" (EEPROM a archivo) o "Grabar" (archivo a EEPROM).
Me recuerda mucho a la interfaz del Win32DiskImager antes de la versión 1.0, excepto que ahí hay que seleccionar la unidad de disco a trabajar.


PD2: No he olvidado lo que estábamos haciendo. Tengo claro que tendré la versión de Java sea como sea y su tutorial.
Ja, esperaba que lo dijeras :D

Metaconta

#4
Aug 18, 2017, 07:10 pm Last Edit: Aug 18, 2017, 07:22 pm by Metaconta
Hola:

A buscar información sobre I2C con Arduino.
hispavila.com/total/3ds/atmega/i2c-eeprom.html

Al menos para entender como funciona. Solo falta saber más datos que tengo que averiguar.

Enviar archivo hex a Arduino que son tramas de Bytes y se va guardando en la EEPROM. Lo mismo para lectura.

¿Cómo funciona por dentro?

No lo se, al menos por ahora, ajjajajaja.

Me imagino que por cada Byte enviado desde el ordenador o PC, lo guarda en memoria, en una variable de Arduino y lo va escribiendo a la EEPROM.

Ahora a buscar ejemplos por todas partes como trabaja para poder ser capaz de enviar y recibir datos desde la EEPROM.

En cuanto a la interfaz alfa, en realidad el % es la cantidad de Bytes transmitido en este caso al pulsar el botón Grabar. Ya lo corregí, ahora pone Bytes en vez del %. ;)

Saludos.



Edito:


Ver enlace.


Desarga ejemplo Ardino y Proteus.

Por lo que veo, usa velocidad muy lento a 9600 baudios.


Lucario448

¿Cómo funciona por dentro?

No lo se, al menos por ahora, ajjajajaja.

Me imagino que por cada Byte enviado desde el ordenador o PC, lo guarda en memoria, en una variable de Arduino y lo va escribiendo a la EEPROM.
Algo así. De hecho el concepto es similar al de cómo transmitir un archivo. La idea de "petición y respuesta" se debe al simple hecho de que el Arduino necesita saber si el flujo de datos viene o va a la EEPROM, además de opcionalmente poder escuchar la petición de cancelar la transmisión mientras esta ocurre (ya sea por decisión del usuario o por el manejo de una excepción); porque si por alguna razón el programa deja de recibir, el Arduino se bloquearía hasta lograr iterar por toda la EEPROM (aunque en vano eso sí).

Lo difícil va a ser cómo cancelar un grabado de EEPROM, porque recuerda que un flujo binario es completamente arbitrario (enviarle un código de paro no es posible porque el Arduino creerá que es parte del contenido a grabar). Una posible solución sería aprovechar el mecanismo de "timeout" que proveen las clases que extienden de Stream (ejemplo: Serial); si el programa dejara de transmitir durante unos segundos, se asume que el grabado se canceló (aquí es necesario que el Arduino envíe una respuesta para indicarle al programa en PC que reconoció el fin de la transmisión y que está listo para recibir otra orden).


Lo que acabo de decir es apenas "una probadita" de lo que tengo en mente de cómo podría funcionar por el lado de Arduino.

Por lo que veo, usa velocidad muy lento a 9600 baudios.
9600 / 11 (una trama "8N1" del protocolo UART necesita al menos 11 bits para transmitir un byte: 2 bits de inicio, 8 bits de datos y 1 de parada) = 873 B/s (bytes por segundo).

Estoy de acuerdo que 873 B/s es extremadamente lento (una EEPROM de 2 Mbits tomaría casi 5 minutos en volcarse o grabarse); sin embargo 115200 bps muy probablemente más bien sea demasiado.
Dependiendo del ritmo de escritura de estas EEPROM, no podremos darnos el lujo de acelerar la comunicación serial; o podría ocurrir una pérdida de bytes durante la grabación.

Metaconta

#6
Aug 18, 2017, 10:43 pm Last Edit: Aug 18, 2017, 10:44 pm by Metaconta
Buenas:

No había caído sobre la cancelación de las EEPROM. IC-Prog, WinPic800 y PonyProg estén leyendo o grabando, se puede cancelar sin problemas y también verificar, que esto es comprobar pero no se su forma interna.

Voy a informarme bien sobre interrumpir la transferencia de escritura o lectura desde Visual Studio, porquemientras envíe datos, no se como interrumpirlo. Cuando lo consiga, pongo el código aquí para que lo sepan.

Poco a poco vamos avanzando. ;)


En cuanto a la velocidad de los baudios, tendré en cuenta cual acepta las EEPROM y desde VB .net, con posibilidad de cambiar su velocidad.

Saludos.

Lucario448

y también verificar, que esto es comprobar pero no se su forma interna.
Usualmente existen dos métodos de verificación:
  • Comprobar igualdad entre el byte ingresado y recuperado: es una verificación que se hace "al vuelo" de la escritura. La IDE de Arduino utiliza este método para verificar el programa a subir (nótese que es por algo que ambos LEDs TX y RX se encienden durante este proceso).
  • Verificación post-proceso: como el nombre lo dice, es grabar e inmediatamente realizar un proceso de lectura. Al final también es comparar contenido en la fuente y destino, generando un código hash. Si estos códigos coinciden, todo bien; caso contrario algo salió mal durante la grabación.

Para efectos de este proyecto, sugeriría que el método de verificación sea el segundo. La lectura de esas EEPROM es a nivel de bytes, pero la escritura es a nivel de bloques (de 64 bytes); el sobrecargo sería enorme si se intenta verificar "al vuelo".

Voy a informarme bien sobre interrumpir la transferencia de escritura o lectura desde Visual Studio, porquemientras envíe datos, no se como interrumpirlo. Cuando lo consiga, pongo el código aquí para que lo sepan.
Inténtalo; yo ya más o menos te dije cómo por el lado de Arduino.

Metaconta

Buenas:

Haciendo pruebas, se me cancela al segundo clic, ejjejeje. Deja ver si lo logro, parece que al final tengo que hacer Thread.

Code: [Select]
            for (int i = 0; i <= archivo.GetUpperBound(0); i++)
            {
                serialPort1.Write(archivo, i, 1);
                progressBar_barrra_progreso.Value = i;
                label_Bytes_transmitidos.Text = i.ToString() + " Bytes.";
                Application.DoEvents();
                if (interrumpir) break;
            }


Saludos.

Lucario448

¿Porqué otro hilo? El clicar el mismo botón debería disparar un evento (función) donde se modifica el valor de interrumpir.

Metaconta

Hola:

Ya funciona, ajajajaj ajjaja, por fin, ya puedo enviar y cancelar.
Code: [Select]
        bool alto = false;

        private void TestDoEvents()
        {
            byte[] archivo = File.ReadAllBytes(textBox_ubicacion_archivo.Text); // Carga el archivo en el array.

            progressBar_barrra_progreso.Maximum = archivo.Length; // Hasta donde llegue el tamaño del archivo.

            for (int i = 0; i <= archivo.GetUpperBound(0); i++)
            {
                serialPort1.Write(archivo, i, 1);

                progressBar_barrra_progreso.Value = i;

                label_Bytes_transmitidos.Text = i.ToString() + " Bytes.";

                Application.DoEvents();
                if (alto == true)
                {
                    alto = false;
                    break; // TODO: might not be correct. Was : Exit For
                }
            }
            button_Cancelar.Text = "Arranque";

        }


Botón.
Code: [Select]
        private void button_Cancelar_Click(object sender, EventArgs e)
        {
            if (button_Cancelar.Text == "Arranque")
            {
                button_Cancelar.Text = "Cancelar";
                TestDoEvents();
                progressBar_barrra_progreso.Value = 0; // Resetear progressBar a 0.
                label_Bytes_transmitidos.Text = "0";
            }
            else
            {
                if (alto == true)
                {
                    alto = false;
                }
                else
                {
                    alto = true;
                    button_Cancelar.Text = "Arranque";
                }
            }
        }


Me falta el santo 100 % que no me sale bien, pero si el conteo de los Bytes.

Lucario448

Me falta el santo 100 % que no me sale bien, pero si el conteo de los Bytes.
Eso se resuelve con una función similar al map en Arduino (regla de tres). Si tuviera la estructura de la función de Arduino, sería como:

Code: [Select]
map(i, 0, archivo.Length, 0, 100);


PD1: creo que también debe solicitar cuál EEPROM exactamente se está programando; no solo varían en capacidad, sino que también en el tamaño de página de escritura. El búfer de salida del I2C es de 32 bytes, espero que eso no implique que no se puedan enviar 64 bytes (tamaño de página de escritura de la de 256 Kbit) en una sola transmisión. Recuerda que en esas EEPROM es más eficiente escribir por páginas (bloques) que por bytes individuales.


PD2: la lectura podría ir tan rápido como lo permita el bus de I2C a 400 KHz; pero la escritura no. Según los datasheets, escribir una página le toma máximo 5 ms; para ir a la segura es mejor mantenerse a ese ritmo.
Como no escribimos un byte cada 5 milisegundos, sino al menos 16 por transmisión; creo que es posible hasta ir más allá de 9600 bps. ¿Hasta dónde? Eso será con prueba y ensayo; si vamos demasiado rápido, se llena el búfer RX de Arduino y se pierden bytes.

Metaconta

#12
Aug 22, 2017, 01:22 am Last Edit: Aug 22, 2017, 02:31 am by Metaconta


Por fin me salió el porcentaje de las narices. El map de Arduino no lo tiene C# ni por asomo.

Código C#:
Code: [Select]
   // Variables.
        bool alto = false;
        int N = 0;
        int P = 0;
        int resul = 0;

        private void TestDoEvents()
        {
            // Carga el archivo en el array.
            byte[] archivo = File.ReadAllBytes(textBox_ubicacion_archivo.Text);

            // Hasta donde llegue el tamaño del archivo.
            progressBar_barrra_progreso.Maximum = archivo.Length;

            // Guarda la cantidad de Bytes del archivo en la variable.
            N = archivo.Length - 1;

            // Transmite byte en byte los datos del archivo al puerto serie.
            for (int i = 0; i <= archivo.GetUpperBound(0); i++)
            {
                // Enviando archivo al puerto serie.
                serialPort1.Write(archivo, i, 1);
                
                // Números de Bytes.
                P = i;
                
                // Resultado de la regla de tres. Cálculo del porcentaje de la barra de progreso.
                resul = 100 * i / N;
                
                // Muestra barra del progreso.
                progressBar_barrra_progreso.Value = i;

                // Muestra la cantidad de Bytes enviados.
                label_Bytes_transmitidos.Text = i.ToString() + " Bytes.";

                // Muestra la cantidad en porciento archivo enviado.
                label_Por_ciento.Text = resul + " %";

                // Evento de cancelación.
                Application.DoEvents();
                if (alto == true)
                {
                    alto = false;
                    break; // TODO: might not be correct. Was : Exit For
                }
            }
            button_Cancelar.Text = "Arranque";
        }

        private void button_Cancelar_Click(object sender, EventArgs e)
        {
            if (button_Cancelar.Text == "Arranque")
            {
                button_Cancelar.Text = "Cancelar";
                TestDoEvents();
                progressBar_barrra_progreso.Value = 0; // Resetear progressBar a 0.
                label_Bytes_transmitidos.Text = "0";
            }
            else
            {
                if (alto == true)
                {
                    alto = false;
                }
                else
                {
                    alto = true;
                    button_Cancelar.Text = "Arranque";
                }
            }
        }


En cuanto a lsa EEPOM, no sabía que por cada una hay diferente tamaño de la página.

Ver lista EEPROM I2C.

Pues mira que lo tengo progamado enviar todo de golpe. Jajajajaajjajjjja, hasta el final no para de enviar archivos bytes por bytes.

Enviar archivo hex al puerto serie en C#:
Code: [Select]
    private void button_Grabar_Click(object sender, EventArgs e)
        {
            byte[] archivo = File.ReadAllBytes(textBox_ubicacion_archivo.Text); // Carga el archivo en el array.
        }


El libro morado de Enrique Palacios sobre PIC16F84A explica muy bien la EEPROM 24LC256, de 64 páginas. Voy a leer bien las hojas de datos de cada modelo, concretamente los que yo tengo, 24LC16B y el 24LC64. Por supuesto que también los demás y pongo aquí en resumen tamaño y paginación de cada uno de ellos.

EEPROM protocolo I2C:

EEPROM - CAPACIDAD - PAGINACIÓN
-----------------------------------
24LC00 - 128 bit - 0 Bytes.
24LC01B - 1 Kbit - 8 Bytes.
24LC02B - 2 Kbit - 8 Bytes.
24LC04B - 4 Kbit - 16 Bytes.
24LC08B - 8 Kbit - 16 Bytes.
24LC16B - 16 Kbit - 16 Bytes.
24LC32A - 32 Kbit - 32 Bytes.
24LC64 - 64 Kbit - 32 Kbytes.
24LC128 - 128 Kbit - 64 Bytes.
24LC256 - 256 Kbit - 64 Bytes.
24LC512 - 512 Kbit - 128 Bytes.
24LC1025 - 1025 Kbit - 128 Bytes.
24LC1026 - 1026 Kbit - 128 Bytes.
AT24CM02 - 2 Mbit - 256 Bytes.

Casi no acabo de escribir todo esto.

Cuando pula un poco más el programa, tendré que remplantearme la forma de escribir código para cada dispositivo.

Hay que tener cosas claras. Desde C#, selección de dispositivo y bien programado para cada uno de ellos. Incluido paginación, y el array de datos a enviar, por ejemplo, 64 Kbit, así que tendrá un máximo y graba hasta ahí.

Si no hay que grabar Byte por Byte que es lo que estaba haciendo.

¿Cómo haces la manera que dices para grabar EEPROM?

Por ejemplo, el 24LC256. ¿Tengo que enviar 64 bytes por 64 bytes?

¿Así?

Envío 64 Bytes.
Delay o timer (5 ms (Mili segudnos)).
Envío 64 Bytes.
Timer (5 ms).
Envío 64 Bytes.
Timer (5 ms).
Envío 64 Bytes.
Timer (5 ms).
Envío 64 Bytes.


Cuando digo 5 ms, me imagino que es su descando, es decir, no enviar nada hasta que pase ese tiempo, luego vuelve a enviar 64 Bytes eguidos, luego descansa otros 5 ms sin enviar nada y así hasta veces cuanta.

24LC256 32K Bytes x 8 bits = 256 Kbits.

32 KBytes divididos en 64 páginas de 256 Bytes cada una.

Me confirma como ejemplo, la realidad de como hacerlo. Luego lo haré en programación y lo pongo aquí.

Saludos.

Lucario448

El map de Arduino no lo tiene C# ni por asomo.
Es obvio que no (o al menos no con ese nombre), porque es un implementación aparte de lo que suele traer C++:
Code: [Select]
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

En AVR eso equivale a tantas instrucciones máquina que a 16 MHz debe tomarle al menos medio milisegundo (o más si lidiar con signos es otro sobrecargo).

Cuando pula un poco más el programa, tendré que remplantearme la forma de escribir código para cada dispositivo.
O puedes delegar esa responsabilidad al Arduino. Podemos implementar un comando que establezca la EEPROM que tiene conectada; así después el mismo Arduino se va a encargar de manejar la capacidad y el tamaño de las páginas.

Si no hay que grabar Byte por Byte que es lo que estaba haciendo.
Ni loco. Cada vez que el maestro finaliza la trasmisión (indiferentemente de cuántos bytes se hayan transmitido), la misma EEPROM realiza una escritura de la página completa. Si lo haces así con una de página de 128 bytes, estarías sobrescribiendo el mismo bloque 128 veces (y tardaría 640 ms en vez de 5 ms en una sola pasada).


¿Cómo haces la manera que dices para grabar EEPROM?

Por ejemplo, el 24LC256. ¿Tengo que enviar 64 bytes por 64 bytes?

¿Así?

Envío 64 Bytes.
Delay o timer (5 ms (Mili segudnos)).
Envío 64 Bytes.
Timer (5 ms).
Envío 64 Bytes.
Timer (5 ms).
Envío 64 Bytes.
Timer (5 ms).
Envío 64 Bytes.


Cuando digo 5 ms, me imagino que es su descando, es decir, no enviar nada hasta que pase ese tiempo, luego vuelve a enviar 64 Bytes eguidos, luego descansa otros 5 ms sin enviar nada y así hasta veces cuanta.
Es correcto. Observa que casualmente el búfer RX también es de 64 bytes; si en un lapso de 5 ms se nos llena, se pueden perder bytes. El flujo debe ser constante pero a la vez que se pueda consumir con rapidez; el balance debe quedar de tal forma que la transmisión no sea lenta, pero a la vez que nunca llegue a llenar el búfer. Recuerda que en ese lapso de 5 ms el Arduino no puede consumir los bytes del búfer RX.

Otra preocupación está en I2C; sé que la librería implementa búferes de 32 bytes para los dos sentidos, pero lo que no sé es si los bytes se encolan hasta el endTransmission(), o si se consumen al vuelo. Los recibidos mediante requestFrom() se consumen mediante Wire.read().




PD: para programar una comunicación "petición-respuesta", debes definir muchas constantes. Puedes ya sea crearlas en líneas #define, o empaquetarlas en enumeraciones. La idea es tener una base que nos facilite este desarrollo. Por ejemplo:

Code: [Select]
// Comandos

/* Establece la EEPROM a trabajar.
Sintaxis: 1 byte que representa el índice de la EEPROM.
Respuesta: 1 byte, puede ser OK o INVALID_ARGUMENT.
*/
#define SET_EEPROM 0x01

/* Ordena al Arduino a volcar la EEPROM.
Sintaxis: N/A.
Respuesta: 5 bytes: un unsigned long que representa el tamaño de la EEPROM (en bytes), luego un WAITING.
*/
#define READ_EEPROM 0x02

/* Ordena al Arduino a grabar en la EEPROM.
Sintaxis: 4 bytes: un unsigned long que representa el tamaño real del archivo que va a recibir.
Respuesta: 1 byte: puede ser READY, SMALLER_THAN_EEPROM_WARNING o LARGER_THAN_EEPROM_WARNING.
*/
#define WRITE_EEPROM 0x03

/* Ordena al Arduino a abortar el volcado de la EEPROM o tarea preasignada.
Sintaxis: N/A.
Respuesta: ABORTED.
*/
#define ABORT_OPERATION 0x10

/* Le indica al Arduino que prosiga con la tarea preasignada. Se recibe cuando este haya respondido con WAITING
Sintaxis: N/A.
Respuesta: N/A.
*/
#define PROCEED 0x00

// Respuestas

#define OK 0x00 // Indica que el comando fue recibido o que la tarea se completó exitosamente.
#define UNKNOWN_COMMAND 0x01 // Indica que se recibió un comando desconocido, o inválido para el contexto actual.
#define INVALID_ARGUMENT 0x02 // Indica que alguno de los valores de la sintaxis es inválido; o que se superó el timeout antes de recibir la cantidad de bytes esperada.
#define ABORTED 0x03 // Indica que la operación en proceso fue abortada exitosamente.
#define WAITING 0x10 // Indica que el Arduino está esperando un acuerdo con el programa que lo manipula. Se suele usar para esperar a que el programa controlador esté listo para recibir un flujo de bytes.
#define READY 0x11 // Indica que el Arduino está listo para recibir un flujo de bytes entrante.
#define SMALLER_THAN_EEPROM_WARNING 0x12 // Funciona igual que READY, con la salvedad de que además advierte que el archivo a grabar tiene menor tamaño que la EEPROM a trabajar.
#define LARGER_THAN_EEPROM_WARNING 0x13 // Funciona igual que READY, con la salvedad de que además advierte que el archivo a grabar tiene mayor tamaño que la EEPROM a trabajar.

Eso como ejemplo; aquí faltaría definir una tabla de valores que se asignaría a cada EEPROM y documentar cómo funciona cada operación que se le podría ordenar al Arduino.

surbyte

A la la interfaz de prueba le falta a la izquierda las posiciones en hexa que ayuden a entender donde estas parado y también agregaría una opción de EDICION.

Go Up