USB HID для микроконтроллеров STM32F103 без использования библиотек

Однажды озадачившись подключением микроконтроллера к ПК через USB, я обнаружил, что это непростая задача. По сравнению с USART, SPI и.т.п., программирование USB оказалось на порядок сложнее. Поиск примеров в интернете практически не дал никаких результатов. Имеющиеся примеры, как правило, основаны на использовании больших и сложных библиотек, которые очень трудно применить, а тем более модифицировать под свои нужды. Также эти примеры обычно состоят из множества файлов, так что даже понять структуру проекта, а не то что принцип работы, USB из них не представляется возможным. Есть неплохие статьи по USB, однако ответа на вопрос, как реализовать обмен данными на конкретном контроллере они не дают. В итоге пришлось самостоятельно, путем длительных экспериментов пытаться запустить USB.
Используемый контроллер STM32F103C8T6. Это наверное самый распространенный и дешевый контроллер с модулем USB. Конкретно использовалась вот такая плата:
ru.aliexpress.com/item/STM32F103C8T6-ARM-STM32-DIY-KIT/32839140960.html?spm=a2g0v.search0104.3.14.1a477b81mKd6hC&ws_ab_test=searchweb0_0%2Csearchweb201602_9_10065_10068_319_317_10696_453_10084_454_10083_10618_10307_10301_537_536_10902_10059_10884_10889_10887_321_322_10915_10103_10914_10911_10910%2Csearchweb201603_58%2CppcSwitch_0&algo_pvid=551618bd-fcbf-49a9-9147-692e88feb8ce&algo_expid=551618bd-fcbf-49a9-9147-692e88feb8ce-5
Цена такой платы практически равна цене микросхемы отдельно. Реализуемый класс устройств HID. Преимущества HID известны. Это отсутствие необходимости использования драйверов на ПК и относительная простота реализации. К недостаткам можно отнести низкую скорость передачи данных. В качестве среды программирования использован CooCox. Программа со стороны ПК компилировалась в Borland C++ 5.5.
Программа для CooCox состоит из одного файла и не использует никаких библиотек (кроме RCC, которая нужна лишь ради функции SystemInit(); в начале программы). Также не используются прерывания, поскольку, на мой взгляд, их использование, затрудняло бы понимание кода и отладку. VID и PID взяты от какого-то STM-овского устройства. При их смене, нужно так-же сменить их и в программе на ПК, поскольку поиск устройства происходит по VID и PID.
Работа рассматриваемой пары программ состоит в следующем. Программа со стороны ПК посылает целое число в контроллер. Контроллер делает инкремент полученного числа и отправляет его назад в ПК. Затем этот цикл повторяется снова и снова. В окне программы выводится полученное число. Дополнительно реализовано управление светодиодом на плате (PC13).
Данная программа не претендует на полное соответствие протоколу USB. В ней реализована обработка ограниченного набора запросов (только тех, что реально попадались при отладке). Как показала практика, набор запросов может различаться на разных компьютерах. Кроме того несмотря на то что удалось добиться работоспособности данной программы, многие вопросы касающиеся USB для меня так и остались непонятными. Этот пример, скорее полуфабрикат, требующий дальнейшей доработки.
Файлы проекта:
drive.google.com/drive/folders/1b3E0YwgRlacK2K2Qykc7OxS11ocNuWig?usp=sharing
  • +8
  • 27 марта 2019, 17:29
  • VVK
  • 1

Захват изображения с USB камеры при помощи STM32

image
Для собственного самообразования решил подключить USB камеру (вебкамеру) к STM32. У меня уже была отладочная плата на базе STM324F429, способная выводить изображение на VGA монитор, так что для проверки работы камеры я использовал именно ее.


Читать дальше
  • +9
  • 29 сентября 2018, 22:18
  • citizen

STM32f4 USB HS DMA HAL. Как это было

Попросил меня как-то один уважаемый заказчик организовать ему передачу данных с контроллера (stm32f407) в компьютер. Всё бы ничего, но скорость ему требовалась аж 40 мегабит в секунду.

Надо сказать, что железка была уже готова, основной код написан, в качестве интерфейса передачи выбран USB High Speed с внешним PHY (USB3300). У программиста заказчика с USB что-то не заладилось, посему решили произвести усиление коллектива вашим покорным слугой. Для полноты картины следует добавить, что весь код контроллера был написан при помощи CubeMX, а программа на ПК — на Delfi.

Читать дальше

Программный USB на микроконтроллерах STM8-STM32

Всем, привет!

Когда делать было не чего я сделал программную реализацию низкого уровня USB на базе STM8.
За прошедшее время было много писем о продолжении проекта и переноса его на STM32.

Сегодня получил в очередной раз письмо на данную тему.
На моё удивление автор письма ни как все, не просит чего-то сделать, а сам сделал перенос с STM8 на STM32 и предлагает совместно продолжить работу над проектом. Однако мне данный проект на текущий момент не интересен, да и времени свободного нет.



Читать дальше
  • +4
  • 19 апреля 2017, 09:11
  • ZiB

Программный USB на микроконтроллерах STM8 (Часть 3)

За два года с момента публикации по данной теме обращались с вопросами только товарищи из Китая, похоже только им интересна эта разработка ;)

Мне самому USB не очень интересен, поэтому я ни чего не делал с момента публикации. Код как был сырой так и остался.

Последнее время количество писем с просьбой помочь “запустить” увеличилось, особенно от товарища по имени James.

Решил помочь ему, нашел платку, прошил подключил к USB хабу и устройство определилось без проблем.


Читать дальше
  • +4
  • 27 июля 2016, 06:44
  • ZiB

Подключение экрана ILI9341 к pic24

