Programación Xilinx FPGA desde SPI Flash sin JTAG

Estoy tratando de poder configurar mi FPGA cargando la configuración en la memoria flash. Puedo escribir en el flash SPI a través de una interfaz de ethernet, por lo que creo que sería posible escribir el flujo de bits en el flash a través de ethernet, y de esa manera podría programar el FPGA a través de la red sin usar un cable JTAG. es posible? ¿Cómo debo generar el flujo de bits en Vivado? ¿Qué dirección en el flash debo usar?

Estoy usando un Kintex-7 FPGA y un chip flash Spansion S25FL256S SPI.

¡¡Gracias!!

Realmente deberías leer la literatura de Xilinx sobre esto. Algunos de sus FPGA pueden actuar como un maestro SPI para leer datos de forma autónoma de algunos tipos de flashes SPI. De lo contrario, cualquier pequeño micro debería poder leer el flash y enviar los datos a través de lo que Xilinx llame su interfaz de flujo de bits "enviar reloj y datos".
@ChrisStratton Gracias por tu comentario. Intenté mirar la documentación de Xilinx y realmente solo pude encontrar información sobre la programación de la memoria flash con el flujo de bits usando JTAG. ¿Puedes señalarme alguna documentación útil? Además, no estoy seguro de lo que quiere decir con "enviar reloj y datos".
Lo llaman serial esclavo: xilinx.com/support/documentation/application_notes/xapp502.pdf Nuevamente, esto es distinto del modo maestro que tienen, que admite algunos flashes, tómese el tiempo para ver todas sus opciones antes de decidir, aunque si ya tener una MCU en el sistema que permita hacerlo a través de una serie esclava puede tener mucho sentido, especialmente porque ese puede ser su camino para cambiar el contenido del flash o desea usar parte del flash para otra cosa.

Respuestas (1)

Esto es definitivamente posible. Me imagino que necesitará escribir un pequeño programa de carga que leerá el archivo de bits y lo enviará a la FPGA a través de Ethernet. En este caso, no necesita hacer nada especial al generar el archivo de bits, simplemente generarlo normalmente como lo haría si fuera a programar el FPGA directamente a través de JTAG. El archivo de bits contiene un poco de información de encabezado en un formato binario relativamente fácil de decodificar. Su secuencia de comandos del cargador debe leer el archivo de bits, quitar el encabezado y luego enviar el resto del archivo de bits a la FPGA para escribir en el chip flash. Después de verificar que los datos se escribieron correctamente, puede hacer que el FPGA se reinicie a través de la interfaz ICAP para cargar la nueva configuración. De hecho, he implementado algo similar, pero en lugar de escribir en la memoria Flash, escribe el flujo de bits directamente en un FPGA diferente con un amplio bus paralelo (SelectMAP esclavo). En realidad, probablemente pueda cargar todo el archivo de bits palabra por palabra sin quitar el encabezado: la sección de datos del archivo de bits contiene información de sincronización, y la FPGA ignorará cualquier cosa antes de los datos de sincronización, incluido el encabezado.

