Пишемо завантажувач ПЛІС в LabVIEW. Частина 1

У більшості “нормальних” програмістів, м’яко кажучи, неоднозначне ставлення до технології LabVIEW. Тут сперечатися можна довго і безрезультатно. Ситуацію погіршує те, що в мережі маса прикладів програм на LabVIEW, але всі вони орієнтовані на початківця і зводяться до “ой, дивіться, як усе просто, поєднав крутилку з індикатором, кручу ручку, змінюється цифра”, або в кращому випадку на графік у циклі виводиться випадкове число або синус, все це супроводжується зубодробильний інтерфейсом у вигляді гігантських тумблерів, крутилок і стрілочних індикаторів. Особисто мене такий підхід свідомого спрощення дратує. У невеличкому циклі статей я спробую познайомити читача з процесом розробки прикладного ПЗ на LabVIEW. Для того, щоб не приділяти багато часу предметної області, скористаємося детально описаним алгоритмом завантаження файлу конфігурації в ПЛІС через FTDI в режимі MPSSE (Завантаження конфігурації ПЛИС через USB або розбираємо FTDI MPSSE). У цій статті я покажу як реалізувати такий же завантажувач ПЛІС, але мовою LabVIEW.

 

Як вже говорилося вище, алгоритм завантаження ПЛІС в режимі Serial Passive (SP) і принцип роботи FTDI добре описані в попередній статті. Повторюватися не буду. Вважаємо, що алгоритм протестований і визнаний придатним. І так, припустимо, що читач хоч би поверхнево вже знайомий з концепцією LabVIEW і непогано розбирається в класичному програмуванні.

 

Хоча процес створення завантажувача не займе багато часу, опис процесу ніяк не вдалося вмістити в обсяг однієї статті, тому буде невелика серія. Так як етап експериментів вже завершений, а в працездатності алгоритму я впевнений, то дозволю собі почати розробку з інтерфейсу користувача. У першій статті створимо користувальницький інтерфейс завантажувача, реалізуємо структуру програми. У другій — dll драйвера FTDI реалізуємо завантаження *.rbf файлу в ПЛІС.

 

Для продуктивності бесіди не зайвим буде нагадати термінологію прийняту в LabVIEW. В LabVIEW прикладна програма називається Віртуальний Прилад, він же ВП, він же Virtual instrument або скорочено VI. ВП має дві “сторони”: передня панель (Front Panel), де розташовуються органи управління і індикатори, і блок–діаграма (Block Diagram), де ці елементи з’єднуються між собою і реалізуються функції і потоки обробки даних. Як правило ВП має ієрархічну структуру, усе ВП у складі ВП верхнього рівня прийнято називати подприбором або SubVI.

Інтерфейс користувача

 

Наше додаток має завантажувати файл конфігурації ПЛИС. При цьому маємо на увазі, що до комп’ютера одночасно може бути підключено кілька FTDI, і деякі з них потенційно можуть бути використані для конфігурування ПЛІС. Пропоную вибір пристрою зробити з розкривного списку, вибір файлу через кнопку з висновком шляху. Для старту завантаження додамо кнопку “програмувати”. Віртуальний світлодіодний індикатор відображає статус операції. Запускаємо LabVIEW.

 

Додаємо необхідні елементи на передню панель (Front Panel). Для оформлення ВП я буду використовувати стиль “Silver”. Нижче на малюнку показаний результат, всі елементи в їх первозданним стані. По назві, при необхідності, їх досить легко знайти в палітрі.

Редагуємо елементи: переносимо, розтягуємо, додаємо написи — наводимо в реквізит вид. Тут, насправді, потрібно рука дизайнера, але як зміг:

І блок-діаграма:

Звертаю увагу. У кожного елемента є дві властивості, які визначають назва — це Label Caption.

Перше властивість задає ім’я елемента, під цим ім’ям він буде відображатися на блок-діаграмі. Label на відміну від Caption не може бути змінений в процесі виконання ВП. У зв’язку з цією особливістю я рекомендую в своїх ВП на передній панелі приховувати Label, а відображати Caption. Для Label придумувати осмислене ім’я змінної в класичному мовою програмування, бажано на латинській розкладці. Для Caption вводимо вже людино орієнтоване ім’я, воно може бути досить довгим, включати прогалини і, при необхідності, російською мовою. Засобами LabVIEW можна налаштувати шрифт відображення Caption. Повинен сказати, що ніхто не змушує нас возитися з Caption: будь-яка напис може бути зроблена безпосередньо на FP у будь-якому вільному місці.

 

