EEPROM: Como guardar y leer datos con PSoC5LP

Proyectos con PSoC

EEPROM: Como guardar y leer datos con PSoC5LP

Muchas veces en nuestros proyectos y aplicaciones, necesitamos algo que sea capaz de guardar algunos tipos de datos que nos proporcionan sensores, llámense posición, temperatura, humedad, Etc. O simplemente datos de inicialización necesarios para que un programa corra sin problemas. Es aquí en donde entra a jugar la memoria EEPROM, que como bien se sabe es una memoria de borrado electrónico que es capaz de retener datos para su almacenamiento durante los cortes de energía de la tarjeta y posterior lectura una vez se requiera.

 

Pero hablemos un poco de la memoria EEPROM de PSoC:

Datasheet EEPROM

Como bien lo dice la hoja de datos de la memoria EEPROM de PSoC5LP dice que tenemos
– 512B a 2KB de memoria

– 1 Millón de ciclos de lectura escritura : Significa que vamos a poder leer y escribir un millón de veces, hace referencia más a la vida útil de estas memorias, para tener en cuenta ;).
– Lectura y y escritura de 1 byte por tiempo
– Capaz de programar 16Bytes A la vez
El uso de una memoria EEPROM tiene como base tratarla como una matriz, una vez se entienda este concepto se puede pensar en como programarla, lo explicaremos con el siguiente gráfico:
Tenemos que pensar en que hay direcciones de memoria que hacen referencia a el lugar en donde guardaremos los datos que para este proyecto seran solo 8 bits de datos.
En cada dirección de memoria esta presente un dato, entonces de esta manera y para el ejemplo de la imagen queda de la siguiente manera:

Dirección: 000 – Dato :0100

Dirección: 001 – Dato :0011

Dirección: 010 – Dato :1000

Etc…

Tener en cuenta que el manejo de las direcciones se muestran en binario pero pueden ser equivalentes a los hexadecimales o a enteros, cosa que no pasa con los datos, los datos son guardados de forma binaria en la memoria, como ya lo dije para este proyecto serán 8 bits , pero a la EEPROM del PSoC5LP guarda mas de 1 byte por dirección. Mi recomendación es que los datos se comparen con la tabla ASCII para ser guardados en 8 bits en la memoria EEPROM, se trata parte por parte y se guardan en diferentes direcciones de la EEPROM, así como haremos aquí.

El proyecto que construiremos se trata de un simple contador de 4 dígitos, lo construiremos a partir de un pulso generado por un PWM y a través de una interrupción incrementaremos dígito por dígito el contador, se hace de esa manera por que como se dice anteriormente vamos a comparar cada dígito con la tabla ASCII y guardar los caracteres en cada posición de la memoria EEPROM, por lo tanto usaremos 4 posiciones de memoria para guardar nuestro contador de 4 dígitos.
Una vez se le quite la energía a nuestro contador, el ultimo valor del contador quedará guardado en la memoria, para que cuando se vuela a energizar, reinicie el contador desde el valor donde iba, gracias a la lectura de este valor de la memoria.
El Objetivo General será aprender a Leer y guardar datos en la memoria EEPROM
Una vez tengamos claro cual es el manejo de lectura y escritura de los datos de la memoria, será fácil seguir a guardar cosas más grandes y en general cualquier tipo de dato, dándole un correcto tratamiento, repito que mi recomendación es tratar todo con la tabla ASCII.
Para comenzar a construir este proyecto tendremos que  empezar a construir el diagrama esquemático del programa
Lo primero que tengo que hablar es que el PWM tiene un reloj tan lento por que necesitamos que las cuentas sean pocas para lograr 1 Seg, el cual tiene a su salida un LED para indicarnos que efectivamente esta funcionando el PWM a 1seg, también tiene una interrupción ligada que será la que nos proporcione el incremento uno a uno de los dígitos.
Necesitamos en donde mostrar los datos, para esto utilizo la librería de LCD custom, en donde podemos asignar los pines a donde queramos, esta librería se las dejare al final del articulo y tendrá que ser añadida manualmente por ustedes, a cada salida se le asigna un pin en strong drive y se asigna los nombres para no confundir nada.
Necesitamos el bloque de la memoria EEPROM también, no hay que configurar nada, el tratamiento de este bloque es solamente por software, bastará entonces con incluir el bloque al diagrama esquemático.
Por ultimo añadimos un botón de reset, este botón he decidido ponerlo externo solamente para mostrar que también funciona, el pin debe estar configurado como entrada en Pull up resistivo y conduce a una interrupción por flanco de subida. Este reset simplemente escribirá ceros en la memoria EEPROM y reiniciará el programa para que las cuentas empiecen de 0.
Lo que hay que hacer antes de compilar este programa :
Para que funcione el sprintf tenemos que hacer algunas cosas en el compilador
1.
2. Accederemos a las opciones del compilador y allí tenemos que añadir la opcion -u_printf_float como lo muestra la imagen:
3. Luego de esto vamos a nuestro archivo de configuración de pines y en el tenemos que cambiar el heap size de 0x80 a 0x200.
Una vez hecho esto tenemos que cablear la protoboard, lo cual es un proceso sencillo por que solamente estamos usando una LCD para mostrar todo el proceso, mi LCD la tengo cableada de la siguiente manera como ya es habitual:
y lo unico que haría falta es el boton de reset externo con una resistencia de pull down, como lo muestra la siguiente imagen:
Lo único que cambio es que yo utilizo una resistencia de 10K en ves de la de 4.7K.

