Escribimos el cargador FPGA en LabVIEW. Parte 1



La mayoría de los programadores "normales", por decirlo suavemente, tienen una actitud ambigua hacia la tecnología LabVIEW . Aquí puedes discutir durante mucho tiempo y en vano. La situación se ve agravada por el hecho de que hay muchos ejemplos de programas de LabVIEW en la red, pero todos están orientados hacia un principiante y se reducen a "oh, mira lo simple que es, conecta el giro al indicador, gira el mando, cambia el número" o, en el mejor de los casos, al gráfico del ciclo. se muestra un número aleatorio o seno, todo esto va acompañado de una interfaz furiosa en forma de interruptores de palanca gigantes, botones giratorios e indicadores de marcación. Personalmente, este enfoque de simplificación consciente me molesta. En una breve serie de artículos, intentaré presentar al lector el proceso de desarrollo de software de aplicación en LabVIEW. Para no dedicar mucho tiempo al área temática, utilizaremos el algoritmo detallado para cargar el archivo de configuración al FPGA a través de FTDI en modo MPSSE ( descargando la configuración al FPGA a través de USB o desmontando FTDI MPSSE ). En este artículo mostraré cómo implementar el mismo cargador FPGA, pero en lenguaje LabVIEW.


Como se mencionó anteriormente, el algoritmo de carga FPGA en modo Serial Pasivo (SP) y el principio de operación FTDI se describen bien en el artículo anterior. No me repetiré Creemos que el algoritmo se prueba y reconoce como apto. Y sí, suponga que el lector está al menos superficialmente familiarizado con el concepto de LabVIEW y está bien versado en programación clásica.


Aunque el proceso de creación de un gestor de arranque no lleva mucho tiempo, la descripción del proceso no logró encajar en el volumen de un artículo, por lo que habrá una pequeña serie. Dado que la etapa de experimentos ya se ha completado, y confío en la operabilidad del algoritmo, me permitiré comenzar el desarrollo desde la interfaz de usuario. En el primer artículo, crearemos la interfaz de usuario del cargador e implementaremos la estructura del programa. En el segundo, a través del controlador FTDI dll, implementamos la carga del archivo * .rbf en el FPGA.


Para la productividad de la conversación, no es superfluo recordar la terminología adoptada en LabVIEW. En LabVIEW, el programa de aplicación se llama Instrumento Virtual, también conocido como VI, también conocido como Instrumento Virtual o VI para abreviar. El VP tiene dos "lados": el Panel frontal, donde se encuentran los controles e indicadores, y el diagrama de bloques (Diagrama de bloques), donde estos elementos están interconectados y se implementan las funciones y los flujos de procesamiento de datos. Como regla general, un VP tiene una estructura jerárquica; todos los VP en un VP de nivel superior generalmente se denominan subdispositivo o SubVI.


Interfaz de usuario


Nuestra aplicación debe cargar el archivo de configuración en el FPGA. Al mismo tiempo, queremos decir que se pueden conectar varios FTDI a la computadora al mismo tiempo, y algunos de ellos se pueden usar potencialmente para configurar FPGA. Sugiero elegir un dispositivo de la lista desplegable, seleccionando un archivo a través de un botón con una salida de ruta. Para iniciar la descarga, agregue el botón "programa". Un LED virtual indicará el estado de la operación. Inicie LabVIEW.


Agregue los elementos necesarios al panel frontal (Panel frontal). Usaré el estilo "Plata" para el VP. La siguiente figura muestra el resultado, todos los elementos en su estado original. Por nombre, si es necesario, son bastante fáciles de encontrar en la paleta.




Editamos elementos: transferimos, estiramos, agregamos inscripciones, lo llevamos al formulario requerido. Aquí, de hecho, se requiere la mano del diseñador, pero como pude:




Y el diagrama de bloques:




Llamo tu atención. Cada elemento tiene dos propiedades que determinan el nombre: etiqueta y título.




