Пролог

В этом тексте я бы хотел провести экскурс по использованию CLI в микроконтроллере. Расскажу про API той CLI, которая сформировалась у меня много лет назад. Стимулом к написанию текста послужило то, что при первом знакомстве с таким понятием как UART-CLI порой бывает даже не понято, что это такое и про что вообще идет речь. Это абсолютно нормальное явления, так как я и сам первые 7 лет опыта во флагманских предприятиях российской микроэлектроники не знал, что оказывается можно отлаживать микроконтроллерные прошивки через UART-CLI. А словосочетания UART-CLI, UART-Shell и диагностика были для меня просто пустой звук.

Прежде всего для подключения к UART на стороне PC я бы порекомендовал Вам бесплатную утилиту TeraTerm так как в ней есть возможность задавать паузу между отправкой байтов в UART. Это не позволит вашей прошивке захлебнуться от чрезмерно плотного потока байт.

UART-CLI можно делать по-разному. Прежде всего CLI - это первичный лог загрузки прошивки. Своеобразная лента черного ящика. Как в самолётах. Инициализация микроконтроллера - это многостадийный, многофазовый, многоступенчатый процесс, в котором многое может пойти не по плану. Какая-нибудь подсистема может при инициализации прошивки вернуть false. Например из-за абсурдного значения в конфигурационной структуре того или иного программного компонента. Поэтому первое, что Вы должны увидеть в UART консоли - это зеленый лог загрузки программы.

После отработки инициализации системы пуска Вы увидите курсор -->. Курсор это приглашение ввести и исполнить свою самую первую CLI команду.

Иной раз можно также перед курсором --> отображать up_time системы. Это позволяет визуально проверять корректность установки тактирования просто нажав и удерживая Enter убеждаться, что секунды в самом деде переключаются раз в секунду.

Все команды консоли можно разделить на две группы: Getter-ы и Setter-ы. Setter-ы что-то меняют в прошивке. Getter-ы просто и безопасно просматривают состояния прошивки под разными срезами. По хорошему getter-ов должно быть столько же сколько и setter-ов.

Самая первая CLI команда - это help. В терминале она сокращена до одной буквы h. Можно даже просто нажать TAB и появится тот же список доступных команд. Их обычно десятки.

У команды h есть два ключа. Это нужно для отображения только тех команд, в имени которых есть указанная в аргументах подстрока. Так среди сотен и тысяч CLI команд консоли можно найти одну конкретную команду даже не зная её точного названия.

Через UART-CLI Вы всегда сможете узнать версию прошивки, версию компилятора и git sha256 коммита, из которого была собрана данная прошивка. Для этого есть команда vi (version information)

Порой отлаживать прошивку можно просто анализируя лог. Это printf-отладка. Чтобы выбирать лог для каждого программного компонента есть команда ll (log level). Можно просмотреть какой уровень логирования назначен каждому модулю.

Удобно, когда есть команда, показывающая частоту ядра процессора.

и команда показывающая включенные тактирования подсистем

При bring-up платы очень полезно получить отчет о состоянии GPIO пинов. Это показывает команда gl (GPIO list)

CLI обладает низкоуровневыми командами. Команда rm (read_mem) позволяет читать произвольные куски памяти. Просто указываешь физический адрес, количество байт, нажимаешь enter и получаешь содержимое памяти в виде массива. Аналогично можно и прописать RAM память командой wm (write_mem).

Можно более осознано вычитать только сырые значение конкретных регистров (например аппаратного таймера 5) и сравнить значения битов с даташитом. Попять как настроен таймер. Это особенно помогает в поиске причин багов.

Благодаря UART-CLI можно читать не только внутренние регистры, но и внешние регистры. Вот тут удалось вычитать по I2C значения внутренних 9-битных регистров ASIC аудиокодека NAU8814 на той стороне I2C шины. Команда nrm (nau read reg map). Красота!

Можно просмотреть степень заполнения flash памяти. Команда fd ( flash_diag)

Если Ваша прошивка испускает PWM сигналы, то в CLI можно просмотреть настройки PWM сигналов командой pwd.

Можно просмотреть состояние LED-ов lmd (led_mono_diag)

В микроконтроллерах очень много источников прерываний. Можно просмотреть настройки прерываний командой intd. Проверить включенные прерывания.

Состояние аппаратных таймеров можно посмотреть командой trd (timer_diag)

В CLI можно просматривать и задавать параметры NVRAM. Так Вы сможете пере конфигурировать прошивку без пере сборки всего проекта.

В CLI можно просмотреть процент заполнения стековой памяти по всем ��драм. Это команда cd (core_diag)

При работе с интерфейсом I2C CLI позволяет удобно просканировать всю шину. Вот так отображается карта I2C адресов, когда к шине подключен RTC DS3231 и еще какая-то eeprom. Это отработала команда i2cs (i2c scan )

Из CLI можно даже инициировать перезагрузку ядра (команда reboot).

Диагностика супер цикла показывает сколько итераций в секунду делает цикл while(1) в main.
Можно прочитать среднюю продолжительность одной итерации и многое другое. Это делает команда scd (super_cycle_diag)

на MCU
на MCU
на Win PC
на Win PC

В CLI можно открыть диспетчер задач и отдельной командой отключить одну из задач по её id. Прямо на лету без пересборки прошивки.

Из UART-CLI можно, например, пульнуть пакет в CAN. Это делается командой cs (can_send). В аргументах через пробел указываем номер CAN трансивера, ID пакета и данные в виде hex строки. Нажимаем Enter и пакет улетает в шину. Принятый же пакет отразится отдельной строчкой в UART логе (при включенном уровне логирования).

Можно отметить CLI команду repeat. Эта тестировочная команда повторяет конкретную команду, имя которой указано в аргументе N раз с периодом P миллисекунд. Команда repeat просто незаменима при отладке софта и железа. Её можно сравнить с 3ей рукой в нужный момент.

Через CLI можно инициировать пуск модульных тестов и увидеть отчет исполнения тестов. Можно запустить только те тесты, которые имеют в своем имени конкретную подстроку (например "i2c" или SPI ).

Калькуляторы

Когда у Вас в прошивке есть CLI, любое ваше устройство, помимо базового функционала, превращается в супер калькулятор покруче любого Casio. Только вместо клавиатуры и дисплея торчит два провода UART. Можно прямо в консоли TeraTerm / PuTTY попросить микроконтроллер расшифровать кусок Base64, RLE, AES256, вычислить SHA256, посчитать CRC16, решить задачку на поиск пересечения временных интервалов, определить точное количество дней между 2мя датами, вычислить расстояние между двумя GNSS координатами на сфере, вычислить коэффициенты линейной функции (ax+b=y) по двум точкам,

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

Или вот, типичная ситуация. Есть у Вас два набора регистров. На одном наборе устройство работает. На другом наборе регистров устройство не работает. Надо понять в чем, собственно, дело. Какие именно биты отличаются? Надо узнать, что именно влияет на работу и куда копать. И тут Вам снова поможет CLI-ха. У меня есть команда (bd), которая автоматически вычисляет отличающиеся биты в двух 32-битных числах.

Или вот другой пример. Прошивка рассчитывает ёмкость керамического конденсатора по его трехбуквенной маркировке. Раньше это была головная боль, теперь - игра.

Конденсаторный калькулятор
Конденсаторный калькулятор

Буквально недавно опять выручила консоль. Вот я в консоли прошивки инициирую алгоритм вычисления коэффициентов PLL для желаемой частоты 220MHz. Это делает CLI команда clock_pll_calc 220000000. Можно менять частоту ядра налету.

clock_pll_calc 220000000
clock_pll_calc 220000000

Калькулятор покажет какие реальные CAN ID будут фактически приняты для данной настройки маски и ID. Это команда cfim (can_filter; CanFilterIdAndMask).

Вам уже нравится UART-CLI? Можно и дальше перечислять другие полезные команды CLI. Я лишь показал основные команды.

Немного фактов про UART-CLI

