STM32 и USB. Часть 2. Немного о драйверах и софте.

Связанные статьи:
STM32 и USB. Часть 1. Проект для Keil.

В прошлой части я рассказал как примерно должен выглядеть проект-заготовка для Keil девайса с USB, дал ссылку на мой проект и рассказал как его настроить под практически любую плату с STM32.

В проекте был реализован интерфейс с двумя bulk-ендпойнтами (in и out), с моим «кастомным» протоколом, при помощи которого можно включать, выключать и заставлять светоиоды мигать с нужными временами горения/не горения.

Ну и выложил небольшую программу для всего этого:



Пользователь Vga в комментариях справедливо заметил, что разработка своего драйвера под Windows — задача далеко не тривиальная, и что проще реализовать стандартный класс, например HID, под который драйверы есть.

В этой статье я проведу небольшой обзор средств, которыми можно воспользоваться, чтобы сильно упростить себе жизнь.

Итак, у нас на повестке следующие варианты:

1) Написать драйвер самому. Задача сложная, неблагодарная, долгая. Тут сразу можно отсылать, например к Windows Driver Foundation. Есть куча примеров, которые можно расковырять и адаптировать под свои задачи.
Несомненный плюс этого варианта — решение получится красивое и компактное. Но стоит ли это потраченного времени…
Извините, если разочаровал тех, кто полагал, что я опишу именно этот вариант :)

2) Реализовать на девайсе один из стандартных классов, например тот же HID.
Но давайте предположим что мы вот буквально вчера наконец-то заставили наш девайс определяться по USB как самостоятельное устройство, и все что мы умеем — это читать и писать в ендпойнты. Нам нужно что-то еще проще.

3) Использовать готовые средства. Вот на этом «варианте для начинающих и не только» мы остановимся.

Но вначале небольшое отступление.

Как Windows опознает наши USB-устройства?
В большинстве случаев это «зашитые» в девайс VID (Vendor ID) и PID (Product ID). Есть исключения, например HID и Mass Storage, там Windows опознает класс устройства и подсовывает уже приготовленный драйвер.

Если мы воткнем наш девайс в компьютер, система определит его, но, очевидно, будет ругаться на отсутствие драйвера, и предложит выбрать .inf- файл.
Именно в этом файле и прописываются, помимо прочего, наши VID и PID, а также путь к драйверу.

Есть, конечно, и более хитрые варианты, но мы на них пока останавливаться не будем.
Наши VID и PID можно подсмотреть в файле usb_desc.c проекта. И обязательно прочтите комментарий ;-)

Итак, встречаем: libusb-win32 и Jungo WinDriver.

Jungo WinDriver

http://www.jungo.com/st/windriver_usb_pci_driver_development_software.html
Заметьте, что поддерживает не только USB, но и PCI, и многое другое.

Весьма удобная штука.
Запускаем Wizard, выбираем по VID-PID наш девайс:


Генерим inf-файл, сохраняем, устанавливаем тут же драйвер, и вуаля. Вот они наши два bulk-ендпойнта + управляющий, нулевой ендпойнт:


А вот наш девайс определился в диспетчере устройств:


Но и это не все. Жмем на волшебную кнопку Generate Code:


И получаем воистину огромный набор вариантов на любой вкус:


Генерим проект, запускаем. Вот — готовая программа для работы с нашим девайсом:

Можем отправлять данные в ендпойнты и читать их оттуда.
Например, отправка пакета на скриншоте согласно моему протоколу зажжет светодиод номер два. (См protocol.txt в проекте Keil)

Я сгенерил проект для C# (.NET) и мне он выдал солюшен с двумя проектами: Собственно сама программа и либа для работы с девайсом по USB. В последней есть все необходимое, вплоть до событий подключения-отключения девайса. А вообще если не заморачиваться, то все можно свести к обычному чтению-записи в ендпойнты.
Дальше сами справитесь? ;-)

Ну а теперь поговорим о недостатках.
1) Jungo WinDriver — штука очень уж платная. Кто хочет расстроиться — цены лежат тут.
2) У некоторых USB-девайсов бывает несколько конфигураций. Такое встречается редко, но встречается.
WinDriver с такими работать не умеет, а функция смены конфигурации помечена как Not Implemented Yet.

libusb-win32

https://sourceforge.net/apps/trac/libusb-win32

Распаковываем и в папочке bin лежит программка inf-wizard.exe. Тоже визард для генерации инф-файла, а заодно и всех остальных файлов, необходимых для установки драйвера.
Запускаем, выбираем наш девайс, сохраняем inf и прочее в отдельную папочку:


Ну и сразу инсталлируем.


Теперь, чтобы создать свой проект, необходимо собрать все нужные от libusb файлы в папках lib, include, подсмотреть как работать с устройством, в папке exampes. А работать — проще простого (см bulk.c)

...
    usb_init(); /* initialize the library */
    usb_find_busses(); /* find all busses */
    usb_find_devices(); /* find all connected devices */
...
    if (!(dev = open_dev()))
    {
        printf("error opening device: \n%s\n", usb_strerror());
        return 0;
    }
...
    if (usb_set_configuration(dev, MY_CONFIG) < 0)
    {
        printf("error setting config #%d: %s\n", MY_CONFIG, usb_strerror());
        usb_close(dev);
        return 0;
    }
...
    if (usb_claim_interface(dev, 0) < 0)
    {
        printf("error claiming interface #%d:\n%s\n", MY_INTF, usb_strerror());
        usb_close(dev);
        return 0;
    }
...
    // Running a sync write test
    ret = usb_bulk_write(dev, EP_OUT, tmp, sizeof(tmp), 5000);
...


Но и этого мне показалось мало. Поскольку меня в свое время подсадили на тяжелый наркотик, именуемый C# + .NET, я стал искать решения, такие же простые, как и Jungo WinDriver.
И нашел следующее:

LibUsbDotNet


https://sourceforge.net/projects/libusbdotnet/

Нет, вы только вдумайтесь: .NET-надстройка над библиотекой, портированной из линукса под win32!
Конечно, изврат извратом, но мне понравилось.

Именно при помощи этой либы я и написал программу из предыдущей статьи. Работать с ендпойнтами так же просто.

UsbDevice SomeUsbDevice;
UsbDeviceFinder usbDeviceFinder = new UsbDeviceFinder(0x0483, 0xfff0);
SomeUsbDevice = UsbDevice.OpenUsbDevice(usbDeviceFinder);
...
UsbEndpointReader ep81Reader;
UsbEndpointWriter ep02Writer;
...
ep81Reader = SomeUsbDevice.OpenEndpointReader(ReadEndpointID.Ep01);
ep02Writer = SomeUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep02);
...
ErrorCode ec = ep02Writer.Write(_req, 1000, out nBytesWritten);
...


Ну а дальше реализуем небольшой протокол, пишем-читаем ендпойнты и радуемся мигающим светодиодам :)
Только не забываем одну тонкость: весь обмен с USB-девайсом происходит по инициативе хоста. Поэтому, данные не попадут в хост до тех пор пока хост сам не захочет их прочитать.
Вот и все.

Итого
Вот, в принципе, все необходимое для того чтобы создать на STM32 примитивный USB-девайс. Весь обмен сводится к чтению и записи в ендпойнты и разбору того, что же туда все-таки пришло и что с этим делать.
Лично мне кажется этот вариант проще, чем реализация на девайсе стандатного класса.

Как всегда, файлы с проектом находятся тут.

Ну а в следующий раз, когда дойдут руки, будем поднимать USB Mass Storage, причем поверх уже сделанного интерфейса для светодиодов, т.е. составное USB-устройство :)

  • +4
  • 21 сентября 2011, 14:03
  • Ezhik

Комментарии (48)

RSS свернуть / развернуть
LibUsb штука хорошая, но стандартные классы тоже не плохи. Например, класс CDC видится в системе как виртуальный КОМ порт, что не может не радовать, а реализуется очень просто. Всё-таки работа на любой системе без установки своих драйверов много стоит.
0
Ну да :) Только CDC-класс все равно потребует inf-файла, а также своих VID-PID. Ну линукс не в счет.

Вообще задача стояла такая: организовать USB-обмен максимально быстро и просто, чтением и записью в ендпойнты. А реализация даже CDC это уже хоть какое, но углубление :)
0
За статьи спасибо, интересно и познавательно. Сейчас помаленьку тоже ковыряю USB. Помаленьку — потому, что пока я не вижу особого смысла креативить свои USB-утройства, ибо есть FT232. VCP — наше все! :)
0
  • avatar
  • _YS_
  • 21 сентября 2011, 19:58
ft232 стоит примерно столько-же, сколько stm32f103. Есть смысл? :)
0
Есть. FTDI дубовая и железная. В ней все уже реализовано и намертво протестировано. Если ничего кроме не требуется, то зачем что либо еще?
0
Зачастую требуется хоть что-то еще. И тогда цена вырастает вдвое.

