Как использовать GDB (Gnu Debugger) и OpenOCD для отладки микроконтроллеров - с терминала?
Стандартный (недорогой) способ программирования ARM-микроконтроллеров - это использование Eclipse со сложным набором инструментов, подключенным к нему. Eclipse определенно имеет свои достоинства, но я бы хотел чувствовать себя независимым от этой IDE. Я хотел бы узнать, что происходит за кулисами, когда я создаю (компилирую - ссылка - прошиваю) свое программное обеспечение и когда я запускаю сеанс отладки. Чтобы получить такое более глубокое понимание, было бы замечательно запустить всю процедуру из командной строки.
Примечание: я использую 64-битную Windows 10. Но большинство вещей, описанных здесь, также применимо к системам Linux. Пожалуйста, откройте все командные терминалы с правами администратора. Это может спасти вас от многих проблем.
1. Сборка программного обеспечения
Первая "миссия" выполнена. Теперь я могу скомпилировать и связать мое программное обеспечение в двоичный файл .bin
и .elf
изображение через командную строку. Ключом к успеху было выяснение, где Eclipse размещает свои make-файлы для конкретного проекта. Когда вы знаете, где они находятся, все, что вам нужно сделать, это открыть командный терминал и набрать GNU make
команда.
Вам больше не нужно Затмение для этого! Особенно, если вы можете прочитать (и понять) make-файл и настроить его под свои нужды, когда ваш проект продвигается.
Обратите внимание, что я нашел инструменты GNU (компилятор, компоновщик, утилита make, GDB, ...) в следующей папке после установки SW4STM32 (System Workbench для STM32):
C:\Ac6\SystemWorkbench\plugins\fr.ac6.mcu.externaltools.arm-none.win32_1.7.0.201602121829\tools\compiler\
Затем я создал новую папку на жестком диске и скопировал в нее все эти инструменты GNU:
C:\Apps\AC6GCC
|-> arm-none-eabi
|-> bin
'-> lib
И я добавляю эти записи в "Переменная среды":
- C:\Apps\AC6GCC\bin
- C:\Apps\AC6GCC\lib\gcc\arm-none-eabi\5.2.1
Хурай, теперь я установил и запустил все инструменты GNU в моей системе! Я поставил следующее build.bat
файл в той же папке, что и makefile
:
@echo off
echo.
echo."--------------------------------"
echo."- BUILD -"
echo."--------------------------------"
echo.
make -j8 -f makefile all
echo.
Запуск этого bat-файла должен сделать всю работу! Если все идет хорошо, вы получаете один .bin
и один .elf
двоичный файл как результат компиляции.
2. Перепрошивка и отладка прошивки
Естественный следующий шаг - прошить прошивку на чип и начать сеанс отладки. В Eclipse это всего лишь один "щелчок по кнопке" - по крайней мере, если Eclipse настроен правильно для вашего микроконтроллера. Но что происходит за кулисами? Я прочитал (часть) магистерскую диссертацию от Доминика Рата - разработчика OpenOCD. Вы можете найти его здесь: http://openocd.net/. Вот что я узнал:
Eclipse запускает программное обеспечение OpenOCD, когда вы нажимаете значок "отладка". Eclipse также предоставляет некоторые файлы конфигурации для OpenOCD, так что OpenOCD знает, как подключиться к вашему микроконтроллеру. "Как подключиться" не тривиальная вещь. OpenOCD необходимо найти подходящий драйвер USB для подключения к адаптеру JTAG (например, STLink). Как JTAG-адаптер, так и его USB-драйвер обычно поставляются изготовителем вашего чипа (например, STMicroelectronics). Eclipse также передает файл конфигурации OpenOCD, который описывает спецификации микроконтроллера. Как только OpenOCD узнает обо всех этих вещах, он может установить надежное соединение JTAG с целевым устройством.
OpenOCD запускает два сервера. Первый - это сервер Telnet через TCP-порт 4444. Он предоставляет доступ к OpenOCD CLI (интерфейс командной строки). Клиент Telnet может подключаться и отправлять команды в OpenOCD. Этими командами могут быть простые команды "stop", "run", "set breakpoint",...
Таких команд может быть достаточно для отладки вашего микроконтроллера, но многие уже знакомы с Gnu Debugger (GDB). Вот почему OpenOCD также запускает сервер GDB на TCP-порту 3333. Клиент GDB может подключиться к этому порту и начать отладку микроконтроллера!
Gnu Debugger - это программное обеспечение для командной строки. Многие люди предпочитают визуальный интерфейс. Это именно то, что делает Eclipse. Eclipse запускает клиент GDB, который подключается к OpenOCD, но все это скрыто для пользователя. Eclipse предоставляет графический интерфейс, который взаимодействует с клиентом GDB за кулисами.
Я сделал рисунок, чтобы объяснить все эти вещи:
>> Запуск OpenOCD
Мне удалось запустить OpenOCD из командной строки. Я объясню как.
- Сначала убедитесь, что ваш программатор STLink-V2 JTAG установлен правильно. Вы можете проверить установку с помощью "Утилиты STLink" от STMicroelectronics. Он имеет приятный графический интерфейс, и вы просто нажимаете кнопку подключения.
- Затем загрузите исполняемый файл программного обеспечения OpenOCD с этого веб-сайта: http://gnutoolchains.com/arm-eabi/openocd/. Установите его и поместите в папку на жестком диске, например "C:\Apps\".
Откройте командный терминал и запустите OpenOCD. Вам нужно будет предоставить OpenOCD несколько файлов конфигурации, чтобы он знал, где искать ваш микроконтроллер. Обычно вам нужно предоставить файл конфигурации, который описывает программиста JTAG, и файл конфигурации, который определяет ваш микроконтроллер. Передайте эти файлы в OpenOCD с помощью
-f
аргумент в командной строке. Вам также необходимо предоставить OpenOCD доступ кscripts
папку, передавая его с-s
аргумент. Вот как я запускаю OpenOCD на моем компьютере из командной строки:> "C:\Apps\OpenOCD-0.9.0-Win32\bin\openocd" -f "C:\Apps\OpenOCD-0.9.0-Win32\share\openocd\scripts\interface\stlink-v2.cfg" -f "C:\Apps\OpenOCD-0.9.0-Win32\share\openocd\scripts\target\stm32f7x.cfg" -s "C:\Apps\OpenOCD-0.9.0-Win32\share\openocd\scripts"
Если вы правильно запустили OpenOCD (с правильными аргументами), он запустится со следующим сообщением:
Open On-Chip Debugger 0.9.0 (2015-08-15-12:41) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'. Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD adapter speed: 2000 kHz adapter_nsrst_delay: 100 srst_only separate srst_nogate srst_open_drain connect_deassert_srst Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : clock speed 1800 kHz Info : STLINK v2 JTAG v24 API v2 SWIM v4 VID 0x0483 PID 0x3748 Info : using stlink api v2 Info : Target voltage: 3.231496 Info : stm32f7x.cpu: hardware has 8 breakpoints, 4 watchpoints Info : accepting 'gdb' connection on tcp/3333 Info : flash size probed value 1024
Обратите внимание, что окно вашего терминала теперь заблокировано. Вы больше не можете вводить команды. Но это нормально. OpenOCD работает в фоновом режиме и блокирует терминал. Теперь у вас есть два варианта взаимодействия с OpenOCD: вы запускаете сеанс Telnet в другом терминале и входите в порт TCP.
localhost:4444
, так что вы можете давать команды OpenOCD и получать обратную связь. Или вы запускаете сеанс клиента GDB и подключаете его к порту TCPlocalhost:3333
,
>> Запуск сеанса Telnet для взаимодействия с OpenOCD
Вот как вы запускаете сеанс Telnet для взаимодействия с запущенной программой OpenOCD:
> dism /online /Enable-Feature /FeatureName:TelnetClient
> telnet 127.0.0.1 4444
Если это работает хорошо, вы получите следующее сообщение на своем терминале:
Open On-Chip Debugger
> ..
И вы готовы отправлять команды в OpenOCD! Но теперь я перейду к сеансу GDB, поскольку это наиболее удобный способ взаимодействия с OpenOCD.
>> Запуск сеанса клиента GDB для взаимодействия с OpenOCD
Откройте еще одно окно терминала и введите следующую команду:
> "C:\Apps\AC6GCC\bin\arm-none-eabi-gdb.exe"
Эта команда просто запускает arm-none-eabi-gdb.exe
GDB клиент. Если все идет хорошо, GDB запускается со следующим сообщением:
GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20151217-cvs
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-w64-mingw32 --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb)..
Теперь подключите этот клиент GDB к серверу GDB внутри OpenOCD:
(gdb) target remote localhost:3333
Теперь вы подключены к OpenOCD! Полезно знать: если вы хотите использовать встроенную команду OpenOCD (как в сеансе Telnet), просто перед командой введите ключевое слово monitor
, Таким образом, сервер GDB внутри OpenOCD не будет обрабатывать саму команду, а передает ее родному демону OpenOCD.
Итак, теперь пришло время перезагрузить чип, стереть его и остановить его:
(gdb) monitor reset halt
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
(gdb) monitor halt
(gdb) monitor flash erase_address 0x08000000 0x00100000
erased address 0x08000000 (length 1048576) in 8.899024s (115.069 KiB/s)
(gdb) monitor reset halt
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
(gdb) monitor halt
Теперь чип готов получить некоторые инструкции от нас. Сначала мы скажем чипу, что его разделы флэш-памяти от 0 до 7 (это все разделы флэш-памяти в моем 1Mb чипе) не должны быть защищены:
(gdb) monitor flash protect 0 0 7 off
(gdb) monitor flash info 0
#0 : stm32f7x at 0x08000000, size 0x00100000, buswidth 0, chipwidth 0
# 0: 0x00000000 (0x8000 32kB) not protected
# 1: 0x00008000 (0x8000 32kB) not protected
# 2: 0x00010000 (0x8000 32kB) not protected
# 3: 0x00018000 (0x8000 32kB) not protected
# 4: 0x00020000 (0x20000 128kB) not protected
# 5: 0x00040000 (0x40000 256kB) not protected
# 6: 0x00080000 (0x40000 256kB) not protected
# 7: 0x000c0000 (0x40000 256kB) not protected
Затем я снова останавливаю чип. Просто чтобы убедиться..
(gdb) monitor halt
Наконец я сдаю двоичный файл .elf
файл в GDB:
(gdb) file C:\\..\\myProgram.elf
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from C:\..\myProgram.elf ...done.
Сейчас момент истины. Я прошу GDB загрузить этот двоичный файл в чип. Скрещенные пальцы:
(gdb) load
Loading section .isr_vector, size 0x1c8 lma 0x8000000
Loading section .text, size 0x39e0 lma 0x80001c8
Loading section .rodata, size 0x34 lma 0x8003ba8
Loading section .init_array, size 0x4 lma 0x8003bdc
Loading section .fini_array, size 0x4 lma 0x8003be0
Loading section .data, size 0x38 lma 0x8003be4
Error finishing flash operation
К сожалению, это не удалось. Я получаю следующее сообщение в OpenOCD:
Error: error waiting for target flash write algorithm
Error: error writing to flash at address 0x08000000 at offset 0x00000000
РЕДАКТИРОВАТЬ: Исправлена проблема с оборудованием.
Видимо это была аппаратная проблема. Я никогда не думал, что мой чип будет дефектным, так как загрузка двоичного файла на чип с помощью утилиты STLink Utility работала без проблем. Только OpenOCD жаловался и давал ошибки. Поэтому, естественно, я обвинил OpenOCD, а не сам чип. Смотрите мой ответ ниже для более подробной информации.
РЕДАКТИРОВАТЬ: Альтернативный элегантный способ прошить чип - используя makefile!
Когда проблема будет решена, сейчас я сосредоточусь на альтернативном способе выполнения прошивки и отладки чипа. Я считаю, что это действительно интересно для сообщества!
Вы могли заметить, что я использовал команды Windows cmd для выполнения всех необходимых шагов. Это может быть автоматизировано в пакетном файле. Но есть более элегантный способ: автоматизировать все в make-файле! Mr./Mss. Отан предложил следующий make-файл для своего Cortex-M? чип. Я полагаю, что процедура для чипа Cortex-M7 очень похожа:
#################################################
# MAKEFILE FOR BUILDING THE BINARY #
# AND EVEN FLASHING THE CHIP! #
# Author: Othane #
#################################################
# setup compiler and flags for stm32f373 build
SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
CROSS_COMPILE ?= arm-none-eabi-
export CC = $(CROSS_COMPILE)gcc
export AS = $(CROSS_COMPILE)gcc -x assembler-with-cpp
export AR = $(CROSS_COMPILE)ar
export LD = $(CROSS_COMPILE)ld
export OD = $(CROSS_COMPILE)objdump
export BIN = $(CROSS_COMPILE)objcopy -O ihex
export SIZE = $(CROSS_COMPILE)size
export GDB = $(CROSS_COMPILE)gdb
MCU = cortex-m4
FPU = -mfloat-abi=hard -mfpu=fpv4-sp-d16 -D__FPU_USED=1 -D__FPU_PRESENT=1 -DARM_MATH_CM4
DEFS = -DUSE_STDPERIPH_DRIVER -DSTM32F37X -DRUN_FROM_FLASH=1 -DHSE_VALUE=8000000
OPT ?= -O0
MCFLAGS = -mthumb -mcpu=$(MCU) $(FPU)
export ASFLAGS = $(MCFLAGS) $(OPT) -g -gdwarf-2 $(ADEFS)
CPFLAGS += $(MCFLAGS) $(OPT) -gdwarf-2 -Wall -Wno-attributes -fverbose-asm
CPFLAGS += -ffunction-sections -fdata-sections $(DEFS)
export CPFLAGS
export CFLAGS += $(CPFLAGS)
export LDFLAGS = $(MCFLAGS) -nostartfiles -Wl,--cref,--gc-sections,--no-warn-mismatch $(LIBDIR)
HINCDIR += ./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/CMSIS/Include/ \
./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/CMSIS/Device/ST/STM32F37x/Include/ \
./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/STM32F37x_StdPeriph_Driver/inc/ \
./
export INCDIR = $(patsubst %,$(SELF_DIR)%,$(HINCDIR))
# openocd variables and targets
OPENOCD_PATH ?= /usr/local/share/openocd/
export OPENOCD_BIN = openocd
export OPENOCD_INTERFACE = $(OPENOCD_PATH)/scripts/interface/stlink-v2.cfg
export OPENOCD_TARGET = $(OPENOCD_PATH)/scripts/target/stm32f3x_stlink.cfg
OPENOCD_FLASH_CMDS = ''
OPENOCD_FLASH_CMDS += -c 'reset halt'
OPENOCD_FLASH_CMDS += -c 'sleep 10'
OPENOCD_FLASH_CMDS += -c 'stm32f1x unlock 0'
OPENOCD_FLASH_CMDS += -c 'flash write_image erase $(PRJ_FULL) 0 ihex'
OPENOCD_FLASH_CMDS += -c shutdown
export OPENOCD_FLASH_CMDS
OPENOCD_ERASE_CMDS = ''
OPENOCD_ERASE_CMDS += -c 'reset halt'
OPENOCD_ERASE_CMDS += -c 'sleep 10'
OPENOCD_ERASE_CMDS += -c 'sleep 10'
OPENOCD_ERASE_CMDS += -c 'stm32f1x mass_erase 0'
OPENOCD_ERASE_CMDS += -c shutdown
export OPENOCD_ERASE_CMDS
OPENOCD_RUN_CMDS = ''
OPENOCD_RUN_CMDS += -c 'reset halt'
OPENOCD_RUN_CMDS += -c 'sleep 10'
OPENOCD_RUN_CMDS += -c 'reset run'
OPENOCD_RUN_CMDS += -c 'sleep 10'
OPENOCD_RUN_CMDS += -c shutdown
export OPENOCD_RUN_CMDS
OPENOCD_DEBUG_CMDS = ''
OPENOCD_DEBUG_CMDS += -c 'halt'
OPENOCD_DEBUG_CMDS += -c 'sleep 10'
.flash:
$(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_FLASH_CMDS)
.erase:
$(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_ERASE_CMDS)
.run:
$(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_RUN_CMDS)
.debug:
$(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_DEBUG_CMDS)
Уважаемый г-н / г-жа Отан, не могли бы вы объяснить, как использовать этот make-файл для следующих шагов:
- Сборка двоичного файла из исходного кода
- Прошить чип
Я знаю некоторые основы о make-файлах, но ваш make-файл действительно идет довольно глубоко. Кажется, вы используете довольно много возможностей утилиты make GNU. Пожалуйста, дайте нам больше объяснений, и я предоставлю вам бонус;-)
------------------------------
5 ответов
Насколько я помню, у меня были некоторые проблемы с командой прямой загрузки, поэтому я переключился на "flash write_image erase my_project.hex 0 ihex" .. очевидно, я использовал шестнадцатеричные файлы, но похоже, что эльфийские файлы должны работать, см. http://openocd.org/doc/html/Flash-Commands.html... хорошая особенность этой команды в том, что она также удаляет только те флэш-разделы, которые записываются, что действительно удобно, и вам не нужно стирать
Перед выполнением вышеуказанной команды вам нужно будет запустить "stm32f1x unlock 0", чтобы убедиться, что чип разблокирован и разрешено подключение к флэш-памяти... См. Таблицу данных об этом
Также для начала работы команда "stm32f1x mass_erase 0" полностью и быстро сотрет чип, поэтому хорошо убедиться, что вы стартуете в известном состоянии.
Я знаю, что некоторые из этих команд говорят, что они предназначены для f1, но поверьте мне, они работают для серии f4, чтобы
Кстати, этот файл содержит большую часть команды, которую я использую для прошивки своего f4, так что это может быть хорошей ссылкой https://github.com/othane/mos/blob/master/hal/stm32f373/stm32f373.mk
Я надеюсь, что вы отклеились
На первый взгляд, дистрибутив на gnutoolchains.com должен быть достаточно хорошим. Существует ряд сценариев сборки для создания собственной версии. У меня есть мой, чтобы включить ARM7TDMI. Он отлично работает под Linux и FreeBSD, но MinGW не удалось в прошлый раз, когда я попробовал:-(
Что касается OpenOCD, я бы порекомендовал запустить его в том же каталоге, что и ваш экземпляр GDB, чтобы бинарная загрузка выглядела прозрачной, если вы вызываете ее из GDB (самый простой способ). У вас также есть возможность создать скрипт, который запускает OpenOCD и загрузить код, но затем вам придется перезапускать его после каждой компиляции.
Это немного кратко и не очень хорошо подходит для стекового потока, но я хотел бы указать на мой код, в котором я настроил его для моей библиотеки "mos" для STM32F4 и STM32F1 ( https://github.com/othane/mos).. Это большая тема, чтобы ответить, поэтому я, хотя пример может быть лучше
Короче говоря, мой проект - это дерево Makefiles, так как ваш код, компилирующий основной, интересующий вас, находится здесь https://github.com/othane/mos/blob/master/hal/stm32f373/stm32f373.mk... в основном вам нужен openocd, а затем у меня есть ряд команд, позволяющих стереть чип, или прошить и отладить новый код и т. д., просто набрав make.erase или make.flash или make.debug
наконец, если вы посмотрите на мои модульные тесты (это в основном примеры программ), вы найдете Makefile для его сборки + файл gdbinit, как этот https://github.com/othane/mos/blob/master/utest/gpio/debug_gpio_utest.gdbinit... тогда вы просто делаете "make && make .flash && make .debug" в одном терминале и вызываете свой кросс-компилятор gdb как этот "arm-none-eabi-gdb -x ./debug_gpio_utest.gdbinit" в другое... это запустит GDB после перепрошивки кода, и вы можете использовать обычные команды break и list из GDB и т. д. для взаимодействия с кодом (обратите внимание, как я определил команду сброса в файле.gdbinit, обратитесь к справке для mon команда... в основном это позволит вам отправлять команды через gdb напрямую в openocd и очень полезно)
Извините, ответ довольно краткий и содержит множество ссылок, но я надеюсь, что это поможет вам.
Теперь вы просто вызываете "gdb" и подключаете его к "удаленному серверу" (localhost, если сервер и gdb работают на одной машине). Настройте GDB так, чтобы он знал местоположение исходного кода и местоположение файла ELF. Есть тонна веб-сайтов, которые проходят основное использование GDB.
Кажется, что есть GDB для Windows ( http://www.equation.com/servlet/equation.cmd?fa=gdb)
Следующие команды в GDB должны помочь вам начать:
целевой удаленный локальный хост:3333
каталог / путь / к / проекту
файл символов /path/to/project.elf
Видимо это была аппаратная проблема. Я никогда не думал, что мой чип будет дефектным, так как загрузка двоичного файла на чип с помощью утилиты STLink Utility работала без проблем. Только OpenOCD жаловался и давал ошибки. Поэтому, естественно, я обвинил OpenOCD, а не сам чип.
Сегодня я попробовал ту же самую процедуру с новым чипом на плате, и теперь он работает!
Я получаю следующий вывод в GDB при выдаче load
команда:
(gdb) load
Loading section .isr_vector, size 0x1c8 lma 0x8000000
Loading section .text, size 0x39e0 lma 0x80001c8
Loading section .rodata, size 0x34 lma 0x8003ba8
Loading section .init_array, size 0x4 lma 0x8003bdc
Loading section .fini_array, size 0x4 lma 0x8003be0
Loading section .data, size 0x38 lma 0x8003be4
Start address 0x8003450, load size 15388
Transfer rate: 21 KB/sec, 2564 bytes/write.
(gdb)
Спасибо всем, кто сделал все возможное, чтобы помочь мне:-)