Descargue la configuración a FPGA a través de USB o desmonte FTDI MPSSE
Escribimos el cargador FPGA en LabVIEW. Parte 1

En el primer artículo, probamos el algoritmo de carga en el viejo C; en el segundo artículo, descubrimos cómo organizar un programa en LabVIEW e implementar una interfaz de usuario simple. Esta vez nos familiarizaremos con los nuevos métodos de trabajo en LabVIEW, analizaremos las características del manejo de errores y completaremos el proyecto: implementamos el protocolo para cargar el archivo de configuración en el FPGA.
Manejo de errores
Abra el código fuente, analice la función MPSSE_open. A pesar de la simplicidad algorítmica (las funciones se llaman una tras otra), se requieren algunos elementos de API D2XX para importar: FT_OpenEx
, FT_ResetDevice
, FT_Purge
, FT_SetUSBParameters
, FT_SetChars
, FT_SetTimeouts
, FT_SetLatencyTimer
, FT_SetFlowControl
FT_SetBitMode
Como se mostró en el artículo anterior , la importación de funciones se lleva a cabo utilizando el nodo Call library Function
. Este nodo tiene terminales dedicadas para el control de errores. LabVIEW tiene una regla simple: todos los VI deben rastrear errores e informar errores devueltos por terminales de error. La mayoría de los VI incorporados lo siguen estrictamente. Espero que todos entiendan lo importante que es controlar y manejar los errores, especialmente en la etapa de depuración, pero hay otra razón por la cual esto es tan importante que no es obvio para los programadores "clásicos". LabVIEW no tiene una secuencia estricta de dispositivos en el diagrama de bloques: el dispositivo se ejecuta cuando los datos están listos en sus entradas. Si los datos de la salida de un VI se transfieren a la entrada de otro VI, entonces está claro que al principio el primer VI funcionará, solo después del segundo. Pero, ¿qué pasa si no hay transferencia de datos y los VI realizan acciones independientes? Por supuesto, puede utilizar la engorrosa "Estructura de secuencia plana", pero es mucho más conveniente conectar los dispositivos entre sí mediante una secuencia de errores.
Al importar funciones D2XX, encontramos dos tipos de errores. El primero, que es un error de importación directa, devuelve el bloque de Call library Function
. El segundo es un error de la biblioteca en sí; casi todas las funciones lo FT_STATUS
través de FT_STATUS
. Todos los valores posibles se describen como enum en el archivo de encabezado ftd2xx.h. Aunque es suficiente saber que el valor FT_OK
es la ausencia de un error, y todos los demás valores son códigos de error, me gustaría rastrear no solo el hecho del error en sí, sino también qué error ocurrió y dónde ocurrió exactamente.
En LabVIEW, los datos de error se propagan a través de grupos de error
. Este es un tipo de datos dedicado tan especial; LabVIEW tiene muchos VI y funciones para trabajar con él. El clúster de error consta de tres elementos: una variable lógica: muestra el estado, un número entero con signo, un código de error, una cadena, la fuente del error. El estado indica si se ha producido un error, el código de error determina su tipo y es utilizado por VI especiales para generar un informe. La línea da una idea más detallada de exactamente dónde ocurrió el error. LabVIEW aceptó que si el estado es TRUE
, entonces esto es un error, si el estado es FALSE
, pero el código no es cero y la línea descriptiva no está vacía, entonces esto es una advertencia , si el estado es FALSE
, el código es cero y la línea está vacía, no hay error.