А если только усб-уарт, то конечно проще использовать железное решение
0
Мне FTDI (а именно FT232RL) не понравился тем что он от малейшего шума зависает. Поставил AT90USB82 (которая как минимум в 2 раза дешевле) — стало все отлично.
0
ORLY??? Может плата кривая? Я так наоборот так и не смог повесить FTDI. А цена… FTDI стоит от 90 до 130 рублей. Может у вас кривой поставщик? ;)
0
Поставщик терраэлектроника, цены у них на FT232RQ-R 215.31р, а AT90USB82 87.15р. На сколько кривой этот поставщик не знаю, ну уж явно лучше чип и дипа. У нас тут в Караганде FT232R в некоторых местах если переводить на ваши деньги вообще за 400р. продают, а AT90USB82 за 120р., но на заказ. А какой поставщик не «кривой». Схему для платы брал из даташита. Питаетcя от USB, за ней стоит ATmega644, которая не висла не разу. Затем поискал в инете, проблема с зависанием FT232 общая, посоветовали посадить все неиспользуемые ножки на землю. Так и сделал, но все равно иногда подвисала. Заменил на AT90USB — все стало ок.
0
Для штучного производства пофигу.

Для серии совсем другие цены будут. Зато FTDI не надо прошивать и не надо париться по поводу возможных глюков в прошивке.
0
Ну в общем как всегда, у всего свои плюсы и минусы. Если нужно быстро и просто и большего не какого функционала кроме бриджа я тоже FTDI, возьму. А по поводу прошивки у atmel есть пример для CDC, ничего править практически не надо. И не думаю что там ошибки могут быть, все таки официальный пример.
Единственное, что смущает как так сделали что FT232RL, без внешнего кварца работает. Причем работает же и неплохо в нормальных условиях.
0
PLL и RC цепочка. У меня STM32F103 тоже без кварца на ура работал с USB и тоже пробовали вынести ему мозг и сбить частоту — не получилось.
0
Для STM32 тоже есть примеры VCP, и не только.
0
Есть еще CP2102. Она втрое дешевле.
0
  • avatar
  • Vga
  • 21 сентября 2011, 22:35
Как она на практике в сравнении с FT232RL?
0
Раньше, при вытыкании провода на этой микрухе из компа, WinХР вываливалась в BSOD.
0
Чудесно. А как теперь, пофиксили? Но вообще это проблема дров.
Дрова FT232 тоже чудненько повисают где-то в ядре, если пытаться писать в ее ком-порт при отключенной микросхеме. В сочетании со странной запиткой фт-шки на пинборде я раз десять с матом к ресету тянулся.
0
  • avatar
  • Vga
  • 22 сентября 2011, 19:09
Не знаю, с тех пор я зарекся юзать эту микруху.

Да? У меня с FTDI таких проблем не было. При попытке рыгнуть что нибудь в несуществующий уже порт не происходит ровным счетом ничего.
0
Ну мож это брей терминал отчебучивал. Но если не закрывать порт, выдернуть микру и туда порыгать — может зависнуть. Чем больше рыгаешь (особенно если по ошибке туда файл пошлешь) — тем вероятнее зависание. С файлом — около 100%.
0
  • avatar
  • Vga
  • 22 сентября 2011, 19:38
не уверен что у меня переходник был именно на cp1202, но на 64 разрядной XP было достаточно просто в программе не закрыть порт перед выходом, ну или просто грохнуть приложение работающее с портом и синий экран появлялся с достаточно большой вероятностью
0
У меня в таком случае терминал зависал, но не более. XP SP3
0
Кстати да, бывало. И отвисал когда порт появлялся
0
ft232 легко можно изолировать от компа. Две оптопары всего. Причем линии TxD и RxD можно инвертировать программно.
0
  • avatar
  • ACE
  • 21 сентября 2011, 23:30
мироконтроллер тоже.
0
наверное имелось ввиду изолировать не ft232 от компа, а ft232 вместе с компом от всего остального.
для того чтобы отвязать мк с усб изоляторы для full speed тоже конечно есть, но по сравнению с любым оптроном это вещь всё-таки довольно специфическая.
0
Таки да, FT232 — проверенное железное решение, которое позволяет вообще забыть про то, что где-то есть USB. Так что смысл есть.

С глюками FT я не сталкивался на разу.
0
Таки Вы будете ставить в устройство FT232 + МК, лишь бы не вспоминать, что у МК где-то есть USB? :)
0
Вы произносите это так, как будто в этом есть что-то плохое. :)
0
Спасибо, полезная статья.
Давно хочу попробовать идею управления USB-устройствами через виртуальную файловую систему.
То есть обмен информацией с mass-storage через чтение/запись файлов на нем.
Получается простая и абсолютно кросс-платформенная система без надобности в каких-либо драйверах (даже на андроиде должно работать), обмен может происходить в любом формате, хоть в текстовом (напр. изменить настройки прибора можно просто набрав в консоли «echo 'param1=0,param2=1,...' >файл_на_флешке»). Возможна реализация и динамического Web-интерфейса, когда броузером открываем html файл и подгружается динамический JSON-контент.
+2
А по скорости не будет лажать?
0
смотря какая нужна. Если просто поменять настройки, то хватит.
0
ini файл на виртуальном диске :)
0
Ну да, как-то так.
Например, универсальный генератор/частотомер/осциллограф — настройки — в одном файле (ini/conf), форма сигнала — в другом (CSV), результат измерения/буфер осциллографа — в третьем. Управление — еще один файл. Просто пишем туда «start» для начала измерения. Тут же на диске Web-интерфейс. Статический html c какой-нибудь GUI библиотекой и рядом Javascript с JSON-данными измерений.
0
О-о-о, мосье знает толк в изысканных забавах! :)