La primera propiedad establece el nombre del elemento, bajo este nombre se mostrará en el diagrama de bloques. La etiqueta, a diferencia de Caption, no se puede cambiar durante la ejecución del VI. En relación con esta función, le recomiendo que oculte la Etiqueta en sus VIs en el panel frontal y muestre Subtítulo. Para Label, busque un nombre significativo, como una variable en un lenguaje de programación clásico, preferiblemente en un diseño latino. Para Caption, presentaremos un nombre orientado a los humanos, puede ser bastante largo, incluir espacios y, si es necesario, en ruso. Usando LabVIEW, puede personalizar la fuente de visualización para el Título. Debo decir que nadie nos obliga a jugar con Caption: cualquier inscripción se puede hacer directamente en FP en cualquier lugar libre.


Implementamos la operación VP de acuerdo con el esquema clásico: controlador de eventos y bucles While. Agregue un bucle While (Programación -> Estructuras -> Bucle While) al diagrama de bloques, y una estructura de controlador de eventos (Programación -> Estructuras -> Estructura de eventos).


Breve ayuda sobre la estructura del evento

La estructura espera a que ocurra el evento, luego se ejecuta el controlador correspondiente. La estructura de eventos tiene uno o varios subdiagramas: controladores de eventos, los llamados casos, uno de los cuales se ejecuta cuando ocurre un evento. Usando el terminal en la esquina superior izquierda, puede especificar el número de milisegundos durante los cuales la estructura espera un evento. Si durante este tiempo no se ha producido ningún evento, se ejecutará el sub-diagrama "Tiempo de espera". El valor predeterminado es menos 1, lo que significa que el tiempo de espera nunca caduca.




  1. La etiqueta del selector de eventos indica qué eventos desencadenan el caso actual. Para ver otros controladores, puede hacer clic en la flecha hacia abajo junto al nombre del evento.
  2. El terminal de timeout establece el número de milisegundos para esperar un evento. Si el valor es distinto de -1, se debe implementar el subdiagrama de tiempo de espera.
  3. Un terminal para ingresar eventos dinámicos. Este terminal no se muestra por defecto. Para mostrarlo, seleccione "Mostrar terminales de eventos dinámicos" en el menú contextual.
  4. Nodo de datos del evento. Cuando ocurre un evento, LabVIEW genera datos asociados con este evento. Este nodo proporciona estos datos al controlador. Puede usar el mouse para cambiar el tamaño del nodo verticalmente y seleccionar los elementos necesarios. Algunos datos, como Type y Time , son comunes a todos los eventos, otros, como Char y VKey , dependen del tipo de evento configurado.
  5. El nodo de filtro de eventos define datos de eventos que puede modificar antes de que la interfaz de usuario procese estos datos. Este nodo se muestra solo en aquellos controladores en los que el filtrado está disponible. Puede conectar y cambiar elementos del nodo de datos del evento al nodo del filtro de eventos. También puede cambiar estos eventos conectando los nuevos valores a los terminales del nodo. ¿Puedo cancelar por completo la reacción de la interfaz al evento si envío true al terminal Discard? . Si no conecta el valor al elemento de filtro, este elemento de datos permanece sin cambios.
  6. Al igual que la estructura Case , la estructura de eventos admite túneles. Si agrega un túnel en un caso, se creará automáticamente para cada controlador. Sin embargo, de forma predeterminada no es necesario conectar los túneles de salida de la estructura de eventos en cada controlador. Todos los túneles no conectados utilizan el valor predeterminado para el tipo de datos del túnel. Potencialmente, esto puede conducir a errores difíciles de detectar. Puede regresar el modo en el que el túnel debe estar conectado en todos los controladores, para esto, seleccione "Usar predeterminado si no está conectado" en el menú contextual.

En primer lugar, nos ocuparemos de cómo termina el ciclo y sale del programa. La forma más fácil es agregar un botón de detención, que detendrá el ciclo, pero, en mi opinión, es habitual finalizar el programa con una cruz roja en la esquina superior de la ventana.
Agregue el controlador apropiado a la Event Structure . En el menú contextual, seleccione "Agregar caso de evento". Como origen del evento, seleccione "Este VI", el evento indicará "¿Cerrar panel?"


Editar eventos


Imagen en la que se puede hacer clic