LabVIEW contiene una base de datos interna en la cual cada código de error está asociado con su descripción. Para cada tipo de error, se asigna un rango especial de valores de código. Por ejemplo, para los errores asociados con la operación de la red, se asignan varios rangos: de –2147467263 a –1967390460, de 61 a 65, de 116 a 118 y 122, 1101, 1114, 1115, 1132 a 1134, de 1139 a 1143 y de 1178 a 1185 Para los errores definidos por el usuario, se reservan dos rangos de –8999 a –8000 y de 5000 a 9999. De estos rangos, podemos elegir valores para los códigos de error de la biblioteca D2XX.
Creemos un VI que reciba el estado de la función D2XX como entrada y convierta este estado en un cluster de error de LabVIEW. La mayoría de las funciones y VIs en LabVIEW, habiendo recibido el estado TRUE
en la entrada Error In
, no ejecutan su código, sino que transmiten información de Error Out
terminal Error Out
. Esto le permite transferir efectivamente información sobre la fuente a través de toda la cadena al controlador de errores, eliminando la ejecución de código en modo de emergencia. Es deseable que nuestros VI se comporten de manera similar.
Organicemos la lista de estados D2XX en forma de enum
y colóquela en un tipo separado (en el artículo anterior hicimos esto con los tipos FTDI).
Guardamos el nuevo VI con el nombre FT_error.vi. Agregamos dos clústeres Error In
y Error Out
panel frontal, puede encontrarlos en el panel "Array, Matrix & Cluster". Los conectamos a los terminales en el panel de conexión en las esquinas inferior izquierda e inferior derecha, respectivamente, como ya se mencionó en el artículo anterior, esta es la ubicación de los terminales de flujo de error adoptados por LabVIEW. Agregamos la estructura Case
al diagrama de bloques, le damos el clúster Error In
a la entrada Case selector
, después de lo cual la estructura Case
cambia de color y divide dos sub-diagramas: "Sin error" - color verde y "Error" - color rojo. Dentro del caso de error, transferimos el clúster de error desde el terminal selector directamente al túnel de salida en el borde derecho. Y en el caso verde, agregamos otro Case
, dependiendo del estado, determinará si se debe crear un error (el estado no es igual a FT_OK), o dejarlo como está: omita el clúster de error de entrada para salir sin cambiar.
Para convertir técnicamente el código de error en un clúster, puede usar el VI Error Cluster From Error Code VI
. Este SubVI agrega una cadena de llamadas a la descripción del error, para que podamos determinar no solo lo que sucedió, sino también dónde sucedió.
Para seleccionar el texto correspondiente al estado de entrada (FT_Status), use el bloque de propiedades: seleccione "RingText.Text". El texto del error se envía a la entrada del error message
de Error Cluster From Error Code VI
.
No olvides dibujar un ícono "parlante".
FT_error.vi
Panel de subinstrumentos frontal (frontal)

Diagrama de bloques Error de entrada

Diagrama de bloques No hay error en la entrada y el estado es FT_OK

Diagrama de bloques No hay error en la entrada, pero el estado es diferente de FT_OK
Para probar FT_error, puede crear un VI vacío, agregar el VI creado allí y ver cómo cambiará el valor al inicio si se aplican varios estados.
Prueba FT_error.vi
Panel frontal (frontal) del dispositivo

Diagrama de bloques
Ahora, después de cualquier llamada de función desde la API D2XX, usaremos SubVI FT_error.vi. Un grupo de errores pasará por todos los VI a lo largo de la jerarquía de llamadas.
En los VI de nivel superior, debemos decidir qué hacer con el error detectado: puede mostrar un mensaje en el cuadro de diálogo, escribirlo en el archivo del informe, ignorarlo o simplemente "en silencio" finalizar la aplicación. El cuadro de diálogo es la forma más fácil y popular de informar errores. También es conveniente para un programador novato, ya que no hay nada que hacer. En cada VI, el modo de manejo automático de errores está habilitado por defecto ( Habilitar manejo automático de errores , ubicado en la categoría Ejecución del menú Propiedades del VI). Funciona así: si en algún nodo el terminal de salida Error Out
no está conectado a ningún lado, y se produce un error en este nodo, LabVIEW detiene la aplicación y muestra un cuadro de diálogo. Si el terminal Error Out
del nodo está conectado, el flujo de error se propaga según lo programado y no se producen acciones adicionales. Sin embargo, la ventana de mensajes se puede llamar mediante programación, para esto debe usar el General Error Handler
y Simple Error Handler
controlador de Simple Error Handler
(ubicados en el panel de diálogo e interfaz de usuario). En este caso, podemos usar la información de error para completar el programa. En un diagrama de bloques, se ve así:

Imagen en la que se puede hacer clic
Cuando se produce un error, el programa se suspenderá, aparecerá una ventana de informe, después de cerrar la ventana, el programa se cerrará correctamente.
Abrir y cerrar FTDI
Entonces, volvamos a la función MPSSE_open
. Crea un nuevo VI . En primer lugar, agregue los terminales para el flujo de error. Agregue una estructura de selección y seleccione la entrada Error In
en el selector. En el caso verde, importamos las funciones en el orden y con los parámetros como en el prototipo de Sishny. Todos los nodos del Call Library Function Node
conectados en una cadena por un flujo de error. En el caso rojo a través del túnel conectamos Error In
con el terminal de salida del error.

Imagen en la que se puede hacer clic