PIC
Недавно приехал ко мне этот девайс, подключил к pic24fj64gb004, нарисовал линии, круги, как то все уныло, захотел выводить изображение, зря что ли покупал, тем более что контроллер позволяет работать с USB флешкой, выкопал микрочиповское демо, поправил под свой контроллер, дописал прошивку, подпаял экран, воткнул флешку и все заработало, описание экрана можно без проблем найти в сети так что вдаваться в дебри что там и как вдаваться не буду, шина работает на частоте 16 мгц, все это конечно скоростями не поражает, все таки 16мгц и отсутствие DMA скорости не прибавляют :-).
видео процесса вывода
youtu.be/ezIEmxJ4txk
вследствии недостаточного размера памяти и быстродействия контроллера, картинки переконвертированы в формат RGB565 и записаны на флешку, программа читает содержимое файлов и выводит на экран,
в main

 while(1)
    {
      USBTasks();

        if(USBHostMSDSCSIMediaDetect())
          {
           deviceAttached = TRUE;
           LED0_IO=1;
           
          if(FSInit())
            {
             if(TickGet() - t >= TICK_SECOND*2)
                {
                  t = TickGet();
                  i++;
                }
             switch(i){
                case 1:TFT_FillScreen(BRIGHTGREEN);
                     break;
                case 2:TFT_FillScreen(BRIGHTBLUE);
                     break;
                case 3:TFT_FillScreen(BRIGHTCYAN);
                     break;
                case 4: TFT_FillScreen(MAGENTA);;
                     break;
                case 5: TFT_FillScreen(YELLOW);
                     break;
                case 6:  TFT_FillScreen(BLACK);;
                     break;
                case 7:TFT_FillScreen(CYAN);;
                     break;
                case 8:TFT_FillScreen(DARKGRAY);;
                     break;
                case 9:TFT_FillScreen(BRIGHTRED);
                     break;
                case 10:
                    
                    myFile = FSfopen("1.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);
                      

                   break;
                  case 11:


                      myFile = FSfopen("2.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                   case 12:
                    
                        myFile = FSfopen("3.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                   case 13:
                     
                        myFile = FSfopen("4.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                   case 14:
                     
                        myFile = FSfopen("5.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                   case 15:
                    
                   myFile = FSfopen("6.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                  case 16:
                    
                      myFile = FSfopen("7.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                   case 17:
                   
                        myFile = FSfopen("8.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                   case 18:
                  
                        myFile = FSfopen("9.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                   case 19:
                  
                        myFile = FSfopen("10.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);

                   break;
                   case 20:
                    
                        myFile = FSfopen("11.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);
                   break;
                   case 21:
                   
                        myFile = FSfopen("1.raw","r");
                    do{
                      charsRead = FSfread((WORD *)myData,2,1024,myFile);
                      WriteDisplayPicture(myData,charsRead);
                       }
                       while(charsRead==1024);
                      FSfclose(myFile);
                      i=1;
                   break;
                 }

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

Приличный (без bit-banging) и дешёвый SPI-flash программатор, c DMA SPI и USB на основе flashrom и maple-mini (stm32).

В общем, понадобилось слить прошивку и прошить роутер TP-link (пересадить его с S25FL032A/P на M25P128). В итоге в сусеках интернета был найден на гитхабе проект github.com/dword1511/stm32-vserprog, который реализует то, что и указано в заголовке. Учитывя, что стоит она $4.2, и она у меня уже есть, я был очень рад.


Читать дальше

Составное USB устройство на STM32F4

После реализации USB audio, захотелось прикрутить к проекту еще и ком-порт. Естественно, через USB CDC. Тема в интернете освещена многократно, но, в основном, по форумам производителей МК. Ближе всего подходит к моему случаю аппнота NXP AN11115 (http://www.nxp.com/documents/application_note/AN11115.zip) в которой разбирается составное устройство UAC+CDC.


Читать дальше

STM8 USB V-USB

2017-12-08~19_58_48 программируемая клавиатура
USB HID keyboard macros for games programming
Добавился отладчик (можно по USB считывать и записывать в регистры МК)
Скорее это больше для управления задумано, чем для отладки.
Добавилась возможность сохранения настроек кнопок в ini файл
github.com/BBS215
debugtool
debugtoolGUI
Чтобы работало прошивку в МК надо обновить.

2017-11-22~10_13_59
STM8S003F3P6 USB HID программируемая клавиатура с АПЧ (без кварца)
+ программа конфига кнопок с графикой и командной строкой.
forum.easyelectronics.ru/viewtopic.php?p=526561#p526561
(https://github.com/selevo/STM8S-VUSB-KEYBOARD/tree/patch-1)

github.com/wlianmin/stm8_usb
в комплекте пример hid мышки самодвигающейся :)
китайцы взяли в основу труды этого товарища:
ziblog.ru/2014/02/20/programmnyiy-usb-na-mikrokontrollerah-stm8.html
и в общем-то довели до рабочей железки

А нашлось сначала вот что:
STM8 USB
vk.com/doc-73481857_408253851

портированные на IAR
vk.com/doc-73481857_408254606

Получение синхронных данных с помощью микросхемы Cypress CY7C68013A (FX2LP) на примере устройства видеозахвата для старых компьюторов.

Постановка задачи.

     Так произошло, что у меня накопилось несколько советских компьютеров, и однажды у меня возникло желание их включить, однако свободного телевизора под рукой не оказалось. Решить данную проблему можно несколькими способами: приобрести телевизор или tv-тюнер, собрать удвоитель числа строк и подключить его к монитору с VGA разъемом или послать видео поток на компьютер и там его обработать. В данной статье будет рассмотрен последний вариант.
скриншот БК0010-01


Читать дальше