Tenga en cuenta que si selecciona "Cerrar panel" (sin una pregunta), este evento no tiene filtro, no se puede deshacer. Y si tiene una pregunta, cuando hace clic en la cruz, podemos tomar el control e independientemente completar correctamente el programa. En el "Panel Cerrar?" a través del túnel conectamos la constante booleana true con el terminal para detener el while . Ingrese "¿Descartar?" También sirven true .


Ahora no hay matices obvios: si el VI actual no se inicia en el entorno de LabVIEW, sino en forma de una aplicación compilada, al hacer clic en la cruz no se cierra la ventana, sino que detiene la aplicación, que no necesitamos. Para resolver este problema, después de completar el ciclo principal, verificaremos si estamos en el entorno de desarrollo o en modo de programa, si todavía estamos en modo de programa, finalizaremos la aplicación. Para comprender dónde se ejecuta el VI actual, use el nodo de propiedades (Programación -> Control de aplicaciones -> Nodo de propiedades). Este nodo proporciona acceso a las propiedades de un objeto por referencia a este objeto. En este caso, deberíamos obtener un enlace a toda la aplicación como un todo. Seleccione la constante de VI Server Reference de la misma paleta. Después de establecer la constante en el diagrama de bloques, debe cambiar su tipo a This Application (botón izquierdo del mouse). Conectamos el enlace resultante con el nodo de propiedad. Seleccione la propiedad Application:Kind Property : devuelve el tipo del sistema LabVIEW en el que se ejecuta el VI actual. Conectamos la salida de la propiedad a la Estructura del caso, agregamos el caso "Sistema de tiempo de ejecución", donde finalizamos la aplicación ( Quit LabVIEW ). Para que este bloque se ejecute después del ciclo, y no antes, conectamos el error in terminal de entrada al ciclo a través del túnel.



Imagen en la que se puede hacer clic


Ahora, cuando inicie el programa, puede detenerlo haciendo clic en la cruz de la ventana. El programa lanzado se ve así:




En mi opinión, mucho superfluo. Vaya a las propiedades de VI (Archivo -> menú de Propiedades de VI), seleccione la categoría "Aspecto de la ventana", configure Personalizado.


Apague la visualización del menú (permanece en el modo de edición), apague la barra de desplazamiento, oculte la barra de herramientas cuando la aplicación se esté ejecutando (Mostrar barra de herramientas al ejecutar). Prohibimos cambiar el tamaño de la ventana, permitimos minimizar y minimizar la ventana. Eso esta mejor:




Por supuesto, valdría la pena eliminar la inscripción "National Instruments. LabVIEW Evaluation Software", pero todavía no quiero comprar una licencia para una computadora en casa, soportaremos la inscripción y administraremos el período de prueba de 45 días.


Naturalmente, puede ajustar el color de fondo y cada elemento, elegir las fuentes, pero no soy diseñador, pero algo me dice que solo lo empeoraré.


Lista de instrumentos


El VP debe ofrecer al usuario una lista de dispositivos conectados a la computadora que sean adecuados para el firmware FPGA para que el usuario pueda seleccionar el deseado. En la biblioteca FTD2XX, las funciones FT_CreateDeviceInfoList y FT_GetDeviceInfoDetail están destinadas para este propósito. Como se discutió en un artículo anterior , las bibliotecas de controladores se pueden usar para usar la API FTD2XX. LabVIEW tiene un mecanismo conveniente para interactuar con bibliotecas dinámicas: el nodo Nodo de función de biblioteca de llamadas, puede encontrarlo en la paleta "Conectividad -> Bibliotecas y ejecutables". El nodo de llamada a la función debe configurarse: primero, especifique la ruta a la dll (la pestaña "Función"), después de lo cual el sistema escanea la biblioteca y ofrece seleccionar el nombre de la función en la lista "Nombre de la función" - seleccione FT_CreateDeviceInfoList , convenio de llamada - seleccione stdcall (WINAPI) . En segundo lugar, en la pestaña "Parámetros", debe ingresar una lista de parámetros de función, donde el primer elemento de la lista es el valor de retorno. Aquí sería bueno tener en cuenta la documentación de la API o el archivo de encabezado. Cuando se configuran parámetros en el área "Prototipo de función", se muestra el prototipo de la función importada. Cuando la firma de la documentación coincida con el prototipo configurado, haga clic en Aceptar.


Suponga que el escaneo se debe realizar una vez por segundo. Colocamos el nodo de llamada en la estructura del controlador de eventos en la pestaña "Tiempo de espera", establecemos el tiempo de espera en 1000 ms. Agregamos indicadores a los pines del nodo, y si todo se hace correctamente, al iniciar el VI, se debe mostrar el número de dispositivos conectados con FTDI:


Panel frontal y diagrama de bloques


Imagen en la que se puede hacer clic



Del mismo modo, cree un nodo para la función FT_GetDeviceInfoDetail . El prototipo de la función es:


 FTD2XX_API FT_STATUS WINAPI FT_GetDeviceInfoDetail( DWORD dwIndex, LPDWORD lpdwFlags, LPDWORD lpdwType, LPDWORD lpdwID, LPDWORD lpdwLocId, LPVOID lpSerialNumber, LPVOID lpDescription, FT_HAN 

Al describir los parámetros, debe tenerse en cuenta que lpdwFlags , lpdwType , lpdwID , lpdwLocId se pasan como punteros a uint32 . Los parámetros lpSerialNumber y lpDescription son la esencia de las cadenas de bytes (matrices de caracteres con un terminador nulo). Los parámetros de este tipo en el nodo de llamada se pueden formatear de varias maneras, puede ingresarlos en una matriz de palabras de 8 bits, pero creo que es más conveniente indicar de inmediato que se trata de una cadena y establecer el tamaño esperado. En este caso, la salida será inmediatamente una línea de "laberinto" válida y no se requerirán transformaciones adicionales.



Función de biblioteca de llamadas


Esta función devuelve información por el número de serie dwIndex . Si hay varios FTDI conectados a la computadora, para leer la información de cada convertidor, la función debe llamarse en un bucle. La función previa FT_CreateDeviceInfoList nos dará el número de iteraciones del bucle.


Panel frontal y diagrama de bloques


Imagen en la que se puede hacer clic



Hay una característica desagradable: todos los puertos del nodo de llamada deben estar conectados al menos en un lado. Por lo tanto, se hace un túnel en el bucle para aquellos terminales de salida que no vamos a usar.


Types matriz de Types contiene tipos de chips FTDI, los necesitamos para limitar la elección solo a aquellos que admiten MPSSE y potencialmente pueden usarse para la programación FPGA. Sin embargo, operar con "números mágicos" es inconveniente: propongo organizar los tipos de FTDI en forma de enum . Además, dicha enum ya enum en el archivo de encabezado ftd2xx.h. En LabVIEW, puede usar dos controles para crear una enumeración: el Anillo de texto y la Enum. Ambos contienen listas de cadenas con valores numéricos entre los que puede cambiar. La principal diferencia es que "Enum" requiere que los valores numéricos sean números enteros consecutivos, mientras que el "Anillo de texto" tiene más libertad: puede especificar cualquier valor.


Enum. Creación

Ingresamos manualmente los valores, es una pena que no haya una función para importar enum desde C



En el panel frontal este indicador se ve así



Seleccionar un valor haciendo clic izquierdo


Para vincular y sincronizar todas las instancias futuras de la lista creada, es conveniente utilizar el "Make Type Def". (selección a través del menú contextual del elemento). Como resultado, se creará un tipo de datos personalizado. El nuevo tipo se coloca en un archivo separado con la extensión * .ctl. La edición de este archivo modificará todas las instancias de este elemento. Creo que no vale la pena explicar qué tan conveniente puede ser esto. El acceso al archivo de definición se puede obtener desde el menú contextual de la instancia seleccionando "Open Type Def", en el mismo menú debe prestar atención a los elementos "Actualización automática desde Type Def". y "Desconectar del tipo Def".


Cambiamos el indicador Types a una matriz de indicadores del FTDI Type y, como resultado, cuando se inicia el VI, se muestra el tipo del convertidor conectado:



Tres dispositivos encontrados


Es fácil notar que la funcionalidad del código resultante en el caso de "Tiempo de espera" está completa, por lo tanto, se puede mover a un SubVI separado. Seleccione los elementos que queremos transferir al subdispositivo y seleccione "Crear SubVI" en el menú principal Editar.


diagrama de bloques con subinstrumento creado

Todos los indicadores permanecieron y se formó un nuevo VI con un icono estándar en lugar de los nodos de llamada.

Imagen en la que se puede hacer clic


Al hacer doble clic en el nuevo subVI se abrirá su ventana de edición. En primer lugar, lo guardamos y le damos un nombre significativo, por ejemplo, "FT_GetDeviceInfo". Configurar terminales de E / S. Para hacer esto, use el Panel de conectores:



El panel es un conjunto de terminales correspondientes a los controles e indicadores VI.


Si selecciona un terminal en el panel de conexión, se resalta el elemento correspondiente en el panel frontal. Si selecciona un terminal vacío y luego hace clic en un elemento en el panel frontal, el elemento se adjuntará al terminal, pero antes de eso no debe asignarse a otro terminal. En el menú contextual, puede desconectar individualmente o de una vez por todas las terminales de los elementos, puede cambiar el patrón del panel como un todo.


No me gusta cómo se asignaron los terminales al crear el subVI actual, por lo que selecciono "Desconectar todos los terminales" y lo marco manualmente. Recomiendo colocar los terminales de entrada a la izquierda y la salida a la derecha, la entrada opcional se puede colocar en la parte superior y la salida opcional en la parte inferior. Esto asegurará una buena legibilidad del código y un orden visual en el diagrama de bloques.


Para controlar los errores, cree dos elementos adicionales, Error in y Error out . El tema de control de errores de LabVIEW es muy extenso y va más allá del alcance de este artículo, por lo que nos limitaremos a un mínimo de explicaciones y nos adheriremos al principio de "haz lo que yo hago". Entonces, creamos dos terminales para errores: entrada y salida.


Es conveniente crearlos usando el menú contextual

Haga clic derecho en la terminal de error de cualquier nodo:



En LabVIEW, es costumbre colocar el terminal de entrada del error en el panel de conexión en la parte inferior izquierda, y el terminal de salida en la parte inferior derecha.


Será más conveniente combinar la salida en una estructura. Para la salida, haremos dos matrices: la primera matriz contendrá todos los dispositivos FTDI encontrados, la segunda matriz contendrá solo aquellos que pueden MPSSE y teóricamente se pueden usar para configurar FPGA.


El toque final al crear un subinstrumento es configurar el icono. Al hacer doble clic en el icono en la esquina superior derecha de la ventana, se inicia el editor. Estamos tratando de crear algún tipo de imagen significativa que nos permita interpretar sin ambigüedades el propósito del dispositivo en el diagrama de bloques.


FT_GetDeviceInfo.vi

Panel frontal



Diagrama de bloques


Y así es como se ve el caso de "Tiempo de espera" después de poner las cosas en orden:

Imagen en la que se puede hacer clic


Hasta este punto, la lista desplegable con el nombre "Seleccionar un dispositivo" estaba vacía, ahora tenemos los datos para completarla. Creamos un nodo de propiedad para la lista con la propiedad "Cadenas []" (menú contextual -> Crear -> Nodo de propiedad -> Cadenas []). Cualquier propiedad se puede escribir y leer; el modo actual se selecciona en el menú contextual del Nodo de propiedad. Al crear un nodo de forma predeterminada, las propiedades se configuran para leer. Cambiar para escribir: "Cambiar para escribir".


Desde el conjunto de estructuras, seleccione el conjunto con la descripción y aliméntelo a Strings[] . Puede seleccionar una matriz usando el For Loop .


Después de iniciar el VI, presionando el botón izquierdo en el elemento "Seleccionar un dispositivo", puede especificar el dispositivo para la configuración. En este caso, la lista de dispositivos se actualiza dos veces por segundo. Por supuesto, sería posible actualizar la propiedad solo si la lista se actualizó, pero hasta ahora esto resultará en un desorden innecesario del diagrama de bloques.


Que paso

Panel frontal



Imagen en la que se puede hacer clic


Anteriormente, olvidé mencionar una característica tan interesante, el bucle For no tiene que indicar el número de iteraciones explícitamente, es suficiente para crear un túnel de entrada de la matriz y el bucle se ejecutará para cada elemento, este comportamiento se asemeja al foreach en C ++ 11. Sin embargo, debe tener cuidado cuando llega más de una matriz a la entrada del bucle.


En la estructura del evento, agregue un controlador para presionar el botón "programa". Si bien no tenemos un VI que sea responsable de cargar el archivo en el FPGA, crearemos un "stub" de subdispositivo. Suponga que toma la ruta del archivo de configuración y el descriptor FTDI como entrada, y de acuerdo con los resultados de la operación, devuelve el estado del firmware: exitoso o no. Y para que sea más interesante probar la interfaz del programa, haremos que este estado sea aleatorio.


Stub FT_MPSSE_SP_FPGA.vi

Panel frontal



Diagrama de bloques


Pasaremos el descriptor FTDI a la entrada de código auxiliar a través de la propiedad de lista (menú contextual -> Crear -> Nodo de propiedad -> Texto de anillo -> Texto), para transferir la ruta del archivo al elemento "Ruta del archivo", crear una variable local (menú contextual -> Crear -> Local Variable) y configúrelo para leer (Cambiar para leer). Y conecte la salida de estado directamente al indicador de Status . El botón Programm se arrastra al controlador de eventos. Es una buena práctica colocar elementos en los que el evento está configurado en controladores: ahora, al hacer doble clic en este elemento en el panel frontal, se mostrará no solo el elemento correspondiente en el diagrama de bloques, sino también el controlador de eventos asociado con este elemento.


Ahora, al presionar el botón "Programa", el indicador se vuelve verde (éxito) o verde oscuro (no éxito). No muy claro. En las propiedades del indicador, cambie el color "Desactivado" a rojo. Eso es mejor Si el indicador es verde, entonces podemos decir que el FPGA en el dispositivo seleccionado está configurado por un archivo, cuya ruta se indica en la ventana:



Panel frontal


Pero esta declaración se vuelve falsa si cambiamos el archivo o seleccionamos otro dispositivo. Al mismo tiempo, no podemos colorear el indicador de rojo, porque no se produjo un error de programación. En el caso de un cambio de archivo o dispositivo, es conveniente enfatizar que el valor del indicador no es relevante: oscurecerlo. Para esto, puede usar la propiedad de indicador Disabled . Esta propiedad puede tomar tres valores: Enabled : visualización normal, el usuario puede controlar el objeto; Disabled : el objeto se muestra en el panel frontal como de costumbre, pero el usuario no puede controlarlo; Disabled and Grayed Out : el objeto se muestra oscurecido en el panel frontal y el usuario no puede controlarlo.


Creamos controladores de eventos para la Devices list y la File Path , y en ellos oscurecemos el indicador de estado, y en el controlador asignamos el botón "Programa" a la propiedad Enabled .


Que paso


Manejador "Programm": cambio de valor.



Controlador de lista de dispositivos: cambio de valor



Así es como se ve el indicador oscuro


Hagamos que la búsqueda del archivo de configuración sea conveniente para el usuario: configuraremos la ventana de vista del archivo. Entramos en las propiedades del elemento File Path del File Path , en la pestaña "Opciones de exploración", completamos Solicitud, Etiqueta de patrón, especificamos el filtro de tipo de archivo (Patrón) y el nombre del botón (Texto del botón).


Ventana de selección de archivos

Solo se muestran los archivos rbf



La creación de una interfaz de usuario puede considerarse completa.



Ejecutando el gestor de arranque


¿Qué conociste hoy?


En este artículo, como ejemplo de crear una aplicación funcionalmente completa con una interfaz minimalista, traté de mostrar varios enfoques para trabajar en LabVIEW.


Como resultado, tocamos esos:


  • Establecer las propiedades del dispositivo virtual. .
  • : .
  • .
  • .
  • dll.
  • .

API FTD2XX MPSSE. .



  1. USB FTDI MPSSE
  2. labview_mpsse . .
  3. .
  4. Software Application Development D2XX Programmer's Guide . API D2XX.

Source: https://habr.com/ru/post/es427529/


All Articles