VI MPSSE_open.vi
Se suministra una línea con la descripción de FTDI ( Description
) a la entrada de SubVI, en la salida está Handle
y un chip FTDI inicializado en modo MPSSE.
Creemos un VP que termine de trabajar con FTDI y ya puede verificar el rendimiento en el hardware.
FT_Close.vi
Diagrama de bloques

Panel frontal
En el artículo anterior, para depurar la interfaz, creamos el stub VI SP_FT_MPSSE_FPGA.vi, ahora es el momento de llenarlo. Agregue MPSSE_open.vi y FT_Close.vi a su diagrama de bloques. En esta etapa, es bastante difícil evaluar si la inicialización fue correcta, sin embargo, un valor Handle
distinto de cero en la salida de MPSSE_open.vi y la ausencia de un error nos dirá mucho.

Diagrama de flujo SP_FT_MPSSE_FPGA.vi
Para ver el valor de Handle
puede usar la "Ventana de vigilancia de la sonda". Esta es una conveniente herramienta de depuración que le permite mostrar el valor de los datos en cualquier (casi cualquier) cable durante la ejecución del dispositivo. Para configurar la muestra en la línea, debe seleccionar "Sonda" en el menú contextual de esta línea. Se abrirá la ventana "Probe Watch Window", y aparecerá un número con el número de muestra en la línea. En la imagen de arriba es "3".
Ventana de reloj de sonda
En la línea Handle, el valor 698389336
Genial Iniciamos los VI de nivel superior, conectamos la placa de depuración a la computadora. Aparece una descripción del chip FTDI conectado en la lista "Seleccionar un dispositivo", haga clic en el botón "Programa" y ... no sucede nada. Solo en la ventana "Probe Watch" apareció el valor Handle
. Y eso está bien.
Apagamos el tablero, se borra la lista de dispositivos. Haga clic en "Programa". Aquí es donde aparece la ventana de informe de errores.
Después de hacer clic en el botón "Continuar", el VI completa su trabajo.
Está prohibido presionar el botón si no se encuentran dispositivos. Modificamos el controlador de eventos "Timeout" del caso. Permítame recordarle que los chips FTDI conectados a una PC se escanean dos veces por segundo, si se detectan y pueden usarse para programar FPGA, sus descriptores se agregan a la Devices list
través de la propiedad Strings[]
. Creamos la propiedad Disabled
para "Programación", y si no se encuentran dispositivos adecuados, apague y oscurezca el botón.
Tiempo de espera del caso
Imagen en la que se puede hacer clic
Dominar GPIO
Después de activar MPSSE, el trabajo se lleva a cabo a través del llamado "código de FT_Write
", y solo se FT_Write
, FT_Read
y FT_Queue
desde las FT_Write
API FT_Write
(para averiguar el estado del búfer receptor). Creamos el VI correspondiente a lo largo de la pista que creamos: FT_Write.vi, FT_Read.vi, FT_Queue.vi.
Un poco de rutina
FT_Write.vi

Diagrama de bloques FT_Write.vi

FT_Read.vi

Diagrama de bloques FT_Read.vi

FT_Queue.vi

Diagrama de bloques FT_Queue.vi
Ahora, a partir de estos tres ladrillos, presentamos los VI para leer el puerto paralelo y escribir en él. El valor se representa convenientemente como una matriz de variables booleanas.
MPSSE_Set_LByte.vi y MPSSE_Get_LByte.vi
MPSSE_Set_LByte.vi

Diagrama de bloques MPSSE_Set_LByte.vi

MPSSE_Get_LByte.vi

Diagrama de bloques MPSSE_Get_LByte.vi
Confieso que era flojo para crear una lista con nombre para todos los códigos de operación, así que los dejé en forma de números mágicos.
Como se indicó en el primer artículo , el protocolo de arranque FPGA pasivo en serie no es más que un SPI con manipulación de bandera adicional. Se utilizan un total de cinco patas: las líneas DCLK , DATA [0] , nCONFIG deben configurarse como salidas, las líneas nSTATUS , CONF_DONE como entradas.
Pinout de diseño de tablaPin FPGA | Nombre pin | Pin | MPSSE | Dirección | por defecto |
---|
DCLK | BDBUS0 | 38 | TCK / SK | Fuera | 0 0 |
DATOS [0] | BDBUS1 | 39 | TDI / DO | Fuera | 1 |
nCONFIG | BDBUS2 | 40 | TDO / DI | Fuera | 1 |
n ESTADO | BDBUS3 | 41 | TMS / CS | En | 1 |
CONF_DONE | BDBUS4 | 43 | GPIOL0 | En | 1 |
Necesitamos un VP que pueda cambiar el valor en el tramo seleccionado sin afectar a todos los demás. En primer lugar, cree Enum
con números de serie de las patas en el puerto, guárdelo como "Strict Type Def" en el archivo SP_LBYTE_BITS.ctl. Creamos un nuevo VI, agregamos los terminales de flujo de error familiares. Leemos el valor actual del puerto paralelo usando MPSSE_Get_LByte.vi, usamos la función Replace Array Subset
para modificar el bit deseado y escribimos el valor nuevamente en el puerto (MPSSE_Set_LByte.vi).
SP_Set_Flag.vi
SP_Set_Flag.vi

