Проект виртуального сом порта для отладочной платы stm32h107

Проект виртуального СОМ порта для отладочной платы STM32H107

Для изучения работы USB в микроконтроллерах STM32F105, STM32F107 существует определенное количество отладочных плат. Большинство из них имеет высокую стоимость, но, при этом, существуют демо-проекты, написанные и отлаженные производителем STMicroelectronics, которые без дополнительных усилий можно сразу загрузить в эти платы и все будет работать.

Существуют и дешевые отладочные платы, например STM32-H107 фирмы Olimex. Но проблема в том, что для дешевых плат нельзя найти готовые для использования демо-проекты. 

Эта статья представляет демо-проект виртуального COM порта, который содержится в библиотеке от STMicroelectronics stm32_f105-07_f2_f4_usb-host-device_lib STM32_USB-Host-Device_Lib_V2.1.0ProjectUSB_Device_ExamplesVCPTrueSTUDIOSTM3210C-EVAL_USBD-FS, адаптированный для работы с отладочной платой STM32-H107 и результаты тестов скорости передачи.

Скачать его можно по ссылке ниже

Распакуйте архив проекта. Запустите Atollic TrueStudio.

Выберите File->Import->General->Existing Projects into workSpace->Next.

Выберите папку проекта VCP.

Установите галку Copy projects into workspace.

Нажмите Finish.

Скомпилируйте проект и он готов к загрузке в плату STM32-H107.

При создании проекта установлена конфигурация JTAG порта процессора как ST-Link.

Я использовал ST-Link, имеющийся на отладочной плате STM32VLDISCOVERY. См. рисунок ниже.

Схема соединений следующая:

 STM32VLDISCOVERY  STM32-H107  

   CN2 “SWD”    JTAG

   2 (SWCLK)    9 (TCK)   

   3 (GND)  ,    8 (GND)   

   4 (SWDIO)    7 (TMS)   

Предварительно, на персональном компьютере (PC) надо установить драйвер от STMicroelectronics VCP_V1.3.1_Setup.exe.

Загрузите исполняемый код в STM32-H107 и запустите его выполнение.

Через небольшое время, необходимое для инициализации виртуального COM порта, на PC в диспетчере оборудования, в разделе порты COM и LPT появится устройство виртуальный COM порт, как показано на рисунке ниже.

Номер порта назначается первый свободный в системе.

Если этот номер не устраивает, его можно изменить средствами операционной системы ОС.

В этой статье не рассматривается использование виртуального COM порта по его прямому назначению, когда данные, принятые от РС через USB, отправляются на передачу через USARTx (UARTx) микропроцессоров STM32F105 или STM32F107, а данные, принятые USARTx(UARTx), отправляются на передачу через USB микропроцессоров на РС. Это требуется только в случае построения USB-serial преобразователей.

Гораздо более интересное использование этого демо-проекта для обмена по USB в режиме CDC (common device class).

В классическом варианте использования CDC должна быть библиотека функций для использования в программе микроконтроллера STM32F10x (это

 библиотека STM32_USB-Host-Device_Lib_V2.1.0 и она свободно распространяется на сайте STMicroelectronics).

Со стороны РС необходим драйвер CDC (можно свободно скачать с сайта STMicroelectronics) и библиотеки функций для работы с USB при написании программы для РС. Последние STMicroelectronics не предоставляет, но можно купить библиотеки, созданные третьей стороной, причем, не дешево.

Обойти вопрос покупки библиотек можно, используя со стороны микроконтроллера режим передачи CDC, а со стороны РС только драйвер виртуального COM порта. Все необходимые функции для работы с виртуальным COM портом такие же, как для обычных СОМ портов и содержатся в WinSDK. Функции объявлены в файле winbase.h, а содержатся в библиотеке kernel32.lib.   

Эти функции следующие:

При помощи этой функции открывается СОМ порт.

