Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Опять про загрузчик...
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
EXeGLuMATOR
Перечитал все что нашел, по этой теме - так и не дошло в чем проблема.
Итак. Написан загрузчик - все пишется, все обновляется, но не получается передать управление на основную программу. Ремаплю-передаю вот так:
Код
    MEMMAP = 2;                    //Map vector table from RAM
        // Copy vectors table
    src = (unsigned long *)START_ADDR;
    dst = (unsigned long *)0x00000000;
        size = 0x40 / sizeof(*dst);
        do  { *dst++ = *src++; } while (--size);

    //Reset controller
    ((void(*)(void))(0x00000000))();


Смотрю в симуляторе, все ремапится, но после перехода на 0 получаю вот это:
*** error 65: access violation at 0x00000000 : no 'execute/read' permission

Загрузчик линкуется вот так:
Код
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x00000000 0x00020000  {   ; load region size_region
  ER_IROM1 0x00000000 0x00020000  { ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x40000040 0x0000FFC0  { ; RW data
   .ANY (+RW +ZI)
  }
}


Основной модуль вот так:
Код
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x00006000 0x0001A000  {   ; load region size_region
  ER_IROM1 0x00006000 0x0001A000  { ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x40000000 0x00010000  { ; RW data
   .ANY (+RW +ZI)
  }
}


В связи с этим вопросы:
1. Что не так делаю?
2. Как надо компилить-линковать основной модуль и загрузчик по расположению в памяти?
aaarrr
Не знаю, как оформлены вектора в основной программе, но такой простой перенос не заработает, если reset вектор сделан как relative branch.
EXeGLuMATOR
Цитата(aaarrr @ Apr 9 2008, 11:24) *
Не знаю, как оформлены вектора в основной программе, но такой простой перенос не заработает, если reset вектор сделан как relative branch.

Да никак особо не оформлял. Стартап по умолчанию, который Кейл предлагает.
если передавать управление на основной модуль - в данном случае на 0х6000, то в симуляторе все работает и без ремапа. Но вот на железе - нет.
aaarrr
Цитата(EXeGLuMATOR @ Apr 9 2008, 11:28) *
Стартап по умолчанию, который Кейл предлагает.

Стартап по умолчанию скорее всего выглядит примерно так:
Код
    b        reset  ; Reset
    b        xxx    ; Undefined instruction
    b        xxx    ; Software interrupt
    b        xxx    ; Prefetch abort
    b        xxx    ; Data abort
    DCD      xxx    ; reserved
    b        xxx    ; IRQ
    b        xxx    ; FIQ

reset
        ...

После копирования векторов из 0x6000 в 0x00 команда b reset будет посылать процессор оч. далеко.
Пишите свой стартап.
EXeGLuMATOR
Цитата(aaarrr @ Apr 9 2008, 11:41) *
После копирования векторов из 0x6000 в 0x00 команда b reset будет посылать процессор оч. далеко.
Пишите свой стартап.


Стартап вот такой:
Код
; Area Definition and Entry Point
;  Startup Code must be linked first at Address at which it expects to run.

                AREA    RESET, CODE, READONLY
                ARM


; Exception Vectors
;  Mapped to Address 0.
;  Absolute addressing mode must be used.
;  Dummy Handlers are implemented as infinite loops which can be modified.

Vectors         LDR     PC, Reset_Addr        
                LDR     PC, Undef_Addr
                LDR     PC, SWI_Addr
                LDR     PC, PAbt_Addr
                LDR     PC, DAbt_Addr
                NOP                           ; Reserved Vector
;               LDR     PC, IRQ_Addr
                LDR     PC, [PC, #-0x0FF0]    ; Vector from VicVectAddr
                LDR     PC, FIQ_Addr

Reset_Addr      DCD     Reset_Handler
Undef_Addr      DCD     Undef_Handler
SWI_Addr        DCD     SWI_Handler
PAbt_Addr       DCD     PAbt_Handler
DAbt_Addr       DCD     DAbt_Handler
                DCD     0                     ; Reserved Address
IRQ_Addr        DCD     IRQ_Handler
FIQ_Addr        DCD     FIQ_Handler

Undef_Handler   B       Undef_Handler
SWI_Handler     B       SWI_Handler
PAbt_Handler    B       PAbt_Handler
DAbt_Handler    B       DAbt_Handler
IRQ_Handler     B       IRQ_Handler
FIQ_Handler     B       FIQ_Handler


; Reset Handler

                EXPORT  Reset_Handler
Reset_Handler


Знать-бы еще как его написать. 05.gif
aaarrr
Цитата(EXeGLuMATOR @ Apr 9 2008, 11:51) *
Стартап вот такой...

С таким должно работать. В симуляторе вектора правильно копируются?
EXeGLuMATOR
То что лежит в 64 байтах от адреса 0х6000 переносится идентично на 0х00000000.
Т.е. после MEMMAP=2 на адресах от 0 стоят 0, потом все заполняется.
А после ((void(*)(void))(0x00000000))();
получаю:
*** error 65: access violation at 0x00000000 : no 'execute/read' permission
aaarrr
Цитата(EXeGLuMATOR @ Apr 9 2008, 12:26) *
получаю:
*** error 65: access violation at 0x00000000 : no 'execute/read' permission

Если все происходит так, как Вы описываете, то никакого криминала при переходе на 0 быть не должно. Симулятор шибко умный у Keil'а.
EXeGLuMATOR
Может что не так скомпилировано? Не по тем адресам? Да, еще глянул память что у загрузчика, что у основной программы первые 32 байта векторов идентичные. Разница начинается только с +0х20 адресов. разве так и должно быть?
aaarrr
Цитата(EXeGLuMATOR @ Apr 9 2008, 13:21) *
Может что не так скомпилировано? Не по тем адресам?

Не похоже.

Цитата(EXeGLuMATOR @ Apr 9 2008, 13:21) *
Да, еще глянул память что у загрузчика, что у основной программы первые 32 байта векторов идентичные. Разница начинается только с +0х20 адресов. разве так и должно быть?

Да. Различаться они должны начинать отсюда:
Код
Reset_Addr      DCD     Reset_Handler
EXeGLuMATOR
Тогда не понятно в чем проблема. sad.gif Ладно-бы симулятор просто не работал - в железе тоже не работает. При передаче управления на 0х6000 в симуляторе все ок. Работает как ни в чем не бывало. На железе опять-же - ничего.
А что может блокировать доступ? Чтобы такая ошибка вылезала? Может быть не тот режим процессора? Тогда какой должен быть и как проверить/переключить?
EXeGLuMATOR
Глас вопиющего в пустыне.
Все делают подобные проекты и никто не знает.
Как скомпилировать исполняемый модуль, чтобы он работал в нужных адресах? Особенно вектора прерываний?
Сергей Борщ
Цитата(EXeGLuMATOR @ Apr 11 2008, 10:51) *
Все делают подобные проекты и никто не знает.
Я бы попытался помочь вам, но я работаю с ИАРом и с GCC. Как это делается в кейле - без понятия. Предлагаю вам обратить внимание на последовательность передачи управления. Вы сначала ремапите в область векторов ОЗУ с мусором, потом заполняете ее, а если в это время произойдет прерывание?. Вы копируйте вектора не в нулевые адреса, а в начало ОЗУ, а уже после этого делайте ремап. Это первое. Второе. Если у вас LPC, то у него ремапится только область векторов и это замечание его не касается. У SAM7 ремапится все ОЗУ, и если программа исполняется в нулевых адресах, то после ремапа команды начинают выбираться из этих же адресов из ОЗУ, а там находятся вовсе не команды.
Чем смог...
amw
Цитата(EXeGLuMATOR @ Apr 11 2008, 10:51) *
Глас вопиющего в пустыне.
Все делают подобные проекты и никто не знает.
Как скомпилировать исполняемый модуль, чтобы он работал в нужных адресах? Особенно вектора прерываний?

Вот минимальный рабочий пример.
Это для LPC2378 для GCC. С Keil/IAR... не работаю.
Только что проверил в плате.
EXeGLuMATOR
да, сорри забыл сказать. камень LPC2106. Память и вектора ремапятся нормально. А передача управления не происходит поскольку стоят неправильные адреса на векторах. Вопрос собсно как скомпилировать программу, чтобы вектора были рассчитаны на работу с 0 адреса, а сама прога с другого. Бьюсь уже сколько времени - все никак. Все компилится либо с 0 либо с адреса - соотв вектора все направлены в космос. Что-то я туплю походу где-то.
amw
Цитата(EXeGLuMATOR @ Apr 11 2008, 22:10) *
да, сорри забыл сказать. камень LPC2106. Память и вектора ремапятся нормально. А передача управления не происходит поскольку стоят неправильные адреса на векторах. Вопрос собсно как скомпилировать программу, чтобы вектора были рассчитаны на работу с 0 адреса, а сама прога с другого. Бьюсь уже сколько времени - все никак. Все компилится либо с 0 либо с адреса - соотв вектора все направлены в космос. Что-то я туплю походу где-то.

Блин сколько уже сказано об этом.
1. Сделайте секцию с нулевого адреса.
2. Разместите в ней вектора.
3. Сделайте секцию с нужного Вам адреса.
4. Разместите в ней всю остальную программу.
5. Скомпилируйте.
6. Наслаждайтесь.
Пример для gcc см выше. С keil помочь не могу.
EXeGLuMATOR
Цитата(amw @ Apr 11 2008, 23:51) *
Блин сколько уже сказано об этом.
1. Сделайте секцию с нулевого адреса.
2. Разместите в ней вектора.
3. Сделайте секцию с нужного Вам адреса.
4. Разместите в ней всю остальную программу.
5. Скомпилируйте.
6. Наслаждайтесь.
Пример для gcc см выше. С keil помочь не могу.


За пример спасибо. Только в кейле както все иначе выглядит совсем. Насколько я смог разобраться. В этом и проблема. Даже примеры на CARM и Real View - разные. синтаксис другой. Вот и мучаюсь.
amw
Цитата(EXeGLuMATOR @ Apr 11 2008, 23:54) *
За пример спасибо. Только в кейле както все иначе выглядит совсем. Насколько я смог разобраться. В этом и проблема. Даже примеры на CARM и Real View - разные. синтаксис другой. Вот и мучаюсь.

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

Стартап придется переписывать. По крайней мере для второй программы, которую должен запускать бутлоадер. И переписать так, чтоб не было конфликтующих действий в разных стартапах.
eml
Цитата(amw @ Apr 12 2008, 11:29) *
Возмите простейшую програмку. Пусть она ничего не делает полезного, но маленькой проще разбираться.
И размещая функции и переменные в разных секциях, подвигайте эти секции в скрипте линкера по разным адресам. Смотрите на резуль дизассемблирования. Что и по каким адресам располагается уже после компиляции.

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


Взял Ваш пример попытался скомпилить, вадало ошибку в скрипре линковшика
$ make
arm-elf-ld -Tboot-lpc2378.lds -nostdlib -o boot.elf crt0.o boot.o
arm-elf-ld:boot-lpc2378.lds:57: parse error
make: *** [boot.elf] Error 1
$ vi boot-lpc2378.lds
.ramvectors :
{
_ramvectors = .;
*(.ramvectors*)
. = _ramvectors + LENGTH(RAMVECTORS); // :57 ?
_eramvectors = .;
PROVIDE(eramvectors = .);
} > RAMVECTORS AT > FLASH

У вас собирался, что то не так сделал?
amw
Цитата(eml @ Apr 17 2008, 12:44) *
У вас собирался, что то не так сделал?

Код
$ arm-elf-as -v
GNU assembler version 2.18 (arm-elf) using BFD version (GNU Binutils) 2.18
$ arm-elf-ld -v
GNU ld (GNU Binutils) 2.18
$ arm-elf-gcc -v
Using built-in specs.
Target: arm-elf
Configured with: /home/amw/devel/ARM/arm7tdmi/tools/src/gcc-4.2.2/configure --target=arm-elf --prefix=/usr/local/arm/arm-elf --enable-interwork --enable-multilib --with-newlib --with-headers=/usr/local/arm/arm-elf/arm-elf/include --with-gnu-ld --with-gnu-as --disable-nls --disable-shared --enable-languages=c
Thread model: single
gcc version 4.2.2

Может в этом?
Vitaliy_ARM
Цитата(eml @ Apr 17 2008, 13:44) *
У вас собирался, что то не так сделал?


Так что там, победили загрузчик?
Переделал тутошний загрузчик для IAR 5.11 и немножко доработал.
Все отлично работает. Получилось, что прикладной программе ничего и знать не нужно
о существовании загрузчика.
user234
Цитата(Vitaliy_ARM @ May 2 2008, 15:33) *
Так что там, победили загрузчик?


Здраствуйте, не подскажите, для инициализации стека достаточно
установить SYS_MODE (нужно ли устанавливать флаги: I_BIT,F_BIT )
и инициализации памяти где этот стек определен ?
--------------------------------------
_start:
ldr r0,=TOP_STACK
@ SET MODE
msr cpsr_c, #(SYS_MODE|I_BIT|F_BIT)
@ SET STACK
mov sp, r0

bl fn_initSdram
bl main_start
--------------------------------------
Нужно ли определяеть стек для FIQ, IRQ, Это необходимо делать ?
Не подскажите где можно скачать свежую версию binutils-arm для linux ?
amw
Цитата(user234 @ May 12 2008, 11:58) *
Здраствуйте, не подскажите, для инициализации стека достаточно
установить SYS_MODE (нужно ли устанавливать флаги: I_BIT,F_BIT )
и инициализации памяти где этот стек определен ?
--------------------------------------
_start:
ldr r0,=TOP_STACK
@ SET MODE
msr cpsr_c, #(SYS_MODE|I_BIT|F_BIT)
@ SET STACK
mov sp, r0

bl fn_initSdram
bl main_start
--------------------------------------

Вопрос слишком расплывчатый.
По минимуму - достаточно переключить режим и занести нужное значение в SP.
А нужны ли Вам прерывания в каждом конкретном случае - решать Вам.
Цитата
Нужно ли определяеть стек для FIQ, IRQ, Это необходимо делать ?

Если используются прерывания - да.
Цитата
Не подскажите где можно скачать свежую версию binutils-arm для linux ?

Скачать исходник отсюда http://ftp.gnu.org/gnu/binutils/ и скомпилировать.
Как и все остальное.
Можете воспользоваться приложенными скриптами.
Перед запуском создайте каталоги:
build
downloads
log
patches
scripts
src
и положите исходники (архивы) в downloads.
Скрипты не шибко умные, только для облегчения набирания нужной последовательности команд.
Инсталлируется все в /usr/local/arm/arm-elf. У Вас должны быть права на запись в ӕтот каталог.
Смотрите начало файла tools.sh и поправте переменные.
user234
Цитата(amw @ May 12 2008, 12:24) *
Вопрос слишком расплывчатый.
По минимуму - достаточно переключить режим и занести нужное значение в SP.
А нужны ли Вам прерывания в каждом конкретном случае - решать Вам.
Если используются прерывания - да.


Спасибо за ссылочку и скрипты для binutils.

Стек:
не получается.
Пока мне не нужны прерывания, но возможно я не понимаю.
Если не нужны то мне не нужно определять флаги: I_BIT, F_BIT
и отводить стек в соответствующих режимах я правильно понял ?

Делаю простые арифметические операции в функции на "c"
// main.c
int f(int a)
{
int rez=1;
rez = rez + a; <---- пропускает инструкцию не изменяет переменную
return rez;
}
//
int main_start(void)
{
int a=2;
int b=8;
int c=0;
c = f(a); // после выхода из функции с=1
b = a + c;
return 0;
}

Смотрю через отладчик и у меня не происходит изменение переменной rez в функции f().
Не подскажите в чем может быть проблема, неправильно инициализирован стек ?
Если так то что может быть неправильно ?
amw
Цитата(user234 @ May 12 2008, 12:52) *
Спасибо за ссылочку и скрипты для binutils.

Стек:
не получается.
Пока мне не нужны прерывания, но возможно я не понимаю.
Если не нужны то мне не нужно определять флаги: I_BIT, F_BIT
и отводить стек в соответствующих режимах я правильно понял ?

Делаю простые арифметические операции в функции на "c"
// main.c
int f(int a)
{
int rez=1;
rez = rez + a; <---- пропускает инструкцию не изменяет переменную
return rez;
}
//
int main_start(void)
{
int a=2;
int b=8;
int c=0;
c = f(a); // после выхода из функции с=1
b = a + c;
return 0;
}

Смотрю через отладчик и у меня не происходит изменение переменной rez в функции f().
Не подскажите в чем может быть проблема, неправильно инициализирован стек ?
Если так то что может быть неправильно ?

Возможно.
Возможно переменная rez в функции "заоптимизарована" до регистра. Но в таком случае возвращаемое значение должно быть правильным.
Смотрите в отладчике, что происходит со стеком.
user234
Цитата(amw @ May 12 2008, 12:57) *
Возможно.
Возможно переменная rez в функции "заоптимизарована" до регистра. Но в таком случае возвращаемое значение должно быть правильным.
Смотрите в отладчике, что происходит со стеком.


1.
оптимизации кода нет, есть только добавление отладочной информации
CFLAGS = -g

Вот disassembler функции f:

0x80014104 <f>: mov r12, sp
0x80014108 <f+4>: stmdb sp!, {r11, r12, lr, pc}
0x8001410c <f+8>: sub r11, r12, #4 ; 0x4
0x80014110 <f+12>: sub sp, sp, #12 ; 0xc
0x80014114 <f+16>: str r0, [r11, -#16]
0x80014118 <f+20>: mov r3, #1 ; 0x1
0x8001411c <f+24>: str r3, [r11, -#20]
0x80014120 <f+28>: ldr r3, [r11, -#16]
0x80014124 <f+32>: add r3, r3, #1 ; 0x1
0x80014128 <f+36>: str r3, [r11, -#24]
0x8001412c <f+40>: strb lr, [r5, #1509]!
0x80014130 <f+44>: ldr r3, [r11, -#24]
0x80014134 <f+48>: add r3, r2, r3 <------ rez = rez + a r2- не определен ?
0x80014138 <f+52>: str r3, [r11, -#20]
0x8001413c <f+56>: ldr r3, [r11, -#20]
0x80014140 <f+60>: mov r0, r3
0x80014144 <f+64>: ldmdb r11, {r11, sp, pc}
End of assembler dump.

Я пока не трассировал с помощью Jtag только gdb, а gdb прыгает по строчкам c-кода
Это что, глюк моего компилятора ?

2. Не подскажите когда нужно определять флаги: I_BIT, F_BIT ?
3. (Плохо понимаю происходящее)
Не подскажите, при выходе из функции пременная возврвщаются в регистре r0 ?
amw
Цитата(user234 @ May 12 2008, 14:08) *
1.
оптимизации кода нет, есть только добавление отладочной информации
CFLAGS = -g

Вот disassembler функции f:
Код
0x80014104 <f>: mov     r12, sp
0x80014108 <f+4>:       stmdb   sp!, {r11, r12, lr, pc}
0x8001410c <f+8>:       sub     r11, r12, #4  ; 0x4
0x80014110 <f+12>:      sub     sp, sp, #12; 0xc
0x80014114 <f+16>:      str     r0, [r11, -#16]
0x80014118 <f+20>:      mov     r3, #1; 0x1
0x8001411c <f+24>:      str     r3, [r11, -#20]
0x80014120 <f+28>:      ldr     r3, [r11, -#16]
0x80014124 <f+32>:      add     r3, r3, #1    ; 0x1
0x80014128 <f+36>:      str     r3, [r11, -#24]
0x8001412c <f+40>:      strb    lr, [r5, #1509]!
0x80014130 <f+44>:      ldr     r3, [r11, -#24]
0x80014134 <f+48>:      add     r3, r2, r3                  <------  rez = rez + a      r2- не определен ?
0x80014138 <f+52>:      str     r3, [r11, -#20]
0x8001413c <f+56>:      ldr     r3, [r11, -#20]
0x80014140 <f+60>:      mov     r0, r3
0x80014144 <f+64>:      ldmdb   r11, {r11, sp, pc}
End of assembler dump.

Я пока не трассировал с помощью Jtag только gdb, а gdb прыгает по строчкам c-кода
Это что, глюк моего компилятора ?

А перед вызовом функции чио в r2?
Цитата
2. Не подскажите когда нужно определять флаги: I_BIT, F_BIT ?

Дык когда нужно - тогда и определять.
Что значит "определять"?
Цитата
3. (Плохо понимаю происходящее)
Не подскажите, при выходе из функции пременная возврвщаются в регистре r0 ?

Вроде того smile.gif.
А вообще есть такой мануал ARM Procedure Calling Standart. Сокращенно APCS.
Берут его на arm.com.
Вот только что глянул
http://infocenter.arm.com/help/topic/com.a...0042B_aapcs.pdf
user234
Цитата(amw @ May 12 2008, 14:29) *
А перед вызовом функции чио в r2?

Дык когда нужно - тогда и определять.
Что значит "определять"?


Извините.
Когда нужно добавлять флаги : I_BIT, F_BIT в маску ?
Скорее, нужно ли маскировать прерывания если у меня нет обработчиков прерываний,
не инициализированы вектора прерываний ? И не предполагается работать в других режимах ARM.


Перед Вызовом:
disassemble main_start
Dump of assembler code for function main_start:
0x80014148 <main_start>: mov r12, sp
0x8001414c <main_start+4>: stmdb sp!, {r11, r12, lr, pc}
0x80014150 <main_start+8>: sub r11, r12, #4 ; 0x4
0x80014154 <main_start+12>: sub sp, sp, #12 ; 0xc
0x80014158 <main_start+16>: mov r3, #2 ; 0x2
0x8001415c <main_start+20>: str r3, [r11, -#16]
0x80014160 <main_start+24>: mov r3, #8 ; 0x8
0x80014164 <main_start+28>: str r3, [r11, -#20]
0x80014168 <main_start+32>: mov r3, #0 ; 0x0
0x8001416c <main_start+36>: str r3, [r11, -#24]
0x80014170 <main_start+40>: ldr r0, [r11, -#16]
0x80014174 <main_start+44>: bl 0x80014104 <f> <---- call f()
0x80014178 <main_start+48>: mov r3, r0
0x8001417c <main_start+52>: str r3, [r11, -#24]
....

r2 так же не определен.
перед вызовом c-функции в r2 записан 0
aaarrr
Цитата(user234 @ May 12 2008, 16:48) *
Когда нужно добавлять флаги : I_BIT, F_BIT в маску ?
Скорее, нужно ли маскировать прерывания если у меня нет обработчиков прерываний,
не инициализированы вектора прерываний ? И не предполагается работать в других режимах ARM.

Флаги I и F нужно устанавливать для запрета соответствующих исключений. Маскировать прерывания в вашем случае нужно. Настоятельно рекомендую прочитать Technical Reference Manual на ядро.


И код какой-то странный сгенерирован. Особенно вот это смущает:
Код
0x8001412c <f+40>: strb lr, [r5, #1509]!
user234
Спасибо.
amw
Цитата(user234 @ May 12 2008, 16:39) *
Спасибо.

???
Помогло? smile.gif

А что за компилятор?
Altemir
Здравствуйте, уважаемые. Понимаю, что этот вопрос уже поднимался, но хотелось бы получить ответы конкретно по своей задаче.
Итак, был мною написан загрузчик для LPC2132, работающий по следующей схеме:
1. Проекты загрузчика и основной программы независимы
2. Для загрузчика определено адресное пространство во флэш:
-DROMSTART=01000
-DROMEND=05FFF
Жирность загрузчика определяется необходимостью поддержки части периферии, возможностью связи с внешним устройством и компом для получения прошивки основной программы и работы с AT45.

Для основной программы (ОП): [200-FFF],[6000-FFFF]
3. При получении прошивки ОП загрузчик проверяет её на валидность, делает подмену стартового адреса своим, сохраняет стартовый адрес ОП в резервной области LPC, корректирует CRC-векторов, записывает нулевую страницу, обходит "свою" область, записывает оставшуюся область ОП.
4. По окончании записи проверяет ОП во flash LPC на валидность, переходит на исполнение ОП.

Всё работает, работает замечательно, но, как можно заметить, необходимо стирать нулевой сектор, что приводит к возможному "слёту" прошивки при выключении питания/сбросе, если не успела записаться область 0x00-0x3F. Хотелось бы узнать пути решения этой проблемы: как вообще не трогать нулевой сектор? Т.е. адреса 0x0000-0x5FFF должны быть неприкосновенными.
Из форума видел пока только одно решение - ремапить в ОЗУ по адресам 0x00-0x3F область INTVEC основной программы. Но, судя опять же по форуму, это ненадёжно, т.к. существует риск затирания этой области некорректным исполнением кода основной программы. Есть ли возможность использования для основной программы векторов из flash, жертвуя использованием прерываний в загрузчике?
Сергей Борщ
Цитата(Altemir @ May 24 2008, 14:50) *
Но, судя опять же по форуму, это ненадёжно, т.к. существует риск затирания этой области некорректным исполнением кода основной программы.
А если основная программа затрет не эту область, а, скажем 0x400000F0 - 0x40000100, то это будет способствовать повышению надежности? Включайте собаку, при слете она будет перезапускать проц, загрузчик будет восстанавливать вектора и так пока не найдете ошибку.

Давно использую вариант с ремапом на LPC2214 и AT91SAM7 - никаких нареканий. Нестирание нулевого сектора дает гарантию сохранение жизнеспособности при пропадании питания, сбросе, при обрыве связи в процессе перепрошивки, но никак не при ошибках в программе.
Altemir
Всё это понятно. Вы с Argon-ом на: Сахаре
обсуждали реализацию ремапа в ОЗУ, я это тоже изучил. Там же указывалось на возможность "задать фиксированное значение векторов" (с переходом на таблицу векторов ОП, к примеру 0x6000-0x603F) в бутлодыре для ОП, так, что прерывания будут исполняться на один переход больше. Такой вопрос не изучали?

Собака у меня всегда включена, а насчёт размещения векторов в ОЗУ здесь на форуме имеются как минимум два противника: zltigo и Kirill Frolov. Очень интересно и их выслушать.
zltigo
Цитата(Altemir @ May 24 2008, 13:50) *
Есть ли возможность использования для основной программы векторов из flash, жертвуя использованием прерываний в загрузчике?

Ну зачем чем-то жертвовать, куда-то мапировать (жертвуя RAM), если банально перепрограммируется контроллер прерываний и все. А, exceptions handlers при этом всегда в загрузчике - так даже лучше.
Первые 0x40 байт загрузчика для LPC21/2xx:
Код
                ORG     0x00
__program_start:
                ldr     pc,(?vect_entry + 4*0) ; 00  Reset
                ldr     pc,(?vect_entry + 4*1) ; 04  UND
                ldr     pc,(?vect_entry + 4*2) ; 08  SWI
                ldr     pc,(?vect_entry + 4*3) ; 0C  P_ABT
                ldr     pc,(?vect_entry + 4*4) ; 10  D_ABT
                dc32    0                       ; 14 Summ of other vectors instructions
                ldr     pc, [pc,#-0xFF0]        ; 18 Jump directly to the address given by the AIC
                                                ; from [0xFFFFF030] Curent 18h +8(conveyer)=20h
                ldr     pc,(?vect_entry + 4*7) ; 1C  FRQ
;----------------------------------------------------------------------------
?vect_entry:
                dc32    ?cstartup              ; Reset
                dc32    ?undf_abort            ; UND
                dc32    (KERNEL_LOCATION+0x08) ; SWI
                dc32    ?pref_abort            ; P_ABT
                dc32    ?data_abort            ; D_ABT
                ldr     pc,(?vect_entry +4*6)  ; Entry Point from application
                dc32    ?entry_point           ;  ...
                dc32    (KERNEL_LOCATION+0x0C) ; FRQ  ( With offset in Kernel )
Altemir
Цитата(zltigo @ May 24 2008, 18:10) *
Ну зачем чем-то жертвовать, куда-то мапировать (жертвуя RAM), если банально перепрограммируется контроллер прерываний и все. А, exceptions handlers при этом всегда в загрузчике - так даже лучше.

Я, конечно, понимаю, что вы давно работаете в этой области и хорошо изучили данный вопрос, но всю силу ARM-ов мне пока не привелось познать. В текущем проекте основной программы я настраивал Vectored Interrupt Controller (VIC), например, так:
Код
//Vectored Interrupt Controller
    
    VICProtection=0x00;                         //No Protection
    VICIntSelect=0x00000000;                //All requests - IRQ
    VICSoftIntClear=0xFFFFFFFF;             //Release all software requests
    VICIntEnClear=0xFFFFFFFF;               //Disable all interrupts
    
    VICIntEnable=((1<<VIC_TIMER0)|        //Включить прерывание по TIMER0
    (1<<VIC_TIMER1)|                //Включить прерывание по TIMER1
    (1<<VIC_PWM0)|                //Включить прерывание по PWM0
    (1<<VIC_UART1));                //Включить прерывание по UART1
    
    
    VICVectAddr0=(DWORD)&Timer0_Int;                //Priority 0 - TIMER0
    VICVectCntl0=0x20|VIC_TIMER0;
    VICVectAddr1=(DWORD)&Timer1_Int;                //Priority 1 - TIMER1
    VICVectCntl1=0x20|VIC_TIMER1;
    VICVectAddr2=(DWORD)&PWM0_Int;        //Priority 2 - PWM0
    VICVectCntl2=0x20|VIC_PWM0;
    VICVectAddr3=(DWORD)&Uart1_Int;        //Priority 3 - UART1
    VICVectCntl3=0x20|VIC_UART1;
    
    VICVectAddr=0;                              //Clear one interrupt


Я понимаю, что векторов 16 и при переинициализации VIC их может использовать, к примеру, загрузчик, но при этом пока не понимаю как соотносить адреса 0x00-0x3F для основной программы и загрузчика. И где это указывать?

Спасибо за терпение.

P.S. Похоже, пока я отвечал, вы добавили код, изучаю...

zltigo
Как я понял:
1. KERNEL_LOCATION - адрес основной программы (ОП)
2. ?cstartup - загрузчик
3. Производится разделение прерываний для ОП и загрузчика. В моём случае хочу так: IRQ - для ОП, FIQ - для загрузчика
4. При инициализации VIC-а в загрузчике: VICIntSelect=0xFFFFFFFF, в ОП: VICIntSelect=0x00000000
5. В итоге - задействую всего 3 адреса в пространстве 0x00-0x3F:
0x0000 0000 Reset
0x0000 0018 IRQ
0x0000 001C FIQ

Я всё правильно понял? Тогда я должен прописать в *.xcl-файле IARа для основной программы -Z(CODE)INTVEC=00-3F и поскольку адрес основной программы предопределён, то никаких последующих изменений и подмен адресов не потребуется?
zltigo
Цитата(Altemir @ May 24 2008, 17:21) *
3. Производится разделение прерываний для ОП и загрузчика.

Нет.
Читаем комментарий: IRQ "Jump directly to the address given by the AIC"
Для FIQ, можно аналогично, но у меня он прямо в приложение направляется.
Если что не понятно, то читаем описание VIC, для углубленного изучения можно зайти на сайт ARM - там есть более подробные описания, нежели от производителей их чипов.
...
И на все последующие вопросы - нет sad.gif
Altemir
Цитата
Нет.
Читаем комментарий: IRQ "Jump directly to the address given by the AIC"

И как определить этот адрес? В бинарнике основной программы он постоянно меняется при её изменении. В LPC есть VIC и даже в оригинальных от arm.com не нашёл AIC sad.gif Не понимаю совершенно, КАК вы разделяли прерывания для основной программы и загрузчика. Везде в форуме написано, что вы это сделали, но нигде не описано, как это повторить и как настраивать прерывания для загрузчика и ОП при этом unsure.gif

Опытным путём удалось установить, что по адресу 0x38 расположен адрес моей функции:
Код
//IRQ exception handler
#pragma vector=0x18
__irq __arm void irq_handler(void)
{
    ((void(*)())VICVectAddr)();     //Call function on vector
    VICVectAddr = 0;                //Clear interrupt in VIC
}

Но как задать этой функции предопределённый адрес во флэш тогда? Обычным @0x6200 не получается, компилер ругается

Цитата
Для FIQ, можно аналогично, но у меня он прямо в приложение направляется.

В какое и как?

Цитата
Если что не понятно, то читаем описание VIC, для углубленного изучения можно зайти на сайт ARM - там есть более подробные описания, нежели от производителей их чипов.

Документ не намного подробнее от NXP sad.gif

Цитата
И на все последующие вопросы - нет sad.gif

Я в отчаянии...
zltigo
Цитата(Altemir @ May 24 2008, 19:01) *
Везде в форуме написано, что вы это сделали, но нигде не описано, как это повторить

Я фигею - в этой теме уже писал:
Код
                ldr     pc, [pc,#-0xFF0]      ; 18 Jump directly to the address given by the AIC

Цитата
и как настраивать прерывания для загрузчика и ОП при этом unsure.gif

А вот так - Вас цитирую:
Код
VICVectAddr0=(DWORD)&Timer0_Int;                //Priority 0 - TIMER0
    VICVectCntl0=0x20|VIC_TIMER0;
    VICVectAddr1=(DWORD)&Timer1_Int;                //Priority 1 - TIMER1
    VICVectCntl1=0x20|VIC_TIMER1;
    VICVectAddr2=(DWORD)&PWM0_Int;        //Priority 2 - PWM0
    VICVectCntl2=0x20|VIC_PWM0;
    VICVectAddr3=(DWORD)&Uart1_Int;        //Priority 3 - UART1
    VICVectCntl3=0x20|VIC_UART1;

Причем процедура ОДИНАКОВА, для обоих.

Что тут можно не понять?
Altemir
Цитата(zltigo @ May 24 2008, 21:51) *
Что тут можно не понять?

Можно тут не понять то, как, имея одно и то же значение по адресу 0x38 проц определит, куда ему переходить на обработку прерывания, но, похоже, догоняю:
1. Приведённый мной irq_handler() для обработки прерывания использует адрес фунции, хранимой в слоте VICVectAddr0-15
2. Поскольку слоты настраиваются для загрузчика и ОП по-своему, то и переход будет именно на те функции, которые актуальны
3. Описанная в основной программе функция irq_handler() использоваться не будет, т.к. её заменяет функция irq_handler() бутлоадера (точнее, по адресу 0x38 будет находиться именно вызов хэндлера загрузчика)

Теперь всё так?

P.S. И ещё, при указании в *.xcl-файле ОП:
-DROMSTART=06000
-DROMEND=0FFFF
по адресу 0x20 лежит значение не 0x6000, а 0x603C. С чем это связано? Чем заняты адреса 0x6000-0x603B? Как корректно предопределить адрес ОП?
Сергей Борщ
Цитата(Altemir @ May 24 2008, 21:06) *
3. Описанная в основной программе функция irq_handler() использоваться не будет, т.к. её заменяет функция irq_handler() бутлоадера (точнее, по адресу 0x38 будет находиться именно вызов хэндлера загрузчика)

Теперь всё так?
Нет. Не так. Весь irq_handler() уже есть. Он один единственный и прибит гвозьдями на вектор прерывания. Вот он:
Код
            ldr     pc, [pc,#-0xFF0]     ; 18 Jump directly to the address given by the AIC
Оно вызывает нужный из ваших Timer1_Int, PWM0_Int и т.д. Кто из них в данный момент нужен - он узнает из регистра [pc,#-0xFF0]. Подробности об этом регистре - в документации. Это регистр VICVectAddr.
Altemir
Цитата(Сергей Борщ @ May 24 2008, 23:38) *
Нет. Не так. Весь irq_handler() уже есть. Он один единственный и прибит гвозьдями на вектор прерывания. Вот он:
Код
            ldr     pc, [pc,#-0xFF0]    ; 18 Jump directly to the address given by the AIC
Оно вызывает нужный из ваших Timer1_Int, PWM0_Int и т.д. Кто из них в данный момент нужен - он узнает из регистра [pc,#-0xFF0]. Подробности об этом регистре - в документации. Это регистр VICVectAddr.

Не знаю, как насчёт его прибиваемости гвоздями, но у меня в программе роль гвоздей играл не
Код
            ldr     pc, [pc,#-0xFF0]    ; 18 Jump directly to the address given by the AIC


а
Код
#pragma vector=0x18
__irq __arm void irq_handler(void)

Если я создам, к примеру, в main.cpp для FIQ:
Код
#pragma vector=0x1С
__fiq __arm void fiq_handler(void)

То адрес этого хэндлера так же будет совпадать с тем, что расположен по 0x3C!
Я говорю о том, что не используя cstartup.s79 в IARe, а обработчик irq_handler, описанный мной в основной программе и загрузчике идентичны. Проверено через листинги и бинарники.

Вопрос для меня остался только за тем, как корректно предопределить адрес основной программы и что лежит по адресам 0x6000-0x603B?
Altemir
Кстати, порывшись в опциях XLINK, обнаружил возможность копирования той или иной области в указанную, т.о. мне для основной программы можно в *.xcl файле прописать такое:

Код
-DROMSTART=06040    //начало ОП
-DROMEND=0FFFF    //конец ОП

-Z(CODE)INTVEC=00-3f //вектора ОП
-KINTVEC=06000,1    //копия векторов


Загрузчик при получении файла-прошивки ОП (скорее всего в ней будет удалён начальный кусок, занятый под загрузчик, чтобы не передавать лишнего) может увидеть реальное расположение точки входа в ОП по адресу 0x6020 (после удаления начального куска станет 0x0020). Зачем такой изврат? Просто меня смущает неясность расположения этой точки входа и не может ли она измениться при смене версии IARа? А так - всё предопределено.
Altemir
Всё сделал. Всё работает. Никакой правки и копания в cstartup.s79 не потребовалось, прекрасно обошёлся #pragma и настройкой *.xcl. Убить загрузчик не получилось smile.gif Всем спасибо за наводки.
zltigo
Цитата(Altemir @ May 26 2008, 21:06) *
Всё сделал.

Сделали жалкую пародию на систему с тупейшим, жестким и совершенно не нужным разделением на IRQ и FIQ и соответственно ничего из написанного на поняли. Печально.
Altemir
Цитата(zltigo @ May 26 2008, 23:31) *
Сделали жалкую пародию на систему с тупейшим, жестким и совершенно не нужным разделением на IRQ и FIQ и соответственно ничего из написанного на поняли. Печально.

Да куда мне...

P.S. И никакого "разделения" я не делал. Просто пример привёл. А строчку с
Код
ldr     pc, [pc,#-0xFF0]
в меру своих способностей расценил как переход на адрес обработчика, лежащего в соответствующем слоте VicAdr. Обратное смещение указывает на адреса VICа, т.к. они расположены в самом верхнем адресном пространстве.
vesago
Хочу разобраться с ремапом основного приложения в LPC2214. Как я понял я должен таким образом получить хекс, чтобы вектора (64 байт) расположены были с адреса 0, а ресет хэндлер и остальное с адреса допустим (0x2000 + 0x40). Я из хекса вырежу первые 64 байта с весторами и запихаю их с адреса 0x2000. Загрузчик скопирует вектора в раму 0x40000000 и дальше передаст управление. Правильна ли моя идея? Проект у меня в карме - не могу сместить ресет и все тело программы в первый сектор флеши. Если кто знает как - подскажите, пожалуйста.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.