Diagrama de bloques SP_Set_Flag.vi

Enum SP_LBYTE_BITS.ctl
Para comenzar la configuración, el MPSSE debe generar una transición de baja a alta en la línea nCONFIG . Tan pronto como el FPGA esté listo para recibir datos, formará un alto nivel en la línea nSTATUS . En esta etapa, todo está listo para el experimento en hierro. En el diagrama de bloques SP_FT_MPSSE_FPGA.v agregamos la línea de control nCONFIG : después de la inicialización del MPSSE, le damos un nivel bajo y luego alto. Después de cada operación (para la depuración) leemos el estado de las patas del puerto.
SP_FT_MPSSE_FPGA.vi
Durante el inicio

Diagrama de bloques
En general, durante el lanzamiento de VI, está claro que el FPGA responde a la transición en la línea nCONFIG : el cero se establece en el tramo nSTATUS , y luego uno. Pero no será superfluo monitorear esto con un osciloscopio. Casi cualquier osciloscopio de dos canales con disparo por gatillo (en espera) es adecuado. Canal A (pista azul) Puse en el punto de control del circuito nCONFIG , canal B (pista roja) - cadena nSTATUS . El disparador se establece en el borde descendente del canal A.

Se puede hacer clic en la imagen. Con los detalles!
Trabajar con archivo
FPGA está listo para aceptar el archivo de configuración. ¿Estamos listos para transferir el archivo a la FPGA?
LabVIEW contiene un amplio conjunto de herramientas para trabajar con archivos. No puedo decir que la funcionalidad sea suficiente para absolutamente todo el rango de tareas, pero las operaciones básicas como leer y escribir son fáciles y agradables. El conjunto básico de VI para trabajar con archivos se puede encontrar en el panel "E / S de archivo". Para resolver el problema, debe abrir el archivo de configuración, evaluar su tamaño (necesitamos saber cuántos bytes enviar el FPGA), leerlo y cerrarlo. Todo es simple y uno tras otro. Usamos Open/Create/Replace File
, Get File Size
, Read from Binary File
, Close File
refnum
, combinarlos con la cadena de flujo de error y refnum
: un número, como un descriptor de archivo, se crea cuando el archivo se abre y debe transferirse a la entrada de otros VI que trabajan con este archivo
Hasta ahora, no tenemos dónde deshacernos de los datos leídos, pero si realmente desea verificar la operatividad de la cadena, puede crear un indicador de tipo String
y configurarlo un poco. En el menú contextual, active la opción "Pantalla hexadecimal", active la barra de desplazamiento vertical (Elementos visibles -> Barra de desplazamiento vertical) y después del inicio, observaremos el contenido del archivo de configuración binario.
SP_FT_MPSSE_FPGA.vi
Panel frontal Nos fijamos en el contenido del archivo.

Diagrama de bloques Karinka clicable
Dos líneas de código paralelas independientes formadas en el diagrama de bloques del VI, por lo tanto, se utilizan cadenas de error separadas para ellos. Para reducir los flujos paralelos en un terminal de Error Out
, se utiliza la función Merge Errors
. Esta función busca errores de entrada de arriba a abajo (sí, puede haber más de dos terminales de entrada, se estira con el mouse) y devuelve el primero que encuentra. Si no hay errores, devuelve el primer mensaje de advertencia. Si no hay advertencias, entonces no hay error en la salida. Es importante tener en cuenta que el orden de conexión de las entradas de Merge Errors
determina la prioridad de los errores, y si se produce un error inmediatamente en dos cadenas, se ignorará el error inferior. Esto debe ser tratado con cuidado.
Si intentamos presionar el botón "Programa" en el VI de nivel superior sin seleccionar un archivo, la entrada SP_FT_MPSSE_FPGA.vi recibirá una ruta vacía, lo que causará el error "Error 1430. LabVIEW: (Hex 0x596) La ruta está vacía o relativa. Debe usar un camino absoluto ". Como dice mi amigo de la infancia: "¡Trivialidades, esto es algo mundano!" Y este error no es un error en absoluto, sino la falta de atención del usuario. No detendremos el programa y lo juraremos con una ventana con una cruz roja, simplemente eliminaremos el error con este código de la transmisión y en el cuadro de diálogo recomendamos al usuario que decida sobre el archivo. Para filtrar el error, use el VI "Borrar errores" de la paleta "Diálogo e interfaz de usuario". Para mostrar el mensaje: "Diálogo de un botón".