Хотя, честно признаться, мне тоже приходили в голову подобные мысли.
0
Пропустили еще один способ — WinUSB.
В качестве драйвера ставится стандартный winusb.sys, а приложение линкуется с winusb.dll
На выходе получаем тот же API чтения/записи в end-point'ыю

msdn.microsoft.com/en-us/library/ff540196%28v=VS.85%29.aspx
0
Да, пропустил. Способ достойный внимания, хотя для начинающих он будет чуть посложнее, чем последние два.
http://msdn.microsoft.com/en-us/library/ff540174(v=VS.85).aspx
И красивеньких визардов для быстрой генерации inf файла там я тоже не нашел :)

Ну и, кроме того, либа LibUsbDotNet также работает с WinUSB:
(где-то в исходниках)
...
    internal const string WIN_USB_DLL = "winusb.dll";
...
    [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_ReadPipe", SetLastError = true)]
    private static extern bool WinUsb_ReadPipe([In] SafeHandle InterfaceHandle,
                                                   byte PipeID,
                                                   Byte[] Buffer,
                                                   int BufferLength,
                                                   out int LengthTransferred,
                                                   IntPtr pOVERLAPPED);
...
0
Никто часом не знает, почему на ST потерли UM0721, что там не так?
0
  • avatar
  • valio
  • 22 октября 2011, 21:39
Может быть он переехал сюда, не? UM1021
0
Спасибо за полезную статью.
Перенес твою разработку на свою Discovery с stm32l152 + сделал кое-какие изменения (скрестил твой проект с примером HID-устройства из либы stm'овской). Я правильно понимаю, что при подсоединении к компу (Win7) мастер установки оборудования сам должен предложить установить драйвер?

Плата без серийного номера устройства (процедура GetSerialNum() в hw_config) не хотела работать, я взял исходник этой процедуры из примера Custom_HID фирменной USB-библиотеки, теперь устройство обнаруживается, но не распознается, и драйвер ставиться не хочет.

Пробывал запускать Installer_x64 из вложения — ноль эффекта. Что сделать, чтобы система распознала устройство?
0
USBView помечает мое устройство как DeviceFailedEnumeration. Все-таки GetSerialNum() ни на что не влияет, выпилил ее совсем. Система по-прежнему видит устройство, но не может его распознать.
0
Проблема решилась — я поставил другой коэфф.умножения для PLLCLK. Внешний кварц почему-то дает 8 МГц вместо заявленных 24.
0
Кто нибудь делал IAD или composite device на F103?
0
  • avatar
  • x893
  • 08 ноября 2012, 20:14
а кто-нибудь видел в сети примеры на STM с двумя VCP в одном?
и ещё вопрос, как калибровать RC, чтобы работать без кварца?
0
Уважаемый автор! Можно вопросы задать по данной программе? Или тема уже закрыта.
0
Здравствуйте. К сожалению, я уже достаточно давно не занимаюсь STMками (пересел на ПЛИС), поэтому не уверен что смогу что-либо вспомнить и вразумительно ответить на вопросы.
Думаю, на этом сайте есть еще много примеров работы с USB, более актуальные.
Но все равно можете написать в личку, вдруг что вспомню.
0
Спасибо! Я так и сделаю. Мне трудно это передать в коротком тексте, но вы осветили именно те проблемы, что меня интересуют на сегодня, и поскольку я только начал изучать STM32, то пересмотрел много примеров — для меня Ваш лучший на порядок, сделан пример реально охватывающий большую нужную часть программирования и проектирования. Потом тут коротко и понятно как в среде Windows, так и в ARM! Профи возможно начнут спорить — но у каждого свой опыт и свои предпочтения.
0
Хочу выразить автору свою искреннюю благодарность за терпеливую и бескорыстную помощь. На мой взгляд, прекрасный пример для освоения ARM начинающими, в нем есть довольно сложная идея и её простая реализация, комплексное решение – не просто помигать светодиодами, а управление от ПК и связь МК с ПК по USB. Для желающих повторить подчеркиваю – нужно взять примеры с этого сайта, а не с сайта автора.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.