В первой части статьи был рассмотрен процесс разработки программ для микроконтроллеров AVR в инструментальной среде Eclipse. В конце первой части представлена общая схема разработки программ для ARM в Eclipse с помощью GNU Tool chain.
Используя практику многосерийных фильмов, напомню окончание первой части статьи и сразу же продолжу изложение материала.
Итак, процесс разработки программ в Eclipse для ARM микроконтроллеров с помощью GNU Tool chain изображен на следующей схеме.
Из схемы видно, что исходные файлы на языках С и Assembler компилируются с помощью arm-none-eabi-gcc. Компилятор arm-none-eabi-gcc может осуществлять вызов ассемблера arm-none-eabi-as, компоновщика arm-none-eabi-ld, поэтому в нашем Makefile вместо них будет указан arm-none-eabi-gcc.
В результате компиляции получается один или несколько объектных файлов. Далее компоновщик arm-none-eabi-ld выполняет компоновку объектных модулей в памяти микроконтроллера. Для микроконтроллеров с архитектурой ARM код программы может находиться в разных областях памяти( FLASH, SRAM и т.д. ).
На размещение кода и данных внутри микроконтроллера можно влиять путем создания файла сценария компоновки. Сценарий компоновки передает линкеру адрес и размер доступных в микроконтроллере объемов памяти, предписывает компоновщику размещение секций программы по конкретным адресам .
Чтобы написать скрипт компоновки необходимо иметь перед глазами карту памяти используемого микроконтроллера. Для большинства микроконтроллеров ARM можно найти готовый файл сценария.
После компоновки создается один файл исполняемого образа программы в формате elf .
Этот файл содержит всю необходимую для выполнения программ информацию, но его нельзя непосредственно загрузить в микроконтроллер.
Для этого необходимо выполнить преобразование утилитой arm-none-eabi-objcopy в один из доступных для прошивки форматов ( bin , intel hex, motorola S-records и т.д. ).
Из полученного после компоновки elf- файла можно получить листинг кода программы на языке ассемблера с помощью утилиты arm-none-eabi-objdump.
Makefile на нашей схеме изображен отдельно , в нем находиться предписание для утилиты make для сборки всего проекта.
При использовании для разработки программ языка С в большинстве случаев применяется стартовый код, — так называемый C — startup код, который выполняет начальную инициализацию микроконтроллера и передает управление основной функции main программы на С.
Стартовый код написан на языке ассемблера. Его вовсе не обязательно разрабатывать самостоятельно, поскольку для всех поддерживаемых GNU Tool chain микроконтроллеров он входит в состав инструментальной среды. В большинстве случаев стартовый код поставляется в виде откомпилированного объектного модуля, который в процессе компоновки вашего проекта присоединяется к нему.
Однако мы рассмотрим более детально стартовый код для различных архитектур ядра ARM.
Далее изображен пример стартового файла crt0.S микроконтроллера компании NXP LPC2138 с архитектурой ядра ARM7. Будем рассматривать этот код частями сверху-вниз.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
.global main @ ;int main(void) .global _etext @ ;инициализированные данные в ROM( FLASH ) .global _data @ ;массив данных в RAM .global _edata @ ;конец массива данных в RAM .global __bss_start @ ;начало инициализированных данных (bss-секция) в RAM .global __bss_end__ @ ;конец bss .global _stack @ ;адрес вершины стека .set UND_STACK_SIZE, 0x00000004 @ ;Размеры стеков различных режимов .set ABT_STACK_SIZE, 0x00000004 .set FIQ_STACK_SIZE, 0x00000004 .set IRQ_STACK_SIZE, 0X00000080 .set SVC_STACK_SIZE, 0x00000004 .set MODE_USR, 0x10 @ ;режим USER .set MODE_FIQ, 0x11 @ ;режим FIQ .set MODE_IRQ, 0x12 @ ;режим IRQ .set MODE_SVC, 0x13 @ ;режим Supervisor .set MODE_ABT, 0x17 @ ;режим Abort .set MODE_UND, 0x1B @;режим Undefined .set MODE_SYS, 0x1F @ ;режим System .equ I_BIT, 0x80 @ ;установка I бита прерываний IRQ .equ F_BIT, 0x40 @ ;установка F бита FIQ |
В этой части кода выполняются объявления. Директива ассемблера (GNU-ASM) .global делает указанный после директивы символ глобальным, это значит, что данный символ можно будет использовать в других модулях программы.
Директивы ассемблера .set и .equ аналогичны директиве #define в языке C и выполняют установку нового значения символу. При компиляции проекта везде в тексте программы символ будет заменен на его значение.
Рассмотрим следующий фрагмент кода:
1 2 3 4 5 6 7 8 |
.text .arm .section .init, "ax" .code 32 .align 2 .global _boot .func _boot _boot: |
Директива .text указывает на начало сегмента кода, все следующие за ней директивы будут размещены в секции «text».
Далее при помощи директивы .arm указывается, что будет использован набор команд ARM.
Для процессоров ARM7 всего существует два набора команд — ARM и Thumb. Второй режим включает набор 16-разрядных команд и предназначен для увеличения плотности кода программы.
Объявление .section .init, «ax» декларирует секцию внутри сегмента кода с названием init и с помощью флагов «ax» указывает на то , что раздел является перемещаемым и содержит исполняемый код.
Директива .code 32 указывает на 32-разрядный код , а директива .align указывает на выравнивание кода по 16-ти разрядам (двум байтам). Метка _boot является глобальной (.global) и указывает на начало функции (.func _boot ).
1 2 3 4 5 6 7 8 9 |
Vectors: b _start @ ;eset - _start ldr pc,_undf @ ;undefined - _undf ldr pc,_swi @ ;SWI - _swi ldr pc,_pabt @ ;program abort - _pabt ldr pc,_dabt @ ;data abort - _dabt nop @ ;reserved ldr pc,[pc,#-0xFF0] @ ;IRQ - read the VIC ldr pc,_fiq @ ;FIQ - _fiq |
Далее расположена таблица векторов прерываний. Директива b _start выполняет переход на адрес _start , а все остальные директивы загружают в счетчик команд адреса обработчиков.
1 2 3 4 5 6 7 8 9 10 11 12 |
_undf: .word __undf @; undefined _swi: .word __swi @ ;SWI _pabt: .word __pabt @ ;program abort _dabt: .word __dabt @ ;data abort _irq: .word __irq @ ;IRQ _fiq: .word __fiq @ ;FIQ __undf: b . @ ;undefined __swi: b . @ ;SWI __pabt: b . @ ;program abort __dabt: b . @; data abort __irq: b . @; IRQ __fiq: b . @; FIQ |
В этом варианте обработчики содержат бесконечный цикл. При необходимости можно организовать функцию-обработчик соответствующего вектора прерывания.
1 2 |
.size _boot, . - _boot @ ;размер кода функции _boot равен разнице текущего адреса и адреса _boot .endfunc @;конец функции _boot |
Теперь объявляем три глобальные метки, по которым можно перейти на следующий код. Код программы всегда начинается с функции _start.
1 2 3 4 5 |
.global _start, start, _mainCRTStartup .func _start _start: start: _mainCRTStartup: |
Далее выполняем инициализацию указателей вершин стеков для всех режимов работы процессора ARM7.
1 |
ldr r0,=_stack |
Величина стека задана в скрипте компоновщика( далее будет описан ).
1 2 3 |
msr CPSR_c,#MODE_UND|I_BIT|F_BIT @; Undefined Instruction Mode mov sp,r0 sub r0,r0,#UND_STACK_SIZE |
В расположенном выше фрагменте кода мы перешли в режим «Undefined Instruction», запретив прерывания установкой I_BIT и F_BIT. Потом загрузили в SP адрес вершины стека из R0. Вычли из текущего значения в R0 размер стека режима «Undefined Instruction» и получили в R0 адрес вершины стека для следующего режима.
Аналогичным образом выполняется инициализация для всех остальных режимов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
msr CPSR_c,#MODE_ABT|I_BIT|F_BIT @ ;Abort Mode mov sp,r0 sub r0,r0,#ABT_STACK_SIZE msr CPSR_c,#MODE_FIQ|I_BIT|F_BIT @ ;FIQ Mode mov sp,r0 sub r0,r0,#FIQ_STACK_SIZE msr CPSR_c,#MODE_IRQ|I_BIT|F_BIT @; IRQ Mode mov sp,r0 sub r0,r0,#IRQ_STACK_SIZE msr CPSR_c,#MODE_SVC|I_BIT|F_BIT @ ;Supervisor Mode mov sp,r0 sub r0,r0,#SVC_STACK_SIZE msr CPSR_c,#MODE_SYS|I_BIT|F_BIT @; System Mode mov sp,r0 |
Следующая инициализация необходима, если код предназначен для загрузки в FLASH память микроконтроллера.
1 2 3 4 5 6 7 |
ldr r1,=_etext @ ; ROM data start ldr r2,=_data @ ; data start ldr r3,=_edata @; end of data 1: cmp r2,r3 @; check if data to move ldrlo r0,[r1],#4 @ ;copy it strlo r0,[r2],#4 blo 1b @ ;loop until done |
Заполняем секцию .bss нолями:
1 2 3 4 5 6 |
mov r0,#0 @; get a zero ldr r1,=__bss_start @; -- bss start ldr r2,=__bss_end__ @; -- bss end 2: cmp r1,r2 @; check if data to clear strlo r0,[r1],#4 @; clear 4 bytes blo 2b @; loop until done |
И , наконец, выполняем передачу управления функции main.
1 2 3 4 5 6 7 8 |
mov r0,#0 @; no arguments (argc = 0) mov r1,r0 mov r2,r0 mov fp,r0 @; null frame pointer mov r7,r0 @; null frame pointer for thumb ldr r10,=main mov lr,pc bx r10 @; enter main() |
Подсчет размера функции _start и ее окончание.
1 2 |
.size _start, . - _start .endfunc |
Бесконечный цикл, переход на который можно совершать из ненужных векторов прерываний или ошибочных ситуаций.
1 2 3 4 5 6 7 8 9 10 |
.global _reset, reset, exit, abort .func _reset _reset: reset: exit: abort: b _reset @; loop until reset .size _reset, . - _reset .endfunc .end |
Для процессорного ядра Cortex-M3 стартовый код вообще является необязательным. В «Кортексах» вся программа может быть написана на языке программирования С.
При компиляции описанного выше стартового кода необходимо указать компилятору использовать режим ARM, а точнее ничего не указывать, так как по-умолчанию код компилируется для режима ARM.
Раздельная компиляция ARM и Thumb исходных кодов, находящихся в разных файлах, является специфической особенностью компилятора GCC.
Для того, чтобы откомпилировать исходный текст программы в режиме Thumb необходимо указать компилятору ключ -mthumb. Если в проект входят файлы, откомпилированные в ARM и Thumb режимах и между ними выполняется вызов функций , то необходимо также указать компоновщику ключ -mthumb-interwork, который позволит осуществлять переход между режимами ARM и Thumb во время выполнения кода.
При сборке программы из объектных модулей компоновщик использует скрипт компоновки, в котором указывается размещение секций внутри памяти микроконтроллера. Если этот скрипт явно не указывать , то будет использоваться встроенный по-умолчанию в компоновщик скрипт.
Для подключения собственного файла скрипта необходимо указать компоновщику с помощью опции -T . название скрипта. Имя файла и расширение для компоновщика не имеют значения. Пример :
1 |
arm-none-eabi-ld -T script.link -o main.out main.o |
Компоновщик вырабатывает исполняемый файл с настраиваемыми адресами. Эти адреса устанавливаются каждый раз при загрузке модуля в память. Каждый раздел описывается двумя адресами — виртуальным адресом (VMA) и загружаемым в память адресом (LMA). Первый предназначен для внутреннего использования, а второй указывает на расположение памяти, куда будет загружен раздел. Процесс определения адреса модуля называется его размещением.
Компоновщик объединяет созданные компилятором объектные файлы в один объектный файл, который содержит разделы( секции ). Каждый раздел имеет свое имя и размер. Секции с одинаковыми именами объединяются в один раздел. Разделы могут содержать исполняемый код, инициализированные значения данных , неинициализированные данные, для которых указывается только имя раздела и размер.
Рассмотрим пример сценария компоновщика для микроконтроллера LPC2138 ( ARM7 ).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
ENTRY(_boot) STACK_SIZE = 0x400; MEMORY { rom(rx) : ORIGIN = 0x00000000, LENGTH = 512k ram(rw) : ORIGIN = 0x40000000, LENGTH = 32k } SECTIONS { . = 0x00000000; .text : { KEEP(*(.init)) *(.text) *(.rodata) }> rom _etext = .; . = 0x40000000; .data : { _data = .; *(.data) }> ram _edata = .; .bss : { __bss_start = .; *(.bss) }>ram __bss_end__ = .; .stack : { . += STACK_SIZE; PROVIDE (_stack = .); }>ram _end = .; } |
Ключевое слово MEMORY используется для присвоения имен блокам адресного пространства. В данном примере указывается местоположение и размер памяти микроконтроллера. Внутренней FLASH памяти присваивается название rom, а внутреннее ОЗУ микроконтроллера поименовано как ram. Атрибуты памяти (rx) указывают на то, что содержимое памяти может читаться и выполняться, аналогичным образом атрибуты (rw) указывают на возможность чтения и записи в данной области памяти.
Ключевое слово SECTIONS указывает на то, что далее будет описана карта распределения памяти для скомпонованного объектного модуля. Точка указывает на текущий адрес, то есть строка
. = 0x00000000 устанавливает текущий адрес в абсолютный со значением 0x00000000. После установки текущего адреса он будет автоматически увеличиваться при добавлении элементов в выходной файл.
Оператор .text : { } помещает начало секции .text выходного файла по текущему адресу. В скобках указываются элементы, которые будут включены в раздел .text выходного файла. Можно указать конкретные имена входных файлов ( компонуемых объектных файлов), в данном примере указаны все ( оператор * ) имена входных файлов.
Строка >rom указывает на то, что данный раздел будет помещен в именованную область памяти rom (то есть в FLASH память ).
Наименования основных секций для компоновщика являются предопределеннымы. В секции .text находиться код программы, также там могут находиться константы (.rodata). Секция .data предназначена для размещения данных , а в секции .bss находятся инициализированные нулевым значением данные. Туда попадают,например, статические переменные в языке С, которые только объявлены, но должны содержать нулевое начальное значение. Поэтому заполнение секции .bss нулевыми значениями производиться в стартовом коде перед вызовом функции main.
Именованные разделы размещаются в том порядке, в котором они указаны. Раздел .bss в нашем примере будет находиться сразу после раздела .data, поскольку для него не указан начальный адрес.
Компоновщику, по большому счету, все-равно на каком языке программирования написан программный модуль, скомпилированный в объектный и используемый в качестве входного . Вы можете использовать при компоновке объектные модули, написанные на языках программирования С и Assembler, как это делается при подключении стартового кода. В большинстве случаев такая необходимость не возникает, поскольку объема памяти и производительности современных микроконтроллеров достаточно для применения языка С.
Все программы из пакета ARM Tool chain( в качестве ARM Tool chain может выступать пакет Sourcery G++, Yagarto и т.д ) имеют интерфейс командной строки. Можно последовательно вызывать из командной строки компилятор, компоновщик, утилиты для преобразования и прошивки исполняемого файла. А можно записать всю последовательность вызовов в Makefile, запустить утилиту make и наблюдать за результатами выполнения команд, перечисленных в Makefile.
В отличии от командного файла Makefile не просто содержит последовательность выполняемых команд, он описывает так называемые зависимости.
Общая форма записи в Makefile на концептуальном уровне выглядит так :
1 2 |
Цель : Зависимость { символ табуляции }Способ достижения цели |
В качестве цели может выступать файл, зависимость содержит все файлы, от которых зависит целевой файл. В качестве способа достижения цели может быть вызов компилятора с определенными параметрами в командной строке.
Если, например, нам необходимо откомпилировать исходный файл main.c, потом скомпоновать объектный модуль main.o и стартовый код crt0.o в исполняемый образ main.out, далее преобразовать main.out в формат intel-hex , а также получить ассемблерный листинг программы, то Makefile будет содержать такие записи :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.PHONY: all clean all : main.hex main.lst main.lst : main.out @echo "Копирую листинг... " arm-none-eabi-objdump -S -D main.out > main.lst main.hex : main.out @echo "Преобразовываю в формат intel-hex... " arm-none-eabi-objcopy -O ihex main.out main.hex main.out : main.o crt0.o @echo "Выполняется компоновка..." arm-none-eabi-ld -nostartfiles -Tscript.link -o main.out crt0.o main.o main.o : main.c @echo "Выполняется компиляция ..." arm-none-eabi-gcc -Wall -gdwarf-2 -mcpu=arm7tdmi-s -c main.c -o main.o crt0.o : crt0.s @echo "Выполняется компиляция ..." arm-none-eabi-gcc -c -mcpu=arm7tdmi-s -gdwarf-2 -adlhs crt0.s -o crt0.o clean: @echo "Очистка файлов *.o, *.out, *.hex ... " rm *.o *.out *.hex *.lst |
Цели all и clean называются псевдоцелями, это просто символьные метки,которые используются для запуска цепочки зависимостей из Makefile. Директива .PHONY: all clean перечисляет все псевдоцели, которые могут вызываться указанием названия цели в командной строке утилиты make.
Если мы запустим утилиту make с параметром all в командной строке, то активируется цель all. Утилита make проанализирует зависимость цели all — файлы main.hex и main.lst. Если эти файлы уже существуют, то на этом работа утилиты прекратится. При первом запуске у нас в наличии есть только исходные файлы crt0.s и main.c.
Содержимое main.c :
1 2 3 4 5 6 7 8 |
int main( void ); static int i; int main() { i = 1; for(;;); return 0; }/* main */ |
Далее анализируется файл main.hex, для его получения необходим main.out. В свою очередь для получения main.out необходимы объектные файлы crt0.o и main.o, которые можно получить из исходных файлов компиляцией. Все действия будут выполнены в обратном порядке для удовлетворения зависимостей. Сначала будут откомпилированы файлы crt0.s и main.c, потом скомпонованы в main.out, а уж после этого из main.out будут получены main.hex и main.lst.
Как видите, ничего сложного в составлении Makefile нет, необходимо научиться правильно создавать зависимости и знать опции используемых утилит( компилятор, компоновщик и т. д.).
Поэкспериментируйте с описанными выше файлами, поместите файлы Makefile, main.c, script.link, crt0.s в один каталог , запустите командную строку, перейдите с помощью команды cd в созданный каталог и наберите в командной строке make all. Потренироваться в написании скрипта компоновки можно путем его редактирования и просмотра результатов компоновки в файле листинга программы main.lst. Команда make clean, набранная из командной строки, удалит все созданные в результате выполнения make all файлы.
Настало время вернуться к Eclipse. Создадим новый проект с названием ARM7_project и добавим к нему все описанные выше файлы. Можете загрузить готовый проект.
Предоставленный код выполняет мерцание светодиодом, подключенным на первый вывод микроконтроллера LPC2138 ( PORT0.21 ), светодиод зажигается при высоком уровне на выводе PORT0.21 и гаснет при низком. Для понимания логики работы этого простого примера рекомендую почитать книгу Т. Мартин «Микроконтроллеры ARM7. Семейство LPC2000 компании Philips. Вводный курс».
Для отладки кода внутри кристалла микроконтроллера используем адаптер FTDI JTAG. Если Вы внимательно читали мои предыдущие статьи на этом сайте, то настраивать Eclipse для использования отладки Вы должны уметь.
В Fedora 13 Electronic Lab окно проекта, созданное в Eclipse Helios под Windows 7 , выглядело следующим образом.
В свежей версии FEL обновлять openocd до версии 0.4.0 не пришлось, так эта версия установлена изначально. Единственное, что пришлось установить, — это Sourcery G++. Путь к каталогу с утилитами из пакета Sourcery G++ в переменной PATH после перезагрузки потерялся, поэтому пришлось явно указать в Makefile расположение необходимых утилит.
Для отладки в Eclipse под FEL 13 вместо знакомого нам плагина ZylinCDT теперь используется GDB Hardware Debugging Plug-in.
На следующих рисунках изображены необходимые для запуска отладки в Eclipse под Fedora 13 (FEL) настройки.
Строка запуска openocd выглядела следующим образом :
1 |
openocd -f interface/ftdi_jtag.cfg -f target/lpc2148.cfg |
Запускаем отладку. Процесс остановиться на входе в функцию main, поскольку мы установили точку прерывания в этом месте. Дальше запускаем пошаговое выполнение и наблюдаем включение-выключение светодиода.
Viewed 31079 times by 8092 viewers
Comments
В инициализационном файле crt0, когда происходит переход к функции main, каким образом цпу поменяет режим??как он узнает,что нужно перходить именно в режим ARM?зачем = перед всеми глобальными переменными ( типа ldr r10,=main )?.
.global main является глобальной.Те комманды
ldr r10,=main
mov lr,pc
bx r10
заставят компилятор перейти к функции main,что в файле main.c,Те int main(void) тоже является меткой??
В GCC для процессоров ARM компиляция исходных файлов для режима ARM и Thumb выполняется раздельно. По-умолчанию используется система команд ARM, для компиляции в Thumb необходимо
установить опции компилятора -mthumb и -mthumb-interwork( для перехода между режимами ARM и Thumb )
Почитайте тут ( страница 99 )
int main(void); — объявление функции main, которое просто указывает компилятору, что далее по тексту будет реализация функции,
.global main — показывает компоновщику, что реализация main будет в другом объектном модуле ( равносильно extern в языке С ) (
страница 53 в руководстве по GNU-AS, указанному выше )
А как Вы знаете,какие адреса для памяти нужно задавать в скрипте для компоновищика
Я вот работаю с arm966e-s, и в результате
monitor flash write_image erase unlock ./main.hex 0×08000000 ihex
получаю,что gdb при работе с openocd пишет,что на данном адресе нет flash
Нужно смотреть в документации карту памяти конкретного микроконтроллера. Просмотрите документацию на ваш микроконтроллер, могут быть отличия от карты памяти, приведенной для ядра arm966e-s
Попробуйте выяснить размер и расположение flash- памяти с помощью команд
flash banks
flash list
flash probe (num)
Если память не заблокирована , то ключ unlock нужно убрать, иначе могут быть ошибки.
Поищите готовый скрипт компоновщика для вашей модели ( семейства) МК
В скрипте линковщика Вы отводите паямять под flash и под sram. На команду
получаю примерно то,что писал выше.Сектор .text записывается нормально. Но дело в том что по адресу 0х0400,куда я записываю .data, .bss (т.е. в SRAM), получаю сообщение об ошибке. Есть ли какие нибудь способы указать openocd.что данный сектор не flash, a sram?или указать это в скрипте линковщика
Карта памяти чипа
Четче
Получается,что используются одна команда openocd — flash, для загрузки в sram и flash
Напишите тип микроконтроллера, текст Вашего скрипта компоновки и параметры при запуске в командной строке openocd
В скрипте компоновщика явно указывается в какую область памяти нужно положить секцию:
Знак больше после фигурной скобки в конце секции и потом название типа памяти
Да,я знаю,вы писали об этом.
CPU: STR912FW44X
Запуск openocd
подключение к openocd через gdb. Стирание и снятие блокировки провожу раздельно,иначе,если это делать через write_image,все виснет. (Вопрос:разве должно стирание происходить так долго(13.6 с)? )
Попробуйте сначала прошить контроллер силами openocd :
openocd -f olimex-arm-usb-ocd.cfg -f str912.cfg -c init -c targets -c "halt" -c "flash write_image erase unlock ./main.out 0x00000000 elf" -c "reset run" -c shutdown
Я решил проблему,используя load_image. flash write_image отказывается прошивать sram.
Хмм,у меня такой вопрос:как быстро у вас работает jtag? операцию записи он проводит c 0,2 кб\с. Стирание 512K происходит за 13 сек. В чем дело?
wrote 1024 bytes from file CMSIS_example.out in 0.240986s (4.150 kb/s)
Частота работы JTAG у меня 1000 кГц :
Info : clock speed 1000 kHz
А у Вас 16 кГц :
Обратите внимание на аналогичную строчку для LPC2138 в статье :
Попробуйте увеличить значение частоты в файле str912.cfg :
# jtag speed. We need to stick to 16kHz until we've finished reset.
jtag_rclk 16
Спасибо. Еще вопрос: в gdb команда continue продолжает выполнение команды до брэйкпоинта. Я устанавливаю метку break main,значит программа должна остановиться на этой метке, но это не происходит,а gdb не то что бы виснет,но после continue ничего не выполняет. Есть только строчка «Note: automatically using hardware breakpoints for read-only addresses». Означает ли это что точка останова не поставлена?
Если поможет,то вот скрин
Скорее всего Вы устанавливаете точку останова не имея привязки к своему коду.
С прошитым контроллером попробуйте заново запустить openocd . Далее gdb :
# cd ПУТЬ_К_ELF_ФАЙЛУ
# arm-none-eabi-gdb ./main.out
(gdb) target remote localhost:3333
В ответ gdb должен выдать адрес, с которого стартует Ваша программа и реальное содержимое по этому адресу
Далее:
(gdb) break main
(gdb) continue
Спасибо
Команда load в gdb загружает в отладчик(gdb) исполняемый файл чтобы тот мог с ним работать,устанавливать точки останова ,но не в процессор. Каким образом вы,уже работая в Eclipse, прошиваете чип?ведь судя по скринам с Eclipse,приведёнными вами выше, с конфигурацией openocd и gdb в среде, происходит только их настройка,а команд для прошивки (flash write_image или в моем случае это load_image) я что-то не увидел.
Команда load
image( в примере установлена галочка напротив «load image» ) выполняет программирование микроконтроллера, это команда gdb, а write_image( и load_image ) — команда openocd, которую можно выполнить без привлечения gdbВот смотрите. Как вы считаете,если я сконфигурирую Run в Commands таким образом
будет ли целесообразно каждый раз при начале отдебаживания прошивать контроллер
Если исходный код программы изменен, то каким образом, по Вашему мнению, не прошивая контроллер можно запустить внутрисхемную отладку? Пользуйтесь симулятором, если не хотите каждый раз прошивать заново память контроллера или загружайте Вашу программу в ОЗУ, а не в FLASH. Если же программа не изменилась, то отладку можно запустить и без команды load( write_image, load_image) , то есть без повторной загрузки образа в память микроконтроллера.
Попробуйте заменить Openocd-команду load_image на gdb -команду load в настройках Eclipse ( или установить галочку «load image» , как у меня в примере ).
Эта команда более универсальна, с ее помощью можно загрузить прошивку как в Flash-память , так и в RAM (с соответствующим загрузке в RAM скриптом компоновки), можно вообще не загружать, если программа не изменялась ( стр. 209 в документации на gdb ).
monitor soft_reset_halt
load
monitor arm7_9 dbgrq enable
monitor gdb_breakpoint_override hard
tbreak main
continue
Подскажите,правильно ли я делаю:
мне нужно разместить одну сишную функцию в sram, и я делаю так
Вроде как FMI_Config должен разместиться вначале sram.
Исполняемый код ( которым является С — функция ) должен размещаться в секции .text.
В одном проекте можно разместить все секции .text либо в ОЗУ , либо в FLASH(Документация на компоновщик стр. 42).
Comments are closed.