Некоторое время назад довелось мне по проектной необходимости поиграть в отладочную плату Teensy 4.1. Что это за зверь – можно посмотреть на сайте разработчика Teensy? 4.1 (pjrc.com). Вообще, штука знатная. Там стоит контроллер MIMXRT1062DVJ6A фирмы NXP. Ядро – Cortex M7. Тактовая частота – до 600 МГц! Впечатляет? Но самое главное – там имеется два контроллера EHCI, реализующих порты USB 2.0 HS. На этой плате один контроллер подключён к разъёму Micro USB, а второй – к разъёму USB Host. Есть там ещё и порт Ethernet, но с ним я пока не возился. Ну, и масса других замечательных штук.

К сожалению, рекомендуемая среда разработки Arduino весьма спартанская, а библиотека же вообще напоминает Авгиевы конюшни. Сама по себе она рабочая. Прикладной программист будет рад воспользоваться ею. Но доработать её – тот ещё процесс. Плюс её делает, по сути, один разработчик, а не огромное сообщество (как, например, ESP8266 или ESP32). Поэтому функционал не богат, а самостоятельная доработка затруднена.

Но мой неугомонный начальник задал простой и естественный вопрос: «А что мешает пользоваться штатной средой разработки от NXP – MCUXpresso?» Дело в том, что там имеется огромный набор готовых библиотек для нужного нам контроллера. Лично я уже работал с этой средой для нашего сервиса All-Hardware. Впечатления были самые приятные, я ими делился вот в этой статье. Попробовав, я понял, что он, как всегда, прав. И возникла идея коротенько, статьи на четыре-пять, зафиксировать результаты экспериментов. Поэтому приступаем. Сегодня мы просто возьмём готовый пример от MCUXpresso, запустим его в Teensy и убедимся, что всё работает.

Важное замечание

Не хотелось перегружать анонс статьи, но, пожалуй, напишу это в самом начале. Обычно, поиграв с тем или иным контроллером или ПЛИС, я покупаю хотя бы одну штучку себе для домашнего пользования. Вот в случае с Teensy за прошедшие полгода я предпочитаю удовлетворять свой интерес за счёт работодателя. Цена макетки для таких характеристик – весьма и весьма вкусная, но на этой макетке напрочь отсутствует отладочный порт. Нет ни JTAG, ни SWD, ни чего бы там ни было похожего. Народ извращается, как может, а автор схемы доказывает, что отладочный порт – зло, и через него данный конкретный кристалл легко убить.

В одной из будущих статей мы рассмотрим полумеры. Поработаем отладчиком GDB через порт UART. Но всё это – особые разновидности извращения. А из моих статей видно, что я являюсь большим фанатом JTAG (а ещё лучше – SWD) отладки. И я не могу заставить себя заплатить сумму, приближающуюся к четырём тысячам рублей за замечательную, обалденную, гениальную плату, но на которой нет отладочного порта.

Какое ПО следует поставить

Сегодня я буду ссылаться на установленную среду разработки Teensyduino. Её можно скачать здесь: Teensyduino: Download and Install Teensy support into the Arduino IDE (pjrc.com).

Но вместо этого можно просто воспользоваться проектом Teensy Loader. В тексте он не будет упоминаться, но прочитать о нём и скачать его можно тут: Teensy Loader Application - available for Windows, Linux and Macintosh systems (pjrc.com).

Ну, и дальше надо скачать и установить среду разработки MCUXpresso от NXP, а в ней – установить SDK и примеры для семейства MIMXRT1060.

Приступаем

Итак. Сегодня мы возьмём готовый пример виртуального COM-порта, удовлетворяющего стандарту CDC и попробуем запустить его на плате Teensy. Запускаем среду разработки MCUXpresso, выбираем там Import Examples from SDK:

Открываем ветку MXMXRT1060 в дереве, выбираем контроллер MXMXRT1062xxxxA (других там всё равно нет), а затем – выбираем плату. Плату, но не её название. Если щёлкнуть по названию, нас кинут на сайт. На самом деле, ни одна из представленных плат всё равно не наша, так что можно выбрать первую попавшуюся.

Ну, и теперь можно нажимать кнопку Next:

Открылось просто-таки громаднейшее дерево возможных примеров. Глаза разбегаются! Всё-таки огромная корпорация это дело сопровождает! Для сегодняшнего опыта раскрываем ветку USB и там выбираем dev_cdc_vcom_bm. Да, я не люблю на Cortex-M использовать какие-то ОС. Поэтому наши опыты будем вестти с BareMetal. А потом вы уже сможете выбрать то, что захотите.

Ну, и Next, как всегда. Теперь перед нами открывается окно, где мы будем выбирать, с каким портом будут работать функции printf/scanf. Нет, можно сделать, чтобы ни с каким, но лучше же, чтобы у нас хоть какой-то отладочный вывод был. Собственно, выбор у нас не велик. На плате Teensy 4.1 нет разъёмов аппаратного отладчика. Поэтому только UART.

Про возможные библиотеки вы можете прочесть в разделе 16  описания MCUXpresso MCUXpresso IDE User Guide (nxp.com) . Я просто скажу, что Redlib не поддерживает язык C++, поэтому даже не привыкаем к ней. Из Newlib и Newlib-Nano в общем случае лучше вторая, так как она компактней. Суффикс должен быть NoHost. А что это такое – найдёте в описании на среду разработки.

После этого уже будут работать специальные функции. Но мне почему-то понравилось также ставить флажки Redirect SDK “PRINTF” to C library printf и Redirect printf/scanf to UART. Сегодня мы этим пользоваться не будем, но потом я буду плясать от сегодняшнего проекта. Итого:

Внизу того же окна расположена карта памяти, не похожая на ту, которую мы можем найти в настройках Teensy:

Почему она не соответствует, и как её можно править, я опишу в одной из следующих статей. Пока оставляем её по умолчанию. Нажимаем Finish. Вот такое получается дерево проекта:

Корпус контроллера не наш. Давайте сразу его изменим. На ветке MCU нажимаем правую кнопку «мыши» и в меню выбираем наш контроллер:

Отлично! Проект готов. Собираем его. Получили файл \NXPworkspace\evkmimxrt1060_dev_cdc_vcom_bm\Debug\evkmimxrt1060_dev_cdc_vcom_bm.axf

Теперь его надо подготовить к заливке в Teensy. Для этого придётся позаимствовать пару утилит у пакета TeensyDuino. Открываем среду разработки Arduino и выбираем пункт меню Файл->Настройки:

Там ставим флажки: Показать подробный вывод: Компиляция и загрузка.

Открываем любой пример и собираем его. Нас будет интересовать концовка процесса:

Вот выделенная строка крупным планом:

"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/teensy_post_compile" -file=CardInfo.ino "-path=C:\\Users\\User\\AppData\\Local\\Temp\\arduino_build_253223" "-tools=C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/" -board=TEENSY41

Это значит, что интересующие нас утилиты лежат здесь:

Причём достаточно увесистые вложенные каталоги нас не интересуют. Нас вообще отсюда только два файла интересуют, но предлагаю скопировать их все. Я специально показал методику поиска, а не точное положение, так как подозреваю, что в Линуксе этим путём тоже всё можно будет найти. Я скопирую это в корень диска c:\. Так мне будет проще не запутаться с каталогами.

Дальше я очень хотел записать все нужные мне шаги на этап Post Build Step. Но, к сожалению, с загрузчиком Teensy при запуске его из Эклипсы (а на самом деле, MCUXpresso – это доработанная Эклипса) мне договориться не удалось. Поэтому сделаем два этапа. Формирование HEX файла будем делать в среде разработки. Идём сюда (в редактирование Post Build Steps):

И там видим такое безобразие:

Вторая и третья строки закомментированы. Причём вторая явно преобразует axf-файл в двоичный. Вот на её основе мы сейчас сделаем формирователь файла в формате Intel Hex:

  • Убираем признак комментария (решётку и пробел за ней);

  • Заменяем тип выходного файла с binary на ihex;

  • Меняем расширение выходного файла с bin на hex.

Итого:

arm-none-eabi-objcopy -v -O ihex "${BuildArtifactFileName}" "${BuildArtifactFileBaseName}.hex"

Ну или на экране:

А на втором этапе пойдут полумеры… Возможно, потом вопрос решится путём использования пакетного загрузчика TeensyLoader CLI, но для простоты, пока для остального, я положу в каталог, куда собирается приложение, bat-файл со следующим содержанием:

C:\Teensy_Tools\teensy_post_compile.exe -file=%~n1 -path=./ -tools=C:\Teensy_Tools

C:\Teensy_Tools\teensy_reboot.exe

 

Получается так:

Запускаю его, передав в качестве аргумента hex файл:

makeTeensy.bat evkmimxrt1060_dev_cdc_vcom_bm.axf.hex

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

Нажимаю кнопку на плате, файл заливается, получается виртуальный COM-порт, у меня это COM8:

Давайте откроем терминал (скорость не важна, у нас же просто протокол CDC без физического UART) и введём что-нибудь. Скажем, «Hello UART»:

Эхо есть. Но как-то скучно всё. Давайте добавим немного забавного функционала. Формирование эха происходит здесь:

Повеселимся и сделаем копирование из входного буфера в выходной таким:

То же самое текстом.
/* Copy Buffer to Send Buff */
for (i = 0; i < s_recvSize; i++)
{
        s_currSendBuf[s_sendSize++] = s_currRecvBuf[i]+1;
}

Собираем, заливаем, входим в терминал, вбиваем заветную фразу… Видим такое эхо:

Работает!  К коду каждого символа прибавилась единичка.

У получившейся «прошивки» имеется один небольшой недостаток. Чтобы не переполнялся буфер, разработчики от NXP пошли на хитрость. Пока данные не забраны – новые передать в такой UART не получится. Нет взятия эха – нет приёма новых символов. Просто именно этой «прошивкой» я делал замеры производительности USB данного устройства, а там же я просто шлю данные, не принимая обратно. Подробнее о методике измерения я писал в предыдущей статье. Но как устранить эту особенность и как делались замеры для NXP, я расскажу в следующий раз. Кроме того, мы научимся работать с GPIO и UART.

Заключение

Мы освоили методику разработки «прошивок» для платы Teensy не средствами Teensyduino, а средствами разработки от NXP. Автор считает, что библиотеки от NXP намного удобнее, чем Ардуиновские аналоги. Ну, или хотя бы полнее. В любом случае, владение различными методиками даёт возможность выбора, а выбор – это всегда здорово.