Diagrama de bloques
Imagen en la que se puede hacer clic
Descargar configuración
Para la transferencia de datos en serie, el procesador MPSSE necesita enviar el código de operación 0x18, los argumentos del comando serán la longitud de la secuencia transmitida (dos bytes, comenzando con el más bajo) y la secuencia de datos en sí. La longitud está codificada menos uno. Enviemos el bloque de datos como VI MPSSE_send.
MPSSE_Send.vi
MPSSE_Send.vi

Diagrama de bloques
El tamaño del búfer de entrada ( Array Size
) se convierte en un tipo de doble byte U16
, restamos uno, intercambiamos los bytes bajo y alto ( Swap Bytes
): debe enviar la longitud comenzando desde el más bajo y convertir el número de doble byte en una matriz de un solo byte ( Type Cast
).
La función Type Cast
merece especial atención. Este es un convertidor de tipo tan universal, cuyo ingenio a veces es muy sorprendente. En resumen, entonces:

Visualmente para el programador
Sin embargo, esto no es solo transmitir datos a un tipo diferente, también es una interpretación heurística. Esta función le permite realizar conversiones entre tipos de datos incompatibles, mientras que la función no duda en alinear los datos de entrada e incluso eliminar las partes "adicionales". Si el tipo de datos solicitado requiere más memoria que los datos de entrada, la función asignará la cantidad faltante. Para un desarrollador novato, LabVIEW Type Cast
puede convertirse en un salvavidas, pero con el crecimiento, es mejor rechazar dicho convertidor; está muy oculto a la vista y puede convertirse en una fuente de errores inesperados. Es mejor usar métodos de conversión más explícitos, como Coerce To Type
.
Al inicializar el procesador MPSSE, establecemos el tamaño máximo permitido del búfer para la transferencia de datos a 65536 bytes, por lo tanto, debemos dividir el archivo de configuración en fragmentos cuyo tamaño no exceda el tamaño especificado. Utilizaremos la función Array Subset
, esta función selecciona una submatriz de la matriz que comienza con el elemento index
y una length
larga. Lo dividiremos en un ciclo While
, incrementaremos cada iteración del índice en 65536, entre las iteraciones pasaremos el valor a través del registro de desplazamiento. Tan pronto como no sea posible pellizcar 65536 bytes de la matriz principal, tomamos todo lo que queda, lo enviamos y detenemos el ciclo.
Según el protocolo de descarga, después de que se hayan transferido todos los datos, se deben aplicar dos pulsos de reloj más para iniciar la inicialización de FPGA. Para hacer esto, después del ciclo, enviamos otro byte "vacío".
SP_FT_MPSSE_FPGA.vi
Imagen en la que se puede hacer clic
Para comprender el éxito del firmware, consideramos los indicadores, y si CONF_DONE se establece en uno, informamos al nivel VI superior que todo está bien.
El programa está completo. Queda por asegurarse de que el FPGA se flashee con éxito y la placa parpadee felizmente con LED.
Sobre VP Naming
, , LabVIEW, , SubVI. . :
- — , FTDI, API D2XX. "FT", FT_Close.vi FT_Read.vi.
- — MPSSE. "MPSSE". : MPSSE_open.vi, MPSSE_Set_LByte.vi, MPSSE_Get_LByte.vi.
- — "Passive Serial" MPSSE. "S". , SP_FT_MPSSE_FPGA.vi ( , ) SP_LBYTE_BITS.ctl.
- . . , .
( ), . subVI .
, , .
, LabVIEW, . , , , ( ). .
Materiales relacionados
- . LabVIEW: . Por. . . .– .:
, 2008 – 400 .: . - labview_mpsse . .
- .
- Software Application Development D2XX Programmer's Guide . API D2XX.