Программирование ARM ESP-IDF: советы по JTAG-отладке Mon, July 07 2025  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


ESP-IDF: советы по JTAG-отладке Печать
Добавил(а) microsin   

В этой статье (перевод документации [1]) приведены рекомендации по отладке с помощью JTAG проектов на процессорах ESP32.

[Доступные точки останова (breakpoints) и точки анализа (watchpoints)]

Отладчик ESP32 поддерживает 2 реализованные аппаратно точки останова (hardware breakpoint) и 64 реализованных программно (software breakpoint). Аппаратные breakpoint реализованы логикой в чипе ESP32, и они могут быть установлены в любом месте кода: либо в областях flash, либо областях IRAM программы. Дополнительно существую 2 типа программных breakpoint, реализованных OpenOCD: flash breakpoints (их до 32 штук) и IRAM breakpoints (тоже до 32 штук). В настоящее время GDB не может устанавливать программные breakpoints в flash. Таким образом, пока это ограничение не снято, эти breakpoint-ы эмулируются OpenOCD как аппаратные (см. далее описание подробностей).

ESP32 также поддерживает 2 watchpoints, с помощью которых можно отслеживать на изменение 2 переменные, либо можно читать их значения GDB-командой watch myVariable. Обратите внимание, что menuconfig-опция CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK использует последнюю watchpoint и не предоставляет ожидаемых результатов, если вы также попытаетесь использовать это в OpenOCD/GDB. См. menuconfig help для подробного описания.

Что еще следует знать по поводу точек останова. Эмуляция части аппаратных breakpoint с помощью программных flash breakpoint означает, что GDB-команда hb myFunction, вызываемая для функции во flash, будет использовать чистую аппаратную breakpoint, если она доступна, иначе будет использована одна из 32 software flash breakpoint. То же самое правило применяется к командам наподобие b myFunction. В этом случае GDB будет сам решать, какой тип breakpoint устанавливать. Если myFunction находится в записываемой области (IRAM), то будет использована software IRAM breakpoint, иначе будет использована аппаратная или программная flash breakpoint, как это делается для команды hb.

[Flash Mappings против SW Flash Breakpoints]

Чтобы установить/очистить программные breakpoint в flash, OpenOCD должна знать их адреса flash. Чтобы выполнить преобразование из адресного пространства ESP32 в адресное пространство flash, OpenOCD использует отображения (mappings) регионов кода программы, находящихся в flash. Эти отображения хранятся в заголовке образа, которые предшествуют двоичным данным программы (сегменты кода и данных), и эти отображения специфичны для каждого образа приложения, записанного во flash. Поэтому для поддержки программных flash breakpoint системе OpenOCD нужно знать, где при отладке находится во flash образ приложения. По умолчанию OpenOCD читает таблицу разделов (partition table) по адресу 0x8000, и использует mapping-и из первого найденного образа приложения, но могут быть случаи, когда это не сработает, например когда таблица разделов находится не в стандартном месте flash, или даже могут быть несколько образов приложений: одно factory-приложение и два OTA-приложения, и вам может понадобиться отлаживать любое из них. Чтобы закрыть все возможные сценарии отладки, OpenOCD поддерживает специальную команду, которая может использоваться для установки произвольного места нахождения образа отлаживаемого приложения. Команда имеет следующий формат:

esp appimage_offset < offset>

Смещение offset должно быть в hex-формате. Для сброса к поведению по умолчанию вы можете указать -1 в качестве offset.

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

$ openocd -f board/esp32-wrover-kit-3.3v.cfg -c "init; halt; esp appimage_offset 0x210000"

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

[Почему шаги "next" не пропускают вызовы подпрограмм?]

Когда код выполняется по шагам командой next, отладчик GDB внутренне устанавливает breakpoint перед кодом, где надо пропустить вызов подпрограммы. Если все 2 breakpoint-а уже установлены, то этот функционал не срабатывает. Если это тот случай, то удалите breakpoint-ы, чтобы иметь одну "в запасе". Когда уже используются все breakpoint-ы, пошаговое выполнение кода командой next будет работать как команда step, и отладчик будет проваливаться внутрь вызова подпрограммы.