Функціонування ВП реалізуємо за класичною схемою: цикл While і обробник подій. На блок-діаграму додаємо цикл While (Programming -> Structures -> While Loop), і структуру обробника подій (Programming -> Structures ->Event Structure).

Короткий Help за структурою Event

Структура очікує настання події, потім виконує відповідний обробник. Структура подій має одну або кілька поддиаграмм — обробників подій, так званих кейсів (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”.
Читайте також  Історії IT юриста. Життя аутсорсинг бізнесу. Частина 1

 

Першим ділом подбаємо про те, як буде відбуватися завершення циклу і вихід з програми. Найпростіший спосіб — це додати кнопку “стоп”, яка зупинить цикл, але, на мій погляд, програму прийнято завершувати червоним хрестиком у правому куті вікна.
В структуру Event Structure додаємо відповідний обробник. У контекстному меню вибираємо “Add Event Case”. В якості джерела події вибираємо “This VI”, подія вказуємо “Panel Close?”

Edit Events


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

 

Звертаю увагу, якщо вибрати “Panel Close” (без питаннячка), то це подія без фільтра, його неможливо скасувати. А якщо з питанням, то при натисканні на хрестик, ми можемо перехопити управління і самостійно коректно завершити програму. В процесорі “Panel Close?” через тунель з’єднуємо булеву константи true з терміналом зупинки циклу while. На вхід “Discard?” також подаємо true.

 

Тепер не очевидний нюанс: якщо поточний СП буде запускатися не в середовищі LabVIEW, а у вигляді откомпилированного додатки, то натискання хрестика не закриє вікно, а зупинить додаток, чого нам не потрібно. Для вирішення цієї проблеми після завершення основного циклу, виконаємо перевірку, знаходимося ми в середовищі розробки або в режимі програми, якщо все ж таки в режимі програми, то завершимо додаток. Для того, щоб зрозуміти, де виконується поточний ВП, скористаємося вузлом властивостей (Programming -> Application Control -> Property Node). Даний сайт надає доступ до властивостей об’єкта з посиланням на цей об’єкт. В даному випадку ми повинні отримати посилання на всі програми в цілому. Вибираємо константу VI Server Reference з тієї ж палітри. Після того, як константа встановлена на блок-діаграму, потрібно змінити її тип This Application (ліва кнопка миші). З’єднуємо отриману посилання з вузлом властивостей. Вибираємо властивість Application:Kind Property — повертає тип системи LabVIEW в якій запущений поточний ВП. Вихід властивості з’єднуємо зі структурою вибору (Case Structure), додаємо кейс “Run Time System”, де завершуємо додаток (Quit LabVIEW). Для того, щоб цей блок виконався після циклу, а не до, вхідний термінал error in з’єднуємо з циклом через тунель.

 


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

 

Тепер при запуску програми її можна зупинити, натиснувши на хрестик вікна. Запущена програма виглядає так:

На мій погляд, багато зайвого. Заходимо у властивості VI (меню File -> VI Properties ), вибираємо категорію “Window Appearance”, встановлюємо Custom.

 

Відключаємо відображення меню (в режимі редагування меню залишається), відключаємо scroll bar, приховуємо панель інструментів, коли додаток запущено (Show toolbar when running). Забороняємо змінювати розмір вікна, дозволяємо згортати і мінімізувати вікно. Ось так краще:

Звичайно, варто було б прибрати напис “National Instruments. LabVIEW Evaluation Software”, але для домашнього комп’ютера купувати ліцензію я поки не бажаю, змиримося з написом і обійдемося 45 денним пробним періодом.

 

Природно, можна налаштувати колір фону і кожного елемента, підібрати шрифти, але я не дизайнер, а щось підказує мені, що зроблю тільки гірше.

 

Список приладів

 

ВП повинен запропонувати користувачеві список підключених до комп’ютера пристроїв, придатних для прошивки ПЛІС, для того, щоб користувач зміг вибрати потрібне. В бібліотеці FTD2XX для цього призначені функції FT_CreateDeviceInfoList і FT_GetDeviceInfoDetail. Як уже зазначалося в попередній статті, для використання API FTD2XX можна використовуватись бібліотеками драйвера. В LabVIEW є зручний механізм взаємодії з динамічними бібліотеками — вузол виклику функції з бібліотеки (Call Library Function Node), знайти його можна в панелі “Connectivity -> Бібліотеки & Executables”. Вузол виклику функції слід налаштувати: по-перше, вказуємо шлях до dll (вкладка “Function”), після чого система сканує бібліотеку і у списку “Function Name” запропонує вибрати ім’я функції — вибираємо FT_CreateDeviceInfoList, угода про виклику (Calling convention) — вибираємо stdcall(WINAPI). По-друге, на вкладці “Parameters” потрібно ввести список параметрів функції, де перший елемент списку — обчислене значення. Тут перед очима непогано б тримати документацію API, або заголовковий файл. При налаштуванні параметрів в області “Function prototype” відображається прототип імпортованої функції. Коли сигнатура з документації збігається з налаштованим прототипом, тиснемо ОК.

 

Покладемо, що сканування повинне виконуватися раз в секунду. Вузол виклику маємо в структурі обробника подій на вкладці “Timeout”, час очікування встановлюємо 1000 мс. Додаємо індикатори на висновки вузла, і якщо все зроблено правильно, то при запуску ВП, повинно відображатися на кількість підключених пристроїв з FTDI:

Читайте також  Курс молодого бійця PostgreSQL

Передня панель і блок-діаграма


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

Аналогічним чином створюємо сайт для функції FT_GetDeviceInfoDetail. Прототип функції має вигляд:

 

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

 

При описі параметрів слід звернути увагу, що lpdwFlags, lpdwType, lpdwID, lpdwLocId передаються як покажчики на uint32. Параметри lpSerialNumber і lpDescription — є суть байтові рядка (масиви типу char з нуль-термінатор). Параметри такого виду у вузлі виклику можуть бути оформлені різними способами, можна ввести їх в масив 8-бітних слів, але я думаю, найбільш зручно відразу вказати, що це рядок, і визначити очікуваний розмір. У цьому випадку на виході відразу буде придатна “лабвьюшная” рядок і не потрібно якихось додаткових перетворень.

Call Library Function

 

Дана функція повертає інформацію за порядковим номером dwIndex. У разі якщо до комп’ютера підключено кілька FTDI, для того щоб прочитати інформацію для кожного перетворювача, потрібно викликати функцію в циклі. Число ітерацій циклу нам дасть попередня функція FT_CreateDeviceInfoList.

Передня панель і блок-діаграма


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

Є неприємна особливість: всі порти вузла виклику повинні бути підключені хоча б з одного боку. Тому в циклі зроблений тунель і для тих терміналів виводу, які ми не збираємося використовувати.

 

У масиві Types міститися типи чіпів FTDI, вони нам потрібні для того, щоб обмежити вибір тільки тими, які підтримують MPSSE і потенційно можуть бути використані для програмування ПЛІС. Однак оперувати “магічними цифрами” незручно — пропоную оформити типи FTDI у вигляді enum. Тим більше, що такий enum вже є в заголовочном файлі ftd2xx.h. В LabVIEW для створення перерахування можна використовувати два елемента керування “Text Ring” і власне сам “Enum”. Обидва містять списки рядків з числовими значеннями, між якими можна перемикатися. Основна відмінність в тому, що “Enum” вимагає, щоб числові значення були послідовними цілими числами, в той час, як в “Text Ring” більше свободи — можна задати будь-які значення.

Enum. Створення

Вводимо значення вручну, шкода що немає функції імпорту enum з Сі

На фронт-панелі так виглядає індикатор цього типу

Вибір значення здійснюється лівою кнопкою миші

 

Для того, щоб зв’язати і синхронізувати всі майбутні примірники створеного списку, зручно скористатися функцією “Make Type Def.” (вибір через контекстне меню елемента). В результаті буде створений користувацький тип даних. Новий тип поміщається в окремий файл з розширенням *.ctl. Редагування цього файлу приведе до зміни всіх примірників цього елемента. Думаю, не варто пояснювати, наскільки це може бути зручно. Доступ до файлу визначення можна отримати з контекстно меню примірника, вибравши пункт “Open Type Def”, в цьому ж меню слід звернути увагу на пункти “Auto-Update from Type Def.” і “Disconnect from Type Def”.

 

Міняємо індикатор Types на масив індикаторів типу FTDI Type і в результаті при запуску ВП відображається тип підключеного конвертера:

Знайдено три пристрої

 

Легко помітити, що функціонал отриманого коду в кейсі “Timeout” носить закінчений характер, отже, його можна винести в окремий SubVI. Виділяємо елементи, які хочемо перенести в подприбор і в головному меню Edit вибираємо пункт “Create SubVI”.

блок-діаграма зі створеним подприбором

Всі індикатори залишилися, а на місці вузлів виклику утворився новий VI зі стандартною іконкою.

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

 

Подвійний клік по новому subVI запустить вікно для редагування. В першу чергу зберігаємо його і даємо осмислене назву, наприклад “FT_GetDeviceInfo”. Налаштуємо термінали вводу-виводу. Для цього служить панель сполук (Connector Pane):

Панель являє собою набір терміналів, відповідних елементам управління і індикаторами VI.

 

Якщо виділити термінал на панелі сполук, то відобразиться відповідний елемент на передній панелі. Якщо виділити порожній термінал, а потім клацнути по елементу на передній панелі, то елемент прив’яжеться до терміналу, однак до цього він не повинен бути закріплений за якимось іншим терміналом. У контекстному меню можна окремо або всіх разом від’єднати термінали від елементів, можна змінити патерн панелі в цілому.

 

Мені не подобається як були призначені термінали при створенні поточного subVI, тому я вибираю пункт “Disconnect All Terminals” і размечаю вручну. Рекомендую вхідні термінали розміщувати ліворуч, а вихідні праворуч, опціональні вхідні можна розмістити зверху, а опціональні вихідні знизу. Це дозволить забезпечити хорошу читаність коду і візуальний порядок на блок-діаграмі.

 

Для контролю помилок створимо два додаткових елемента Error in і Error out. Тема контролю помилок в LabVIEW вельми обширна і виходить за рамки цієї статті, тому обмежимося мінімумом пояснень і будемо дотримуватися принципу “роби як я”. Отже, створюємо два термінали для помилок — вхідний і вихідний.

Їх зручно створити за допомогою контекстного меню

Права кнопка миші по терміналу помилки будь-якого вузла:

В LabVIEW прийнято вхідний термінал помилки на панелі сполук розміщувати зліва знизу, а вихідний — праворуч знизу.

 

Буде зручніше вихідні дані об’єднати в структуру. Для виведення зробимо два масиви: перший масив буде містити всі знайдені пристрої FTDI, другий масив — тільки ті, які вміють MPSSE і теоретично можуть бути використані для конфігурування ПЛІС.

Читайте також  Вся правда про ОСРВ. Групи прапорів подій: введення і базові служби

 

Останнім штрихом при створенні подприбора налаштуємо іконку. Подвійний клік по іконці в верхньому правому кутку вікна запускає редактор. Намагаємося створювати якесь осмислене зображення, що дозволяє однозначно інтерпретувати призначення приладу на блок-діаграмі.

FT_GetDeviceInfo.vi

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

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

 

А так виглядає кейс “Timeout” після наведення порядку:

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

 

До цього моменту розкривний список з назвою “Виберіть пристрій” був порожній, тепер у нас є дані, щоб наповнити його. Створюємо для списку вузол властивостей з властивістю “Strings[]” (контекстне меню -> Create -> Property Node -> Strings[]). Будь-властивість доступна для запису і читання, вибір поточного режиму виконується в контекстному меню Property Node. При створенні сайту за замовчуванням властивості налаштовані на читання. Міняємо на запис: “Change To Write”.

 

З масиву структур виділяємо масив з описом і подаємо його на Strings[]. Виділити масив можна за допомогою циклу For Loop.

 

Після запуску ВП натиснувши ліву кнопку на елементі “Виберіть пристрій” можна вказати прилад для конфігурування. При цьому список пристроїв оновлюється два рази в секунду. Звичайно можна було б оновлювати властивість, тільки якщо список оновився, але поки це виллється в зайве захаращення блок-діаграми.

Що вийшло?

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

 


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

 

Раніше я забув згадати таку цікаву особливість, циклу For не обов’язково вказувати кількість ітерацій в явному вигляді, досить створити вхідний тунель масиву і цикл виконатися для кожного елемента, це поведінка нагадує цикл foreach в C++11. Проте потрібно бути обережним, коли на вхід циклу надходить більше одного масиву.

 

В структуру подій додаємо обробник натиснення кнопки “програмувати”. Поки у нас немає VI, який відповідає за завантаження файлу в ПЛІС, зробимо подприбор “заглушку”. Покладемо, що він приймає на вхід шлях до файлу конфігурації і дескриптор FTDI, а за результатами роботи повертає статус прошивки: успішна чи ні. А щоб було цікавіше випробувати інтерфейс програми, зробимо цей статус випадковим.

Заглушка FT_MPSSE_SP_FPGA.vi

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

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

 

Дескриптор FTDI передамо на вхід заглушки через властивість списку (контекстне меню -> Create -> Property Node -> Ring Text -> Text), для передачі шляху до файлу елементу “File Path” створимо локальну змінну (контекстне меню -> Create -> Local Variable) і налаштуємо її на читання (Change To Read). А вихід статусу з’єднаємо безпосередньо з індикатором Status. Кнопку Programm перетягнемо в обробник події. Це хороша практика, поміщати елементи на які налаштоване подія в обробники — тепер подвійний клік по цьому елементу на передній панелі покаже не тільки відповідний елемент на блок-схемі, але і обробник події, пов’язані з цим елементом.

 

Тепер по натисненню кнопки “Програмувати” індикатор стає або зеленим (успіх), або темно зеленим (не успіх). Не дуже наочно. У властивостях індикатора міняємо колір “Off” на червоний. Так краще. Якщо індикатор зелений, то ми можемо стверджувати, що ПЛІС на вибраному пристрої налаштований файл, шлях до якого вказаний у вікні:

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

 

Але це твердження стає хибним, якщо ми змінили файл або вибрали інший пристрій. При цьому ми не можемо пофарбувати індикатор в червоний колір, так як помилки програмування не сталося. Зручним рішенням буде у разі зміни файлу або пристрою, підкреслити, що значення індикатора не актуальні — затемнити його. Для цього можна скористатися властивістю індикатора Disabled. Ця властивість може приймати три значення Enabled — нормальне відображення, користувач може управляти об’єктом; Disabled — об’єкт відображається на передній панелі як зазвичай, але користувач не може управляти об’єктом; Disabled and Grayed Out — об’єкт відображається на передній панелі затемненим, і користувач не може управляти об’єктом.

 

Створюємо обробники подій для Devices list і File Path, і в них затемнюємо індикатор статусу, а в оброблювачі кнопки “Програмувати” присвоюємо властивості Enabled.

Що вийшло


Обробник “Programm”:Value Change.

 


Обробник “Devices list”:Value Change

Ось так виглядає затемнений індикатор

 

Зробимо зручним для користувача пошук файлу конфігурації — налаштуємо вікно перегляду файлів. Заходимо у властивості елемента File Path, на вкладці “Browse Options” заповнюємо Prompt, Pattern Label, вказуємо фільтр типу файлу (Pattern) і назву для кнопки (Button Text).

Вікно вибору файлу

Відображаються лише файли rbf

Створення користувацького інтерфейсу можна вважати закінченим.

Запущений завантажувач

 

З чим познайомилися?

 

В даній статті, на прикладі створення функціонально повного програми з мінімалістичним інтерфейсом, я спробував показати різні підходи до роботи в LabVIEW.

 

У підсумку ми торкнулися тем:

 

  • Налаштування властивості віртуального приладу. Дізналися як відключити непотрібні елементи типу меню.
  • Структура віртуального приладу: цикл з подіями.
  • Робота зі структурою подій.
  • Оформлення подприбора.
  • Імпортувати функції з dll.
  • Робота з властивостями елемента.

 

У наступній статті ми заглибимося в роботу з API FTD2XX на прикладі MPSSE. Завантажимо в ПЛІС бінарники конфігурації.

 

Матеріали по темі

 

  1. Завантаження конфігурації в ПЛІС через USB або розбираємо FTDI MPSSE
  2. labview_mpsse. Репозиторій з проектом.
  3. Навчальний стенд для ЦГЗ. Залізо для досвіду
  4. Application Software Development D2XX programmer’s Guide. Керівництво по API D2XX.

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *