Оглавление:

Часть 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 шагов
Часть 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 шагов

Видео: Часть 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 шагов

Видео: Часть 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 шагов
Видео: Part 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo 2024, Июль
Anonim
Image
Image

Основное внимание в этом руководстве уделяется микроконтроллеру STM32 Nucleo. Мотивация для этого, чтобы иметь возможность создать проект сборки из голых костей. Это поможет нам углубиться и понять проект MSP432 Launchpad (TI-RSLK), который уже был темой нескольких инструкций.

В Интернете не очень много помощи по созданию проекта только для сборки для MSP432 с помощью Code Composer Studio. До сих пор мы просто копировали / вставляли из уже существующего проекта сборки. Такой подход сослужил нам хорошую службу.

Однако сейчас, в лабораторной работе 7, мы столкнулись с небольшой проблемой. Или хотя бы временная икота. Лабораторная работа 7 представляет конечные автоматы, и первое, с чем мы сталкиваемся, - это необходимость создавать и использовать массив значений. Поскольку в курсе TI в основном используется программирование на C - это не проблема. Но эти Instructables сосредоточены на сборке, а не на C.

Кроме того, поскольку массив имеет значения только для чтения, было бы хорошо поместить его во флэш-память, а не в ОЗУ.

Похоже, что в Интернете гораздо больше справки для проектов сборки с использованием MCU STM32, поэтому мы начинаем с этого руководства с целью использовать то, что изучено, чтобы затем применить к MSP432 и Code Composer Studio.

На пути к этой цели у нас также будет опыт работы с еще одним популярным микроконтроллером.

Шаг 1: Начальное тестирование устройства

Первоначальный тест устройства
Первоначальный тест устройства
Первоначальный тест устройства
Первоначальный тест устройства
Первоначальный тест устройства
Первоначальный тест устройства

Опять же, зачем выбирать именно STM32 Nucleo?

Честно? Потому что я искал хорошие статьи по проектам сборки без покрытия для контроллеров ARM, и я наткнулся на эту серию. А также потому, что STM32 кажется популярным MCU.

Я провел небольшое исследование (есть много версий на выбор - см. Изображение выше), но в конце концов это стало тем, что я действительно могу получить, поскольку собирался использовать Amazon (в США).

Он поставляется в простой, но профессиональной упаковке с некоторыми инструкциями по запуску. Было немного забавно видеть, что демо, записанное в контроллер, было почти в точности тем, что мы делали в прошлых Instructables - светодиод мигает и меняет скорость в зависимости от нажатия кнопки.

Кажется, что эта плата разработки очень похожа на MSP432 в том, что есть 2 светодиода и одна пользовательская кнопка. MSP432 имеет 2 пользовательские кнопки.

Как вы можете видеть на фотографиях, я был немного ошеломлен тем, что на плате есть mini, а не micro USB. Пришлось бежать покупать шнур.

Еще один хороший тест: когда вы подключаете его к своему компьютеру (я использую Linux), он отображается в моем файловом менеджере как файловая система под названием «NODE_F303RE». Открытие, которое показывает два файла, один HTML и один текст.

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

Теперь мы готовы начать.

Я постараюсь не повторять какую-либо полезную информацию из серии статей IVONOMICON Bare Metal, а скорее дополню ее.

Шаг 2: Основы

Первым делом нам понадобится компилятор.

А потом нам понадобится отладчик:

devchu @ chubox: ~ $ sudo apt-get install gdb-arm-none-eabiReading списки пакетов… Готово Построение дерева зависимостей Чтение информации о состоянии… Готово Будут установлены следующие НОВЫЕ пакеты: gdb-arm-none-eabi 0 обновлено, 1 недавно установлено, 0 для удаления и 8 не обновлено. Необходимо получить 2 722 КБ архивов. После этой операции будет использовано 7 738 КБ дополнительного дискового пространства. Получить: 1 https://us.archive.ubuntu.com/ubuntu xenial / universe amd64 gdb-arm-none-eabi amd64 7.10-1ubuntu3 + 9 [2, 722 кБ] Получено 2, 722 кБ за 1 с (1, 988 kB / s) Выбор ранее невыбранного пакета gdb-arm-none-eabi. (Чтение базы данных… 262428 файлов и каталогов, установленных на данный момент.) Подготовка к распаковке… / gdb-arm-none-eabi_7.10-1ubuntu3 + 9_amd64.deb… Распаковка gdb-arm-none-eabi (7.10-1ubuntu3 + 9)… Обработка триггеры для man-db (2.7.5-1)… Настройка gdb-arm-none-eabi (7.10-1ubuntu3 + 9)…

