Hola. He estado viendo el datasheet de esa memoria, la 23LC1024.
El tema de las páginas, lo que he visto es que tiene 32 páginas de 32 KB ( KiloBITS) no confundas con Kb (Kilobyte). Eso son 32 x 32 = 1024 Kbits = 1 Mbit.
De todas formas no te rayes con las paginas, más abajo verás por qué.
Admite escritura secuencial desde el byte 0 al ultimo. Pero hay que activarlo, por defecto el modo es Byte. Tal y como el chip se alimenta arranca preparado para modo SPI (también admite SQI), y arranca en modo byte a byte, esto es, que primero hay que poner CS = 0, luego hay que enviarle el comando de escritura = 0b00000010 seguido de los 24 bits del Address , y luego el byte a grabar y por ultimo CS = 1; y así para cualquier byte.
De este modo puedes apuntar a cualquier byte sin importar en qué página esté, pero este modo salta a la vista que pierde un huevo de tiempo. Descartado.
Luego tiene otro modo que es por pagina, este modo es secuencial, pones CS = 0, envias comando de escritura, la posicion de inicio y a partir de ahi empiezas a mandar byte a byte todos los que quieras. El chip internamente te los va ordenando consecutivamente, pero solo hasta agotar la pagina donde estés, una vez agotada, si sigues enviando bytes saltaría a la posicion cero de esa página y empieza a sobreescribirla.
Y por ultimo está el modo que creo que te interesa: Secuencial. Funciona exactamente igual que el anterior pero aqui ya no va grabando dentro de una página sino toda la memoria entera a partir de la posición indicada en Addres.
Para implementar esto, al dar alimentación y arrancar tu programa lo primero que tienes que hacer es configurar la memoria para que trabaje en este modo, (secuencial), para ello el datasheet indica que la memoria arranca en modo Standby y que tienes que poner CS = 0; y seguidamente CS = 1; (un pulso) con eso el chip despierta.
Luego:
Poner CS= 0;
Enviar comando de escritura en el registro Mode (0b0000001) seguido de la configuración deseada que para activar el modo secuencial sería 0b01000000.
Poner CS = 1;
Con eso ya tendrías activada la memoria en modo secuencial.
Repite todas las operación con las otras dos memorias, no olvides el pulso al pin CS para despertar cada una de las memoria. También puedes mandar el pulso a las tres a la vez y luego activar también las tres a la vez poniendo a nivel bajo los tres CS’s, enviar el comando de configuración y los tres CS ‘s de nuevo a 1. Como prefieras.
No te voy a explicar con tramas de código por que desconozco el lenguaje que usas, pero el planteamiento sería:
Como te dije, los tres CS de las tres memorias los pones a tres puertos del pic, los que quieras.
Define esos puertos como CS1, CS2, y CS3 para acceder a ellos mas cómodamente.
SDI,SDO,SCLK en paralelo entre el micro y las tres memorias.
CS1 a CS de la memoria 1.
CS2 a CS de la memoria 2.
CS3 a CS de la memoria 3.
Eso en cuanto a Hardware.
Pon los tres CS´s como salida y arranca el programa poniendo los tres a nivel alto.
Cada memoria tiene 128 Kb (Kbytes) por lo que para llevar el control de "por donde va la memoria" necesitaras 17 bits, es decir, creas una variable de 32 bits para usarla como contador.
Haz un bucle, por ejemplo con un while, en ese bucle metes todas las rutinas de lectura del ADC.
Si el modulo ADC de tu micro almacena el resultado en un solo registro de 16 bits, luego separalos tu en dos variables distintas, ten en byte alto en una variable de 8 bits (ADCH por ejemplo) y el byte bajo en otra variable (ADCL por ejemplo).
Si el micro te da el resultado en dos registros de 8 bits entonces ya tienes este trabajo adelantado, no necesitas crear variables para el resultado.
Lo que hay que hacer es lo siguiente:
Te creas una variable global de tipo entero de 32 bits sin signo (accesible desde cualquier parte del programa) que puedes llamar por ejemplo “byte_counter = 0;” y la inicializas a cero. Esta variable contendrá la cuenta del numero de bytes exactos que llevas escritos en las memorias. Cada vez que envíes un byte a las memorias, una vez grabado esta variable se incrementará en una unidad.
Crea tres banderas (variable de tipo bool mismamente) que se llamen por ejemplo (memory1_open = 0;), (memory2_open = 0;), (memory3_open = 0;) y las inicializas a cero las tres, mas abajo verás para qué son estas banderas.
Ahora Haces una rutina que va a recibir byte a byte desde la rutina o bucle del ADC, leerá tu contador y en función de su valor seleccionará la memoria adecuada y así los datos irán a ella, por ejemplo:
Si (byte_counter <= (es menor o igual) a 127999) Y ADEMÁS (memory1_open = 0) { // Se tienen que cumplir las dos condiciones.
Pones CS1 = 0;
Envias a la memoria 1 el comando de escritura (0b00000010) seguido del address que sería CERO, para empezar a escribir la memoria desde el byte cero.
memory1_open = 1; // Indicamos que la memoria ya está abierta y asi no se repita el envío del comando a la memoria.
}
Todo lo anterior significa lo siguiente: Si el byte que acabamos de enviar está comprendido entre 0 y 127999 (eso son los 128.000 bytes) significa que estamos escribiendo en la memoria 1, o vamos a escribir en la memoria 1. Y además, la bandera Memory open debe ser cero, eso significa que vamos a EMPEZAR a escribir en la primera memoria que aun está cerrada, (hay que enviarle el comando de escritura y la dirección de donde vamos a empezar a escribirla, normalmente cero.
Entonces envías el comando a la memoria y la dirección de partida (cero) en tu caso y pones la bandera memory_open = 1. ¿ Para qué?. Para que la próxima vez que esta función sea llamada NO vuelva a enviarte el comando a la memoria, sino solo el byte en si.
Ya tienes abierta la primera memoria, a partir de ahora cada byte que le envíes se grabará el primero en la posición indicada y los siguientes en posiciones consecutivas.
Ahora entonces agregamos el segundo condicional, va a ser exactamente igual, pero para la segunda memoria:
Si (byte_counter <= (es menor o igual) a 255999) Y ADEMÁS es >= (Mayor o igual a 128.000 Y ADEMÁS, (memory2_open = 0) { // Se tienen que cumplir las TRES condiciones.
Pones CS1= 1; Desactivas la memoria anterior.
Pones CS2 = 0; Activas la segunda memoria.
Envias a la memoria 2 el comando de escritura (0b00000010) seguido del address que de nuevo sería CERO, para empezar a escribir la memoria desde el byte cero.
memory2_open = 1; // Indicamos que la memoria ya está abierta y asi no se repita el envío del comando a la memoria.
}
Esto es exactamente igual que el caso anterior, pero aquí preguntas si el contador está por encima de 127.999 y por debajo de 256.000 y de ser así, ya sabes que esos datos tienen que ir a la memoria 2, entonces preguntas además si la memoria 2 está abierta, si no lo está (memory2_open = 0;) cierras la anterior, CS1 = 1; abres la segunda memoria, CS2 =0; le envías el comando, informas de memoria abierta memory2_open = 1; y nada más.
Te quedaría hacer lo mismo, para la tercera memoria.
Preguntas si el contador está a 256.000 o por encima. Aquí ya no hace falta que preguntes si está por debajo de 384000 que sería el limite de información total, por que ya no tienes mas memorias puestas. Solo pregunta si está por encima de 256.000 Y ADEMAS
si la memoria 3 está abierta, igual que en los dos casos anteriores. No olvides cerrar la memoria 2 CS2 = 1;
Como ultima pregunta añade si el contador está a 384000 o por encima y en ese caso suspende el envió de bytes por que si no lo suspendes te sobreescribirá esa memoria desde el principio y por supuesto pon CS3 = 1; para desactivar la memoria 3.
Ahora manda al SPI a escribir tu byte de dato relevante.
Y por ultimo la función acaba incrementando el contador byte_counter = byte_counter + 1;
Fin de función o rutina de escrituras de byte.
Tu bucle inicial cada vez que lea un resultado del ADC mandará a esta fucnión DOS veces seguidas, una para el byte alto y otra para el bajo o al revés, como tu lo prefieras.
Tu bucle inicial debería interrumpirse cuando esta función indique que la memoria se ha llenado (La ultima pregunta de la función). Podrías hacer que la función devuelva 1 si puede seguir recibiendo datos o que devuelva cero cuando la memoria esté completa.
Uff, que tostón... Espero no liarte mas todavía.
Es muyyy fácil lo que quieres hacer.
Ah, y no tengas miedo de poner el SPI a 20 Mhz si tu pic te lo admite, esa memoria te los admite aunque si quieres seguridad déjalo en 15 Mhz. No importa que se estropee el square del SCL, la memoria tiene internamente su buffer preparado para amoldarse bien a lo que le llegue en el clock. como si es sinusoidal la señal, la sigue detectando bien.