En cuanto a dónde grabar los datos de configuración para flashear... depende exactamente de lo que quieras implementar. Es posible almacenar varias configuraciones en flash y activar la FPGA para restablecer y cargar una configuración diferente. La idea es que pueda tener una configuración 'dorada' que se carga primero y luego una configuración adicional que se puede actualizar. Creo que es posible que deba configurarlo para que el FPGA siempre se inicie en la configuración 'dorada', luego la configuración 'dorada' intentará restablecer el FPGA y cargar el otro a través de escrituras en la primitiva ICAP. Si la configuración falla, la FPGA volverá a cargar la configuración "dorada". Deberá realizar accesos ICAP con una pequeña máquina de estado para verificar el estado de la configuración cuando se inicie la configuración 'dorada'. El Dorado' La configuración debería al menos implementar una forma de acceder a la memoria Flash para que pueda actualizar el firmware. También es posible implementar la inicialización de la placa y la prueba de la placa en el flujo de bits 'dorado'. Otra opción es editar el archivo de bits para configurar la escritura en WBSTAR y activar un reinicio con IPROG para omitir la carga de la configuración dorada e intentar cargar inmediatamente la configuración principal. Si no se puede cargar la segunda configuración, la FPGA recurrirá a la configuración dorada. Eche un vistazo a la guía del usuario de configuración para obtener más detalles; esto no es algo con lo que haya experimentado antes. Otra opción es editar el archivo de bits para configurar la escritura en WBSTAR y activar un reinicio con IPROG para omitir la carga de la configuración dorada e intentar cargar inmediatamente la configuración principal. Si no se puede cargar la segunda configuración, la FPGA recurrirá a la configuración dorada. Eche un vistazo a la guía del usuario de configuración para obtener más detalles; esto no es algo con lo que haya experimentado antes. Otra opción es editar el archivo de bits para configurar la escritura en WBSTAR y activar un reinicio con IPROG para omitir la carga de la configuración dorada e intentar cargar inmediatamente la configuración principal. Si no se puede cargar la segunda configuración, la FPGA recurrirá a la configuración dorada. Eche un vistazo a la guía del usuario de configuración para obtener más detalles; esto no es algo con lo que haya experimentado antes.

Consulte UG470 y XAPP1247 para obtener más información. XAPP1247 también contiene lo que necesita poner en los archivos XDC para ajustar los archivos de bits para iniciar automáticamente la imagen 'principal' y recurrir automáticamente a la imagen 'dorada' sin tener que realizar operaciones ICAP en el diseño mismo.

Aquí hay un código de Python para analizar el encabezado en un archivo de bits:

import struct
import sys

bit_name = 'some_bit_file.bit'

print("Reading bit file %s" % bit_name)

try:
    bit_file = open(bit_name, 'rb')
except Exception as ex:
    print("Error opening \"%s\": %s" %(bit_name, ex.strerror), file=sys.stderr)
    exit(1)

# parse bit file header

# Field 1
# Unknown header
l = struct.unpack(">H", bit_file.read(2))[0]
hdr = bit_file.read(l)

# Field 2
# Unknown header
l = struct.unpack(">H", bit_file.read(2))[0]
hdr = bit_file.read(l)

# Field 3
# Design name
l = struct.unpack(">H", bit_file.read(2))[0]
design_name = bit_file.read(l).decode("utf-8")
print("Design name: %s" % design_name)

# Field 4
# Part name
k = bit_file.read(1)
l = struct.unpack(">H", bit_file.read(2))[0]
part_name = bit_file.read(l).decode("utf-8")
print("Part name: %s" % part_name)

# Field 5
# date
k = bit_file.read(1)
l = struct.unpack(">H", bit_file.read(2))[0]
date = bit_file.read(l).decode("utf-8")
print("Date: %s" % date)

# Field 6
# time
k = bit_file.read(1)
l = struct.unpack(">H", bit_file.read(2))[0]
t = bit_file.read(l).decode("utf-8")
print("Time: %s" % t)

# Field 7
# data
k = bit_file.read(1)
l = struct.unpack(">L", bit_file.read(4))[0]
config_data = bit_file.read(l)

print("Bitfile contains %d bytes" % len(config_data))
¡Muchas gracias! ¡Gran respuesta! Al final, estaba planeando tener dos configuraciones como usted describió, pero por ahora, estoy interesado en tener solo una como prueba de que es posible. Si estoy haciendo solo uno, ¿debería programar el archivo de bits para la dirección cero del flash? Además, gracias por el script, pero aprendí que Vivado puede generar un archivo .bin que no tiene encabezados.
Sí, solo escríbelo en la dirección cero. Ahí es donde la FPGA buscará primero hasta que se le informe de lo contrario a través de los registros de configuración de inicio internos.
Además, lo bueno de analizar el encabezado del archivo de bits es que puede hacer algunas comprobaciones de cordura (es decir, asegurarse de que el campo de la parte sea correcto)
También recomiendo mirar XAPP1247; tiene más información sobre cómo generar los archivos de bits para hacer uso de algunas de las funciones de configuración de FPGA para omitir el flujo de bits 'dorado' y luego retroceder automáticamente en caso de falla sin tener que implementar en la lógica con escrituras ICAP.