Как использовать GDB (отладчик Gnu) и OpenOCD для отладки микроконтроллеров - от терминала?

Стандартный (недорогой) способ программирования ARM-микроконтроллеров - использование Eclipse со сложной привязкой к нему. Eclipse, безусловно, имеет свои достоинства, но я бы хотел чувствовать независимость от этой среды разработки. Я хотел бы узнать, что происходит за кулисами, когда я создаю (компиляцию - ссылку - flash) свое программное обеспечение и когда запускаю сеанс отладки. Чтобы получить более глубокое понимание, было бы замечательно запустить всю процедуру из командной строки.

Примечание. Я использую 64-разрядную Windows 10. Но большинство вещей, объясненных здесь, также применимы к системам Linux. Откройте все командные терминалы с правами администратора. Это может сэкономить массу проблем.

1. Построение программного обеспечения

Первая "миссия" выполнена. Теперь я могу скомпилировать и связать свое программное обеспечение с двоичным .bin и .elf изображением через командную строку. Ключом к успеху стало выяснение того, где Eclipse ставит свои make файлы для конкретного проекта. Как только вы узнаете, где они находятся, все, что вам нужно сделать, это открыть командный терминал и ввести команду GNU make.

введите описание изображения здесь

Вам больше не нужен Eclipse! Особенно, если вы можете читать (и понимать) make файл и настраивать его в соответствии с вашими потребностями, когда ваш проект продвигается.

Обратите внимание, что я нашел инструменты GNU (компилятор, компоновщик, make utility, 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, когда вы нажимаете значок "debug". Eclipse также предоставляет некоторые файлы конфигурации для OpenOCD - так, что OpenOCD знает, как подключиться к вашему микроконтроллеру. "Как подключиться" - это не тривиальная вещь. OpenOCD необходимо найти правильный USB-драйвер для подключения к адаптеру JTAG (например, STLink). Как адаптер JTAG, так и его USB-драйвер обычно поставляются производителем чипов (например, STMicroelectronics). Eclipse также передает файл конфигурации в OpenOCD, который описывает спецификации микроконтроллера. Как только OpenOCD знает обо всех этих вещах, он может сделать надежное соединение JTAG с целевым устройством.

  • OpenOCD запускает два сервера. Первым из них является сервер Telnet на TCP-порту 4444. Он предоставляет доступ к CLI OpenOCD (интерфейс командной строки). Клиент Telnet может подключать и отправлять команды OpenOCD. Этими командами могут быть просто "стоп", "запустить", "установить точку останова",...

  • Такие команды могут быть достаточными для отладки вашего микроконтроллера, но многие люди уже знакомы с Gnu Debugger (GDB). Именно поэтому OpenOCD также запускает сервер GDB на TCP-порт 3333. Клиент GDB может подключиться к этому порту и начать отладку микроконтроллера!

  • Отладчик Gnu - это программное обеспечение командной строки. Многие люди предпочитают визуальный интерфейс. Это именно то, что делает Eclipse. Eclipse запускает клиент GDB, который подключается к OpenOCD, но все это скрыто от пользователя. Eclipse предоставляет графический интерфейс, который взаимодействует с клиентом GDB за кулисами.

Я сделал цифру, чтобы объяснить все это:

введите описание изображения здесь

→ Запуск OpenOCD

Мне удалось запустить OpenOCD из командной строки. Я объясню, как.

  • Сначала убедитесь, что ваш программник STLink-V2 JTAG установлен правильно. Вы можете протестировать установку с помощью утилиты STLink Utility от 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 и подключаете его к TCP-порту localhost:3333.

→ Запуск сеанса Telnet для взаимодействия с OpenOCD

Вот как вы запускаете сеанс Telnet для взаимодействия с текущей программой OpenOCD:

> dism /online /Enable-Feature /FeatureName:TelnetClient

> telnet 127.0.0.1 4444

Если он работает хорошо, вы получите следующее сообщение на своем терминале:

Open On-Chip Debugger
> ..

И вы готовы отправить Commmands на 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.

Итак, теперь пришло время reset чипа, стереть его и остановить его:

    (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 - и не сам чип. См. Мой ответ ниже для более подробной информации.


EDIT: альтернативный элегантный способ flash-чипа - использование make файла!

По мере исправления проблемы я теперь сосредоточусь на альтернативном способе выполнения флеш-памяти и отладки чипа. Я считаю, что это действительно интересно для сообщества!

Возможно, вы заметили, что я использовал команды cmd для Windows, чтобы выполнить все необходимые шаги. Это может быть автоматизировано в пакетном файле. Но есть более элегантный способ: автоматизировать все в make файле! Mr./Mss. Othane предложил следующий файл для своего 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) 

Уважаемый господин /Mss. Othane, не могли бы вы объяснить, как использовать этот make файл для следующих шагов:

  • Создайте двоичный код из исходного кода
  • Вспышка чипа

Я знаю некоторые основы make файлов, но ваш make файл действительно идет довольно глубоко. Кажется, вы используете некоторые функции утилиты GNU make. Пожалуйста, дайте нам еще несколько объяснений, и я дам вам бонус; -)