HANDLE CreateFile( LPCTSTR lpFileName, // pointer to name of the file DWORD dwDesiredAccess, // access (read-write) mode DWORD dwShareMode, // share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes DWORD dwCreationDistribution, // how to create DWORD dwFlagsAndAttributes, // file attributes HANDLE hTemplateFile // handle to file with attributes to copy );

Ниже дается пример вызова функции:

const char* port = “COM1”; HANDLE hCommPort; hCommPort = ::CreateFile( port, //port name GENERIC_READ|GENERIC_WRITE, //access read and write 0, //(share) 0:cannot share the COM port 0, //security (None) OPEN_EXISTING, // creation : open_existing FILE_FLAG_OVERLAPPED, // we want overlapped operation 0 // no templates file for COM port… );

При помощи этой функции закрывается СОМ порт.

BOOL CloseHandle(HANDLE hObject); // handle to object to close 

Пример вызова:

BOOL result; result = CloseHandle(hCommPort);

Функция для передачи данных от PC на COM порт:

BOOL WriteFile( HANDLE hFile, // handle to file to write to LPCVOID lpBuffer, // pointer to data to write to file DWORD nNumberOfBytesToWrite, // number of bytes to write LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written LPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O );

Пример вызова:

bool result; DWORD dwBytesWritten; OVERLAPPED ovTx; byte Buf[64]; result = WriteFile (hCommPort, Buf, sizeof(Buf), &dwBytesWritten, &ovTx);

Данные от СОМ порта принимаются в отдельном потоке при помощи:

BOOL ReadFile( HANDLE hFile, // handle of file to read LPVOID lpBuffer, // address of buffer that receives data DWORD nNumberOfBytesToRead, // number of bytes to read LPDWORD lpNumberOfBytesRead, // address of number of bytes read LPOVERLAPPED lpOverlapped // address of structure for data );

Пример вызова:

byte BufRx[64]; OVERLAPPED ov; DWORD dwBytesRead; result = ReadFile(hCommPort, BufRx, sizeof(BufRx), &dwBytesRead,&ov);

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

uint16_t CDC_DataTx (uint8_t* Buf, uint32_t Len);  , которая является аналогом имеющейся там функции uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len);

, с разницей в источнике данных для передачи. Для первой функции это uint8_t* Buf – массив данных, который требуется передать, второй функции данные поставляет USARTx(UARTx) микроконтроллера.

Таким образом, функция CDC_DataTx является точкой входа для передачи данных по USB от микроконтроллера на РС.

На стороне PC использовалась самодельная программа для приема/передачи байтов по порту RS232, окно которой показано ниже:

 
Рис.1

Она позволяет:
– оперативно открывать/закрывать COM порт с любым номером
– устанавливать требуемую скорость работы порта
– имеет поток, который принимает байты от порта и выводит их на левый экран.

 Для случая проверки максимальной скорости передачи, вывод принятых байтов на экран заблокирован, а добавлен счетчик, который выводит на форму количество принятых байтов в секунду(обведено красным).

– передавать из правого окна одиночные байты, массивы байтов и строки.

Для проверки максимальной скорости передачи от микроконтроллера к PC, на плате STM32-H107 надо нажать кнопку WKUP. Загорается зеленый светодиод, микроконтроллер в цикле main следит за переменной USB_Tx_State. Когда она становится равной 0(т.е.ресурсы USB на передачу свободны), загружает эти ресурсы очередным массивом данных.

Из рис.1 видно, что скорость передачи составила 424.5 килобайт/сек.  Такая скорость получена при установке в 0 параметра

#define CDC_IN_FRAME_INTERVAL 0 /* Number of frames between IN transfers */ в файле usbd_conf.h. Если параметр увеличивать, скорость будет уменьшаться. 

В этой проверке установленная скорость виртуального порта не играет никакой роли.

Прием байтов от РС

Из программы на РС передается байт 123 (см.рис.2)  

 
Рис.2

На рис.3 видно, в каком месте проекта появляется принятый от РС пакет.

 
Рис.3

Принятый от РС пакет содержит переданный байт 123(фигурная скобка), USB_Rx_Cnt=1, т.е длина пакета равна 1.

Для проверки максимальной скорости передачи байтов от PC на микроконтроллер программа на РС передавала пакет из 64 байтов и ждала подтверждения от микроконтроллера о приеме пакета. Потом цикл повторялся. Функция usbd_cdc_DataOut в программе микроконтроллера была модифицирована следующим образом:

Т.е функция APP_FOPS.pIf_DataRx(USB_Rx_Buffer, USB_Rx_Cnt); закомментирована, чтобы она не передавала принятые байты в USART микроконтроллера. Поток, работающий на прием на РС, подсчитывал, при этом, 1-байтовые ответы от микроконтроллера.

На рис.4 показан результат теста:

  
Рис.4

Скорость передачи составила 8926 х 64 = 571264 байт/с.

Следует отметить, что и в этом тесте установленная скорость виртуального порта не имеет никакого значения. Можно поставить малую скорость, например 115200 бит/с, а результат остается тем же.

Можно подвести итог:

  1. Данные по скорости обмена по USB получены при минимальной их обработке со стороны микроконтроллера. Если обработка данных будет более сложная, скорость обмена уменьшится.
  2. Скорость обмена ограничивается быстродействием микроконтроллера, работающего на частоте 72МГц.
  3. Скорость обмена достаточно большая и позволяет использовать описанные в статье методы приема и передачи данных по USB микроконтроллеров STM32F105, STM32F107 при написании программ для широкого круга приложений.

Прикрепленные файлы:

Источник: http://cxem.net/mc/mc269.php

STM32F103C8T6 aka Blue Pill + STM32duino + IAR ARM: быстрый старт

разделы: STM32 , STM32duino , дата: 08 сентября 2017г

Отладочная плата на микроконтроллере stm32f103c8t6, является одной из самых популярных в любительской среде “электронщиков”. Это одна из самых удачных плат в соотношении “цена/функционал”, а сам stm32f103xxxx, который выпускается уже 10 лет, является ветераном и первопроходцем микроконтроллеров на ядрах ARM Cortex M3.

    Для быстрого знакомства с платой я предлагаю пройтись по следующим пунктам:
  • Краткий обзор платы;
  • Исправление аппаратного бага с помощью термофена и паяльника;
  • Прошивка загрузчика STM32duino;
  • “Подъем” виртуального COM порта на USB-модуле микроконтроллера stm32f103c8t6 с помощью STM32Cube MX и IAR ARM. Подключение микроконтроллера к планшету на Android.
  • Подключение и написание программы опроса I2C модуля RTC DS3231 с помощью STM32duino.

Вроде не много.

  • В отличии от Maple Mini, данная плата имеет штыревой разъем для подключения китайского клона ST-Link. Что на мой взгляд является большим плюсом, т.к. на проверку, загрузчик Leafmaple/STM32duino из-за постоянного переключения между DFU-загрузчиком и виртуальным COM-портом, оказался довольно проблемным.
  • Плата имеет на борту два кварца: на 8 MHz для тактирования HSE и на 32768 Hz для LSE. Для сравнения, на Maple Mini установлен только кварц на 8 MHz.
  • Сам микроконтроллер stm32f103c8t6, несмотря на то что по документации поставляется с флешпамятью на 64KБайта, фактически поставляется с флеш-памятью на 128КБайт(!) Хотя, гарантии на это никто не дает конечно.
  • Также имеется два джампика для прошивки микроконтроллера через USB-TTL конвертер, кнопка сброса Reset, два светодиода: красный для индикации питания и зеленый подключенный к выводу PC13. Причем загорается он при логическом нуле.
  • Цифровые выводы имеют маркировку в соответствии с даташитом, за тем исключением, что из их обозначения отброшена литера “P”.
  • Довершает “обвес” микро-USB разъем, который мы сегодня попытаемся задействовать.
  • Сфера применения микроконтроллера, на мой взгляд- это коммутация по USB-интерфейсу с традиционными компьютерами, одноплатными компьютерами, устройствам на Android которые возможно использовать как дисплеи(вторая жизнь для устаревших телефонов и планшетов) и т.д. Также думаю, что будет неплохая связка микроконтроллеров STM32 с SPI-дисплеями.

Полезная информация о плате собрана на страничке проекта STM32duino.

Для начала взглянем на раcпиновку платы:

и принципиальную схему:

На схеме нас будет интересовать резистор R10. На вики STM32duino, относительно этого резистора утверждается следующее:

The USB standard requires a 1.5 kΩ pullup resistor on D+, but this board is known to have a wrong value (R10 on the board). It ships with either a 10 kΩ resistor or a 4.7 kΩ resistor, but it should be replaced with a 1.5 kΩ resistor, or put an appropriate resistor value (e.g 1.8 kΩ) in between PA12 and 3.3V. It is also true that some PCs are tolerant of incorrect value so, before you change the resistance, you can try if it works in your case.

Т.е. они пишут, что согласно спецификации USB, на линии D+ должен быть установлен резистор номиналом 1.5K в то время как китайцы ставят резисторы на 4.7К или 10К. И далее предлагается поменять его на резистор требуемого номинала. Там даже прилагается фото с результатом переделки:

Еще там сказано, что несмотря на неправильный номинал резистора, USB-хостами наш микроконтроллер все же может восприниматься корректно. Нужно пробовать, но никакой гарантии нет.

На моей версии платы был установлен резистор на 10K:

Протестировав плату на паре стационарных компьютеров и на одном планшете с Android я могу сказать, что плата скорее всего будет работать и без переделки, но возможно будет подглючивать. У меня она не всегда распознавалась в Windows, а в Android не отображалась в списке подключенных устройств, хотя терминальная программа при этом устройство видела и принимала с него данные.

Поэтому, если есть такая возможность, то резистор все же лучше поменять:

Ну и заодно я впаял штыревой разъем, что бы в лишний раз не мараться. Получилось как-то так:

Ок. теперь когда отремонтирован USB, можно начать программировать.

Прошивка и программирование Blue Pill

Подключаем плату к ST-Link и запускаем “STM32 ST-LINK Utility”:

Жмем “Connect to the target” и если в графе Device чип определился правильно, значит все Оk, чип живой и готов к работе. Хотя, это конечно следовало проверить ДО того как браться за паяльник 😉

Попробуем прошить Blink через ST-Link из Arduino. Для этого запустим Arduino с установленным паком Arduino_STM32. В меню выбора платы щелкнем по Generic-STM32F103C series

Из примеров загрузим вариант Blink'а для STM32:

В тексте скетча исправим номер пина PB1 на PC13, т.е. на пин с зеленым светодиодом.

В меню выбора программатора выберем ST-Link:

После чего пробуем прошить:

В итоге имеем вес прошивки в 13 КБайт, и успешный лог выполнения. К конце прошивка немного подвисает, на этапе “waiting for tty device”, т.е. в ожидании последовательного порта, как будто бы прошивка происходила через USB-загрузчик, но в целом, все ОК.

Установка USB загрузчика STM32duino

Попробуем поставить загрузчик STM32duino для прошивки через USB-кабель. Для этого скачиваем отсюда прошивку с суффиксом PC13(пин со светодиодом):

Далее загружаем скачанную прошивку в микроконтроллер:

Откладываем в сторону ST-Link, и подключаем микроконтроллер к компьютеру через microUSB разъем. Затем снова запускаем Arduino IDE и в опции “Upload Method” указываем “STM32duino bootlooder”.

После чего снова пробуем прошить скетч, но уже через USB. Если все сложится удачно, то выйдет такой лог:

Замечу, что прошивалось через Linux версию Arduino IDE.

Здесь есть один нюанс. Джампики на плате должны находиться в положении “ноль”. Если они, допустим, будут вообще сняты, то Arduino не сможет перезагрузить микроконтроллер перед прошивкой, и он не сможет войти в режим загрузчика. Так же должно быть понятно, что если теперь прошить микроконтроллер через ST-LINK, то загрузчик затрётся.

Теперь я отложу эту плату в сторону чтобы не затереть загрузчик STM32duino, который еще понадобится, и возьму другую. Попробуем поднять на микроконтроллере Virtual COM Port c помощью STM32Cube MX и IAR ARM.

Прошивка в Virtual COM PORT

Запускаем “куб” и открываем новый проект:

Выбираем смою модель микроконтроллера:

Выставляем тактирование от кварца, и включаем отладку по SWD:

Включаем USB Full-Speed модуль:

Выставляем режим работы USB модуля как Virtual COM Port:

Для индикации рабочего цикла задействуем светодиод на PC13 ножке:

С конфигурацией GPIO покончено, переходим к настройке тактирования. Сразу же откажемся от автоматических настроек:

Настроим тактирование например так:

Осталось дело за малым, задать идентификатор для ножки PC13:

С “кубом” закончили, экспортируем проект в IAR ARM:

Настройка параметров экспорта: имя проекта, среда разработки, рабочие каталоги:

После чего открываем проект в IAR:

В главный цикл добавим следующий код:

HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); HAL_Delay(1000); HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); HAL_Delay(1000); CDC_Transmit_FS(“Hello World!
“,13);

В начало main.c нужно еще будет добавить заголовочный файл usbd_cdc_if.h:

Все, можно нажимать на компиляцию и загружать прошивку в микроконтроллер. “Весит” она кстати тоже не мало, десять килобайт. Можно убирать в стол ST-Link, он больше не понадобится. Подключаем микроконтроллер через USB к компьютеру, если речь идет о Linux, то больше ничего делать не надо, драйвер уже имеется в ядре и при подключении выдает такой лог:

[15928.181626] usb 6-3: new full-speed USB device number 124 using ohci-pci
[15928.338706] usb 6-3: New USB device found, idVendor=0483, idProduct=5740
[15928.338717] usb 6-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[15928.338724] usb 6-3: Product: STM32 Virtual ComPort
[15928.338730] usb 6-3: Manufacturer: STMicroelectronics
[15928.338735] usb 6-3: SerialNumber: 00000000001A
[15928.340836] cdc_acm 6-3:1.0: ttyACM0: USB ACM device

Можно открывать терминальную программку и смотреть на всплывающие строки: “hello world!”

Если же речь идет о Windows, то потребуется еще поставить драйвер com-порта. Для этого зайдем на my.st.com, залогинимся и в строке поиска ведем запрос: “stm32 virtual com port”

В выпадающем списке нам сразу предлагается STSW-ST32102, он то нам и нужен. Скачиваем, распаковываем, находим инсталятор:

Подводный камень кроется в том, что после установки драйвера его еще нужно будет установить 😉

Т.к. у меня виртуальная машина, я пробрасываю в нее свое устройство:

Операционка обнаруживает новое устройство и предлагает установить драйвер:

Нам нужно указать папку в которую распаковались драйвера.

https://www.youtube.com/watch?v=4iSRUcb9GWM

Они должны быть в “Program FilesSTMicroelectronicsVirtual comport driverWin7”. Я не знаю, чем руководствовались парни из STM кидая драйвера от WinXP в папку Win7. Если у вас операционка Win7 или Win8, то в соответствующих папках будут находиться инталяторы для этих операционок, их нужно запустить. А делать так как я показываю, не надо. Это только для Win2000/XP/Vista.

Щелкаем на установку драйвера:

В случае успеха, система выдаст соответствующий репорт:

Теперь устройство можно будет найти в диспетчере устройств:

Теперь можно запустить терминальную программку, чтобы посмотреть на выводимые микроконтроллером через USB данные:

Подключение микроконтроллера STM32F103C8T6 к Android-планшету

Микроконтроллер с USB портом можно подключить не только к стационарному компьютеру, но и Ardroid устройству.

На моем планшете с root-доступом, устройство прекрасно видно:

Скачанная наугад программка usb-терминал, сразу нашла устройство:

прием данных:

В принципе, даже не изучая Java и AndroidStudio, используя лишь NDK, можно написать хороший код для сопряжения Android-девайсов и STM32-микроконтроллеров. Это может дать новую жизнь старым смартфонам и планшетам, которые можно использовать для отображения информации или управления чем-то.

Подключение I2C модуля DS3231

Теперь я снова беру плату с прошитым загрузчиком STM32duino, и попробую сделать, как говориться, без лишней пыли, что-то более полезное чем hello_world, а именно подключить RTC DS3231 через интерфейс I2C.

Микроконтроллер stm32f103c8t6 имеет два аппаратных I2C интерфейса. Дефолтовый интерфейс в Medium_Density чипах висит на пинах PB6 и PB7:

Подключаем модуль к микроконтроллеру:

В Arduno IDE копируем этот скетч, компилируем, загружаем, смотрим на результат работы:

По-моему, проще не бывает)

поделиться:

Источник: http://www.count-zero.ru/2017/bluepill/

AVR: отладочный вывод через UART (RS232 debug)

Источник: http://microsin.net/programming/AVR/avr-uart-debug.html

Виртуальный COM-порт на STM32

?32bit_me (32bit_me) wrote,
2016-07-22 11:28:0032bit_me
32bit_me
2016-07-22 11:28:00Рассмотрим пример того, как поднять виртуальный COM-порт на микроконтроллере STM32, и навеки забыть про б-гомерзкую FTDI.

Итак, у нас есть плата STM32F7 Discovery (например). На других платах всё должно быть аналогично.

Запускаем Stm32CubeMX, создаём новый проект, выбираем наш микроконтроллер из списка и производим некоторую настройку проекта.1.

Вкладка Pinout:открываем Peripherials/USB_OTG_FS, выбираем Mode – Device Onlyоткрываем Peripherials/RCC, выбираем High Speed Clock (HSE)- Crystal/Ceramic Resonatorоткрываем Peripherials/SYS, выбираем Debug – Serial Wireоткрываем MiddleWares USB_DEVICE, выбираем Class For FS IP – Communication Device Class (Virtual Com Port)2.

Вкладка Clock Configuration:устанавливаем HCLK = 216MHz (или другое значение, в зависимости от микроконтроллера)CubeMX настраивает всё автоматически3.

Вкладка Configuration:Нажимаем на кнопку USB_FS, ставим VBUS sensing = DisabledВ меню Project/Settings:Вкладка Project: выбираем нужную IDE, например, EWARM, также настраиваем пути к папкам проектаВкладка Code Generator:включаем опцию Add necessary library files…включаем Generate peripherial initialization…

включаем Set all free pins as analog…Закрываем окно, генерируем код (Project/Generate Code)Генерируем код, открываем IDE.В файле usbd_cdc_if.

c пишем следующее:в функции CDC_Transmit_FS:
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{ uint8_t result = USBD_OK; /* USER CODE BEGIN 7 */ USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); /* USER CODE END 7 */ return result;
}
в функции CDC_Receive_FS:
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
{ /* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
CDC_Transmit_FS(Buf, *Len);
USBD_CDC_ReceivePacket(&hUsbDeviceFS); return (USBD_OK); /* USER CODE END 6 */ }
Этот код обеспечивает “эхо”, при приеме символа в виртуальный com-порт он будет сразу передан обратно.Компилируем и прошиваем контроллер. Подключаем плату (разъем USB_FS) к компьютеру.И ту нас ожидают первые грабли. Windows видит, что подключено устройство, но драйвер не работает. Примерно так (кликабельно):Другие ОС плату вообще не видят.Что делать? Ищем в исходниках проекта и заменяем:в файле usbd_cdc_if.c:

#define USB_HS_MAX_PACKET_SIZE

с 512 на 256.в файле usbd_cdc.c:

#define CDC_DATA_HS_MAX_PACKET_SIZE

с 512 на 256.Прошиваем снова, теперь всё работает. Открываем любую программу терминала (я использую putty), и проверяем.Подключаем плату к Mac, смотрим, что появилось:ls /dev/tty*плата появилась под именем /dev/tty.usbmodemfd121. Я не знаю, почему именно такое имя, но теперь можно проверить её работу:screen /dev/tty.

usbmodemfd121(или можно поставить ту же putty). Всё работает без проблем.Теперь Linux. Аналогично, проверяем ls /dev/tty*, появилось устройство /dev/ttyACM0. Проверяем, и здесь нас ждут ещё одни грабли: отказано в доступе.

Нужно добавить себя в группу dialout:sudo adduser user dialoutsu – user(где user – ваше имя пользователя)

Проверяем, теперь всё работает.

Источник: https://32bit-me.livejournal.com/114562.html

STMicroelectronics выпускает серию отладочных плат STM32 Nucleo-32 для 32-выводых микроконтроллеров

Источник: https://www.rlocman.ru/news/new.html?di=161754

Реализация PPPOS на stm32f4-discovery

Однажды передо мной возникла задача обеспечить выход в сеть Интернет на STM32 имея для этого только COM порт. Для решения этой задачи мне понадобился PPP, или, еcли быть точным, PPPoS (англ.

Point-to-Point Protocol over Serial — один из способов реализации PPP, используется при подключении через COM-порт).

В процессе решения поставленной передо мной задачи я столкнулся с некоторыми трудностями, одна из которых недостаточное, на мой взгляд, освещение вопросов связанных с PPPoS в сети Интернет.

Этим постом я постараюсь закрыть обозначенный пробел, на сколько позволят мои скромные знания. Статья описывает создание проекта для System Workbench for STM32 с нуля. Показывает пример работы с UART. Есть примеры кода для реализации PPP. Ну и конечно, пример отправки сообщения на соседний компьютер.

Введение

PPP (англ. Point-to-Point Protocol) — двухточечный протокол канального уровня (Data Link) сетевой модели OSI. Обычно используется для установления прямой связи между двумя узлами сети, причём он может обеспечить аутентификацию соединения, шифрование и сжатие данных.

Используется на многих типах физических сетей: нуль-модемный кабель, телефонная линия, сотовая связь и т. д.

Часто встречаются подвиды протокола PPP, такие, как Point-to-Point Protocol over Ethernet (PPPoE), используемый для подключения по Ethernet, и иногда через DSL; и Point-to-Point Protocol over ATM (PPPoA), который используется для подключения по ATM Adaptation Layer 5 (AAL5), который является основной альтернативой PPPoE для DSL. PPP представляет собой целое семейство протоколов: протокол управления линией связи (LCP), протокол управления сетью (NCP), протоколы аутентификации (PAP, CHAP), многоканальный протокол PPP (MLPPP).

Из Wikipedia.

Подготовка

Для решения поставленной задачи нам понадобится:

Железо:

  1. Отладочная плата stm32f4_discovery:
  2. Переходник USB — miniUSB для подключения платы к компьютеру.
  3. Два переходника USBtoUART FT232:
  4. Так же пригодятся два USB удлинителя, не обязательно, но просто удобно.

Софт:

  1. Виртуальная машина VirtualBox. Скачать можно тут. Также качаем и устанавливаем Extension Pack для VirtualBox.
  2. Два установочных диска с операционными системами Windows и Linux.

    Windows берем тут, Linux тут.

    После установки ОС потребуется установка дополнений гостевой ОС.

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

  3. Для Windows нам понадобится программа способная принимать запросы и отвечать на них по протоколу TCP/IP, ну и терминальная программа для работы с COM портом. PacketSender качаем тут (нажмите на «No thanks, just let me download.»), терминал тут. Кроме того нам понадобится STM32CubeMX для первоначальной настройки проекта. Качаем с st.com (после регистрации ссылка придет на электронную почту).
  4. На основную ОС ставим System Workbench for STM32. Качаем отсюда (потребуется регистрация).

Этап 1. Создание проекта

Первым делом открываем STM32CubeMX и создаем там новый проект под нашу плату stm32f4-discovery. Включаем RCC, Ethernet (ETH), SYS, USART2, USART3, после чего включаем FREERTOS и LWIP.
Для диагностики нам понадобятся светодиоды на плате. По этому настроем ноги PD12-PD15 как GPIO_Output.

На вкладке Clock Configuration настраиваем частоту, как на картинке ниже.Далее, на вкладке Configuration настраиваем порты USART. Мы будем работать с ними в режиме DMA. У нас два порта USART, один мы будем использовать для передачи и получения данных по протоколу PPP, второй для логирования.

Чтобы они заработали нам нужно настроить DMA на RX и TX для обоих портов. Для всех ножек настройки DMA приоритет ставим «Medium». Для USART2 ножке RX устанавливаем режим «Circular». Остальные настройки оставляем по-умолчанию.Также потребуется включить глобальное прерывание для обоих портов на вкладке «NVIC Settings».

На этом первоначальная настройка проекта в STM32CubeMX завершена. Сохраняем файл проекта и делаем генерацию кода для System Workbench for STM32.

Реализация

Теперь проверим, что выгруженный код компилируется и работает. Для этого в файле main.c в функции «StartDefaultTask» заменим тело бесконечного цикла for(;;) на код включения и выключения светодиодов.

Должно получиться так:/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{ /* init code for LWIP */ MX_LWIP_Init(); /* USER CODE BEGIN 5 */ /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); } /* USER CODE END 5 */ }
Компилируем прошиваем и смотрим. На плате должны моргать все четыре светодиода.

Этап 2. Работа с USART

Следующая наша задача это проверить правильность работы наших USART. Первое, что нам нужно сделать это подключить наши FT232 к discovery. Для этого смотрим на какие ножки разведены USART интерфейсы. У меня это PD6 и PD5 для USART2_RX и USART2_TX соответственно.А также PD9 и PD8 для USART3_RX и USART3_TX соответственно.Кроме того нам понадобится ножка GND.

Находим эти выводы на плате и соединяем с выводами FT232 при этом вывод GND на плате может быть любым, вывод RX на плате должен быть соединен с выводом TX на FT232, а вывод TX на плате должен быть соединен с выводом RX на FT232. Остальные выводы не используются.

Осталось подключить наши FT232 к USB портам компьютера, а также подключить к компьютеру саму плату discovery через разъем miniUSB (не путать с microUSB). После подключения FT232 основная ОС установит для них драйвера, после чего эти устройства нужно будет пробросить в гостевую Windows на виртуальной машине.

Теперь добавляем программный код, который нужен для работы наших USART. Для этого мы добавим четыре файла: usart.h, usart.c, logger.h, logger.c. Содержимое файлов:

файл usart.h

#ifndef _USART_
#define _USART_ #include “stm32f4xx_hal.h” void usart_Open(void);
bool usart_Send(char* bArray, int size_bArray);
uint16_t usart_Recv(char* bArray, uint16_t maxLength); #endif /* _USART_ */

файл usart.c
#include “usart.h”
#include “logger.h” #include “cmsis_os.h” #define Q_USART2_SIZE 200 xQueueHandle g_qUsart;
osThreadId g_usart_rxTaskHandle; extern UART_HandleTypeDef huart2; void usart_rxTask(void); uint8_t bGet[Q_USART2_SIZE] = {0};
uint16_t g_tail = 0; void usart_Open(void)
{ g_qUsart = xQueueCreate( Q_USART2_SIZE, sizeof( unsigned char ) ); osThreadDef(usart_rxTask_NAME, usart_rxTask, osPriorityNormal, 0, Q_USART2_SIZE/4+128); g_usart_rxTaskHandle = osThreadCreate(osThread(usart_rxTask_NAME), NULL); HAL_UART_Receive_DMA(&huart2, bGet, Q_USART2_SIZE); } void usart_rxTask(void)
{ for(;;) { uint16_t length = Q_USART2_SIZE – huart2.hdmarx->Instance->NDTR; while(length – g_tail) { uint8_t tmp = bGet[g_tail]; xQueueSendToBack( g_qUsart, &tmp, 100 ); g_tail++; if (g_tail == Q_USART2_SIZE) g_tail = 0; } }
} bool usart_Send(char* bArray, int size_bArray)
{ HAL_StatusTypeDef status; status = HAL_UART_Transmit_DMA(&huart2, bArray, size_bArray); while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY) { if (HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_RX) break; osDelay(1); } if (status == HAL_OK) return true; return false;
} uint16_t usart_Recv(char* bArray, uint16_t maxLength)
{ uint8_t tmp = 0; uint16_t length = 0; while(uxQueueMessagesWaiting(g_qUsart)) { xQueueReceive( g_qUsart, &tmp, 100 ); bArray[length] = tmp; length++; if (length >= maxLength) break; } return length;
}

файл logger.h
#ifndef _LOGGER_
#define _LOGGER_ void logger(const char *format, …); #endif /* _LOGGER_ */

