Стандартный (недорогой) способ программирования 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. Пожалуйста, дайте нам еще несколько объяснений, и я дам вам бонус; -)