------------------------------

Ответы

Ответ 1

Как я помню, у меня были некоторые проблемы с командой прямой загрузки, поэтому я переключился на "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

Надеюсь, что ты расстегнёшься

Ответ 2

Это немного короткий и не большой стиль stackoverflow, но я бы указал вам на мой код, где я установил это для своей библиотеки "mos" для STM32F4 и STM32F1 (https://github.com/othane/mos)... Это большая тема для ответа, поэтому, хотя пример может быть лучше

Короче говоря, мой проект - это дерево Make файлов, так как у вас есть сводный код, основной интерес для вас находится здесь https://github.com/othane/mos/blob/master/hal/stm32f373/stm32f373.mk... в основном вам нужен openocd, а затем у меня есть серия команд, позволяющих стирать чип или мигать и отлаживать новый код и т.д., просто набрав make.erase или сделайте .flash или сделайте .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 и т.д. для взаимодействия с кодом (обратите внимание, как я определил команду reset в .gdbinit file, checkout help для команды mon... в основном это позволит вам отправлять команды через gdb непосредственно в openocd и действительно полезно)

Извините, что ответ довольно короткий и много ссылок, но я надеюсь, что он вам поможет.

Ответ 3

На первый взгляд, распределение на gnutoolchains.com должно быть достаточно хорошим. Существует несколько версий script to brew вашей собственной версии. У меня есть мой, чтобы включить ARM7TDMI. Он отлично работает под Linux и FreeBSD, но MinGW потерпел неудачу в прошлый раз, когда я попробовал: - (

Что касается OpenOCD, я бы рекомендовал запустить его в том же каталоге, что и ваш экземпляр GDB, так что бинарная загрузка кажется прозрачной, если вы вызываете ее из GDB (самый простой способ). У вас также есть возможность создать script, который запустит OpenOCD и загрузит код, но затем вам придется перезапустить его после каждой компиляции.

Ответ 4

Теперь вы просто вызываете "gdb" и подключаете его к "удаленному серверу" (localhost, если сервер и gdb работают на одном компьютере). Настройте GDB таким образом, чтобы он знал местоположение исходного кода и местоположение файла ELF. Существует тонна сайтов, которые проходят основное использование GDB.

Кажется, есть GDB для Windows (http://www.equation.com/servlet/equation.cmd?fa=gdb)

Следующие команды в GDB должны начать работу:

target remote localhost: 3333

каталог/путь/в/проект

symbol-file/path/to/project.elf

Ответ 5

По-видимому, это была проблема с оборудованием. Я никогда не думал, что мой чип будет дефектом, так как загрузка двоичного файла на чип с помощью утилиты 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)

Спасибо всем, кто сделал все возможное, чтобы помочь мне: -)