Рик Кимбалл
Ср. 18 июля 2018 г. 18:05
Я работаю над пользовательской средой Arduino, и моя последняя цель-автоматизация загрузки и отладка с использованием openocd с Stlink-V2 на Linux. Я прикрепил свой сценарий Arduino-Debugger Bash. В моем случае это вызвано с моей пользовательской платформы.TXT и доски.текст . Тем не менее, мой сценарий также может быть полезен для остальных. Это может быть вызвано из командной строки в сочетании с запущенным Arduino IDE.
Обновление: в качестве альтернативы, вы можете взглянуть на прикрепленный zip -файл для использования с ядром Roger's Libmaple, непосредственно из Arduino IDE.
Предполагая, что я тестирую сценарий под названием working_leds. Я собрал его и загрузил на свой чертеж, и Arduino все еще работает. Я посмотрел в /tmp и вижу, что каталог сборки - это /tmp /arduino_build_14749, вот как я призываю его только делать отладка:
$ ./arduino -debugger -d1 /tmp /arduino_build_14749.ino no_upload
Вот как это выглядит на моем рабочем столе:
Примечание. Этот скрипт предполагает, что исполняемые файлы openocd и arm-none-ebi-gdb находятся на вашем пути.
Файл: Arduino-Debugger
Обновление: в качестве альтернативы, вы можете взглянуть на прикрепленный zip -файл для использования с ядром Roger's Libmaple, непосредственно из Arduino IDE.
Предполагая, что я тестирую сценарий под названием working_leds. Я собрал его и загрузил на свой чертеж, и Arduino все еще работает. Я посмотрел в /tmp и вижу, что каталог сборки - это /tmp /arduino_build_14749, вот как я призываю его только делать отладка:
$ ./arduino -debugger -d1 /tmp /arduino_build_14749.ino no_upload
Вот как это выглядит на моем рабочем столе:
Примечание. Этот скрипт предполагает, что исполняемые файлы openocd и arm-none-ebi-gdb находятся на вашем пути.
Файл: Arduino-Debugger
#!/bin/bash
# File: arduino-debugger - upload and auto-launch debugger
# Desc: linux specific uploader and debugger using openocd and arm-none-eabi-gdb
# note: this might work on Mac OS/X (not tested)
#
# Author: Rick Kimball
#
#set -x
export ARG_CNT="$#"
if [ ${ARG_CNT} -lt 3 ]; then
echo "usage: $0 [-d0|-d1] arduino_build_tmp_path sketch [no_upload]"
echo " debug flag - openocd debug flags [-d0 silent|-d1 verbose]"
echo " arduino_build_tmp_path - the temp /tmp/arduino_build_nnnnn directory"
echo " sketch - the sketch name .. blink.ino"
echo " [no_upload] - optionally skip upload, just debug"
echo " example:"
echo " $0 -d1 /tmp/arduino_build_433659 blink.ino"
exit 1
fi
export TOOLS_DIR=$(dirname $0)
export DEBUG_FLG=${1}
export BUILD_DIR=${2}
export SKETCH=${3}
export BIN_FILE=${BUILD_DIR}/${3}.bin
export HEX_FILE=${BUILD_DIR}/${3}.hex
export ELF_FILE=${BUILD_DIR}/${3}.elf
#-----------------------------------------------------------------------
# if you define OPENOCD_TARGET we use it, if not we default to stm32f1x.cfg
if [ -z ${OPENOCD_TARGET+x} ]; then
export OPENOCD_TARGET=stm32f1x.cfg
fi
#----------------------------------------------------------------------------
# if openocd is hanging around, kill it
killall openocd >/dev/null 2>&1
set -e # worry about errors and exit from now on
#----------------------------------------------------------------------------
cd "${BUILD_DIR}"
#----------------------------------------------------------------------------
# upload to the board using the .bin or .hex file
if [ ${ARG_CNT} -eq 3 ]; then
if [ -f ${BIN_FILE} ]; then
openocd ${DEBUG_FLG} -f interface/stlink.cfg -f target/${OPENOCD_TARGET} \
-c "program ${BIN_FILE} verify reset exit 0x08000000"
else
openocd ${DEBUG_FLG} -f interface/stlink.cfg -f target/${OPENOCD_TARGET} \
-c "program ${HEX_FILE} verify reset exit"
fi
else
echo "skipping upload will use firmware already on flash"
fi
#----------------------------------------------------------------------------
# start up openocd server in the background minimized
xterm -geometry 80x43 -iconic \
-T 'Arduino GDB Server' \
-e openocd -f interface/stlink.cfg -f target/${OPENOCD_TARGET} &
#----------------------------------------------------------------------------
# start up the arm-none-eabi-gdb ui and wait for it to exit
xterm -geometry 100x45 -bg \#ffffe0 -fg \#000000 \
-T 'Arduino Debugger' \
-e arm-none-eabi-gdb \
-n \
-ex 'set print repeats 1024' \
-ex 'set pagination off' \
-ex 'set confirm off' \
-ex 'set mem inaccesible-by-default off' \
-ex "source ${TOOLS_DIR}/armv7m-vecstate.gdb" \
-ex 'target remote :3333' \
-ex 'mon reset init' \
-ex 'tbreak setup' \
-ex 'layout split' \
-ex 'continue' \
"${ELF_FILE}"
set +e
#----------------------------------------------------------------------------
# if anything went wrong this will kill the openocd gdb server
killall openocd >/dev/null 2>&1
exit 0
Рик Кимбалл
Ср. 18 июля 2018 г. 18:57
Вот пример отладки жесткого качества, вызванного эскизом доступа к неверному адресу памяти. В мой код я добавил строку:
volatile uint8_t crashme = *(volatile uint8_t *) 0x30000000; // Неверный адрес Это плохой код, он пытается получить доступ к 0x30000000, который является неверным адресом. В конце концов, он окажется в моем обработчике исключений по умолчанию (который является лишь вечным циклом). Обычно вы попадаете в обработчик исключений и не узнаете, почему он не исправит. Потому что я автоматически включаю Vectstate.Скрипт GDB в Arduino-Debugger вы можете вызвать эту пользовательскую команду GDB и выяснить, какая линия кода вызвала вашу проблему.
Вот как это выглядит непосредственно перед тем, как код вызовет инструкцию с плохим доступом:
После того, как я продолжил команду GDB 'C', она застряла и перестала работать. В командной строке GDB я нажал Ctrl+C, чтобы прервать выполнение, а затем набрал команду GDB «Vecstate», чтобы увидеть, что вызвало твердую ошибку:
Код был в загруженном цикле из -за вызова обработчика исключений Hardfault. Занятая петля - это инструкция:
0x80003a0 <Reset_handler+48> беременный.n 0x80003a0 <Reset_handler+48>
Команда VECSTATE ходит по стеку и запрашивает регистры системы, чтобы выяснить, откуда она и что было вызвано исключением. Вы можете видеть, что он идентифицирует working_leds.Ино, строка 55 в качестве источника аварии ... Довольно хорошо!
volatile uint8_t crashme = *(volatile uint8_t *) 0x30000000; // Неверный адрес Это плохой код, он пытается получить доступ к 0x30000000, который является неверным адресом. В конце концов, он окажется в моем обработчике исключений по умолчанию (который является лишь вечным циклом). Обычно вы попадаете в обработчик исключений и не узнаете, почему он не исправит. Потому что я автоматически включаю Vectstate.Скрипт GDB в Arduino-Debugger вы можете вызвать эту пользовательскую команду GDB и выяснить, какая линия кода вызвала вашу проблему.
Вот как это выглядит непосредственно перед тем, как код вызовет инструкцию с плохим доступом:
После того, как я продолжил команду GDB 'C', она застряла и перестала работать. В командной строке GDB я нажал Ctrl+C, чтобы прервать выполнение, а затем набрал команду GDB «Vecstate», чтобы увидеть, что вызвало твердую ошибку:
Код был в загруженном цикле из -за вызова обработчика исключений Hardfault. Занятая петля - это инструкция:
0x80003a0 <Reset_handler+48> беременный.n 0x80003a0 <Reset_handler+48>
Команда VECSTATE ходит по стеку и запрашивает регистры системы, чтобы выяснить, откуда она и что было вызвано исключением. Вы можете видеть, что он идентифицирует working_leds.Ино, строка 55 в качестве источника аварии ... Довольно хорошо!
fpistm
Ср. 18 июля 2018 г. 20:24
Спасибо, Рик.
michael_l
Чт, 19 июля, 2018, 19:37
Рик, это очень круто !
Вассилис
Пт 20 июля 2018 г. 13:45
Прохладный !
Рик Кимбалл
Sun 22 июля 2018 г., 18:49
В первом посте этого потока я добавил zip-файл, который содержит изменения и мой скрипт Arduino-Debugger для использования с ядром Roger's Libmaple. Он добавляет еще один метод загрузки «openocd+отладка». Пункт меню запускает сценарий Arduino-Debugger из Arduino IDE. Он загрузит код с помощью openocd, а затем начнет сеанс отладки.
Я только добавил этот метод загрузки на плату GenericStm32f103c (так иначе плата Bluepill). Если вы хотите использовать его с другими досками, вы можете скопировать пасту, что я сделал с досками.txt file. Кроме того, я тестировал только с Linux, он, вероятно, будет работать для OS/X, но не был протестирован. Однако это окончательно не сработает для Windows.
Я проверил это на эскизе. После нажатия загрузки Arduino-Debugger работает до тех пор, пока вы не выйдете. Из -за этого вы не можете использовать серийный монитор Arduino для просмотра собственного USB -вывода. Это легко решается путем запуска сеанса серийного терминала замазку после начала функции setup (). Ожидание with setup () запускается. После запуска Putty вы можете выпустить команды отладки и одновременно посмотреть серийный вывод.
Я только добавил этот метод загрузки на плату GenericStm32f103c (так иначе плата Bluepill). Если вы хотите использовать его с другими досками, вы можете скопировать пасту, что я сделал с досками.txt file. Кроме того, я тестировал только с Linux, он, вероятно, будет работать для OS/X, но не был протестирован. Однако это окончательно не сработает для Windows.
Я проверил это на эскизе. После нажатия загрузки Arduino-Debugger работает до тех пор, пока вы не выйдете. Из -за этого вы не можете использовать серийный монитор Arduino для просмотра собственного USB -вывода. Это легко решается путем запуска сеанса серийного терминала замазку после начала функции setup (). Ожидание with setup () запускается. После запуска Putty вы можете выпустить команды отладки и одновременно посмотреть серийный вывод.
Стивестронг
Вт 24 июля 2018 г. 9:16 утра
Рик, спасибо за это хорошее руководство.
Вы тоже пытались отладить чип F4?
Вы тоже пытались отладить чип F4?
Рик Кимбалл
Вт 24 июля 2018 г. 11:36 утра
Я не stevestrong. Вам нужно изменить сценарий openocd_target на STM32F4X.CFG, чтобы это работало.
Стивестронг
Вт 24 июля 2018 12:16
Я помню, что у меня были проблемы с отладкой чипа F4 при прохождении кода, окно памяти показало альтернативно разные или недопустимые значения для определенного диапазона памяти (я думаю, что это была область кода). Вот почему я спрашиваю, столкнулись ли вы также с некоторыми проблемами для F4 или нет. И, конечно, я использовал CFG для F4.
Рик Кимбалл
Вт 24 июля 2018 12:25
Какой отладчик вы использовали? Был ли код скомпилирован для отладки или оптимизации?
В целом, оптимизированный код действительно следит за линейным путем через код. Вам нужно посмотреть на код C, код ASM, значения регистрации и память сброса, чтобы следить за происходящим. Следовательно, причина, по которой я открываю с помощью сплит -макета GDB.
В целом, оптимизированный код действительно следит за линейным путем через код. Вам нужно посмотреть на код C, код ASM, значения регистрации и память сброса, чтобы следить за происходящим. Следовательно, причина, по которой я открываю с помощью сплит -макета GDB.
Стивестронг
Вт 24 июля 2018 г. 13:57
Я использовал Eclipse (Sloeber) + OpenOcd, с информацией о отладке.
Несмотря на то, что я думаю, что бы ни использовала оптимизация, область кода не должна показывать разные или недействительные значения при прохождении.
Несмотря на то, что я думаю, что бы ни использовала оптимизация, область кода не должна показывать разные или недействительные значения при прохождении.
Рик Кимбалл
Вт 24 июля 2018 г. 15:52
Я склонен компилировать для оптимизации размера, поэтому я привык к ошибочному шагу C -источнику C. Если вы пройдете на уровне ASM, это, кажется, даст ожидаемые результаты.
Оптимизированный C -код не приравнивает один к одному для произведенного ASM. Оператор C при оптимизировании может использовать код в другом операторе. Когда вы прошли, вы можете покинуть текущую линию и перейти к другой линии в той же функции.
Я склонен использовать инструкции GDB Nexti или (Ni) и STEPI или (SI), чтобы пройти через. Здесь часто используются команды, которые я использую в GDB
Команды GDB написали:(GDB) Помогите Nexti
Шаг первой инструкции, но пройдите через подпрограмму вызовы.
Использование: Nexti [n]
Аргумент n означает шаг n раз (или до того, как программа останавливается по другой причине).
(GDB) Помогите Stepi
Шаг первой инструкции точно.
Использование: Stepi [n]
Аргумент n означает шаг n раз (или до того, как программа останавливается по другой причине).
(GDB) Помощь Информация Регистры
Список целочисленных регистров и их содержимого, для выбранного кадра стека.
Зарегистрировать имя как аргумент означает, что опишите только этот регистр.
(GDB) Помощь x
Осмотрите память: адрес x/fmt.
Адрес является выражением адреса памяти для проверки.
FMT - это счет повторения, за которым следует буква формата и буква размера.
Форматные буквы - O (окт), x (шестнадцатеричный), D (десятичный), U (Decimal), Decimal),
T (BINARY), F (float), A (адрес), I (инструкция), C (char), s (String)
и Z (Hex, нулевой мягкой слева).
Размер буквы B (Byte), H (Halfword), W (Word), G (гигант, 8 байтов).
Указанное количество объектов указанного размера печатается
Согласно формату.
По умолчанию для формата и размеров буквы, которые ранее используются.
Счет по умолчанию составляет 1. Адрес по умолчанию следуют за последним напечатано
С этой командой или «печати».
Оптимизированный C -код не приравнивает один к одному для произведенного ASM. Оператор C при оптимизировании может использовать код в другом операторе. Когда вы прошли, вы можете покинуть текущую линию и перейти к другой линии в той же функции.
Я склонен использовать инструкции GDB Nexti или (Ni) и STEPI или (SI), чтобы пройти через. Здесь часто используются команды, которые я использую в GDB
Команды GDB написали:(GDB) Помогите Nexti
Шаг первой инструкции, но пройдите через подпрограмму вызовы.
Использование: Nexti [n]
Аргумент n означает шаг n раз (или до того, как программа останавливается по другой причине).
(GDB) Помогите Stepi
Шаг первой инструкции точно.
Использование: Stepi [n]
Аргумент n означает шаг n раз (или до того, как программа останавливается по другой причине).
(GDB) Помощь Информация Регистры
Список целочисленных регистров и их содержимого, для выбранного кадра стека.
Зарегистрировать имя как аргумент означает, что опишите только этот регистр.
(GDB) Помощь x
Осмотрите память: адрес x/fmt.
Адрес является выражением адреса памяти для проверки.
FMT - это счет повторения, за которым следует буква формата и буква размера.
Форматные буквы - O (окт), x (шестнадцатеричный), D (десятичный), U (Decimal), Decimal),
T (BINARY), F (float), A (адрес), I (инструкция), C (char), s (String)
и Z (Hex, нулевой мягкой слева).
Размер буквы B (Byte), H (Halfword), W (Word), G (гигант, 8 байтов).
Указанное количество объектов указанного размера печатается
Согласно формату.
По умолчанию для формата и размеров буквы, которые ранее используются.
Счет по умолчанию составляет 1. Адрес по умолчанию следуют за последним напечатано
С этой командой или «печати».
Стивестронг
Вт 24 июля 2018 г., 17:16
Я говорю о окне памяти с фиксированным адресом, он чередуется между показанием хороших значений / все 0 / бессмысленные значения для последовательных шагов.
Вы говорите, что это должен быть процесс обновления затмения? HM, для синей таблетки этого не произошло.
Вы говорите, что это должен быть процесс обновления затмения? HM, для синей таблетки этого не произошло.
Рик Кимбалл
Вт 24 июля 2018 г., 18:26
У меня не установлено Slaeber, но я попробовал атоллический отладчик и оставил окно браузера памяти открытым. Может быть, вы видите, как окно памяти меняется и отображает мусор во время работы.
Единственный раз, когда окно памяти действителен и будет обновлять, - это когда вы нажимаете точку разрыва или когда вы прерываете выполнение. В другое время он не обновляет дисплей. Когда я нажимаю на точку перерыва, я вижу обновление браузера памяти. Я заметил, по крайней мере, в атолике, если память, которую я смотрел.
Тем не менее, это все еще является частью моей точки зрения о графических отладчиках. Когда точка останова достигнута, пользовательский интерфейс Eclipse должен запросить сервер GDB и обновить все значения в окнах, которые видны.
После того, как я сыграл с этим еще, я заметил, что есть способ контролировать частоту обновления браузера памяти. Вы можете проверить, есть ли Sloeber также эта опция:
Я заметил, что если вы выберете «Всегда» по мере того, как вы будете на одном шаге, если изменится память, она обновит. Если вы выбрали «в точке останова», он не обновляется, как вы, но обновят значение, которое содержалось во время точки останова. Если вы выберете «Руководство», если никогда не обновляются, если вы не щелкните правой кнопкой.
Единственный раз, когда окно памяти действителен и будет обновлять, - это когда вы нажимаете точку разрыва или когда вы прерываете выполнение. В другое время он не обновляет дисплей. Когда я нажимаю на точку перерыва, я вижу обновление браузера памяти. Я заметил, по крайней мере, в атолике, если память, которую я смотрел.
Тем не менее, это все еще является частью моей точки зрения о графических отладчиках. Когда точка останова достигнута, пользовательский интерфейс Eclipse должен запросить сервер GDB и обновить все значения в окнах, которые видны.
После того, как я сыграл с этим еще, я заметил, что есть способ контролировать частоту обновления браузера памяти. Вы можете проверить, есть ли Sloeber также эта опция:
Я заметил, что если вы выберете «Всегда» по мере того, как вы будете на одном шаге, если изменится память, она обновит. Если вы выбрали «в точке останова», он не обновляется, как вы, но обновят значение, которое содержалось во время точки останова. Если вы выберете «Руководство», если никогда не обновляются, если вы не щелкните правой кнопкой.