We write the FPGA loader in LabVIEW. Part 1

  • Tutorial


Most "normal" programmers, to put it mildly, have an ambiguous attitude towards LabVIEW technology.. Here you can argue long and to no avail. The situation is aggravated by the fact that there are a lot of examples of programs on LabVIEW on the network, but they are all focused on the beginner and come down to "oh, look how simple it is, connect the twist to the indicator, twist the handle, change the dial", or at best, the graph in the cycle a random number or a sine is output, all this is accompanied by a furious interface in the form of giant toggle switches, twists and dial gauges. Personally, this conscious simplification annoys me. In a small series of articles I will try to acquaint the reader with the process of developing application software on LabVIEW. In order not to devote a lot of time to the subject area, we will use the described in detail algorithm for loading the configuration file into FPGA via FTDI in the MPSSE mode (Download configuration to FPGA via USB or parse FTDI MPSSE ). In this article I will show how to implement the same FPGA loader, but in the LabVIEW language.


As mentioned above, the algorithm for loading the FPGA in Serial Passive (SP) mode and the principle of operation of FTDI are well described in the previous article. I will not repeat. We believe that the algorithm has been tested and found valid. And yes, suppose that the reader is at least superficially familiar with the concept of LabVIEW and is well versed in classical programming.


Although the process of creating a loader does not take much time, the description of the process could not fit into the volume of one article, so there will be a small series. Since the stage of experiments has already been completed, and I am sure that the algorithm will work, I will allow myself to start development from the user interface. In the first article we will create the user interface of the loader, we will implement the structure of the program. In the second - through the dll of the FTDI driver we implement the loading of the * .rbf file into the FPGA.


For the productivity of the conversation is not superfluous to recall the terminology adopted in LabVIEW. In LabVIEW, an application program is called a Virtual Device, also known as a VP, or Virtual Instrument or abbreviated VI. The VI has two "sides": the front panel (Front Panel), where the controls and indicators are located, and the block diagram (Block Diagram), where these elements are interconnected and the functions and processing flows are implemented. As a rule, the VP has a hierarchical structure, all VPs in the composition of the top-level VIs are usually called a sub-instrument or SubVI.


User interface


Our application must load the configuration file into the FPGA. In this case, we assume that several FTDI can be simultaneously connected to the computer, and some of them can potentially be used to configure the FPGA. I suggest choosing a device from a drop-down list, selecting a file through a button with a path output. To start the download, add the "program" button. A virtual LED indicator will display the status of the operation. Launch LabVIEW.


Add the required elements to the front panel (Front Panel). For the design of the VP I will use the style "Silver". The figure below shows the result, all elements are in their original state. By name, if necessary, they are quite easy to find in the palette.




We edit elements: we transfer, we stretch, we add inscriptions - we bring in a necessary type. Here, in fact, requires the hand of a designer, but as I could:




And block diagram:




Paying attention. Each element has two properties that define the name - this is Label and Caption.




The first property specifies the name of the element; under this name it will be displayed on the block diagram. Label, unlike Caption, cannot be changed during the execution of a VI. In connection with this feature, I recommend hiding the Label in my VIs on the front panel and displaying Caption. For Label to come up with a meaningful name as a variable in a classical programming language, preferably in the Latin layout. For Caption, enter the already human-oriented name, it can be quite long, include spaces and, if necessary, in Russian. Using LabVIEW, you can customize the Caption display font. I must say that no one forces us to tinker with Caption: any inscription can be made directly on the FP in any free space.


The VP is implemented according to the classical scheme: While loop and event handler. Add a loop to the block diagram While(Programming -> Structures -> While Loop), and an event handler structure (Programming -> Structures -> Event Structure).


Concise Help for Event Structure

Структура ожидает наступления события, затем выполняет соответствующий обработчик. Структура событий имеет одну или несколько поддиаграмм — обработчиков событий, так называемых кейсов (case), один из которых выполняется при наступлении события. С помощью терминала в левом верхнем углу можно задать количество миллисекунд, в течение которых структура ожидает события. Если в течении этого времени ни одно событие не произошло, то выполниться поддиаграмма "Timeout". По умолчанию установлено значение минус 1, это означает, что время ожидания никогда не истекает.




  1. Метка селектора событий указывает, какие события вызывают выполнение текущего кейса. Для просмотра других обработчиков можно щелкнуть по стрелке вниз рядом с именем события.
  2. Терминал timeout задает количество миллисекунд для ожидания события. Если значение отлично от -1, то обязательно должна быть реализована поддиаграмма Timeout.
  3. Терминал для ввода динамических событий. Данный терминал по умолчанию не отображается. Чтобы отобразить его нужно в контекстном меню выбрать пункт "Show Dynamic Event Terminals".
  4. Узел данных события. Когда происходит событие LabVIEW генерирует данные, связанные с этим событием. Этот узел предоставляет эти данные обработчику. Мышкой можно изменить размер узла по вертикали и выбрать необходимые элементы. Некоторые данные, например Type и Time, являются общими для всех событий, другие, как например Char и VKey, зависят от типа настроенного события.
  5. Узел фильтра событий определяет данные события, которые можно изменить, прежде чем пользовательский интерфейс обработает эти данные. Этот узел отображается только в тех обработчиках, в которых доступна фильтрация. Можно подключить и изменить элементы из узла данных события в узел фильтр событий. Можно также изменить данные события, подключив новые значения к клеммам узла. Можно полностью отменить реакцию интерфейса на событие, если подать true на терминал Discard?. Если не подключить значение к элементу фильтра, то этот элемент данных остается без изменения.
  6. Как и структура Case, структура событий поддерживает туннели. Если добавить туннель в одном кейсе, он автоматически будет создан для каждого обработчика. Однако по умолчанию нет необходимости подключать выходные туннели структуры событий в каждом обработчике. Все туннели без подключения используют значение по умолчанию для типа данных туннеля. Потенциально это может привести к трудно обнаруживаемым ошибками. Можно вернуть режим, при котором туннель должен быть связан проводом во всех обработчиках, для этого в контекстном меню выбираем "Use Default If Unwired".

First of all, we will take care of how the cycle will end and exit the program. The easiest way is to add a stop button, which will stop the cycle, but, in my opinion, the program is usually completed with a red cross in the upper corner of the window. Add the appropriate handler to the
structure Event Structure. In the context menu, select "Add Event Case". As the source of the event, select "This VI", specify the event "Panel Close?"


Edit Events


Картинка кликабельная


I draw attention, if you select "Panel Close" (without a question), then this event without a filter, it can not be canceled. And if with a question, when you click on the cross, we can take control and correctly complete the program on our own. In the handler "Panel Close?" through the tunnel, we connect the Boolean constant trueto the cycle stop terminal while. At the entrance "Discard?" also served true.


Now it’s not an obvious nuance: if the current VI is launched not in the LabVIEW environment, but as a compiled application, pressing the cross will not close the window, but will stop the application, which we do not need. To solve this problem after the completion of the main cycle, let's check whether we are in the development environment or in the program mode, if we are still in the program mode, then we will terminate the application. In order to understand where the current VI is executed, use the properties node (Programming -> Application Control -> Property Node). This node provides access to object properties by reference to this object. In this case, we should get a link to the entire application as a whole. Choose a constant VI Server Referencefrom the same palette. After the constant is set on the block diagram, you need to change its type toThis Application(left mouse button). We connect the resulting link with the properties node. Select a property Application:Kind Property- returns the type of LabVIEW system in which the current VI is running. We connect the output of the property with the selection structure (Case Structure), add the "Run Time System" case, where we terminate the application ( Quit LabVIEW). In order for this block to be executed after the cycle, and not before, the input terminal is error inconnected to the cycle through the tunnel.



Clickable image


Now when you start the program, you can stop it by clicking on the cross of the window. The running program looks like this:




In my opinion, a lot of excess. Go to the properties VI (menu File -> VI Properties), select the category "Window Appearance", set Custom.


Turning off the menu display (in the edit mode the menu remains), turn off the scroll bar, hide the toolbar when the application is running (Show toolbar when running). We forbid to change the window size, we allow to minimize and minimize the window. That's much better:




Of course, it would be worthwhile to remove the inscription "National Instruments. LabVIEW Evaluation Software", but for the home computer I still do not want to buy a license, accept the inscription and do a 45-day trial period.


Naturally, you can adjust the background color and each element, select fonts, but I’m not a designer, but something tells me that I’ll only make it worse.


Instrument List


The VP must offer the user a list of devices connected to the computer suitable for the FPGA firmware in order for the user to select the right one. In the FTD2XX library functions FT_CreateDeviceInfoListand are intended for this FT_GetDeviceInfoDetail. As already discussed in a previous article , driver libraries can be used to use the FTD2XX API. LabVIEW has a convenient mechanism for interacting with dynamic libraries - the Call Library Function Node; you can find it in the "Connectivity -> Libraries & Executables" palette. The function call node should be configured: first, specify the path to the dll (the "Function" tab), after which the system scans the library and in the "Function Name" list will offer to select the function name - selectFT_CreateDeviceInfoListCalling convention - select stdcall (WINAPI) . Secondly, on the tab "Parameters" you need to enter a list of the parameters of the function, where the first element of the list is the return value. Here before my eyes it would be nice to keep the documentation on the API, or the header file. When setting the parameters, the prototype of the function being imported is displayed in the "Function prototype" area. When the signature from the documentation matches the configured prototype, click OK.


Suppose that the scan should be performed once per second. The call node is located in the structure of the event handler on the "Timeout" tab, the waiting time is set to 1000 ms. Add indicators to the node outputs, and if everything is done correctly, then when the VI is started, the number of connected devices with FTDI should be displayed:


Front panel and block diagram


Картинка кликабельна



Similarly, create a node for the function FT_GetDeviceInfoDetail. The function prototype is:


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

In the description of the parameters should be noted that lpdwFlags, lpdwType, lpdwID, lpdwLocIdare passed as pointers uint32. The parameters lpSerialNumberand lpDescription- are the essence of byte strings (arrays of the type charwith null terminator). Parameters of this type in the call node can be styled in various ways, you can enter them into an array of 8-bit words, but I think it is most convenient to immediately indicate that this is a string and set the expected size. In this case, the output will immediately be a suitable lably string and no additional transformations will be required.



Call Library Function


This function returns information by sequence number dwIndex. If several FTDI are connected to the computer, in order to read the information for each converter, the function must be called in a loop. The number of loop iterations will be given by the previous function FT_CreateDeviceInfoList.


Front panel and block diagram


Картинка кликабельна



There is an unpleasant feature: all ports of the call site must be connected on at least one side. Therefore, a tunnel is made in the loop for those output terminals that we are not going to use.


The array Typescontains the types of FTDI chips, we need them in order to limit the choice only to those that support MPSSE and can potentially be used to program the FPGA. However, it is inconvenient to operate with “magic numbers” - I propose to issue the FTDI types as enum. Moreover, this is enumalready in the header file ftd2xx.h. In LabVIEW, you can use two controls to create an enumeration: the Text Ring and the Enum itself. Both contain lists of strings with numeric values ​​between which you can switch. The main difference is that Enum requires that numeric values ​​be consecutive integers, while there is more freedom in the Text Ring — you can set any values.


Enum. Creature

Вводим вручную значения, жаль что нет функции импорта enum из Си



На фронт-панели так выглядит индикатор этого типа



Выбор значения осуществляется левой кнопкой мыши


In order to link and synchronize all future instances of the created list, it is convenient to use the function "Make Type Def." (selection through the context menu of the element). This will create a custom data type. The new type is placed in a separate file with the extension * .ctl. Editing this file will change all instances of this item. I think you should not explain how it can be convenient. Access to the definition file can be obtained from the context menu of the instance by selecting "Open Type Def", in the same menu you should pay attention to the items "Auto-Update from Type Def." and "Disconnect from Type Def".


We change the indicator Typesto an array of type indicators FTDI Typeand as a result, when the VI is started, the type of the connected converter is displayed:



Three devices found


It is easy to see that the functionality of the resulting code in the Timeout case is complete, therefore it can be transferred to a separate SubVI. Select the elements that we want to transfer to the sub-device and in the main menu Edit select the item "Create SubVI".


block diagram with sub-instrument created

Все индикаторы остались, а на месте узлов вызова образовался новый VI со стандартной иконкой.

Картинка кликабельна


Double click on the new subVI will launch its edit window. First of all we save it and give a meaningful name, for example "FT_GetDeviceInfo". Configure I / O terminals. To do this, use the Connections Pane:



A panel is a set of terminals corresponding to controls and indicators VI.


If you select the terminal on the connections panel, the corresponding element on the front panel will be highlighted. If you select an empty terminal, and then click on the element on the front panel, the element will bind to the terminal, but before that it should not be assigned to any other terminal. In the context menu you can individually or for all at once disconnect the terminals from the elements, you can change the pattern of the panel as a whole.


I don’t like how the terminals were assigned when creating the current subVI, so I select the "Disconnect All Terminals" option and mark it manually. I recommend the input terminals to be placed on the left, and the weekend on the right, optional input can be placed on top, and optional output below. This will ensure good code readability and visual order on the block diagram.


For error control, we create two additional elements Error inand Error out. The topic of error control in LabVIEW is very extensive and is beyond the scope of this article, therefore we limit ourselves to a minimum of explanations and will adhere to the principle of "do as I do." So, we create two terminals for errors - input and output.


It is convenient to create them using the context menu.

Правая кнопка мыши по терминалу ошибки любого узла:



In LabVIEW, the input terminal accepted errors on the connection panel to be placed on the left below, and the output one - on the right below.


It will be more convenient to combine the output into a structure. For output, we will make two arrays: the first array will contain all the FTDI devices found, the second array - only those that can MPSSE and can theoretically be used to configure the FPGA.


The final touch when creating a sub-device is setting up an icon. Double click on the icon in the upper right corner of the window launches the editor. We try to create some kind of meaningful image that allows us to unambiguously interpret the purpose of the device on the block diagram.


FT_GetDeviceInfo.vi

Передняя панель



Блок-диаграмма


А так выглядит кейс "Timeout" после наведения порядка:

Картинка кликабельна


Up to this point, the drop-down list with the name "Select device" was empty, now we have the data to fill it. Create a property node for the list with the property "Strings []" (context menu -> Create -> Property Node -> Strings []). Any property is available for writing and reading, the current mode is selected in the context menu of the Property Node. When creating the default node, properties are configured to be read. Change to write: "Change To Write".


From the array of structures, select the array with the description and submit it to Strings[]. You can select an array using a loop For Loop.


After starting the VI by pressing the left button on the element "Select device" you can specify the device to configure. At the same time, the list of devices is updated twice a second. Of course, it would be possible to update the property only if the list has been updated, but for the time being this will result in unnecessary blocking of the block diagram.


What happened?

Передняя панель



Картинка кликабельна


Ранее я забыл упомянуть такую интересную особенность, циклу For не обязательно указывать число итераций в явном виде, достаточно создать входной туннель массива и цикл выполниться для каждого элемента, это поведение напоминает цикл foreach в C++11. Однако нужно быть осторожным, когда на вход цикла поступает более одного массива.


In the event structure, we add an event handler for pressing the "program" button. As long as we do not have a VI responsible for loading the file into the FPGA, we will make a sub-device "stub". Suppose that it takes as input the path to the configuration file and the FTDI descriptor, and returns the status of the firmware as a result of the work: successful or not. And in order to make it more interesting to test the interface of the program, we will make this status random.


Plug FT_MPSSE_SP_FPGA.vi

Передняя панель



Блок-диаграмма


The FTDI descriptor will be passed to the stub via the list property (context menu -> Create -> Property Node -> Ring Text -> Text), to transfer the file path to the "File Path" element, create a local variable (context menu -> Create -> Local Variable) and configure it to read (Change To Read). And we will connect the status output directly to the indicator Status. The button will Programmdrag to the event handler. It is good practice to place elements on which the event is configured in the handlers - now double clicking on this element on the front panel will show not only the corresponding element on the block diagram, but also the event handler associated with this element.


Now, by pressing the "Program" button, the indicator becomes either green (success) or dark green (not success). Not too visually. In the properties of the indicator, change the color "Off" to red. That's better. If the indicator is green, then we can state that the FPGA on the selected device is configured by a file, the path to which is specified in the window:



Front Panel


But this statement becomes false if we change the file or choose another device. At the same time, we cannot dye the indicator red, as programming errors did not occur. A convenient solution would be to change the file or device, emphasizing that the indicator value is not relevant - to darken it. For this, you can use the indicator property Disabled. This property can take three values Enabled- the normal display, the user can control the object; Disabled- the object is displayed on the front panel as usual, but the user cannot control the object; Disabled and Grayed Out- the object is displayed on the front panel as dark, and the user cannot control the object.


We create event handlers for Devices listand File Path, and in them we dim the status indicator, and in the handler of the "Programming" button we assign a property Enabled.


What happened


Обработчик "Programm":Value Change.



Обработчик "Devices list":Value Change



Вот так выглядит затемненный индикатор


We will make it easy for the user to search for the configuration file - we will configure the file viewing window. Go to the properties of the element File Path, on the "Browse Options" tab, fill in the Prompt, Pattern Label, specify the filter of the file type (Pattern) and the name for the button (Button Text).


File selection window

Отображаются только rbf файлы



Creating a user interface can be considered complete.



Running bootloader


What did you meet today?


In this article, using the example of creating a functionally complete application with a minimalist interface, I tried to show different approaches to working in LabVIEW.


As a result, we touched on:


  • Setting the properties of the virtual device. We learned how to disable unnecessary menu type items.
  • The structure of the virtual device: a cycle with events.
  • Work with the structure of events.
  • The design of the sub-device.
  • Import functions from dll.
  • Work with item properties.

In the next article, we will delve into working with the API FTD2XX using the example of MPSSE. Load the configuration binary into the FPGA.


Materials on the topic


  1. Download configuration to FPGA via USB or disassemble FTDI MPSSE
  2. labview_mpsse . Repository with the project.
  3. Training stand for DSP . Iron for experience
  4. Software Application Development D2XX Programmer's Guide . API Guide D2XX.

Also popular now: