RTT с помощью OpenOCD (без J-Link и без софта от Segger)

Фирменный софт от Segger, разработчика программаторов J-Link, имеет одну очень удобную функцию, а именно терминал реального времени — Real Time Terminal (RTT) (есть информация на русском и пример использования). Вещь удобная, позволяет получить терминал до МК прямо во время отладки по SWD. По скорости и функционалу превосходит Semihosting и вывод информации через пин SWO. И хотя идея не оригинальна (например, до недавнего времени что-то подобное было в в составе набора утилит stlink utils от Texane), реализация оказалась удачной и удобной для использования. Поддерживаются все МК ARM Cortex-M. Жирный минус — привязка к недешёвым программаторам J-Link и к их фирменному софту. И если первая проблема уже давно решается покупкой клона или превращением ST-Link в J-Link OB, то вторая до недавнего времени не имела решений — или используй фирменный софт и бойся, что он залочит клон, или забудь об RTT. Но решение появилось: проект открытого отладчика для чипов OpenOCD (Open On-Chip Debugger) уже несколько лет поддерживает программаторы J-Link (без проблем работает прошивка и отладка), а в марте в репозитории проекта OpenOCD появился патч от Marc Schink, добавляющий поддержку RTT. Более того — вещь получилась универсальная, работает даже с другими SWD программаторами (я тестировал с ST-Link). И хотя патч ещё не включён основную ветку OpenOCD, ничто не мешает нам его попробовать.

Тестирование будем проводить на Linux (но можно повторить и на других ОС), программаторы J-Link-OB-072 и ST-Link-v1. Первым делом, устанавливаем необходимые для сборки пакеты:
sudo apt-get install build-essential libftdi-dev libtool automake

Затем скачиваем OpenOCD и нужный нам патч:
git clone http://openocd.zylin.com/openocd
cd ./openocd
git fetch http://openocd.zylin.com/openocd refs/changes/55/4055/5 && git checkout FETCH_HEAD

Собираем. Для установки выберем каталог ~/openocd:
./bootstrap
./configure --prefix ~/openocd
make 
make install

На этом этапе имеем собранный и установленный OpenOCD в каталоге ~/openocd. Далее необходимо создать пару конфигурационных файлов. Первый — для запуска программатора J-Link с интерфейсом SWD, это файл ~/openocd/share/openocd/scripts/interface/jlink_swd.cfg:
interface jlink
transport select swd

И ещё один файл ~/openocd/share/openocd/scripts/interface/rtt.cfg для автоматического запуска RTT:
$_TARGETNAME configure -event resume-end {
	rtt start
}

$_TARGETNAME configure -event halted {
	rtt stop
}

