разработка и программирование электронных устройств

Программирование AVR и ARM микроконтроллеров в Eclipse. Часть 2

В первой части статьи был рассмотрен процесс разработки программ для микроконтроллеров 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 и выполняют установку нового значения символу. При компиляции проекта везде в тексте программы символ будет заменен на его значение.

Рассмотрим следующий фрагмент кода:

22
23
24
25
26
27
28
29
     .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 ).

30
31
32
33
34
35
36
37
38
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 , а все остальные директивы загружают в счетчик команд адреса обработчиков.

39
40
41
42
43
44
45
46
47
48
49
50
_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

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

51
52
.size _boot, . - _boot	@ ;размер кода функции _boot равен разнице текущего адреса и адреса _boot
.endfunc		@;конец функции _boot

Теперь объявляем три глобальные метки, по которым можно перейти на следующий код. Код программы всегда начинается с функции _start.

53
54
55
56
57
.global _start, start, _mainCRTStartup
        .func   _start
_start:
start:
_mainCRTStartup:

Далее выполняем инициализацию указателей вершин стеков для всех режимов работы процессора ARM7.

58
    ldr   r0,=_stack

Величина стека задана в скрипте компоновщика( далее будет описан ).

59
60
61
 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 адрес вершины стека для следующего режима.
Аналогичным образом выполняется инициализация для всех остальных режимов.

62
63
64
65
66
67
68
69
70
71
72
73
74
75
  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 память микроконтроллера.

76
77
78
79
80
81
82
 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 нолями:

83
84
85
86
87
88
   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.

89
90
91
92
93
94
95
96
 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 и ее окончание.

97
98
.size   _start, . - _start
        .endfunc

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

99
100
101
102
103
104
105
106
107
108
   .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 . название скрипта. Имя файла и расширение для компоновщика не имеют значения. Пример :

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 указывает на то, что далее будет описана карта распределения памяти для скомпонованного объектного модуля. Точка указывает на текущий адрес, то есть строка
. = 0×00000000 устанавливает текущий адрес в абсолютный со значением 0×00000000. После установки текущего адреса он будет автоматически увеличиваться при добавлении элементов в выходной файл.

Оператор .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 на концептуальном уровне выглядит так :

Цель :   Зависимость
 { символ табуляции }Способ достижения цели

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

Если, например, нам необходимо откомпилировать исходный файл 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 выглядела следующим образом :

openocd -f interface/ftdi_jtag.cfg -f target/lpc2148.cfg

Запускаем отладку. Процесс остановиться на входе в функцию main, поскольку мы установили точку прерывания в этом месте. Дальше запускаем пошаговое выполнение и наблюдаем включение-выключение светодиода.

24 Comments to Программирование AVR и ARM микроконтроллеров в Eclipse. Часть 2

  1. sasha's Gravatar sasha
    30 января 2011 at 23:23 | Permalink

    В инициализационном файле crt0, когда происходит переход к функции main, каким образом цпу поменяет режим??как он узнает,что нужно перходить именно в режим ARM?зачем = перед всеми глобальными переменными ( типа ldr r10,=main )?.
    .global main является глобальной.Те комманды
    ldr r10,=main
    mov lr,pc
    bx r10
    заставят компилятор перейти к функции main,что в файле main.c,Те int main(void) тоже является меткой??

  2. sasha's Gravatar sasha
    31 января 2011 at 22:27 | Permalink

    А как Вы знаете,какие адреса для памяти нужно задавать в скрипте для компоновищика

    MEMORY
    {
    rom(rx) : ORIGIN = 0×00000000, LENGTH = 512k
    ram(rw) : ORIGIN = 0×40000000, LENGTH = 96k
    }

    Я вот работаю с arm966e-s, и в результате
    monitor flash write_image erase unlock ./main.hex 0×08000000 ihex
    получаю,что gdb при работе с openocd пишет,что на данном адресе нет flash

  3. sasha's Gravatar sasha
    4 февраля 2011 at 22:44 | Permalink

    В скрипте линковщика Вы отводите паямять под flash и под sram. На команду

    monitor flash write_image ./main.out

    получаю примерно то,что писал выше.Сектор .text записывается нормально. Но дело в том что по адресу 0х0400,куда я записываю .data, .bss (т.е. в SRAM), получаю сообщение об ошибке. Есть ли какие нибудь способы указать openocd.что данный сектор не flash, a sram?или указать это в скрипте линковщика

    Карта памяти чипа

  4. sasha's Gravatar sasha
    4 февраля 2011 at 23:02 | Permalink

    Четче
    Получается,что используются одна команда openocd – flash, для загрузки в sram и flash

  5. sasha's Gravatar sasha
    5 февраля 2011 at 12:01 | Permalink

    CPU: STR912FW44X

    Запуск openocd

    подключение к openocd через gdb. Стирание и снятие блокировки провожу раздельно,иначе,если это делать через write_image,все виснет. (Вопрос:разве должно стирание происходить так долго(13.6 с)? )

    ENTRY(_boot)

    STACK_SIZE = 0×400;

    MEMORY

    {

    rom(rx) : ORIGIN = 0×00000000, LENGTH = 512k

    ram(rw) : ORIGIN = 0×04000000, LENGTH = 32k

    }

    SECTIONS

    {

    . = 0×00000000;

    .text : {

    KEEP(*(.init))

    *(.text)

    *(.rodata)

    }>rom

    _etext = .;

    . = 0×04000000;

    .data : {

    _data = .;

    *(.data)

    }>ram

    _edata = .;

    .bss : {

    __bss_start = .;

    *(.bss)

    }>ram

    __bss_end__ = .;

    .stack : {

    . += STACK_SIZE;

    PROVIDE (_stack = .);

    }>ram

    _end = .;

    }

  6. sasha's Gravatar sasha
    7 февраля 2011 at 21:59 | Permalink

    Я решил проблему,используя load_image. flash write_image отказывается прошивать sram.

    Хмм,у меня такой вопрос:как быстро у вас работает jtag? операцию записи он проводит c 0,2 кб\с. Стирание 512K происходит за 13 сек. В чем дело?

  7. sasha's Gravatar sasha
    13 февраля 2011 at 15:12 | Permalink

    Команда load в gdb загружает в отладчик(gdb) исполняемый файл чтобы тот мог с ним работать,устанавливать точки останова ,но не в процессор. Каким образом вы,уже работая в Eclipse, прошиваете чип?ведь судя по скринам с Eclipse,приведёнными вами выше, с конфигурацией openocd и gdb в среде, происходит только их настройка,а команд для прошивки (flash write_image или в моем случае это load_image) я что-то не увидел.

  8. sasha's Gravatar sasha
    13 февраля 2011 at 17:45 | Permalink

    Вот смотрите. Как вы считаете,если я сконфигурирую Run в Commands таким образом

    monitor soft_reset_halt
    monitor load_image ./main.out 0
    monitor soft_reset_halt
    monitor arm7_9 dbgrq enable
    monitor gdb_breakpoint_override hard
    tbreak main
    continue

    будет ли целесообразно каждый раз при начале отдебаживания прошивать контроллер

  9. sasha's Gravatar sasha
    6 марта 2011 at 19:00 | Permalink

    Подскажите,правильно ли я делаю:
    мне нужно разместить одну сишную функцию в sram, и я делаю так

    _data:
    ldr pc,_FMI_Config
    _FMI_Config: .word FMI_Config

    Вроде как FMI_Config должен разместиться вначале sram.

Leave a Reply

You must be logged in to post a comment.