--UART-CLI нужна в debug сборке. В релизе shell может и не быть.
--Количество команд можно варьировать в зависимости от объёма Flash на микроконтроллере
--CLI можно гонять по любому интерфейсу или протоколу. Не обязательно именно UART.
--Через CLI можно обновлять прошивку. Просто используя команды модуля flash и boot.
--UART-CLI не зависает, если перетыкать питание PCB, как SWD/JTAG link.
--Через UART-CLI можно калибровать FW.
--Постоянно включенная UART-CLI работает как заземление между электронной платой и компьютером.

Реализация UART-CLI

Буквально пару слов про то, как обычно работает CLI. Ничего сложного тут нет в помине. Любая приличная прошивка состоит из множества программных компонентов. UART-CLI - это тоже не один файл, а набор папок. Получается иерархическая связь между программными компонентами.

Из чего обычно состоит UART-CLI:

1.Драйвер UART. Приём байтов в прерывании и помещение символа в очередь.

2.Программный компонент string_reader - это по сути однострочный текстовый редактор. Чисто для того, чтобы позволить пользователю исправлять опечатки кнопкой backspace.

3.Парсер CSV строк В случае с CLI символом разделителя является обыкновенный пробел.

4.Набор функций для распознавания базовых типов данных из строчек ( вещественные числа) . По сути конечный автомат, который реализовывает конкретное регулярное выражение. Распознать float из текстовой строки.

5. Сам компонент CLI. Набор команд - это константный массив структур в Flash памяти, где в каждом элементе находится имя команды, короткое имя команды и указатель на функцию с двумя аргументами: argc, argv. Массив структур формируется на стадии препроцессора (cpp) #ifdef-ми. То есть при пуске main CLI уже частично проинициализирован.

Исходные коды с реализацией CLI

Ядро CLI
https://github.com/aabzel/trunk/tree/main/source/connectivity/protocols/cli\_drv
Однострочный текстовый редактор
https://github.com/aabzel/trunk/tree/main/source/connectivity/protocols/string\_reader
Умное логирование
https://github.com/aabzel/trunk/tree/main/source/connectivity/log
Для CLI нужна реализация протокола CSV.
https://github.com/aabzel/trunk/tree/main/source/connectivity/protocols/csv
Текстовое описание как работает код разбора CSV строчек.
https://habr.com/ru/articles/765066/

Итог

Вы конечно можете реализовать CLI по-своему. Добавить историю команд. Добавить авторизацию. Добавить авто дополнение и прочие крутые механизмы. Я лишь показал то, какая CLI сформировалась у меня. При формировании API для UART CLI я делал упор на лаконичность команд, переносимость кода и простоту. CLI не боится неверно введенных команд. В случае некорректных аргументов CLI сама красным текстом пишет, что не так. Чтобы научиться пользоваться CLI надо пробовать с ней работать.

Ссылки

Название

URL

Только консоль. Почему текстовый интерфейс настолько эффективен @ru_vds

https://habr.com/ru/companies/ruvds/articles/747396/

Command line interpreter на микроконтроллере своими руками @Corviniol

https://habr.com/ru/post/247507/

консоль в микроконтроллере с micro readline @Helius

https://habr.com/ru/articles/127890/

Реализация многофункционального терминального интерфейса для МК AVR @R3EQ

https://habr.com/ru/articles/780710/

Пишем терминальный сервер для микроконтроллера на С @Neoprog

 https://habr.com/ru/articles/572630/

embedded-cli

https://github.com/funbiscuit/embedded-cli

MCU-CLI-w25Q80-emulEEPROM

https://github.com/NetDm/MCU-CLI-w25Q80-emulEEPROM

Почему Нам Нужен UART-Shell? 

https://habr.com/ru/articles/694408/

https://www.youtube.com/watch?v=Fkmt7N6he5U

Как наш shell похорошел @Katbert

https://habr.com/ru/companies/whoosh/articles/978192/

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вы отлаживаете прошивки через UART-CLI?
35%да14
65%нет26
Проголосовали 40 пользователей. Воздержались 5 пользователей.