[Поддержка опций для OpenOCD во время компиляции]

ESP-IDF имеет некоторую поддержку опций для отладки OpenOCD, которые можно установить во время компиляции:

CONFIG_ESP_DEBUG_OCDAWARE (разрешена по умолчанию). Если выбрасывается panic или unhandled, и JTAG-отладчик подключен (например OpenOCD работает), то ESP-IDF выполнит остановку (break) в отладчике.

CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK (запрещена по умолчанию) установит watchpoint с индексом 1 (вторая из двух) в конце любого стека задач. Это самый точный способ отладки переполнения стека задач. Кликните на ссылку для получения дополнительной информации.

Также см. описание меню конфигурации проекта (idf.py menuconfig [2]) для подробностей по установке опций времени компиляции.

[Поддержка FreeRTOS]

OpenOCD имеет явную поддержку для ESP-IDF версии FreeRTOS. GDB может видеть задачи FreeRTOS (tasks) как потоки (threads). Их все можно просматривать GDB-командой i threads, изменение на определенную задачу осуществляется командой thread n, где n это номер потока. Детектирование наличия FreeRTOS может быть запрещено в конфигурации target. Подробности см. далее в секции "Конфигурирование OpenOCD для определенной цели отладки (target)".

GDB имеет расширение Python для поддержки FreeRTOS. ESP-IDF автоматически загружает этот модуль в GDB с командой idf.py gdb, когда удовлетворены системные требования. Для дополнительной информации см. секцию "Debugging FreeRTOS Objects" примеров отладки [3].

[Зачем в конфигурации OpenOCD устанавливается напряжение SPI flash?]

Вывод MTDI кристалла ESP32, вместе с другими четырьмя выводами, используемыми для обмена JTAG, это также один из выводов управления загрузкой (ESP32 bootstrapping pins). При включении питания ESP32 анализирует двоичный уровень на MTDI, чтобы установить внутренний регулятор напряжения, используемый для питания внешнего чипа SPI flash. Если двоичный уровень MDTI при включении питания низкий, то регулятор напряжения устанавливается для формирования 3.3V, а если уровень MDTI при включении питания высокий, то напряжение регулятора устанавливается на 1.8V. Вывод MTDI должен иметь внешний резистор верхней подтяжки к высокому уровню (pull-up), или можно полагаться на внутреннюю слабую подтяжку к низкому уровню (weak pull down, подробности см. в описании серии ESP32 [4]), в зависимости от типа используемого чипа SPI flash. Как только JTAG подключен, он отменит уровень резистора pull-up или pull-down, который должен управлять начальной загрузкой (bootstrapping).

Чтобы решить эту проблему, конфигурационный файл платы OpenOCD (например board\esp32-wrover-kit-3.3v.cfg для платы разработчика ESP-WROVER-KIT) предоставляет параметр ESP32_FLASH_VOLTAGE для установки состояния ожидания (idle state) сигнала TDO в указанный двоичный уровень, уменьшая тем самым шанс неправильной загрузки приложения из-за некорректного напряжения flash.

Проверьте спецификацию модуля ESP32, подключенного к JTAG, какое он использует напряжение питания чипа SPI flash. Затем соответствующим образом установите ESP32_FLASH_VOLTAGE. Большинство модулей WROOM используют 3.3V flash. WROVER, более ранние чем ESP32-WROVER-B, используют 1.8V flash, в то время как модули ESP32-WROVER-B и ESP32-WROVER-E используют 3.3V flash.

[Оптимизация скорости JTAG]

Чтобы достичь повышенных скоростей обмена данными и минимизировать количество отброшенных пакетов, рекомендуется оптимизировать настройку тактовой частоты JTAG, чтобы настроить максимальную частоту, при которой все еще обеспечивается стабильная работа JTAG. Для этого воспользуйтесь следующими советами.

1. Верхний предел частоты тактов JTAG составляет 20 МГц, если CPU работает на 80 МГц, или 26 МГц, если CPU работает на 160 МГц или 240 МГц.
2. В зависимости от конкретного JTAG-адаптера и длины его кабеля подключения может понадобиться уменьшить частоту JTAG ниже 20 МГц или 26 МГц.
3. В частности уменьшите частоту, если вы получаете ошибки DSR/DIR (и они не относятся к OpenOCD, которая пытается прочитать из области памяти без присутствия там физической памяти).
4. ESP-WROVER-KIT стабильно работает на 20 МГц или 26 МГц.

[Что такое Debugger Startup Commands?]

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

• set remote hardware-watchpoint-limit 2 — ограничивает GDB для использования доступных hardware watchpoints, поддерживаемых чипом, что составляет 2 для ESP32. Для дополнительной информации см. описание удаленной отладки [4].
• mon reset halt — сбросит чип и оставит процессор в остановленном состоянии (CPU halted).
• maintenance flush register-cache — команда monitor (mon) не может информировать GDB, что поменялось состояние target. GDB будет подразумевать, что какой бы ни был стек у target перед mon reset halt, он все равно остается достоверным. Фактически после сброса состояние target изменится, и выполнение maintenance flush register-cache это способ заставить GDB получить новое состояние от target.
• thb app_main — вставит временную hardware breakpoint на app_main. Если необходимо отлаживать другую функцию, то поменяйте здесь имя app_main.
• c — возобновление работы программы. Это будет, когда произошла остановка на breakpoint, вставленной на app_main.

[Конфигурирование OpenOCD для определенной цели отладки (target)]

Есть несколько видов файлов конфигурации OpenOCD (*.cfg). Все файлы конфигурации находятся в подкаталогах директории share/openocd/scripts дистрибутива OpenOCD (или директории tcl/scripts исходного репозитория). В контексте этого руководства самыми важными будут подкаталоги board (файлы конфигурации платы), interface (файлы конфигурации интерфейса) и target (файлы конфигурации целевого процессора).

Файлы конфигурации интерфейса (interface configuration files) описывают адаптер JTAG. Примеры JTAG-адаптеров: ESP-Prog и J-Link.
Файлы конфигурации целевого процессора (target configuration files) описывают определенный отлаживаемый чип, или в некоторых случаях описывают модули.
Файлы конфигурации платы (board configuration files) предоставляются для плат разработчика (development boards) со встроенным на них адаптером JTAG. Такие файлы подключают файл конфигурации интерфейса для выбора адаптера, и файл конфигурации целевого процессора для выбора чипа/модуля.

Для ESP32 доступны следующие файлы конфигурации:

board/esp32-wrover-kit-3.3v.cfg Файл конфигурации платы для ESP-WROVER-KIT с модулем 3.3V ESP32-WROOM-32 или модулем ESP32-WROVER-B/ESP32-WROVER-E.

board/esp32-wrover-kit-1.8v.cfg Файл конфигурации платы для ESP-WROVER-KIT с модулем 1.8V ESP32-WROVER.

board/esp32-ethernet-kit-3.3v.cfg Файл конфигурации платы для ESP-Ethernet-KIT с модулем 3.3V ESP32-WROVER-B/ESP32-WROVER-E.

target/esp32.cfg Файл конфигурации целевого процессора ESP32. Может использоваться с одним из файлов конфигурации интерфейса/конфигурации.

target/esp32-solo-1.cfg Файл конфигурации целевого процессора для модуля ESP32-SOLO-1. Отличается от esp32.cfg тем, что конфигурирует только один CPU.

interface/ftdi/esp32_devkitj_v1.cfg Файл конфигурации адаптера JTAG для плат ESP-WROVER-KIT и ESP-Prog.

Если вы используете одну из плат, для которых есть готовый файл конфигурации, то вам нужно только предоставить его аргументу -f для OpenOCD, указав соответствующий файл.

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

Пользовательские файлы конфигурации. Файлы конфигурации OpenOCD написаны на TCL, и они включают различные варианты для настроек и написания скриптов. Это может быть полезно для нестандартных ситуаций отладки. Для справочника по TCL см. руководство OpenOCD [6].

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

Синтаксис TCL для установки переменной:

set VARIABLE_NAME value

Для установки переменной из командной строки (замените имя .cfg файла на правильный для вашей платы файл):

$ openocd -c 'set VARIABLE_NAME value' -f board/esp-xxxxx-kit.cfg

Важно установить переменную перед подключением специфичного для ESP файла конфигурации, иначе переменная не даст эффекта. Вы можете установить несколько переменных, указав несколько опций -c.

Общие относящиеся к ESP переменные OpenOCD:

Переменная Описание
ESP_RTOS Установите в none для запрета поддержки RTOS. В этом случае список потоков будет недоступен в GDB. Может быть полезным, когда отлаживается сама FreeRTOS, и осуществляется пошаговая отладка в коде планировщика.
ESP_FLASH_SIZE Установите в 0 для запрета поддержки Flash breakpoints.
ESP_SEMIHOST_BASEDIR Установите в путь (на хосте), который будет директорией по умолчанию для semihosting-функций.
ESP_ONLYCPU Для многоядерных target можно установить в 1, чтобы разрешить одноядерную отладку (single core debugging).

Относящиеся к ESP32 переменные OpenOCD:

Переменная Описание
ESP32_FLASH_VOLTAGE Когда используются модули ESP32 с памятью flash 1.8V, то установите эту переменную в 1.8. См. "Зачем в конфигурации OpenOCD устанавливается напряжение SPI flash?".
ESP_ONLYCPU Для многоядерных target можно установить в 1, чтобы разрешить одноядерную отладку (single core debugging).

[Как отладчик сбрасывает ESP32?]

Плату можно сбросить вводом в GDB команды mon reset или mon reset halt.

[Можно ли выводы JTAG использовать для других целей?]

Работа JTAG может быть нарушена, если к выводам JTAG подключена какая-то другая аппаратура помимо модуля ESP32 и адаптера JTAG. ESP32 JTAG использует следующие выводы:

Вывод ESP32 Сигнал JTAG
MTDO / GPIO15 TDO
MTDI / GPIO12 TDI
MTCK / GPIO13 TCK
MTMS / GPIO14 TMS

Обмен JTAG скорее всего прервется, если конфигурация выводов JTAG изменена приложением пользователя. Если OpenOCD инициализируется корректно (определяет все ядра CPU в SOC), но теряет синхронизацию и выбрасывает много ошибок DTR/DIR, когда запускается программа, то скорее всего причина в том, что приложение переконфигурирует выводы JTAG для чего-то еще, или пользователь забыл подключить Vtar к JTAG-адаптеру, который этого требует.

Ниже показана выдержка из серии ошибок на двухядерном ESP32, о которых сообщает GDB после того, как приложение проходит шаги кода, который переконфигурирует вывод MTDO на вход:

cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates target still busy!
cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an exception!
cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an overrun!
cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates target still busy!
cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an exception!
cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an overrun!

[JTAG с Flash Encryption или Secure Boot]

По умолчанию разрешение шифрования программы (Flash Encryption) и/или технологии безопасной загрузки (Secure Boot) запретит отладку JTAG. При первой загрузке bootloader прожжет бит eFuse для постоянного запрета JTAG и одновременного разрешения других функций.

Опция конфигурации проекта CONFIG_SECURE_BOOT_ALLOW_JTAG сохранит в это время JTAG разрешенным, удаляя всю физическую безопасность, но позволяя отладку (хотя имя предполагает Secure Boot, эта опция может быть применена даже когда разрешено только Flash Encryption).

Однако OpenOCD может попытаться автоматически прочитать и записать flash, чтобы установить программные точки останова (software breakpoints). Это создает 2 проблемы:

• Software breakpoints несовместимы с Flash Encryption, система OpenOCD в настоящее время не имеет поддержки для шифрования и дешифровки защищенного содержимого flash.
• Если разрешена Secure Boot, установка software breakpoint поменяет цифровую подпись подписанного приложения, и тем самым сделает подпись недопустимой. Это означает, что если будет установлена software breakpoint, и затем произойдет сброс, то верификация сигнатуры приведет к остановке загрузки (приложение не запустится).

Для запрета программных точек останова при использовании JTAG добавьте дополнительный аргумент -c 'set ESP_FLASH_SIZE 0' в командную строку запуска OpenOCD, см. выше описание переменных конфигурации OpenOCD.

Замечание: по той же причине приложение ESP-IDF может не пройти проверку загрузчиком сигнатур приложения, когда эта опция разрешена, и была установлена software breakpoint.

[Проблема совместимости JTAG и прошивки ESP32-WROOM-32 AT]

Серия модулей ESP32-WROOM поставляется с предварительно прошитым AT firmware. Это firmware конфигурирует выводы GPIO12 .. GPIO15 как интерфейс SPI slave, что делает невозможным использование JTAG.

Чтобы сделать JTAG доступным, соберите новое firmware, которое не использует выводы GPIO12 .. GPIO15, чтобы они были выделены для обмена JTAG. После этого прошейте новое firmware в модуль. См. также секцию выше "Можно ли выводы JTAG использовать для других целей?".

[Как сообщить о проблемах с OpenOCD/GDB]

Если вы столкнулись с проблемой самих программ OpenOCD или GDB, и не нашли решение в Интернете, то отройте проблему (issue report) в OpenOCD issue tracker https://github.com/espressif/openocd-esp32/issues.

1. В issue report предоставьте информацию о вашей конфигурации:

a) Тип JTAG-адаптера, и отлаживаемого чипа/модуля.
b) Версия релиза ESP-IDF, используемого для компиляции и загрузки отлаживаемого приложения.
c) Информация об операционной системе, под которой происходила отладка.
d) Операционная система реально работала на PC, или это была виртуальная машина (или docker)?

2. Создайте простой пример, который демонстрирует наблюдаемую проблему. Опишите шаги, которые надо выполнить, чтобы проблема проявилась. В таком примере на отладку не должно влиять недетерминированное поведение, вносимое стеком Wi-Fi, поэтому проблемы, вероятно, будет легче воспроизвести, если они возникнут один раз.

3. Подготовьте логи из сессии отладки путем добавления дополнительных команд в команды настройки запуска (start up commands).

OpenOCD:

openocd -l openocd_log.txt -d3 -f board/esp32-wrover-kit-3.3v.cfg

Вывод в файл лога предотвращает отображение информации в терминале. Это может оказаться полезным, когда выводится много информации при установленном повышенном уровне отладки (debug level -d3). Если вы все еще видите лог на экране, то вместо этого используйте другую команду:

openocd -d3 -f board/esp32-wrover-kit-3.3v.cfg 2>&1 | tee openocd.log

Отладчик:

xtensa-esp32-elf-gdb -ex "set remotelogfile gdb_log.txt" < все другие опции>

Опционально добавьте команду remotelogfile gdb_log.txt в файл gdbinit.

Присоедините оба файла openocd_log.txt и gdb_log.txt к вашему issue report.

[Ссылки]

1. JTAG Debug Tips and Quirks site:docs.espressif.com.
2. Конфигурация проекта ESP-IDF.
3. Debugging Examples site:espressif.com.
4. ESP32 Series Datasheet site:espressif.com.
5. 20.4 Remote Configuration.
6. OpenOCD User’s Guide.
7. ESP-IDF: JTAG-отладка.

 

Добавить комментарий


Защитный код
Обновить

Top of Page