Xilinx programando FPGA desde SPI Flash sin JTAG

1

Estoy tratando de poder configurar mi FPGA cargando la configuración en la memoria flash. Soy capaz de escribir en el flash SPI a través de una interfaz 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 bitstream en Vivado? ¿Qué dirección en el flash debo usar?

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

¡Gracias!

    
pregunta Ethan

1 respuesta

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 genérelo 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. La secuencia de comandos del cargador debe leer el archivo de bits, quitar el encabezado y luego enviar el resto del archivo de bits al FPGA para escribir en el chip flash. Después de verificar que los datos se han escrito correctamente, puede hacer que el FPGA se restablezca a sí mismo 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 bus paralelo ancho (SelectMAP esclavo). En realidad, es probable que pueda seguir cargando todo el archivo de bits literalmente sin eliminar el encabezado; la sección de datos del archivo de bits contiene información de sincronización, y el 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 quiera implementar. Es posible almacenar múltiples configuraciones en flash y activar el FPGA para reiniciar y cargar una configuración diferente. La idea es que puede 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 arranque en la configuración 'dorada', luego la configuración 'dorada' intentará reiniciar el FPGA y cargar la otra vía escrituras en la primitiva ICAP. Si la configuración falla, el FPGA volverá a cargar la configuración "dorada" nuevamente. Tendrá que 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". La configuración 'dorada' 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 alimentación a bordo y las pruebas 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 desencadenar un reinicio con IPROG para omitir la carga de la configuración dorada e inmediatamente intentar cargar la configuración principal. Si la segunda configuración no se puede cargar, entonces el FPGA retrocederá en la configuración dorada. Echa un vistazo a la guía de usuario de configuración para 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 colocar en los archivos XDC para ajustar los archivos de bits para iniciar automáticamente la imagen 'principal' y volver automáticamente a la imagen 'dorada' sin tener que realizar operaciones ICAP en el propio diseño.

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))
    
respondido por el alex.forencich

Lea otras preguntas en las etiquetas