файл logger.c
#include “logger.h” #include “stm32f4xx_hal.h”
#include extern UART_HandleTypeDef huart3; #define MAX_STRING_SIZE 1024 HAL_StatusTypeDef logger_Send(char* bArray, uint32_t size_bArray)
{ HAL_StatusTypeDef status; for(int i=0;i 0) { if (!usart_Send(data, len)) return 0x05; } logger(“write – ppp_output_cb() len = %d
“, len); return len;
} void pppConnect(void)
{ ppp = pppos_create(&pppos_netif, ppp_output_cb, ppp_link_status_cb, NULL); ppp_set_default(ppp); osThreadId PppGetTaskHandle; osThreadDef(PPP_GET_TASK_NAME, PppGetTask, osPriorityNormal, 0, 128*10); PppGetTaskHandle = osThreadCreate(osThread(PPP_GET_TASK_NAME), NULL); err_t err = ppp_connect(ppp,0); if (err == ERR_ALREADY) { logger(“Connected successfully”); } for(int i=0;iphase >= PPP_PHASE_RUNNING) break; } } /* USER CODE END 0 */
Затем в функцию MX_LWIP_Init(), в блок «/* USER CODE BEGIN 3 */» добавляем вызов функции pppConnect(). Кроме того нужно увеличить размер кучи, для этого в файле FreeRTOSConfig.h нужно закомментировать дефайн configTOTAL_HEAP_SIZE, а в конце файла, в блоке /* USER CODE BEGIN Defines */ объявить его с новым значением./* USER CODE BEGIN Defines */ /* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
#define configTOTAL_HEAP_SIZE ((size_t)1024*30)
/* USER CODE END Defines */ А также в файле usart.c изменить значение дефайна Q_USART2_SIZE на 2048. Настройка соединения начинается с функции MX_LWIP_Init() она создана автоматически мы лишь добавили в нее вызов функции pppConnect(). В этой функции запускаются задачи обслуживающие PPPOS соединение. Функции pppos_create() нужно передать адреса функций, которые будут обслуживать отправку сообщений и вывод информации об изменении статуса соединения. Для нас это функции ppp_output_cb() и ppp_link_status_cb() соответственно. Кроме того в функции pppConnect() будет запущена задача по обслуживанию полученных сообщений. В конце своей работы функция pppConnect() дождется установления соединения с сервером, после чего завершит свою работу. Работа с сетью будет осуществляться на более высоком уровне, как только LWIP решит, что нужно отправить сообщение в сеть, автоматически будет вызвана функция ppp_output_cb(). Ответ из сети будет получен функцией PppGetTask(), в рамках задачи по обслуживанию входящих сообщений, и передан в недра LWIP. Если изментися статус соединения то автоматически будет вызвана функция ppp_link_status_cb(). И наконец мы изменим задачу StartDefaultTask. Теперь она должна иметь такой вид:void StartDefaultTask(void const * argument)
{ /* init code for LWIP */
// MX_LWIP_Init(); /* USER CODE BEGIN 5 */ usart_Open(); MX_LWIP_Init(); /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); } /* USER CODE END 5 */ }
Готово, можно компилировать и прошивать. На этом этапе нужно запустить сервер PPP. Для этого нужно сначала развернуть виртуалку с ОС Linux. Я использовал Ubuntu 16.04 x32. После установки операционной системы нужно настроить использование COM порта. В этой части нам не нужна виртуальная машина с Windows, можно ее смело выключить. Оба FT232 подключаем в Linux. В Linux прежде чем начинать работу с COM портом нужно разрешить пользователю его использовать. Для этого выполним следующую команду:sudo addgroup USERNAME dialoutгде USERNAME — имя текущего пользователя. Чтобы посмотреть доступные в системе COM порты нужно выполнить команду:dmesg | grep tty
Мы видим, что в системе присутствуют два порта ttyUSB. Мы не можем сразу сказать какой из них logger, а какой usart2. Просто нужно их проверить по очереди. Сначала выполним команды для чтения из одного порта:stty -F /dev/ttyUSB0 115200
cat /dev/ttyUSB0затем из другого:stty -F /dev/ttyUSB1 115200
cat /dev/ttyUSB1Где увидим такую картину тот и есть logger.Можно оставить это окно, оно нам не будет мешать. Далее нужно разрешить пакетам отправленным из нашей платы покидать пределы своей подсети. Для этого нужно настроить iptables. Выполняем следующие действия: 1. Откроем новое окно консоли

2. Нужно узнать свой ip и имя сетевого интерфейса (выполните команду ifconfig)

3. Выполните команды настройки natsudo echo 1 | sudo tee -a /proc/sys/net/ipv4/ip_forward > /dev/null
sudo echo 1 | sudo tee -a /proc/sys/net/ipv4/ip_dynaddr > /dev/null
sudo iptables -F FORWARD
sudo iptables -F -t nat
sudo iptables -t nat -A POSTROUTING -o enp0s3 -j SNAT –to-source 192.168.10.196
sudo iptables -t nat -Lгде enp0s3 — имя сетевого интерфейса 192.168.10.196 — ваш IP адрес /proc/sys/net/ipv4/ — путь к соответствующему файлу. Эти команды можно переписать в пакетный файл и выполнять его каждый раз перед запуском PPP сервера. Можно добавить и в автозапуск, но я этого не делал.

Теперь мы готовы к запуску сервера, осталось только создать файл настроек. Я назвал его «pppd.conf», предлагаю использовать следующие настройки:

nodetach
noauth
passive
local
debug
lock
192.168.250.1:192.168.250.2
/dev/ttyUSB1
115200
lcp-echo-interval 10
lcp-echo-failure 1
cdtrcts
Переписываем настройки в файл после чего можно запускать сервер. Это делается командой sudo pppd file ./pppd.conf Сервер PPPD должен быть запущен до старта discovery, по этому после старта PPPD нужно нажать на кнопку «Reset» расположенной на плате. Если вы все сделали правильно, то увидите такую картину:Слева запущенный pppd, справа logger.

Этап 4. Отправляем пакетик

На этом этапе нам понадобятся обе виртуалки. Linux для pppd и Windows для приема пакета.

Для упрощения задачи нужно чтобы обе машины были в одной подсети, идеальным решением будет указать в настроках сети VirtualBox для обоих машин соединение типа «Сетевой мост», а в Windows отключить брандмауэр. Запускаем виртуалки и настраиваем ppp соединение платы discovery с pppd.

На Windows узнаем IP адрес машины (команда ipconfig), у меня он получился 192.168.10.97. Запускаем Packet Sender и настраиваем его следующим образом:

Теперь снова изменим задачу StartDefaultTask, в файле main.c.

/* USER CODE BEGIN 4 */
#include “logger.h”
#include “sockets.h”
typedef uint32_t SOCKET;
/* USER CODE END 4 */ /* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{ /* init code for LWIP */
// MX_LWIP_Init(); /* USER CODE BEGIN 5 */ usart_Open(); MX_LWIP_Init(); /* Infinite loop */ uint8_t sendStr[]=”Test message TCP/IP.”; uint8_t resvStr[100]={0}; int resvLength = 0; struct sockaddr_in sockAddr; sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons( 6565 ); uint32_t addr = inet_addr(“192.168.10.97”); sockAddr.sin_addr.s_addr = addr; SOCKET socket = NULL; int nError = 0; /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); socket = socket( AF_INET, SOCK_STREAM, 0 ); nError = connect( socket, (struct sockaddr*)&sockAddr, sizeof(sockAddr) ); if ( nError == 0 ) { nError = send( socket, sendStr, sizeof(sendStr)-1, 0 ); if ( nError < 0 ) logger("SEND ERROR %d ", nError); else { logger("SEND - %s ", sendStr); resvLength = 0; while(resvLength < 1) resvLength = lwip_recv( socket, resvStr, sizeof(resvStr), MSG_WAITALL); resvStr[resvLength]=0; logger("GET - %s ", resvStr); } lwip_close(socket); } else logger("CONNECT ERROR %d ", nError); } /* USER CODE END 5 */ } В качестве значения переменной addr используем адрес Windows машины, номер порта 6565. Отправляемое сообщение «Test message TCP/IP.», ответ «The message is received.» Здесь можно увидеть, что функции PPP непосредственно не используются для отправки и приема сообщений. Вся работа происходит на более высоком уровне, а наши функции вызываются автоматически. Компилируем и прошиваем. Результат соединения с pppd видим на Linux машине:Полученные запросы и отправленные ответы можно увидеть в программе Packet Sender на Windows-машине:Ну, вот, собственно и все, отправленный нами пакет из платы discovery отправился в COM порт, попал на pppd сервер, был отправлен на порт 6565 Windows машины, там он был успешно получен, в ответ на него был отправлен другой пакет, который прошел этот путь в обратном направлении и был успешно принят на плате. С таким же успехом вы сможете отправлять сообщения на любую машину в сети Интернет.

→ Полный код проекта можно скачать здесь

Источник: https://habr.com/post/419037/

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}
");let k=document.querySelector(".flat_pm_modal[data-id-modal=\""+a.ID+"\"]");if(-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(k,d):jQuery(k).html(b+d),"px"==a.how.popup.px_s)e.bind(h,()=>{e.scrollTop()>a.how.popup.after&&(e.unbind(h),f.unbind(i),j())}),void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{e.unbind(h),f.unbind(i),j()});else{let b=setTimeout(()=>{f.unbind(i),j()},1e3*a.how.popup.after);void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{clearTimeout(b),f.unbind(i),j()})}f.on("click",".flat_pm_modal .flat_pm_crs",()=>{jQuery.arcticmodal("close")})}if(void 0!==a.how.outgoing){let b,c="0"==a.how.outgoing.indent?"":" style=\"bottom:"+a.how.outgoing.indent+"px\"",e="true"==a.how.outgoing.cross?"":"",f=jQuery(window),g="scroll.out"+a.ID,h=void 0===flatPM_getCookie("flat_out_"+a.ID+"_mb")||"false"!=flatPM_getCookie("flat_out_"+a.ID+"_mb"),i=document.createElement("div"),j=jQuery("body"),k=()=>{void 0!==a.how.outgoing.cookie&&"false"==a.how.outgoing.cookie&&h&&(jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show"),j.on("click",".flat_pm_out[data-id-out=\""+a.ID+"\"] .flat_pm_crs",function(){flatPM_setCookie("flat_out_"+a.ID+"_mb",!1)})),(void 0===a.how.outgoing.cookie||"false"!=a.how.outgoing.cookie)&&jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show")};switch(a.how.outgoing.whence){case"1":b="top";break;case"2":b="bottom";break;case"3":b="left";break;case"4":b="right";}jQuery("body > *").eq(0).before("
"+e+"
");let m=document.querySelector(".flat_pm_out[data-id-out=\""+a.ID+"\"]");-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(m,d):jQuery(m).html(e+d),"px"==a.how.outgoing.px_s?f.bind(g,()=>{f.scrollTop()>a.how.outgoing.after&&(f.unbind(g),k())}):setTimeout(()=>{k()},1e3*a.how.outgoing.after),j.on("click",".flat_pm_out .flat_pm_crs",function(){jQuery(this).parent().removeClass("show").addClass("closed")})}countMode&&(flat_count["block_"+a.ID]={},flat_count["block_"+a.ID].count=1,flat_count["block_"+a.ID].click=0,flat_count["block_"+a.ID].id=a.ID)}catch(a){console.warn(a)}}function flatPM_start(){let a=flat_pm_arr.length;if(0==a)return flat_pm_arr=[],void jQuery(".flat_pm_start, .flat_pm_end").remove();flat_body=flat_body||jQuery("body"),!flat_counter&&countMode&&(flat_counter=!0,flat_body.on("click","[data-flat-id]",function(){let a=jQuery(this),b=a.attr("data-flat-id");flat_count["block_"+b].click++}),flat_body.on("mouseenter","[data-flat-id] iframe",function(){let a=jQuery(this),b=a.closest("[data-flat-id]").attr("data-flat-id");flat_iframe=b}).on("mouseleave","[data-flat-id] iframe",function(){flat_iframe=-1}),jQuery(window).on("beforeunload",()=>{jQuery.isEmptyObject(flat_count)||jQuery.ajax({async:!1,type:"POST",url:ajaxUrlFlatPM,dataType:"json",data:{action:"flat_pm_ajax",data_me:{method:"flat_pm_block_counter",arr:flat_count}}})}).on("blur",()=>{-1!=flat_iframe&&flat_count["block_"+flat_iframe].click++})),flat_userVars.init();for(let b=0;bflat_userVars.textlen||void 0!==a.chapter_sub&&a.chapter_subflat_userVars.titlelen||void 0!==a.title_sub&&a.title_subc&&cc&&c>d&&(b=flatPM_addDays(b,-1)),b>e||cd||c-1!=flat_userVars.referer.indexOf(a))||void 0!==a.referer.referer_disabled&&-1!=a.referer.referer_disabled.findIndex(a=>-1!=flat_userVars.referer.indexOf(a)))&&(c=!0),c||void 0===a.browser||(void 0===a.browser.browser_enabled||-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser))&&(void 0===a.browser.browser_disabled||-1==a.browser.browser_disabled.indexOf(flat_userVars.browser)))){if(c&&void 0!==a.browser&&void 0!==a.browser.browser_enabled&&-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser)&&(c=!1),!c&&(void 0!==a.geo||void 0!==a.role)&&(""==flat_userVars.ccode||""==flat_userVars.country||""==flat_userVars.city||""==flat_userVars.role)){flat_pm_then.push(a),flatPM_setWrap(a),flat_body.hasClass("flat_pm_block_geo_role")||(flat_body.addClass("flat_pm_block_geo_role"),flatPM_ajax("flat_pm_block_geo_role")),c=!0}c||(flatPM_setWrap(a),flatPM_next(a))}}}let b=jQuery(".flatPM_sticky");b.each(function(){let a=jQuery(this),b=a.data("height")||350,c=a.data("top");a.wrap("
");let d=a.parent()[0];flatPM_sticky(this,d,c)}),debugMode||countMode||jQuery("[data-flat-id]:not([data-id-out]):not([data-id-modal])").contents().unwrap(),flat_pm_arr=[],jQuery(".flat_pm_start, .flat_pm_end").remove()}

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

Немногие программисты (особенно начинающие) имеют в своем распоряжении аппаратный отладчик (типа JTAGICE mkII или AVR Dragon).

Поэтому светодиод, осциллограф и текстовый вывод остаются актуальным средством отладки и поиска ошибок. Однако даже при наличии аппаратного отладчика часто нужно в реальном времени видеть, что делает выполняющийся код.

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

Самый простой способ реализации такого вывода – использование аппаратного UART, который имеется почти во всех моделях AVR. Вывод получается быстрый и нересурсоемкий (т. е.

он не занимает много процессорного времени ядра AVR).

Для вывода через UART для AVR есть уже готовые подпрограммы и макросы, один из них – модуль oddebug, который есть в составе библиотеки V-USB.

[Использование модуля oddebug.c для отладки]

1. Скачайте библиотеку V-USB [1].

2. В папке vusb-20120109usbdrv возьмите файлы usbportability.h, oddebug.c и oddebug.h, и скопируйте их в папку своего проекта.

3. Добавьте в проект компиляцию модуля oddebug.c.

Если у Вас проект AVR GCC, то добавьте модуль oddebug.c в список компиляции и линковки makefile:

SRC = $(TARGET).c
Descriptors.c
oddebug.c
$(LUFA_SRC_USB)
$(LUFA_SRC_USBCLASS)

Если у Вас проект IAR, то добавьте модуль oddebug.c в дерево модулей проекта.

4. Добавьте в модули, где нужно использовать отладочный вывод, подключение заголовка oddebug.h (директивой include).

5. Задайте глобальное макроопределение DEBUG_LEVEL, не равное 0.

Если у Вас проект AVR GCC, лучше всего это сделать в makefile проекта:

DEBUG_LEVEL = 1
..
CDEFS += -DDEBUG_LEVEL=$(DEBUG_LEVEL)

Если у Вас проект IAR, то добавьте определение DEBUG_LEVEL в свойствах проекта (Options -> Compiler -> Preprocessor -> Defined symbols).

Модуль oddebug написан таким образом, что значение макроопределения DEBUG_LEVEL может быть либо 0, либо 1, либо 2:
DEBUG_LEVEL=0 отладка через UART не активна, код oddebug не компилируется, и макросы DBG1 и DBG2 не работают (хотя они могут присутствовать в коде пользователя).
DEBUG_LEVEL=1 работает только макрос DBG1, DBG2 не работает (хотя DBG2 может встречаться в коде пользователя).
DEBUG_LEVEL=2 работает и DBG1, и DBG2.

6. Перед главным циклом main сделайте вызов odDebugInit().

Макрос odDebugInit настраивает UART на скорость 19200 бит/сек, 8 бит данных, один стоп-бит, без четности (19200 baud rate, 8 bit data, 1 stop bit, no parity) – имейте это в виду при подключении к порту отладки.

7. Для отладочного вывода используйте макросы DBG1() и DBG2(). Первый параметр макроса – байт префикса, он выведется в HEX-виде (и за ним будет двоеточие), второй параметр – если не 0, то адрес памяти, откуда будут выведены значения байт (указатель), а третий параметр – если не ноль, то количество байт для вывода. Примеры использования:

Как Вы уже наверное догадались, использование макросов DBG1 и DBG2 позволяет вести отладку на 2 уровнях, в зависимости от значения DEBUG_LEVEL. Если DEBUG_LEVEL = 2, то вывод может быть максимально подробным, так как будут выводить инфу и DBG1, и DBG2. Если DEBUG_LEVEL = 1, то отладочного вывода может быть меньше (будет выводится только макрос DBG1).

[Устранение проблем]

1. oddebug.h:39:5: warning: #warning “Debugging disabled because device has no UART”

Наверное, Вы забыли подключить заголовок, который задает символические имена Вашего микроконтроллера – oddebug.h не нашел имена TXEN или TXEN0, подключите нужный заголовок перед подключением oddebug.h. В проекте AVR GCC нужно подключить файл io.h:

2. Если у Вас чип, у которого нет имен TXEN или TXEN0, но задано имя TXEN1 или другое (например, так у чипа AT90USB162), то поправьте файл oddebug.h примерно так:

исправьте на

а также

исправьте на

Аналогичным образом поправьте условия определения ODDBG_TXEN, ODDBG_UBRR, ODDBG_USR USR, ODDBG_UDRE UDRE, ODDBG_UDR UDR.

Готовый oddebug.h с внесенными исправлениями можете скачать по ссылке [2].

[Как подключить AVR к компьютеру]

Для согласования уровней TTL RS232 (0..+5V) и стандартного RS232, который использовался на PC (+-12V), нужен специальный адаптер, наподобие [3]. По минимуму нужно соединить с инверсией TTL TXD отлаживаемого микроконтроллера с RXD компьютера.

Сложность тут в необходимости обеспечить инверсию, сделать изолирующую развязку от статического электричества и одновременно обеспечить двухполярный сигнал TXD. На рисунке показан вариант такого подключения, обеспечивающий электрическую изоляцию отлаживаемого устройства и компьютера. Оптрон 6H2017C можно заменить на любой другой фототранзисторный.

Напряжения +12V и -12V можно снять с коннектора ATX блока питания компьютера.

[Адаптер USB – TTL RS232]

Если в Вашем компьютере нет порта RS232, то нужен переходник USB – TTL RS232 (его еще называют VCP переходник, Virtual COM port). Его можно собрать на чипе FTDI [7], а можно на микроконтроллере AVR.

На фото показан пример такого адаптера, сделанного из макетной платы AVR-USB162MU [6], и подключенного к отлаживаемой макетной плате AVR-USB-MEGA16 (на которой, кстати, можно сделать точно такой же адаптер USB – TTL RS232).

Вверху – плата AVR-USB-MEGA16, программа которой отлаживается, а внизу – адаптер USB – TTL RS232, собранный на плате AVR-USB162. 

Сама плата AVR-USB162 физически уже готовый адаптер, который нужно просто прошить программой USB CDC (см. [2], папка bin) и подключить тремя проводками – GND, TXD, RXD (проводок TXD использовать необязательно, если нужен только отладочный вывод):

При первом подключении к компьютеру адаптера USB – TTL RS232 операционная система Windows запросит драйвер, укажите мастеру установки оборудования папку driver из архива [2].

Подключение адаптера USB – TTL RS232 к макетной плате AVR-USB-MEGA16 (микроконтроллер ATmega32A).

Подключение адаптера USB – TTL RS232 к макетной плате AVR-USB162 (микроконтроллер AT90USB162).

Подключение адаптера USB – TTL RS232 к макетной плате AVR-USB162MU (микроконтроллер AT90USB162MU).

[Переходники USB – TTL RS232 на аппаратных чипах]

Переходник USB TTL COM-port (он подключается с одной стороны к 6-pin коннектору FTDI, а с другой стороны к компьютеру по USB) можно купить готовый. Обычно такой переходник сделан по простейшей схеме на основе чипа FT232 (компания FTDI) или CP210x (компания Silicon Labs).

Драйвер для переходника можно скачать с сайта соответствующей компании. Хорошие переходники USB to TTL Serial Cable FTDI (или на чипе CP210x) можно купить на eBay, dealextreme или aliexpress, есть даже предложения с бесплатной доставкой.

 При покупке выбирайте 5V версию (иногда бывают версии на 3.3V). Самый лучший вариант – когда можно выбрать перемычкой рабочие уровни порта TTL RS-232 (3.3V или 5V).

Если уровни сигналов на переходнике USB to TTL и отлаживаемом устройстве не совпадают, то понадобятся последовательно включенные резисторы номиналом около 1…2 кОм.

[Использование класса USB CDC для отладки]

Если Ваше устройство на AVR имеет интерфейс USB (как например макетные платы AVR-USB-MEGA16 или AVR-USB162), то Вы можете запустить на них программное обеспечение класса USB CDC, что дает возможность работать USB-устройству в качестве виртуального COM-порта. В этом случае переходник USB – TTL RS232 вообще не нужен. Пример использования виртуального COM-порта для AVR-USB-MEGA16 см. в [4] и для AVR-USB162 в библиотеке LUFA [5].

[Отладка кода в среде программирования Arduino IDE]

Переходник VCP можно также использовать для отладочного вывода и загрузки кода скетча (в платах Arduino, которые не оборудованы собственным портом VCP), что может помочь в отладке кода программы [2]. В Arduino IDE для этой цели используется оператор println

int x = 0;   void setup() { Serial.begin(9600); Serial.println(“Hello world”); delay(2000); //Задержка, чтобы можно было увидеть вывод. }   void loop() { Serial.println(x); delay(500); x=x+1; if (x>5) {x=0;}; }

[Назначение файлов и папок архива по ссылке [2]]

bin готовые прошивки переходника USB – TTL RS232 (проект LUFA-110528ProjectsUSBtoSerial), скомпилированные для плат AVR-USB162, AVR-USB162MU (чип AT90USB162) на частоты кварца 8 и 16 МГц.
doc даташиты на микроконтроллеры AT90USB162 (макетные платы AVR-USB162, AVR-USB162MU) и ATmega32A (макетная плата AVR-USB-MEGA16).

download скачанные пакеты библиотек LUFA, V-USB, пакет утилит разработки WinAVR.
driver inf-файл для переходника USB – TTL RS232, который нужно предоставить мастеру установки оборудования Windows.

LUFA-110528 библиотека LUFA
LUFA-110528ProjectsUSBtoSerial проект USBtoSerial, из которого скомпилированы прошивки переходника USB – TTL RS232.
LUFA-110528DemosDeviceClassDriverGenericHID проект, в котором в качестве примера используется отладочный вывод через USART (применен модуль oddebug). См.

также пример LUFA-110528DemosDeviceLowLevelGenericHID.
LUFA-110528DemosDeviceClassDriverGenericHIDoddebug.h исправленный файл oddebug.h, в который добавлена поддержка микроконтроллера AT90USB162.

Как компилировать прошивки переходника USB – TTL RS232 (у Вас должен быть установлен пакет разработки WinAVR):

1. Перейдите в каталог LUFA-110528ProjectsUSBtoSerial.
2.

Проверьте в makefile опции MCU, BOARD, F_CPU – они должны соответствовать используемому микроконтроллеру, макетной плате, частоте кварца.
3. Выполните команду make clean.
4.

Выполните команду make, получите файл USBtoSerial.hex – это и будет скомпилированный файл прошивки для переходника USB – TTL RS232.

Проект USBtoSerial можно скомпилировать для всех 8-битных микроконтроллеров Atmel AVR USB (микроконтроллеры Atmel, имеющие на борту аппаратную поддержку интерфейса USB).

[Часто задаваемые вопросы, FAQ]

120428. Сделал вывод отладочной информации через преобразователь уровней, заработало. Однако в PuTTY отображаются иероглифы (кракозябры и псевдографика). Скриншот прилагаю.

Наверное, где-то не совпадает кодировка, не подскажете ли – что нужно подправить?

Ответ: причин может быть две. Первая – несовпадение кодировок текста, кодировка отладочного вывода и кодировка отображения в puTTY. Исправить просто – свойства сессии puTTY -> Window ->Translation. Попробуйте кодировку Win1251 (Cyrillic) или другие русскоязычные кодировки.

Вторая возможная причина (в том случае, если используется физический UART AVR, что наверное имеет место у Вас) – несовпадение параметров приема / передачи (скорость, число бит, количество стоп-битов, наличие бита четности). Настраивается через свойства сессии puTTY -> Connection -> Serial.

Параметры должны соответствовать настройкам UART AVR.

[Ссылки]

1. V-USB download site:obdev.at – библиотека V-USB, ссылки на загрузку.
2. 131106USBtoSerial.

ZIP – примеры проектов с использованием oddebug (в библиотеке vusb-20121206), исходный код для адаптера USBtoSerial и готовые прошивки (скомпилированные для плат AVR-USB162, AVR-USB162MU, AVR-USB32U4, userial, USBKEY) для виртуального COM-порта USB CDC (в библиотеке LUFA-130901).
3. Сопряжение микроконтроллера с компьютером без MAX232. 
4.

USB консоль для управления радиолюбительскими приборами. 
5. LUFA – бесплатная библиотека USB для микроконтроллеров Atmel AVR. 
6. AVR-USB162MU: VCP переходник (TTL virtual COM port). 
7. Плата FT232R-Breakout. 

Компания STMicroelectronics дополнила ассортимент отладочных плат серии STM32 Nucleo, добавив компактные варианты плат для 32-выводных микроконтроллеров семейства STM32.

Серия компактных, но в тоже время масштабируемых отладочных плат STM32 Nucleo-32  представляет собой бюджетное решение с открытым кодом, для прототипирования устройств на микроконтроллерах STM32 в сочетании с платами и модулями расширения форм-фактора Arduino.

На данный момент серия представлена тремя отладочными платами, выполненных на микроконтроллерах STM32F031, STM32F042 и STM32F303: Nucleo-F042K6 (STM32F042), Nucleo-F031K6 (STM32F031) и Nucleo-F303K8 (STM32F303). Все платы выполнены в форм-факторе Arduino Nano, имеют обновленную версию интегрированного программатора/отладчика ST-LINK/V2-1 и поддерживаются широким спектром сред разработки, включая IAR, Keil и GCC.

Общие отличительные особенности плат серии STM32 Nucleo-32:

  • полнофункциональные компактные отладочные платы в форм-факторе Arduino Nano;
  • установлен микроконтроллер семейства STM32 в 32-выводном корпусе;
  • возможность подключения плат расширения Arduino;
  • встроенный программатор-отладчик ST-LINK/V2-1;
  • возможность использования платы в качестве программатора ST-LINK/V2-1;
  • гибкая система подачи внешнего питания:
    • интерфейс USB;
    • внешний источник;
  • пользовательский светодиод, светодиод индикации питания, кнопка сброса;
  • функционал USB интерфейса:
    • виртуальный COM-порт;
    • внешний накопитель;
    • отладочный порт;
  • полная программная поддержка:
    • программные библиотеки и программные инструменты STM32Cube;
    • демонстрационные приложения и примеры;
    • поддержка сред разработки IAR, KEI, GCC.

Полностью оценить все возможности микроконтроллеров можно с помощью программного пакета STM32Cube, в состав которого входят:

  • инструменты для конфигурирования микроконтроллера и генерирования Си-кода;
  • инструменты генерирования готового проекта для интегрированной среды разработки;
  • калькулятор энергопотребления для пользовательского приложения;
  • библиотеки HAL абстрактного аппаратного уровня, обеспечивающие возможность портирования проектов;
  • подборка промежуточного ПО, включая ОС реального времени, библиотеки USB и файловой системы, TCP/IP стек, библиотеку сенсорного интерфейса и др.
  • примеры и демо-приложения.

Представленные отладочные платы доступны для заказа. В первом квартале 2016 г. планируется выпуск плат STM32 Nucleo-32 на микроконтроллерах серии STM32L0 и STM32L4.