Далее скачаем J-Link Software and Documentation Pack, нужен вариант в TGZ архиве. Распаковываем и забираем оттуда файлы:
  • Samples/RTT/SEGGER_RTT_V614c/RTT/* — собственно файлы, которые необходимо добавить в проект для МК (SEGGER_RTT_printf.c — не обязателен)
  • Samples/RTT/SEGGER_RTT_V614c/Examples/* — примеры использования RTT
  • Doc/UM08001_JLink.pdf — оттуда интересен раздел Chapter 13 RTT где есть описание API
Для тестирования создаём для МК пустой проект, добавляем к проекту файлы SEGGER_RTT_Conf.h, SEGGER_RTT.h, SEGGER_RTT.c и Main_RTT_InputEchoApp.c и собираем его, получив на выходе файл ~/test/bin/firmware.elf.

Перед запуском OpenOCD с RTT необходимо узнать несколько параметров, а именно адрес контрольного блока RTT в RAM памяти МК и размер этого блока и буферов. Адрес можно получить, узнав с помощью отладчика адрес переменной _SEGGER_RTT. Сделаем это на примере gdb (как с ним работать, можно почитать тут). Запускаем OpenOCD (пока что без RTT), указав интерфейсом SWD через J-Link и указав целевой МК:
~/openocd/bin/openocd -f interface/jlink_swd.cfg -f target/stm32f1x.cfg

Запускаем gdb, указав путь до скомпилированного файла:
arm-none-eabi-gdb -ex "target remote localhost:3333" ~/test/bin/firmware.elf

далее останавливаем МК, загружаем прошивку, запускаем и узнаём адрес переменной:
monitor reset halt
load
monitor reset run
print &_SEGGER_RTT

Получим вывод $1 = (SEGGER_RTT_CB *) 0x20000a68 <_SEGGER_RTT> т.е. адрес в моём случае 0x20000a68. Размер считается по методике, описанной в 13.2.6 Memory footprint из документа UM08001_JLink.pdf, если ничего не меняли в файле SEGGER_RTT_Conf.h то он составит 3216 байта (24 байта ID + 3 канала * (24 байта на канал + 1024 байта буфер UP + 16 байт буфер DOWN)).
Перезапускаем OpenOCD с новыми параметрами, добавив запуск RTT сервера на порту 9090:
~/openocd/bin/openocd -f interface/jlink_swd.cfg -f target/stm32f1x.cfg -f interface/rtt.cfg -s tcl -c "rtt setup 0x20000a68 3216 \"SEGGER RTT\"" -c "rttserver start 9090 0"

Здесь мы указали канал 0, их может быть несколько (соответственно и несколько терминалов, например один для управления, один для вывода отладочных сообщений) и каждому каналу можно привязать свой порт, например:
~/openocd/bin/openocd -f interface/jlink_swd.cfg -f target/stm32f1x.cfg -f interface/rtt.cfg -s tcl -c "rtt setup 0x20000a68 168 \"SEGGER RTT\"" -c "rttserver start 9090 0" -c "rttserver start 9091 1"

Подключаемся телнетом к этому порту — это и будет наш терминал с МК (можете использовать Putty или любой другой telnet клиент, даже JLinkRTTClient подойдет):
telnet localhost 9090

Запускаем gdb на выполнение прошивки:
arm-none-eabi-gdb -ex "target remote localhost:3333" ~/test/bin/firmware.elf
monitor reset halt
continue

Всё, в окне телнет-клиента имеем терминал до МК. Пример Main_RTT_InputEchoApp при старте программы выдаст сообщение «SEGGER Real-Time-Terminal Sample» и будет возвращать обратно всё, что ему отправят. Для ST-Link запуск будет выглядеть так (протестировано на плате STM32 VL Discovery):
~/openocd/bin/openocd -f interface/stlink-v1.cfg -f target/stm32f1x.cfg -f interface/rtt.cfg -s tcl -c "rtt setup 0x20000a68 168 \"SEGGER RTT\"" -c "rttserver start 9090 0" -c "rttserver start 9091 1"


Добавим немного удобств: чтобы каждый раз не лезть за адресом переменной _SEGGER_RTT можно указать компилятору всегда располагать её по известному адресу (например — на начало RAM 0x20000000). Есть несколько способов, для gcc можно сделать так: в файл SEGGER_RTT_Conf.h добавим строчку:
#define SEGGER_RTT_SECTION ".rtt"

тогда после подстановок препроцессора объявление переменной _SEGGER_RTT будет выглядеть так:
__attribute__ ((section (".rtt"))) SEGGER_RTT_CB _SEGGER_RTT

Это указание компилятору поместить эту переменную в секцию ".ram". И в ключи вызова линкера добавим указание располагать секцию ".ram" по нужному нам адресу:
-Wl,-section-start=.ram=0x20000000

На этом всё. Не стоит забывать, что функционал ещё в процессе разработки, если будете использовать и найдёте ошибки — сообщайте автору — Marc Schink (для связи он предпочитает IRC #openocd), это позволит быстрее включить патч в основную кодовую базу OpenOCD.
  • +1
  • 02 апреля 2017, 14:10
  • arhiv_6

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

RSS свернуть / развернуть
Этот софт под Windows есть?
0
  • avatar
  • Aneg
  • 03 апреля 2017, 13:23
Готовой сборки под Win именно с этим патчем нет. Можете сами собрать по инструкции.
0
Я очень смутно представляю как это все проделывается. Можешь подсказать с чего начать? Как я понимаю нужна среда для компиляции, Visual Studio подойдет?
0
Проще поставить линукс)
0
И все таки, хочется под Windows!!!
0
Я слил сорцы, посмотрел на скачанное, посмотрел на зависимости и снес. Но если хочешь — можешь попробовать. Ставь git, MinGW или TDM-GCC, MSYS2 (при установке укажешь, где mingw), pkg-config, libftdi-dev для винды и пробуй собрать приведенными в топике командами. Команды git можно выполнять из консоли винды, все остальное из MSYS2.
Когда от этих экспериментов винда сломается — ставь линукс и дальше по инструкции из топика.
0
Очень сложно!
0
Вот и я о том.
0
А можешь сделать под Win? Для непросвещенных в деле программирования для ПК.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.