SOFTWARE

Como ya lo había explicado este es un proyecto que se basa más en software que en hardware, por tanto voy a dar la descripción completa del algoritmo del proyecto y dejaré el código comentado para que se pueda entender:
lo primero que hice fue partir de la interrupcion generada por el PWM, en el método de interrupción, se hacen las reglas de incremento , separé los 4 dígitos del contador y los asigne a un vector entero de 4 posiciones. Cada vez que se generaba una interrupción se hacían las reglas de incremento de dígitos, para así completar el contador de 4 dígitos de 0 a 9999. Seguido a esto en el mismo método de interrupción se hace la conversión de el vector de enteros a vector de caracteres (ASCII), necesario para poder almacenar en la memoria EEPROM, seguido se hace la escritura en la memoria EEPROM mediante la siguiente instrucción:

writeStatus=EEPROM_WriteByte(numaimp[3],0);
La variable writeStatus hace referencia a si la lectura o escritura fue correcta, la función EEPROM_WriteByte() devuelve un 0 o 1 haciendo referencia a si la escritura fue correcta, de esta manera poder hacer un buen control del proceso.
Esta instrucción recibe dos parámetros, el primero es el dato a escribir, en este caso será un caracter de 8 bits que será almacenado. El segundo parámetro hace referencia a la dirección, como lo dije al principio esta era binaria pero se podía escribir su equivalencia en entero. Para este proyecto utilizaremos las direcciones 0, 1, 2 y 3 de la memoria.
El código se encarga de almacenar los 4 dígitos de la memoria EEPROM.
Se han guardado los datos pero no se han leído
En el metodo de inicializacion se añaden las líneas que se ocupan para leer la memoria EEPROM las cuales son:

lectura[i]=EEPROM_ReadByte(i);
 
la instrucción es más sencilla que la de escribir, recibe la dirección la cual queremos leer y nos devuelve el dato en ella, para este caso lo que haremos será a través de un ciclo for, preguntar por las direcciones de la 0 a la 3 y guardar estas en un vector de caracteres que se llama lectura.
Pero este vector lectura no serviría para nada ya que no podemos hacer operaciones con el, por lo tanto cambiamos de caracter a entero.
por tanto este ultimo vector entero será el que podemos operar, y lo asignamos a el vector de numeros inicial para que pueda continuar los incrementos desde donde iba.
Por ultimo lo que queda por hacer es añadir la funcionalidad del reset. Simplemente hay que añadir el metodo de la interrupcion ligada al boton de reset, en este solamente a traves de la funcion de escribir datos en la memoria EEPROM, escribimos ceros en las posiciones de memoria que estamos utilizando y por ultimo para que el proceso se reanude, aplicamos un reset por software, el cual es:

CySoftwareReset();
 
Esto es a grandes rasgos el esquema del algoritmo utilizado para este proyecto, les dejaré el código completo y comentado aquí:

 

#include <project.h>
#include <stdio.h>//libreria para utilizar la funcion sprintf
#include <stdlib.h>//libreria para utilizar la funcion atoi y itoa
#include <string.h>//libreria para manejo de caracteres

int numero[4]={0,0,0,0};//vector central de 4 posiciones en donde estarán cada uno de los digitos del contador
char numaimp[4];//vector que contendra los 4digitos pero convertidos en caracter para su almacenamiento en EEPROM
char lectura[4];// vector que almacena los caracteres leidos de la memoria EEPROM

cystatus writeStatus;//Variable para verificar si la escritura fue correcta o no

int i=0;//variable utilizada en el ciclo for de lectura

CY_ISR(InterruptReset)
{
    for(i=0;i<=3;i++)// ciclo for para escribir ceros en la EEPROM
    {
        writeStatus=EEPROM_WriteByte('0',i); // escribimos en las direcciones de memoria que estamos usando los ceros
    }
    
    if(writeStatus == CYRET_SUCCESS)
    {
        
    }else{
    }
    
    CySoftwareReset();// reset por software
    
}