Шаг 3. Основы - Windows

Вышеупомянутый шаг предполагал, что мы используем Linux. Что, если мы используем Windows?

Вы можете перейти на сайт разработчика arm, и там доступно несколько вариантов загрузки. Я использую машину с Windows 8.

Во время установки я решил установить его на корневой диск "C: \" вместо Program Files только потому, что я также использую cygwin, и было проще создать ссылку из моего локального бункера на корневую папку C:, чем все остальные беспорядок в пути к программным файлам (с пробелами и т. д.).

Таким образом, моя среда cygwin, путь и т. Д. Выглядят так:

C: / cygwin64 / home / bin / arm-none-eabi-gcc, где arm-none-eabi-gcc - это ссылка на C: / GNUToolsArmEmbedded / 7.2018.q2.update / bin / arm-none-eabi- gcc.

Затем я создал папку «dev» в домашнем каталоге cygwin, куда я поместил файл core. S и выполнил команду компилятора. (подробнее о компиляторе см. ниже).

Я сделал то же самое для gdb (arm-none-eabi-gdb).

Шаг 4: что необходимо

Так что же такое «gcc-arm-none-eabi»?

Компилятор GNU (GCC) будет компилировать языки программирования (например, C) в собственный код для машины, на которой он работает. Например, если вы скомпилируете код C с помощью GCC на вашем компьютере с Windows, он будет создан для работы на компьютере с Windows. Сгенерированный исполняемый файл (обычно) не запускается на микроконтроллере ARM.

Итак, чтобы создавать программы для загрузки и записи в микроконтроллер ARM (в нашем случае это был бы STM32 Nucelo), нам нужно предоставить GCC кое-что еще: возможность «кросс-компиляции». То есть возможность создавать исполняемый файл не для собственной системы (и процессора), а для целевой системы (микроконтроллер ARM). Вот где в игру вступает «gcc-arm-none-eabi».

Так что же тогда такое «gdb-arm-none-eabi»?

После того, как мы загрузили и записали (прошили) вновь созданный исполняемый файл в микроконтроллер, мы, вероятно, захотим отладить его - поэтапно по строке кода. GDB - это отладчик GNU, и ему тоже нужен способ выполнять свою работу, но нацеленный на другую систему.

Таким образом, gdb-arm-none-eabi для GDB то же самое, что gcc-arm-none-eabi для GCC.

Другой предлагаемый пакет для установки - "libnewlib-arm-none-eabi". Что это?

Newlib - это библиотека C и математическая библиотека, предназначенная для использования во встроенных системах. Это совокупность нескольких библиотечных частей, каждая из которых находится под лицензиями бесплатного программного обеспечения, что позволяет легко использовать их во встраиваемых продуктах.

И, наконец, пакет «libstdc ++ - arm-none-eabi». Это довольно очевидно; это библиотека C ++ для кросс-компилятора; для встроенных микроконтроллеров ARM.

Шаг 5: файл компоновщика

Файл компоновщика
Файл компоновщика
Файл компоновщика
Файл компоновщика

Создадим скрипт компоновщика.

Одной из ключевых частей или блоков в этом файле будет команда MEMORY.

--- с sourceware.org:

Конфигурация компоновщика по умолчанию позволяет выделить всю доступную память. Вы можете изменить это с помощью команды MEMORY. Команда MEMORY описывает расположение и размер блоков памяти в целевом объекте. Вы можете использовать его, чтобы описать, какие области памяти могут использоваться компоновщиком и какие области памяти следует избегать. Затем вы можете назначить разделы конкретным областям памяти. Компоновщик установит адреса разделов на основе областей памяти и предупредит о переполнении областей. Компоновщик не будет перемещать разделы, чтобы они поместились в доступные области. Сценарий компоновщика может содержать множество вариантов использования команды MEMORY, однако все определенные блоки памяти обрабатываются так, как если бы они были указаны внутри одной команды MEMORY. Синтаксис для MEMORY следующий.:

ОБЪЕМ ПАМЯТИ

{имя [(attr)]: ORIGIN = origin, LENGTH = len…}

Пример в статье:

/ * Определение конца ОЗУ и предела памяти стека * // * (4 КБ SRAM в строке STM32F031x6, 4096 = 0x1000) * / / * (ОЗУ начинается с адреса 0x20000000) _estack = 0x20001000;

ОБЪЕМ ПАМЯТИ

{FLASH (rx): ORIGIN = 0x08000000, LENGTH = 32K RAM (rxw): ORIGIN = 0x20000000, LENGTH = 4K}

Итак, нам нужно выяснить, сколько FLASH (для нашей программы, констант и т. Д.) И сколько RAM (для использования программой; куча, стек и т. Д.) Для нашей конкретной платы. Это становится немного интересным.

На красивой маленькой карте Nucleo указано, что у нее флэш-память объемом 512 Кбайт, а SRAM - 80 Кбайт. Однако, подключив его к USB, он монтируется как файловая система с двумя файлами, и как файловый менеджер, так и GParted указывают, что у него более 540 Кбайт свободного места. (БАРАН?).

НО, попытка удалить два файла с помощью файлового менеджера, отключение, а затем повторное подключение устройства, по-прежнему показывает два файла. (и файловый менеджер что-то распознал, потому что на каждом файле есть маленький значок «замок».

Итак, давайте перейдем к цифрам на карте. Итак, теперь мы возьмем приведенный выше пример и преобразуем его в нашу конкретную доску.

Вы можете использовать что-то вроде этого онлайн-конвертера памяти, чтобы перейти от общего КБ к определенному количеству байтов.

Тогда вы можете использовать онлайн-конвертер десятичных чисел в шестнадцатеричные.

/ * Определяем конец RAM и предел памяти стека * /

/ * (4KB SRAM в строке STM32F031x6, 4096 = 0x1000) * // * пример * /

/ * шаг 1: (80 КБ SRAM на STM32F303RE, 81920 = 0x14000) * // * наша плата * /

/ * шаг 2, добавляем шестнадцатеричный размер к шестнадцатеричному начальному адресу (ниже). * /

/ * (ОЗУ начинается с адреса 0x20000000) * /

_estack = 0x20001000; /* пример */

_estack = 0x20014000; / * наша доска * /

ОБЪЕМ ПАМЯТИ {

FLASH (rx): ORIGIN = 0x08000000, LENGTH = 512 КБ

RAM (rxw): ORIGIN = 0x20000000, LENGTH = 80 КБ

}

Назовем указанный выше файл «linker.script.ld».

Шаг 6: таблица векторов

Таблица векторов
Таблица векторов

Теперь мы собираемся создать небольшой сборочный файл (с директивами), чтобы выполнить очень простую обработку прерываний. Мы последуем примеру статьи и создадим файл с именем «core. S».

Опять же, вот содержимое файла примера, но я внес изменения для нашей конкретной платы:

// Эти инструкции определяют атрибуты нашего чипа и

// язык ассемблера, который мы будем использовать:.syntax unified / * См. ниже после этой области кода * / /*.cpu cortex-m0 * / / * закомментируйте эту строку примера * /.cpu cortex-m4 / * вместо этого добавьте кору нашей платы. см. изображение выше в этом шаге * / /*.fpu softvfp * / / * закомментируйте эту строку примера * /.fpu vfpv4 / * добавьте вместо этого нашу плату; у него есть FPU * /.thumb // Ячейки глобальной памяти..global vtable.global reset_handler / * * Фактическая таблица векторов. * Для простоты включены только размер ОЗУ и обработчик сброса *. * /.type vtable,% object vtable:.word _estack.word reset_handler.size vtable,.-vtable

Хм.. Нет директивы ".align"

Однако это не критично. Подробнее об этом (возможно) позже.

.syntax унифицированный

.syntax [унифицированный | разделенный]

Эта директива устанавливает синтаксис набора инструкций, как описано в разделе ARM-Instruction-Set.

9.4.2.1 Синтаксис набора команд Для инструкций ARM и THUMB поддерживаются два немного разных синтаксиса. По умолчанию, разделенный, используется старый стиль, в котором инструкции ARM и THUMB имели свой собственный, отдельный синтаксис. Новый унифицированный синтаксис, который можно выбрать с помощью директивы.syntax.

.fpu vfpv4

Компилятор GCC может создавать двоичные файлы с несколькими параметрами, относящимися к плавающей запятой: soft - подходит для работы на ЦП без FPU - вычисления выполняются в программном обеспечении с помощью сгенерированного компилятором softfp - подходит для работы на ЦП с FPU или без него - будет использовать FPU, если он есть. В нашем конкретном случае (вам придется провести собственное исследование) FPU этой конкретной платы соответствует vfpv4. Возможно, вам придется поиграть с этим. Или даже оставьте его на softfp.

.thumb (против.arm)

Эти микроконтроллеры ARM на самом деле имеют набор команд. Один - ARM, другой - THUMB. Одно отличие - 16-битные инструкции против 32-битных инструкций. Таким образом, эта директива указывает компилятору обрабатывать последующие инструкции как THUMB или ARM.

Мы собираемся просто взять оставшуюся часть файла как есть, поскольку эти Instructables еще не вникали в программирование сборки, управляемой прерываниями.

Шаг 7. Сборочная версия программы Hello World

Следующее может также войти в ранее созданный файл "core. S". Это опять же из примера в статье.

/ * * Обработчик Reset. Вызывается при перезагрузке. * /.type reset_handler,% function reset_handler: // Устанавливаем указатель стека в конец стека. // Значение '_estack' определено в нашем скрипте компоновщика. LDR r0, = _estack MOV sp, r0

// Устанавливаем фиктивные значения. Когда мы видим эти ценности

// в нашем отладчике мы будем знать, что наша программа // загружена на микросхему и работает. LDR r7, = 0xDEADBEEF MOVS r0, # 0 main_loop: // Добавляем 1 в регистр 'r0'. ADDS r0, r0, # 1 // Обратный цикл. B main_loop.size reset_handler,.-Reset_handler

Таким образом, задача вышеупомянутой программы состоит в том, чтобы загрузить распознаваемый шаблон в один регистр основного MCU (в данном случае R7) и значение приращения, начинающееся с нуля, в другой регистр основного MCU (в данном случае R0). Если мы пройдемся по исполняемому коду, мы увидим приращение данных R0.

Если вы следовали инструкциям относительно MSP432 и курса / лабораторных работ TI-RSLK, то почти вся вышеуказанная программа должна быть вам знакома.

Единственное, что я вижу, это использование символа «=» при загрузке «DEADBEEF» в регистр R7. Мы этим не пользовались.

Прикрепленный сюда файл "core. S" теперь содержит полный исходный код.

Шаг 8: Компиляция кода

Пора заняться командной строкой. Наконец-то что-то настоящее.

Однако мы еще не совсем там. Нам снова нужно настроить команду, приведенную в статье, и изменить ее в соответствии с нашей ситуацией.

Вот пример кода:

arm-none-eabi-gcc -x ассемблер-with-cpp -c -O0 -mcpu = cortex-m0 -mthumb -Wall core. S -o core.o

Если мы перейдем на сайт gnu.org для GCC (в данном случае версия 7.3),

Икс

-X указывает язык. В противном случае, если нет -x, компилятор попытается угадать, используя расширение файла. (в нашем случае *. S).

В приведенном выше примере из статьи указан ассемблер-с-cpp, но мы могли бы просто сделать ассемблер.

c

-C говорит: «компилировать, но не связывать.

O0

Параметр -O предназначен для установки уровня оптимизации. Использование -O0 (oh-zero) означает «сократить время компиляции и сделать отладку ожидаемыми результатами. Это значение по умолчанию».

mcpu = кора-m0

-Mcpu указывает имя целевого процессора. В нашем случае это cortex-m4.

mthumb

-Mthumb указывает выбор между генерацией кода, который выполняет состояния ARM и THUMB.

Стена

-Wall, конечно, очень распространен и хорошо известен. Включает все предупреждающие флаги.

Наконец, в конце команды у нас есть входной файл core. S и выходной файл core.o.

Вот получившаяся новая командная строка, подходящая для нашего конкретного случая.

arm-none-eabi-gcc -x ассемблер -c -O0 -mcpu = cortex-m4 -mthumb -Wall core. S -o core.o

И это скомпилировано.

Шаг 9: Связывание программы

Непосредственно из примера в статье мы имеем следующее:

arm-none-eabi-gcc core.o -mcpu = cortex-m0 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./STM32F031K6T6.ld -o main.elf

Большинство из вышеперечисленного вы видели. Ниже что нового.

specs = nosys.specs

Это немного сложно объяснить.

Это связано с «полухостингом» и «перенацеливанием», а также с вводом / выводом. Это также связано с системными вызовами и библиотеками.

Обычно встроенные системы не имеют стандартных устройств ввода / вывода. Это повлияет на системные или библиотечные вызовы (пример: printf ()).

Полухостинг означает, что отладчик (см. Изображение шага 11 с отладочной частью, обведенной красным) имеет специальный канал и использует протокол полухостинга, и вы можете видеть вывод printf () на хост-машине (через отладчик).

С другой стороны, ретаргетинг означает, что те же самые системные или библиотечные вызовы означают что-то другое. Они делают что-то еще, что имеет смысл для встроенной системы. В некотором смысле, скажем, для printf (), есть новая реализация, перенаправленная реализация этой функции.

Сказав все это, --specs = nosys.specs означает, что мы не будем использовать полухостинг. Обычно это означает, что мы выполняем ретаргетинг. Это подводит нас к следующему флагу.

nostdlib

Параметр компоновщика -nostdlib используется для компоновки программы, предназначенной для автономного запуска. -nostdlib подразумевает индивидуальные параметры -nodefaultlibs и -nostartfiles. Ниже мы обсуждаем эти два варианта по отдельности, но наиболее типичным является использование nostdlib для универсального использования. При компоновке размещенной программы стандартные системные библиотеки, такие как libc, связываются по умолчанию, предоставляя программе доступ ко всем стандартным функциям (printf, Стрлен и друзья). Параметр компоновщика -nodefaultlibs отключает компоновку с этими библиотеками по умолчанию; связаны только библиотеки, которые вы явно указываете компоновщику с помощью флага -l.

lgcc

libgcc.a - это стандартная библиотека, которая предоставляет внутренние подпрограммы для устранения недостатков конкретных машин. Например, процессор ARM не включает команду деления. Версия libgcc.a для ARM включает функцию деления, и компилятор посылает вызовы этой функции там, где это необходимо.

T

Это просто способ указать компоновщику использовать этот файл в качестве скрипта компоновщика. В нашем случае имя файла - linker.script.ld.

o main.elf

Наконец, мы сообщаем компоновщику, каким будет имя окончательного выходного файла изображения, который будет записан / прошит на нашем устройстве.

Вот наша версия полной командной строки, измененная для нашей конкретной ситуации:

arm-none-eabi-gcc core.o -mcpu = cortex-m4 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./linker.script.ld -o main.elf

Убедитесь, что файл сценария и файл core.o находятся в одном каталоге, в котором мы запустим указанную выше командную строку.

И связывает без проблем.

Проверка

Затем мы запускаем:

рука-none-eabi-nm main.elf

и получаем:

devchu @ chubox: ~ / Development / Atollic / TrueSTUDIO / STM32_workspace_9.1 $ arm-none-eabi-nm main.elf 20014000 A _estack 08000010 t main_loop 08000008 T reset_handler 08000000 T vtable

Выглядит неплохо. Команда arm-none-eabi-nm - это способ перечислить символы в объектных файлах.

Шаг 10: Тестирование подключения к STM32 Nucleo-64

Тестирование Подключение к STM32 Nucleo-64
Тестирование Подключение к STM32 Nucleo-64
Тестирование Подключение к STM32 Nucleo-64
Тестирование Подключение к STM32 Nucleo-64

Ваша первая миссия, если вы решите принять ее, - это заставить вашу систему увидеть вашу доску разработки.

Использование Windows

Для Windows я решил установить TrueSTUDIO от Atollic (бесплатная версия). Это была безболезненная установка, и она автоматически установила драйвер, поэтому я мог использовать st-link для проверки соединения. После того, как я установил TrueSTUDIO и диспетчер устройств увидел устройство, я загрузил инструменты texan / stlink, предложенные в статье о Bare Metal, за которой мы следили. Я снова поместил папку прямо под "C: \" и снова создал несколько ссылок из моей локальной домашней корзины cygwin на команды.

ln -s /c/STM32. MCU/stlink-1.3.0-win64/bin/st-info.exe ~ / bin / st-info

В качестве первоначального теста, чтобы увидеть, действительно ли мы можем общаться с устройством, я выполнил:

st-info --probe

И вернулся:

Найдено 1 программистов stlink

Итак, теперь мы знаем, что можем поговорить / запросить нашу доску разработки.

Использование Linux

Для Linux драйвер действительно не нужен. Но для Debian вам придется собирать инструменты st из исходников.

git clone

Убедитесь, что у вас установлена libusb-1.0-0-dev.

список подходящих | grep -E "* libusb. * dev *"

Тебе следует увидеть:

libusb-1.0-0-dev / xenial, теперь 2: 1.0.20-1 amd64 [установлено]

или что-то подобное.

Чтобы установить его:

sudo apt-get install libusb-1.0-0-dev

Обратите внимание, что приведенное выше не то же самое, что:

sudo apt-get установить libusb-dev

Правильный отсутствующий libusb dev может вызвать проблемы с cmake.

Ошибка CMake: в этом проекте используются следующие переменные, но для них установлено значение NOTFOUND. Задайте их или убедитесь, что они установлены и правильно протестированы в файлах CMake: LIBUSB_INCLUDE_DIR (ADVANCED)

Перейдите в корневой каталог проекта (… blah / blah / stlink). Сделайте «релиз».

После сборки инструменты должны находиться в ".. / build / Release".

Затем вы можете запустить "st-info --probe". Вот результат с подключенным Nucleo, значит, нет.

devchu @ chubox: ~ / Development / stlink $./build/Release/st-info --probeFound 1 stlink programmers serial: 303636414646353034393535363537 openocd: "\ x30 / x36 / x36 / x41 / x46 / x46 / x35 / x30 / x34 / \ x39 / x35 / x35 / x36 / x35 / x37 "flash: 524288 (размер страницы: 2048) sram: 65536 chipid: 0x0446 descr: F303 устройство высокой плотности devchu @ chubox: ~ / Development / stlink $./build/Release/st- info --probe Найдено 0 stlink программистов devchu @ chubox: ~ / Development / stlink $

Шаг 11: давайте использовать GDB с Linux

Давайте использовать GDB с Linux
Давайте использовать GDB с Linux
Давайте использовать GDB с Linux
Давайте использовать GDB с Linux

Если вы все это пробовали, и вы дошли до этого - отлично! Превосходно. Давайте теперь немного повеселимся.

Когда вы покупаете эти платы разработки ARM, будь то панель запуска MSP432 от Texas Instruments или обсуждаемая сейчас, Nucleo-F303 (STM32 Nucleo-64), они обычно приходят уже с запущенной программой, обычно некоторая мигающая программа, которая также включает в себя нажатие переключателя, чтобы изменить частоту мигания светодиода (ов).

Прежде чем мы так быстро переписываем это, давайте посмотрим, что можно увидеть и сделать.

В Linux откройте терминал, перейдите в каталог только что созданного проекта stlink git и найдите инструмент st-util.

devchu @ chubox: ~ / Разработка / stlink $ find. -name st-util

./build/Release/src/gdbserver/st-util

Запустите этот инструмент. Поскольку мы уже ранее тестировали наше соединение с помощью st-info --probe, мы должны получить такой вывод:

devchu @ chubox: ~ / Разработка / stlink $./build/Release/src/gdbserver/st-util

st-util 1.4.0-50-g7fafee2 2018-10-20T18: 33: 23 INFO common.c: Загрузка параметров устройства…. 2018-10-20T18: 33: 23 INFO common.c: Подключено устройство: F303 устройство высокой плотности, id 0x10036446 2018-10-20T18: 33: 23 INFO common.c: Размер SRAM: 0x10000 байт (64 КиБ), Flash: 0x80000 байт (512 КиБ) на страницах по 2048 байт 2018-10-20T18: 33: 23 ИНФОРМАЦИЯ gdb-server.c: ID чипа - 00000446, ID ядра - 2ba01477. 2018-10-20T18: 33: 23 INFO gdb-server.c: Прослушивание по адресу *: 4242…

Это сервер GDB, работающий сейчас, и он видит нашу плату разработки, и, что более важно, он прослушивает порт 4242 (порт по умолчанию).

Теперь мы готовы запустить клиент GDB.

В Linux откройте другой терминал, введите это:

рука-none-eabi-gdb -tui

Это то же самое, что и запуск gdb строго из командной строки, однако вместо этого он создает текстовый терминал (я предполагаю, что он использует проклятия).

У нас запущены клиент GDB и сервер GDB. Однако клиент не подключен к серверу. На данный момент он ничего не знает о нашем Nucleo (или о плате по вашему выбору). Мы должны это сказать. В терминале ваше приглашение теперь должно быть "(gdb)". Входить:

цель помощи

Это даст вам список. Обратите внимание, что нам нужен целевой расширенный удаленный - используйте удаленный компьютер через последовательную линию.

Но мы также должны указать ему местоположение. Итак, в приглашении (gdb) введите:

(gdb) целевой расширенный удаленный локальный хост: 4242

Вы должны получить ответ примерно так:

(gdb) целевой расширенный удаленный локальный хост: 4242

Удаленная отладка с использованием localhost: 4242 0x080028e4 в ?? ()

Тем временем на терминале, на котором запущен st-util gdbserver, мы получили следующее:

2018-10-20T18: 42: 30 INFO gdb-server.c: найдено 6 регистров hw точки останова

2018-10-20T18: 42: 30 INFO gdb-server.c: GDB подключен.

Шаг 12: Давайте повторим, с Windows и Flash наша программа

Давайте повторим, с Windows и Flash наша программа
Давайте повторим, с Windows и Flash наша программа
Давайте повторим, с Windows и Flash наша программа
Давайте повторим, с Windows и Flash наша программа
Давайте повторим, с Windows и Flash наша программа
Давайте повторим, с Windows и Flash наша программа

Шаги по запуску st-util gdbserver и клиента arm-none-eabi-gdb по сути такие же, как и на предыдущем шаге. Вы открываете два терминала (cygwin, DOS cmd или Windows Powershell), находите расположение st-util, запускаете его. В другом терминале запустите клиент arm-none-eabi-gdb. Единственное отличие состоит в том, что режим -tui (текстовое представление на основе терминала), скорее всего, не поддерживается.

Если все вышеперечисленное сработало в Windows, вам, вероятно, придется остановиться (только на клиенте). На этом этапе вам нужно каким-то образом запустить клиент GDB в том месте, где находится ваш файл сборки ("core.out"), или добавить полный путь к этому файлу в качестве аргумента для клиента GDB.

Я упростил себе жизнь, используя cygwin и создав ссылки из моего локального каталога $ HOME // bin, где находятся оба этих инструмента.

Хорошо, мы скомпилировали и скомпилировали, как и раньше, и у нас есть файл main.elf, готовый к прошивке.

У нас в одном окне работает st-util. Мы перезапускаем клиент GDB, на этот раз делаем:

arm-none-eabi-gdb main.elf

Мы позволяем ему запуститься, ждем приглашения (gdb), выполняем ту же команду подключения к серверу GDB (st-util), и мы готовы прошить исполняемый файл. Это очень антиклиматично:

(gdb) загрузка

При работе с терминалами cygwin существует известная проблема, связанная с тем, что иногда консольные команды не выводятся. Таким образом, в нашем случае окно, в котором запущен сервер, было полностью безмолвным. Тот, на котором запущен клиент, на котором мы запускали загрузку, выводит это:

Раздел загрузки.text, размер 0x1c lma 0x8000000 Начальный адрес 0x8000000, размер загрузки 28 Скорость передачи: 1 КБ / сек, 28 байт / запись.

Шаг 13: перепрошивка с помощью Linux - больше наград: D

Прошивка с Linux - больше наград: D
Прошивка с Linux - больше наград: D

Шаг 14: давайте погрузимся немного глубже

Если ты добрался сюда, отлично. Давайте двигаться дальше.

Почему бы не заглянуть внутрь исполняемого файла main.elf? Выполните следующее:

arm-none-eabi-objdump -d main.elf

Вы должны увидеть что-то вроде этого:

main.elf: формат файла elf32-littlearm

Разборка раздела.text:

08000000:

8000000: 00 40 01 20 09 00 00 08.@. ….

08000008:

8000008: 4802 ldr r0, [pc, # 8]; (8000014) 800000a: 4685 mov sp, r0 800000c: 4f02 ldr r7, [pc, # 8]; (8000018) 800000e: 2000 мов r0, # 0

08000010:

8000010: 3001 добавляет r0, # 1 8000012: e7fd b.n 8000010 8000014: 20014000.word 0x20014000 8000018: deadbeef.word 0xdeadbeef

Какие маленькие самородки мы можем получить из вышеприведенного вывода?

Если вы помните, когда мы обсуждали и создавали файл linker.script.ld, мы заявляли, что эти устройства ARM имеют RAM, начинающуюся с 0x20000000, и что FLASH-память начинается с 0x08000000.

Таким образом, мы можем видеть, что программа действительно такова, что все она находится во FLASH-памяти.

Затем, выше, но на более позднем этапе, когда мы обсуждали часть «Hello World», был оператор, в котором мы загружали непосредственное постоянное буквальное значение («0xDEADBEEF») в основной регистр MCU («R7»).

Заявление было:

LDR R7, = 0xDEADBEEF

В нашем коде это единственное место, где мы даже упоминаем DEADBEEF. Нигде более. И все же, если вы посмотрите на приведенные выше дизассемблированные / восстановленные инструкции и т. Д., Вы увидите, что с DEADBEEF есть больше, чем мы думали.

Итак, компилятор / компоновщик каким-то образом решил навсегда прошить значение DEADBEEF во флэш-адрес в местоположении 0x8000018. А затем компилятор изменил нашу указанную выше инструкцию LDR на:

LDR R7, [ПК, №8]

Это даже вызвало для нас комментарий. Как мило. И он говорит нам взять текущее значение программного счетчика (регистр ПК), добавить к этому значению 0x8, и именно там DEADBEEF был записан, и получить это значение и вставить его в R7.

Это также означает, что программный счетчик (ПК) указывал на адрес 0x8000010, который является началом main_loop, и что значение DEADBEEF находится по двум адресам после конца main_loop.

Шаг 15: Наконец, краткий обзор работающей программы

Даже если вы выйдете из GDB, просто введите команду еще раз. Вам даже не нужно передавать ему какой-либо файл; мы больше не мигаем, просто запускаем.

После повторного подключения клиента GDB к серверу GDB в командной строке (gdb):

(gdb) регистры информации

Вы должны увидеть что-то вроде этого:

r0 0x0 0

r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20014000 0x20014000 lr 0xffffffr 0x20014000 0x20014000 lr 0xffffffr 0x800000 16000 0x800000 c200080000 c2

Но затем в приглашении (gdb) введите:

(gdb) продолжить

И очень быстро нажмите CTRL-C. Это должно приостановить программу. Снова введите команду "info registers".

На этот раз все выглядит иначе:

(gdb) регистры информации

r0 0x350ffa 3477498 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0xdeadbeef 3735928559 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0ff 0x09000000 0x14000000 0x14000000 0x14000000 16777216

Что случилось? Именно то, что мы хотели. DEADBEEF был загружен в R7, а R0 (очень быстро) увеличивался. Если вы повторите, вы снова увидите R0 с другим значением.

Шаг 16: мы хотели создать массив только для чтения во Flash

Один из способов создания эквивалента массива с помощью сборки и директив заключается в следующем:

.type myarray,% object // имя или метка myarray определяется как тип объекта.

myarray: // это начало объявления myarray // (из чего он будет состоять)..word 0x11111111 // первый член или значение, содержащееся в myarray..word 0x22222222 // второе значение (смежные адреса)..word 0x33333333 // и так далее..size myarray,. -myarray // компилятор / ассемблер теперь знает, где конец или // граница myarray.

Теперь, когда мы установили его во FLASH-памяти, мы можем использовать его в программе. Ниже представлена часть:

LDR R1, myarray // загружает данные, содержащиеся в 1-м месте myarray. // это не то, что мы хотим.

LDR R1, = myarray // загружает само значение местоположения (1-й адрес), // не данные.. // это то, что мы хотим.

MOV R2, # 0 // R2 будет вести счет, чтобы убедиться, что мы не уйдем

// конец массива. LDR R3, = myarrsize // R3 будет эквивалентом myarrsize.

// R0 будет хранить наши данные

main_loop:

LDR R0, [R1] // Загружаем данные, на которые указывает R1 ('myarray'), в R0. CMP R2, R3 // Находимся ли мы на границе массива? BEQ main_loop // Если мы, мы закончили, поэтому мы просто будем зацикливаться навсегда.

ADD R2, # 1 // В противном случае мы можем продолжить итерацию по массиву.

ADD R1, # 4 // Добавьте 4 в регистр R1, чтобы он правильно указывал на следующий

// адрес..

B main_loop // цикл назад.

Видео проходит все это, и в нем есть ошибка. Это хорошо; это показывает, что это важно для запуска и отладки кода. Он показывает классический случай выхода за пределы массива.

Рекомендуемые: