Memoria Flash Serie por SPI - Obijuan/Cuadernos-tecnicos-FPGAs-libres GitHub Wiki
Introducción
La tarjeta Alhambra-II incluye el chip de memoria flash N25Q032A de 4MBytes (32Mbits), accesible a través del SPI. Esta memoria ya se utilizó en elCuaderno ténico CT6: SPI Maestro
El objeto ahora es realizar un controlador específico para esta memoria desde 0. Para ello partiremos de la información disponible en su Hoja de datos 1
Esta otra Hoja de datos 2 es para una memoria compatible, y que parece que tiene más información. Usaremos una u otra según lo vayamos necesitando
LOG
2023-08-30
Comenzamos leyendo la hoja de datos para obtener información general sobre la memoria. Esta información luego la resumiremos en el apartado Memoria Flash N25Q032A
- Frecuencia máxima de funcionamiento 108Mhz. Esto significa que se puede utilizar directamente con el reloj de 12Mhz de la Alhambra, sin ningún tipo de preescalado (spi de 12Mhz)
Las señales se muestran en la página 10 del Datasheet 1:
- Señal de reloj (C): Los datos de entrada (direcciones, comandos, datos...) se capturan en el Flanco de subida. Los datos de salida están disponibles en el Flanco de bajada
- Chip Select (S#): Activa a nivel bajo. Mientras esté a 1, la salida de la memoria (MISO) está en alta impedancia
- MISO: Datos de entrada en la FPGA (de la memoria a la FPGA)
- MOSI: Datos de salida de la FPGA (De la FPGA a la memoria)
La señal de datos de lectura (MISO) debe estar por defecto a nivel alto. Esto es lo primero que vamos a comprobar. Si dejamos el SS del SPI a 1 (desacivado), MOSI a 1 y conectamos el reloj al reloj del sistema.... qué valores se leen en MISO?
Experimento 1
Para ello vamos a conectar el analizador lógico. Antes de usarlo vamos a asegurarnos que el software está bien instalado y que podemos leer correctamente. La versión del pulseView que estoy usando es: 0.5.0-git-153225b. Conecto el pulsador SW1 al pin D0 y lo medimos con el analizador a una frecencia de 20Hz... vemos cómo efectivamente se ven los pulsos... está funcionando!
Este es el resultado. Los pulsos se corresponden con pulsación del botón 1 de la Alhambra II
Experimento 2
En el siguiente experimento vamos a medir el SPI completo entre la FPGA y la Memoria: MISO, MOSI, SS y SCK. Metemos un '1' por SS y otro '1' por MOSI
Leemos un '1' por MISO siempre... esto es lo esperado....
Activamos el protocolo SPI en el PulseView, y sobre él el protocolo de la memoria flash
Vemos que se está enviando el comando 0xFF (pero con ss desactivado) y por eso el protocolo de la memoria dice que no se conoce
Experimento 3
Ahora vamos a hacer un circuito para enviar el byte 0x9F
que se corresponde con el Identificador de la Flash. En principio se debería leer 0xFFFFFFFF ya que la memoria está apagada, en modo de bajo consumo. Pero vamos a hacer pruebas...
Al apretar el pulsador se envía un pulso por la señal start
(que se envía también al analizador por el canal 4):
Este pulso hace que la señal ss
se active (se pone a 0) y se deja de resetear el registro de desplazamiento, comenzando el envío del comando 0x9F
La señal de reloj está a 0 y se activa cuando ha comenzado la transmisión
Esto es lo que se lee en el analizador lógico:
Efectivamente el valor leido (miso) es siempre '1', como esperábamos. El protocolo del pulseview detecta que se trata del comando de la lectura del identificador...
2023-08-31
Experimento 4
LO que vamos a hacer ahora es enviar primero el comando 0xAB
para despertar a la memoria (wake-up) y que salga del modo de bajo consumo y después enviamos el comando READID otra vez...
Como no sabemos todavía qué temporización necesitamos tras el comando de wake up, lo vamos a hacer manualmente. Al apretar el pulsador SW2 se envía el comando AB, con lo que la memoria se quedaría lista... si ahora apretamos SW1 y enviamos READID se debería leer algo...
Pero empecemos primero con un circuito para enviar el comando wake-up...
Estoy teniendo problemas para generar la correcta temporización, de una manera sencilla... así que voy a dividir el experimento en partes más pequeñas... Lo primero que voy a hacer es un circuito para generar 4 ciclos de la señal del sistema
Para aislar los 4 pulsos de reloj se utiliza un pulso de 4 ciclos de anchura y se hace una and entre esta señal (busy
) y la señal de reloj clk
.
La señal de busy
se obtiene a partir de un registro de desplazamiento que tiene un único bit a 1 al comenzar la señal de busy. Con una puerta or
se obtiene esta señal de busy
El resultado se muestra en el analizador lógico:
Apreciamos que la señal de reloj sólo tiene 4 ciclos
2023-09-05
Experimento 5
Ahora que tenemos esta generación controlada, vamos a enviar el comando wake-up (0xAB). Para simplificar no voy a emitir 8 pulsos de reloj, sino que vamos a dejar el reloj emitiendo continuamente y lo que cambiamos es la señal de ss. Al fin y al cabo, cuando ss está desactivado (1
) el periférico en cuestión ignora lo que llega por su entrada de reloj... Esto simplifica las cosas... aunque todavía está por probar si esto funciona o no...
El circuito simplificado es este:
Tenemos los siguientes sub-circuitos:
- Uno para generar la señal
ss
. Se pone a0
al comenzar y se lleva a1
al terminar - Otro para la transmisión del comando: Es un registro de desplazamiento de 8 bits (con el valor idle 0xFF). Se carga al comenzar, y en los siguientes ciclos realiza el desplazamiento
- Controlador: Indica las fases por las que se pasa
El controlador está formado por biestables conectados en cascada. Inicialmente están todos a 0. Cuando se aprieta el pulsador se general el tic en start
. Este tic se mete en el primer biestable, indicando que estamos en la fase 1. En esta fase es donde se ha activado ss
y se ha cargado el comando 0xAB
en el registro de desplazamiento
A continuación pasa al siguiente registro (de 8 bits) que tiene un 1 por cada transmisión. Así este registro tieen los estados 1000_0000, 0100_000, ..., 0000_0001
Cuando se activa el último bit significa que ya se ha transmitido el último bit, y que se puede terminar. Es nuestra señal done
. Esta es la que se usa para volver a poner ss
a 1
Este es el resultado al medir con el analizador lógico:
Con el protocolo de la SPI eeprom vemos que el comando se ha enviado correctamente (en principio) y que lo ha detectado como Release from Deep Powerdown (RDP)
No hace falta resetear el circuito. Cada vez que se apriete el pulsador SW1 se envía un nuevo comando. Esto permite realizar varias lecturas con el analizador y comprobar que se envía el comando correctamente
Otra cosa es si la flash lo está recibiendo bien... Al menos el analizador comprueba que el protocolo SPI está funcionando...
Experimento 6
Ahora vamos a crear, por fin, el circuito que envía el comando 0xAB
(WAKEUP) con el pulsador SW1 y el comando 0x9F
(READID) con el pulsador SW2. Para hacer una prueba rápida clonamos el circuito anterior, pero sustituimos un comando por otro, y cambiamos el nombre de las etiquetas. Las señales finales de mosi
y ss
las obtenemos como la combinación de las anteriores. Si fuesen de lógica positiva las combinamos con una puerta OR. Pero como su estado desactivado es 1
las tenemos que combinar con una AND
Si con este circuito primero medimos el comando READID, como hicimos en el experimento 3, obtenemos idénticos resultado: el analizador detecta que se ha enviado el comando 0x9F... pero por MISO siempre leemos '1' (es decir, que la flash no envía nada)... como era de esperar
Si lo que apretamos es SW1, con el analizador medimos efectivamente el comando WAKEup se envía (como en el experimetno 5). Es para comprobar que no se ha roto nada al relizar la combinación de ambos comandos
La clave viene ahora. Primero resetemos la placa (con el circuito del experimento 6 cargado). Apretamos SW1 para despertar a la flash (sin medir nada todavía con el analizador), y ahora medimos el comando READID:
SIIIIIIII!!!!!! Hemos leido algo por el miso!!! La flash nos ha enviado algo!!!!! Los bytes recibidos son: EF 40 16 00... Es importante establecer los paramétros del SPI como Clock polarity 1 y Clock phase 0
Desde Icestudio comprobamos el identificador de la flash, que aparece en la ventana View/Command Output
Es la misma identificación!!!!! ¡Vaaaamos!!!!!! ¡¡Ya tenemos operativos los dos primeros comandos 0xAB y 0x9F!!!
Esto es un hito importantísimo para a partir de aquí ir construyendo el controldor de manera modular y poco a poco...
Experimento 7: Transmisor SPI del sistema
Vamos a refactorizar los circuitos de transmisión del SPI y encapsularlos. Creamos un que tenga la entrada start
y una de datos: es el transmisor. Como salida tiene un busy, un done y un mosi....
En este ejemplo se envía el valor 0xAA
y se lee con el analizador
La señal de busy
tiene la lógica típica de las máquinas: 0 significa que el transmisor está en reposo, y 1 que está transmitiendo. Por ello en el protocolo del analizador hay que poner la polaridad de ss en lógica positiva (su estado normal es negativa)
Esta es la salida del analizador:
Esta es la implementación del transmisor SPI:
Experimento 8: Lectura de la identificación
Esta es la reimplementación del ejemplo 6, pero usando el nuevo transmisor
Este es el resultado en el analizador lógico:
2023-09-06
Experimento 9: Envío de un byte
Voy a seguir frikeando con este transmisor spi... vamos a estudiar las diferentes formas de hacerlo...
Comenzamos con el envío de un byte al apretar un pulsador, pero usando una máquina de estados, que iremos ampliando poco a poco para incluir más cosas. En esta primera versión sólo hay una transmisión al apretar el botón SW1. Sucesivas pulsaciones de SW1 no tendrán efecto. El diagrama de estados es el siguiente:
Donde:
- E0: Es el estado inicial: IDLE. El circuito está en reposo hasta que se aprieta el botón SW1 (transición)
- E1: Es el estado final: Transmisión del dato. Al entrar en ese estado se genera la salida o1, asociada a la acción de envío del byte (señal
start
del transisor SPI) - t1: Transición 1: Es la señal del pulsador la que causa esta transición desde el estado
E0
- o1: Salida 1, asociada a la acción de comenzar con la transmsión de un dato
Este autómata se implementa mediante 2 biestables DFF, uno para cada estado. Como el estado inicial es E0, está inicializado a 1. La señal move
actúa sobre ambos biestables y es la encargada de realizar el movimiento del autómata. En este caso el movimiento sólo es debido a la única transición que hay: t1
La transición se produce sólo cuando el autómata está en el estado E0 y se aprita el pulsador. Este es el circuito:
Y este es la medición con el analizador. Sólo se muestr el envío del byte. Si se aprieta el pulsador más veces NO hay transmisión (porque el transmisor SPI nunca más se activará)
El dato 0xAA se envía perfectamente...
Experimento 10: Envío de un byte con cada pulsación
Ahora modificamos la máquina de estados para que se envíe un byte (siempre el mismo) con cada pulsación del botón. Pero sólo puede comenzar el siguiente envío cuando ha terminado el anterior. El nuevo diagrama de estados es el siguiente:
Desde el estado E1 se vuelve al estado inicial cuando se termina la transmisión (señal done
). Si estando en E1 se aprieta el pulsador, el controlador NO hace nada. Sólo cuando está devuelta en el estado E0 es cuando se puede volver a transmitir el byte
El autómata es muy parecido al anterior: Dos biestables pero ahora están en bucle, para volver del estado E1 al E0
La transición t2 se produce cuando estamos en E1 y llega Done. La señal de actualización del autómata (move) ahora se cambia bien cuando se produce la transición t1 o bien la t2
El resultado en el analizador es el mismo que en el experimento 9
Experimento 11: Envío de un byte y una espera de 4 ciclos
Modificamos la máquina de estados para que tras la transmisión del dato se entre en un estado de espera (de 4 ciclos). Al cabo de este tiempo se vuelve al estado inicial
Este es el nuevo autómata. En total hay 3 transiciones. Una al apretar el pulsador, otra cuando se termina la transmisión y otra cuando se termina la temporización de los 4 ciclos (o el tiempo que sea...)
Este es el circuito:
El autómata tiene 3 estados, por lo que hay 3 biestables D. Para la espera de los 4 ciclos se utiliza un registro de desplazamiento a la derecha que se activa con la transición 2. Cuatro ciclos después se genera la señal done2. Ambas señales, done y done2 se muestran en el mismo canal 5 del analizador (porque se producen en instantes diferentes)
Esta es el resultado en el analizador lógico:
Vemos que la señal done2
sale efecivamente 4 ciclos tras la señal de done que indica el fin de la transmisión spi
2023-09-07
Experimento 12: Envío de dos bytes iguales, con espera entre medias
Modificamos la máquina estado para que cada vez que se apriete el pulsador se envía un byte, seguido de 4 ciclos de retardo y luego se envía otra vez el mismo valor. Tras esto se vuelve al estado inicial
La máquina de estados es la siguiente:
Hay un total de 4 transiciones. Ahora el transmisor se activa en las transiciones t1 y t3
Este es el circuito:
Y en el analizador lógico vemos que efectivamente se envían los 2 bytes separados por una pausa:
2023-09-09
Experimento 13: Envío de dos bytes diferentes, con espera entre medias
Vamos a enviar dos bytes diferentes. Para ello ya no introducimos por la entrada del SPI un dato constante, sino uno variable. La forma más sencilla es añadir un registro de 8 bits con el primer dato (0x01) y por su entrada una constante con el segundo dato (0x02). Cuando se active la señal de load de este registro, el dato mostrado al SPI (para su siguiente envío) será 0x02. Basta con activar esta señal en la transición t2 (aunque sería totalmente equivalente hacerlo también con la t1). Cuando llega la señal done indicando que el primer dato se ha transmitido, se actualiza el dato, se realiza la pausa de 4 ciclos y se envía el nuevo valor
El autómata de estados es exactamente el mismo que el anterior
El circuito es este:
Y este es el resultado. Vemos los dos bytes enviados: 0x01
y 0x02
Experimento 14: Envío de dos bytes diferentes sin espera
Ahora vamos a enviar los dos mismos valores pero sin pausa. Uno a continuación del otro. Eliminaos el estado de espera, y nos quedamos sólo con 3 estados
El circuito es el siguiente:
Este es el resultado con el analizador lógico:
El primero byte se lee coorectamente pero el segundo no. Aparece un bit 1
de más, entre el primer byte y el segundo...
He estado haciendo pruebas y más ejemplos, y no consigo solucionarlo
2023-09-13
Experimento 15: Envío de dos bytes diferentes sin espera
Hoy se me ha ocurrido una solución... la máquina de estados del transmisor tiene 9 estados (uno de load y 8 de desplazamiento). Pero esto no debería ser así, porque con el load ya se está enviando el bit más significativo por tanto tendría que haber 7 estados adicionales... lo voy a probar...
siiiiiiii!!!!!!!!! Vaaaaamos!!!!!!!! Ya funciona!!!
El circuito es exactamente el mismo que del experimento 14, pero ahora con el transmisor modificado (versión 0.5):
Y este es el resultado:
Ahora ya sí que vemos que efectivamente se envía el byte 01
y a continuación el byte 02
2023-09-15
Experimento 16: Envío de wakeup + readid
En este ejemplo vamos a enviar el comando de wakeup seguido de una pausa de 1 ciclo (para que ss se desactive) y luego se envía el comando de readid seguido de infinitos ciclos de reloj... El objetivo es comprobar si se lee bien la flash con este nuevo controlador, y usando un autómata
Tras el envío del comando READID
se envían los bytes 0xFF indefinidamente (para realizar la lectura) (y SS queda activo todo el rato)
Este es el circuito:
El estado 4 (E4) se usa para mantener el SS a nivel bajo indefinidamente... Las transisiones t2 y t3 se usan para pasar al siguiente dato a transmitir
Y este es el resultado en el analizador lógico:
¡Funciona!!!!! siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii Se lee la identificación de puta madre: 0xEF 0x40 0x16
Experimento 17: Envío de wakeup + readid
En este experimento repetimos lo mismo que el anterior: enviar wakeup + readid para leer el identificador de la memoria. Pero al terminar se vuelve al principio. Cada vez que se apriete el pulsador se repite el proceso
El autómata ahora tiene 8 estados:
El circuito es mucho más grande porque hay que implementar todas las transiciones. En los siguientes experimentos lo reduciremos, si funciona bien
Este es el resultado:
siiii! Funciona!!! Ahora el analizador sí que detecta el modelo de la memoria, porque la transacción ha finalizado (ss se ha puesto a 1). Detecta que se trata de una memoria modelo: Macronix MX25L6405D
2023-09-17
Experimento 18: Leer un byte del identificador y mostrarlo en los LEDs
En este experimento vamos a leer el primer byte del identificador de la memoria y mostrarlo por los leds. Así poco a poco iremos construyendo el receptor spi
Para realizar la captura utilizamos la transición t5
que se produce cuando se ha recibido el primer byte. Este es el circuito:
El resultado en el osciloscopio es este (el mismo):
En los LEDs se lee correctamente el primer byte del identificador: 0xEF
Experimento 19: Leer el segundo byte del identificador y mostrarlo en los LEDs
Para leer el segundo byte bastaría con usar la señal de transición t6
en lugar de t5
. Esto es lo que se hace en este circuito:
El resultado en el analizador es similar al anterior. Las señales t5
y t6
se muestran en el canal done
:
SIN EMBARGO, el byte que se lee y que se muestra en los LEDs es 0x05
cuando debería ser 0x40
. En el analizador se muestra correctamente pero NO es lo que se lee en el registro de lectura del miso.... NO ESTÁ FUNCIONANDO, y hay que averiguar porqué...
Experimento 20: Leer dos bytese del identificador y mostrarlos en los LEDs
¡Ya he encontrado el fallo! El más gordo estaba en que se usaba un registro de desplazamiento a la derecha, cuando se debería usar uno hacia la izquierda, ya que el SPI envía primero los bytes de mayor peso.... El segundo problema estaba en que hay que hacerlo en flanco de bajada del reloj, por ello realizamos las lecturas en los flancos de bajada de t5 y t6
Este es el circuito:
Ahora al apretar el pulsador SW1 se hace la captura y en los LEDs se muestra el valor de menor peso: 0x40
. Al apretar SW2
se muestra el byte de mayor peso 0xEF
. ¡¡¡FUNCIONA!!!!!
Experimento 21: Leer los 4 bytes del identificador y mostrarlo en los LEDs
Usando las señales t5,t6,t7 y t8 se capturan los 4 bytes del identificador, y se muestran en los leds. Con el pulsador SW2 se cambia el byte a observar
¡Este circuito FUNCIONA! La lectura se hace correctamente!!! Ahora es el momento de modularizarlo y simplificarlo
2023-09-19
Experimento 22: Lectura inicial del identificador
Vamos a modificar el experimento 21 para hacer que se envíe el comando wakeup + rdid nada más arrancar la placa
Para ello vamos a añadir un tic en la transición t1, para comenzar bien cuando se apriete la tecla SW1 o bien cuando llegue el tic inicial
He comprobado que si se pone un tic inicial (con el circuito start) el sistema no funciona. Para encontrar el problema lo he sustituido por un tic retrasado un número de ciclos usando el componente sys-delay. He comprobado EXPERIMENTALMENTE que se necesitan al menos 50 ciclos de relog (0x32) para que la memoria flash sea accesible a través del SPI. Si se hace antes de esos 50 ciclos, por miso sólo se recibe el valor 0xFF
Este es el circuito de pruebas:
En los LEDs se puede comprobar que efectivamente se lee el valor correcto: 0xEF 0x40 0x16 0x00
Experimento 23: Lectura inicial del identificador
Ahora refinamos un poco el circuito de espera para consumir menos recursos. Usamos un contador de 6 bits para esperar 64 ciclos. Cuando el contador llega al máximo, se activa la transición t1 y el contador se queda inactivo (en estado de reset): Ya no vuelve a generar el tic de inicialización
El identificador se sigue leyendo correctamente en los LEDs
Experimento 24: Lectura identificador automática y con pulsador
Vamos a modificar el autómata para que nada más arrancar se despierte la flash y se lea el identificador. Al apretar el pulsador SW1 se lee directamente el identificador (sin enviar wake-up)
Este es el nuevo autómata a implementar:
En el circuito hemos cambiado la parte que envía el dato al transmisor del SPI. Ahora son unos multiplexores que envían el comando WAKEUP (0xAB) cuando el autómata está en el estado E0, el comando READID (0x0F) cuando estamos en los estados E2 y E8, y en el resto de estados el valor que se envía es 0xFF
En todos los casos el identificador se muestra correctamente por los LEDs
En el analizador vemos los siguiente: Al apretar reset se ve que se envían los dos comandos: wakeup y rdid:
Ahora al apretar SW1, sólo se envía el comando de lectura del identificador:
¡¡FUNCIONA MUY BIEN!!!
Experimento 25: Enviar sólo wakeup al arrancar el circuito
VAmos a empezar el proceso de simplificación. Lo primero es crear un circuito que envíe el comando wakeup al arrancar (con la temporización adecuada). Una vez enviado, el circuito queda ya inicializado. Al apretar el pulsador lo que se envía es el comando READID (pero sólo el comando, no los valores 0xFF para la lectura)
Este es el circuito:
Este es el cronograma que aparece al arrancar la placa:
y este es el que aparece al apretar el pulsador SW1
Experimento 26: Transmisor spi de bus
El circuito es el mismo que el del experimento 25, pero ahora se ha creado un bloque con el transmisor SPI con una entrada de bus. Los 8 bits más significativos de este bus son el dato a enviar, y el bit de menor peso es la señal de transmisión (start)
Este es el nuevo circuito:
Experimento 27: transmisor spi de bus simplificado
Este es el mismo circuito que el 26, pero con un controlador más simplificado. Inicialmente el biestable RS de estado (config) está a 0, indicando que NO está configurada la eeprom. Al cabo de 64 ciclos, se realiza el envío del comando wakeup. Cuando termina, al señal de done se retrasa 1 ciclo y se cambia el estado a config=1. Esto hace que en los próximos comandos ya no sean wakeup. Además ahora ya se devuelve la señal busy y done del propio controlador del SPI (sin retrasar)
Este es el cronograma al arrancar:
Y este es el cronograma al apretar el pulsador sw1:
2023-09-21
Experimento 28: SPI flash con inicializacion
El transmisor del SPI básico junto con el controlador para enviar el comando WAKEUP de inicialización se ha encapsulado todo en el bloque de Nivel 1 sys-spi-tx-bus-zero
Nada más arrancar el circuito este controlador envía el comando WAKEUP y lo señaliza activando la señal done0
. A partir de ese momento ya se comporta como un controlador SPI normal: envía el comando y cuando termina activa done
. La señal de busy
está a 1 durante toda la transmisión
En este experimento se envía el comando READID
justo al terminar la inicialización y también cada vez que se aprieta el pulsador SW1
Este es el resultado al apretar el pulsador de RESET
:
Vemos que efectivamente se envía el comando WAKEUP
y justo a continuación el READID
. Entremedias la señal de SS
se pone a 1 durante un ciclo
Al apretar el pulsador SW1
se envía el comando READID
. Este es el resultado en el analizador:
Falta por comprobar si el comando READID funciona correctamente cuando se envían más ciclos de reloj. Ese es el trabajo del próximo experimento
Experimento 29: Comando READID
En este experimento se transmite indefinidamente el comando READID para comprobar que el identificador se puede leer. Sólo se lee una vez ya que la señal SS no se debería poner a 1 (por el envío continuo de READID)
Este es el circuito de pruebas:
Y este es el resultado en el analizador lógico:
El controlador está funcionando!!! El identificador que se lee es correcto: 0xEF
, 0x40
, 0x16
, 0x00
Experimento 30: Lectura de la identificación en los LEDs
En este experimento se lee la identificación de la flash y se muestra en los LEDs. Es lo mismo que se ha hecho en el experimento 21 pero usando el transmisor spi con la inicialización
Este es el circuito:
Y esto es lo que se muestra en el analizador lógico:
Efectivamente el identificador se ve en los LEDs... ¡¡FUNCIONA!!
2023-09-22
Experimento 31: Lectura de la identificación en los LEDs
El circuito de este experimento es igual al del experimento 30, pero simplificando el autómata del controlador. En vez de colocar 5 biestables D para los estados, se usa un registro de desplazamiento de 5 bits. Los 4 primeros bits representan los estados de transmisión de los 4 primeros bytes, de los cuales, el primero es el comando readid y los 3 siguientes se usan para la recepción
El último estado es para la recepción del cuarto byte del identificador. Lo necesitamos para saber cuándo termina el controlador
El cronograma es exactamente el mismo que en experimento 30
Experimento 32: Lectura de la indentificación en los LEDs
El circuito para la lectura del identificador lo encapsulamos en el elemento flash-readid. Este experimento es igual que el 31, pero mucho más simplificado
El cronograma es exactamente el mismo que el experimento 31
Experimento 33: Lectura de la indentificación en los LEDs al inicio
Si ahora queremos leer automáticamente el identificador de la flash, al arrancar el circuito, basta con conectar la salida done0
con la entrada start
del bloque flash-readid
Con el analizador lógico vemos que al hacer el reset se envía el comando wakeup y luego el readid. En los leds se ve perfectamente el identificador
Experimento 34: hacia la lectura de un byte
Lo siguiente es empezar con la lectura de un byte de la flash. Lo primero es localizar el comando y saber cómo se usa
Leo en la hoja de datos que el comando para leer la flash es READ cuyo código es 03
. A continuación hay que enviar la dirección a la que se quiere acceder (3 bytes) y luego tantos bytes como se quieran leer. Con este comando se podría volcar la memoria completa... Esto es muy interesante
Comenzamos enviando el comando READ cuando se aprieta el pulsador. Y no metemos nada más
Este es el circuito:
En el analizador lógico vemos que el comando READ
se envía bien. El protocolo del analizador lo detecta correctamente
Experimento 35: hacia la lectura de un byte
Ampliamos el circuito del experimento 34 para enviar la dirección. Son direcciones de 3 bytes, y se envían primero los bytes de MAYOR PESO. Vaos a hacer pruebas con la dirección 0x000000. Los 4 bytes a enviar (1 del comando más 3 de las direcciones) los guardamos en registros de 8 bits conectados entre ellos, para enviarlos secuencialmente.
Definimos un autómata controlador. En el estado E0 se envía el primer byte, en el E1 el primero y en el E2 el segundo. Los bytes se envían en las transiciones. La primera transición es la entrada a E0, luego de E0->E1, E1->E2 y al salir de E3 (4 transiciones en total)
En el analizador lógico vemos que funciona correctamente. El protocolo del analizador detecta el comando READ y la dirección de acceso (0x000000)
Experimento 36: hacia la lectura de un byte
Llega el momento de la verdad... ahora enviamos infinitos bytes adicional para que se realice la lectura de la dirección 0x000000 y las siguientes. El autómata lo metemos en un bucle infinito. Cuando llega al estado E4
se queda ahí indefinidamente
Este es el circuito:
En el analizador lógico vemos los primeros 7 bytes que se leen a partir de la dirección 0x000000:
Los valores leídos son: 0xFF 0x00 0x00 0xFF 0x7E 0xAA 0x99
Para comprobar si esas bytes leídos son correctos, vamos a ver el contenido del fichero con el bitstream, que es el que se graba en la flash.
SIIIIIIIIIIIIIIIIII!!! FUNCIONA!!!!!!!!!!!!! VAAAAAMOS!!!!!
Para hacer otra prueba vamos a leer de la dirección 0x000001. Simplemente ponemos el valor 0x01 en el byte bajo de la dirección (A0) y repetimos. Esto es lo que sale en el analizador:
Ahora los bytes leídos son: 0x00 0x00 0xFF 0x7E 0xAA 0x99 0x7E
, que son correctos
Experimento 37: Lectura de la flash y escritura desde el PC
El objetivo es escribir bytes en la flash usando un programa desde el PC, y luego leerlos desde la FPGA con el controlador flash por SPI. Elegimos como dirección de prueba 0x04AABB
, que es la misma que usamos en el tutorial del spi
Primero volcamos 8 bytes de esa dirección para conocer sus valores. Esto lo podemos hacer con el programa iceprog
El comando que utilizamos es este:
apio raw "iceprog -o 0x04AABB -R 8 dump.bin" && hd dump.bin
Si nunca antes habíamos escrito nada en esa posición, estará todo a 0xFF:
El comando anterior vuelca los 8 bytes en el fichero dump.bin
y luego se utiliza hd
para visualizarlo
Modificamos el circuito anterior para acceder a la dirección 0x04AABB y ver su volcado
En el analizador vemos el volcado. Comprobamos que efectivamente TODO está a 0xFFs
Ahora creamos el fichero test.bin
con el siguiente patrón de 8 bits: 0x81 0x42 0x24 0x18 0x08 0x04 0x02 0x01
. Para comprobar que lo tenemos correcto lo visualizamos con hd:
Guardamos este fichero en la flash, en la dirección 0x04AABB, usando el comando:
apio raw "iceprog -o 0x04AABB test.bin"
Comprobamos, también con iceprog, que efectivamente ahora tenemos ese patrón grabado en la dirección 0x04AABB:
Hacemos la prueba DEFINITIVA con el analizador para ver si nuestro circuito lee el nuevo patrón:
SIIIIIII!!!! FUNCIONA!!!!
Ya tenemos la seguridad que nuestro circuito lee correctamente la información de la flash, al menos de momento en modo "continuo"
Experimento 38: Lectura de un byte de la flash
En este experimento leemos sólo un byte de la dirección 0x04AABB, y lo mostramos en los LEDs. Lo que tiene que aparecer es el valor 0x81 que es el primer número del patrón que hemos guardado previamente en esa dirección
El circuito es este:
Con el analizador vemos que se lee el valor correcto:
Y lo más importante, este valor sale por los LEDs!!! ¡¡FUNCIONA!!
2023-09-25
Experimento 39: Bloque SL-block-3x8
El bloque SL-block-3x8 es igual que el registro de desplazamiento a la izquierda SL, pero usando bytes (grupos de 8 bits). El desplazamiento a la izquierda es de 1 bloque (1 byte)
Este bloque nos servirá para simplificar y organizar mejor el circuito para leer un byte de una dirección de la flash
Este es el circuito de prueba:
2023-09-25
Experimento 40: Lectura de un byte de la flash
Simplificamos el circuito para leer un byte de la flash usando el elemento SL-block. La dirección se pasa como parámetro
Este es el circuito:
El cronograma sigue siendo el mismo:
Experimento 41: 3x8 SL-block-ld
El bloque SL-block-ld-3x8 es igual que el SL-block-3x8 del experimento 39, pero añadiendo la entrada de load para cargar el valor desde el exterior
Lo utilizaremos para el circuito de la lectura de la flash
Experimento 42: Lectura de un byte de la flash
Este es el nuevo circuito usando el bloque SL-block-ld-3x8. Ahora la lectura se realiza con cada pulsación de SW1 (antes había que resetear antes de pulsar SW1)
El cronograma sigue siendo el mismo
Experimento 43: Lectura de un byte de la flash
Este es el mismo circuito, pero más simplificado y ordenado para encapsularlo en el bloque flash-read-byte
Mismo cronograma (se incluye la señal de start para comprobar que busy y done funcionan bien)
2023-09-28
Experimento 44: Bloque Flash-readbyte-bus
Es el momento de encapsularlo todo en un bloque controlador que se conecta directamente al bus spi. Que existan bloques de bus spi nos permite añadir comandos fácilmente (readid, readbyte...)
Este circuito lee el byte de la posición de memoria 0x04AABB y lo muestra en los LEDS. Lo hace automáticamente al arrancar
Este es el resultado con el analizador lógico. Al apretar el botón de RESET se envía primero el comando wakeup y luego el de lectura del byte. El byte leído es el 0x81, que se muestra correctamente en los LEDs
Experimento 45: Controlador flash-readbyte-bus: Lectura de varios bytes
Vamos a modificar el experimento anterior para visualizar en los LEDs varios bytes. Cada vez que se aprieta SW1 se lee el siguiente byte de la memoria y se muestra en los LEDs. Esto permite recorrer la memoria flash manualmente y byte a byte
Al probarlo vemos que efectivamente en los leds salen los bytes 0x81, 0x42, 0x24, 0x18, 0x08, 0x04, 0x02, 0x01 y a partir de ahí todo 0xFFs... (Esos son los valores guardados en la flash)... ¡¡FUNCIONA!!
Experimento 46: Controlador flash-readbyte-bus: desplazamiento por la memoria
En este experimetno se usan los botones SW2 y SW1 para incrementar o decrementar la posición actual de la memoria y mostrar el byte que almacena en los LEDs
¡¡Funciona!!
Experimento 47: Bloque Flash-readbyte
Ya lo tenemos todo listo para encapsular nuevamente el controlador flash y el spi en un único bloque de acceso al a flash que permite leer un byte
Este es el mismo circuito del experimento 47, pero con el nuevo bloque flash. Las señales del SPI de salida se han agrupado en un bus para que sea más sencillo
¡¡Funciona!!
Experimento 48: Bloque Flash-readbyte
Simplificamos el experimento anterior, encapsulando en un componente nuevo la parte de incremento/decremento de la dirección. También eliminamos la parte de visualización con el analizador, que ya no es necesario
El circuito simplificado es el siguiente:
Funciona correctamente
Experimento 49: Lectura de media palabra (16-bits)
Vamos a crear un controlador para leer una media palabra (16-bits).
Partimos del experimento 43, y lo modificamos para la lectura de 16-bits
El registro de estado de la transmisión (ETX) es de 4 bytes. Se ha incrementado a 5 bytes, ya que ahora hay un byte más (y se debe transmitir el valor 0xFF para su recepción). El resto del autómata se deja igual
El registro de desplazamiento que recibe por miso pasa a ser de 16 bits (que es el tamaño del dato a recibir). Este controlador funciona en little-endian. En la memoria están guardados los bytes a y b en ese orden (ab). Primero se lee el a
y luego el b
. En el registro de desplazamiento quedan almacenadmos como ab, donde a es el de mayor peso y b el de menor peso. Pero como es little endian, hay que dar la vuelta a los bytes. Se capturan en el registro como ba
Este es el circuito:
Con el analizador vemos que se han recibido los dos bytes: 0x81 y 0x42
Estos bytes se ven en los LEDs, ya con la ordenación correcta. Primero el 0x81 (el de menor peso) y luego 0x42 (el de mayor peso)
Experimento 50: Lectura de media palabra (16-bits)
Encapsulamos la funcionalidad de cambiar los pesos de los bytes en el bloque reversal-2x8, de la colección icewires. Este es el nuevo circuito, que funciona exactamente igual que el anterior
Experimento 51: Controlador flash-read16-bus
Encapsulamos el experimento anterior en el nuevo controlador flash-read16-bus
Experimento 52: bloque Flash-read16
Este es el controlador final para leer una media palabra (16-bytes) de la memoria flash
Experimento 53: Lectura de una palabra (32-bits)
El controlador es similar al de 16 bits pero usando un registro de desplazamiento de 7 bits para incluir la transmisión de 2 bytes adicionales. Los registros de recepción pasan de 16 a 32 bits
En el analizor se observan los 4 bytes leidos. En los LEDs se ven sus valores correctos
2023-09-29
Experimento 54: Lectura de una palabra (32-bits)
Creamos el bloque reversal-4x8 para encapsular lo relacionado con el formato little endian. Se encuentra en la colección icewires
El circuito completo es este
El cronograma es el mismo que el anterior. Funciona correctamente (y en los LEDs se muestran los 4 bytes correctamente)
Experimento 55: Controlador flash-read32-bus
Encapsulamos el circuito en el controlador flash-read32-bus que se conecta por el bus SPI
Este es el circuito:
Experimento 55: bloque Flash-read32
Este es el controlador final para leer una palabra (32-bytes) de la memoria flash
¡¡FUNCIONA!!!