CY_ISR(InterruptTemp)// interrupcion ligada al PWM que la genera cada 1seg
{
    /*********************************************************************
    Hay que entender un poco la lógica de un contador de 4digitos, al utilizar
    uno a uno tenemos que preguntar por cada dígito, una vez llegue a 10, 
    incrementar el siguiente digito y volver a cero los anteriores, una vez que
    se halla incrementado el digito más significativo a 10, quiere decir que 
    hemos desbordado el contador entonces hay que volver todas las variables a 
    ceros
    *********************************************************************/
    
    numero[3]=numero[3]+1;
    if(numero[3]==10)
    {
        numero[2]=numero[2]+1;
        numero[3]=0;
    }
    if(numero[2]==10)
    {
        numero[1]=numero[1]+1;
        numero[2]=0;
        numero[3]=0;
        
    }
    if(numero[1]==10)
    {
        numero[0]=numero[0]+1;
        numero[1]=0;
        numero[2]=0;
        numero[3]=0;
        
    }
    if(numero[0]==10)
    {
        numero[0]=0;
        numero[1]=0;
        numero[2]=0;
        numero[3]=0;
    }
    
    /*
    Esta funcion sprintf convierte de una vez todos los enteros del vector numero
    y los convierte a caracter en la variable numaimp para su posterior almacenamiento
    */
    sprintf(numaimp,"%d%d%d%d",numero[3],numero[2],numero[1],numero[0]);
    
    writeStatus=EEPROM_WriteByte(numaimp[0],3);//almacenamiento de datos de la variable numaimp en la dirección de memoria 3
    writeStatus=EEPROM_WriteByte(numaimp[1],2);//almacenamiento de datos de la variable numaimp en la dirección de memoria 2
    writeStatus=EEPROM_WriteByte(numaimp[2],1);//almacenamiento de datos de la variable numaimp en la dirección de memoria 1
    writeStatus=EEPROM_WriteByte(numaimp[3],0);//almacenamiento de datos de la variable numaimp en la dirección de memoria 0
    
    
}


int main()
{
    CyGlobalIntEnable; 
    
    PWM_Start();//inicializacion del PWM
    EEPROM_Start();//Inicializacion de la memoria EEPROM
    LCD_Start();//inicializacion de la LCD
    
    LCD_Position(0,0);//ubicarse en la posicion de la lcd 0,0
    LCD_PrintString("Demo EEPROM");//imprimir texto
    
    isrTemp_StartEx(InterruptTemp);//liga la interrupcion del pwm en el esquematico, con el metodo que ejecuta
    isrReset_StartEx(InterruptReset);// liga la interrupcion del reset en el esquematico con el metodo que ejectuta
    
    for(i=0;i<=3;i++)//ciclo for dedicado a leer la memoria EEPROM y guardar los datos en el vector lectura
    {
        lectura[i]=EEPROM_ReadByte(i);//Lectura de eeprom, recibe la dirección y devuelve el dato de dicha direccion
    }
    
    numero[0]=(int)(lectura[0]-48);// conversion de la variable leida de la EEPROM que es caracter a entero
    numero[1]=(int)(lectura[1]-48);// conversion de la variable leida de la EEPROM que es caracter a entero
    numero[2]=(int)(lectura[2]-48);// conversion de la variable leida de la EEPROM que es caracter a entero
    numero[3]=(int)(lectura[3]-48);// conversion de la variable leida de la EEPROM que es caracter a entero

    for(;;)
    {
        LCD_Position(2,0);//posicion 2,0 de la LCD
        LCD_PrintString("Val Cont: ");// imprimir texto
        LCD_PutChar(numaimp[3]);//imprimir variable convertida a caracter del entero que se esta incrementando
        LCD_PutChar(numaimp[2]);
        LCD_PutChar(numaimp[1]);
        LCD_PutChar(numaimp[0]);
        
        LCD_Position(3,0);// posicion 3,0 de la LCD
        LCD_PrintString("Ult val: "); // impresion de texto
        LCD_PrintString(lectura);// se imprime la variable lectura que hace referencia a todo el numero que estaba guardada en la EEPROM
        
    }
}

Solamente queda asignar los pines a donde tienen su LCD su LED y el boton de RESET, y a hacer las pruebas de funcionamiento, las imagenes del proyecto final funcionando:

Por ultimo les comparto un vídeo tutorial de este proyecto, explicado todo al detalle:

No se olviden de compartir 😉

Archivos del proyecto :

 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Bitnami