Как использовать 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. Эти команды могут быть простыми «останов», «запустить», «установить точку останова», ...

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

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

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

>> Запуск OpenOCD

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

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

Ваш ответ на вопрос