Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопросы по созданию своего загрузчика для LPC17xx
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Altemir
Всем доброго времени суток.
Адаптирую загрузчик с LPC2xxx на LPC176x. Копался в мануалах, столкнулся с тем, что у кортекса таблица векторов прерываний гораздо больше, чем у arm7. Как я понял, она может занимать максимум 1КБ против 64 байт у arm7. Для предыдущих проектов использовалась программа шифрования прошивки, которая знала расположение спецтаблицы, находящейся по определённому адресу сразу следом за таблицей векторов. Получается, теперь необходимо или ремапить таблицу векторов в кортексе для сохранения совместимости с софтом верхнего уровня, либо переписывать этот софт? Можно ли занимать адреса, скажем, 0x40...0x100 объявлением массива через __root const? И ещё, в каком документе от ARM описан участок памяти 0x0000 - 0x0400? В DDI0337H_cortex_m3_r2p0_trm.pdf нет. Просто code и всё. Кто может подсказать, что и где там обычно расположено? Компилятор - IAR.
gladov
Цитата(Altemir @ Sep 4 2011, 01:42) *
Всем доброго времени суток.
Адаптирую загрузчик с LPC2xxx на LPC176x. Копался в мануалах, столкнулся с тем, что у кортекса таблица векторов прерываний гораздо больше, чем у arm7. Как я понял, она может занимать максимум 1КБ против 64 байт у arm7. Для предыдущих проектов использовалась программа шифрования прошивки, которая знала расположение спецтаблицы, находящейся по определённому адресу сразу следом за таблицей векторов. Получается, теперь необходимо или ремапить таблицу векторов в кортексе для сохранения совместимости с софтом верхнего уровня, либо переписывать этот софт? Можно ли занимать адреса, скажем, 0x40...0x100 объявлением массива через __root const? И ещё, в каком документе от ARM описан участок памяти 0x0000 - 0x0400? В DDI0337H_cortex_m3_r2p0_trm.pdf нет. Просто code и всё. Кто может подсказать, что и где там обычно расположено? Компилятор - IAR.


Да, придется спецтаблицу передвинуть за таблицу векторов. Но проблемы не вижу, т.к. со сменой ядра Вам обязательно пересобирать как загрузчик, так и основной софт. Вот и сдвиньте все дальше. Адреса 0х40 и выше конечно можно использовать как угодно (и объявлять тоже), но только есть ли гарантия, что не произойдет прерывания, адрес вектора которого попадет на ваши личные данные?
Описание на области памяти ищите в DS на контроллер. Cortex-M3 стандартизует лишь область векторов прерываний, да и то не строго, а остальное, как правило, отдано под пользовательский код.
Altemir
Цитата(gladov @ Sep 5 2011, 08:10) *
Да, придется спецтаблицу передвинуть за таблицу векторов...

Да, к этому и пришёл. Спасибо. Думаю, в моём случае сдвинуть на 1КБ - не проблема.

Цитата
Описание на области памяти ищите в DS на контроллер. Cortex-M3 стандартизует лишь область векторов прерываний, да и то не строго, а остальное, как правило, отдано под пользовательский код.

Если б NXP где-то явно это описала... В UM10360.pdf Rev. 2 — 19 August 2010 только на стр. 19 общая карта памяти sad.gif Похоже, дизасмить придётся. А такой вопрос - где обычно после IARа находится стартовый вектор? Т.е., по какому адресу вызывать свою программу из загрузчика, если в *.icf файле я определяю:
Код
define symbol __ICFEDIT_region_ROM_start__ = 0x00008000;
gladov
Цитата(Altemir @ Sep 5 2011, 09:09) *
Да, к этому и пришёл. Спасибо. Думаю, в моём случае сдвинуть на 1КБ - не проблема.


Если б NXP где-то явно это описала... В UM10360.pdf Rev. 2 — 19 August 2010 только на стр. 19 общая карта памяти sad.gif Похоже, дизасмить придётся. А такой вопрос - где обычно после IARа находится стартовый вектор? Т.е., по какому адресу вызывать свою программу из загрузчика, если в *.icf файле я определяю:
Код
define symbol __ICFEDIT_region_ROM_start__ = 0x00008000;


Если внимательно прочесть, то ничего дизасмить не придется. После стандартных 16 прерываний ядра Cortex-M3 лежат ВСЕ векторы, которые имеются в данном камне. Считате, умножаете на 4 и т.д. После векторов память используется ИАРом по своему усмотрению. Но имхо и это знать вовсе не обязательно. Какая Вам разница куда именно ИАР положит какой код? Если обязательно сделать "дырку" между векторами и кодом для служебной информации, так сделайте ее с помощью конфига линкера. Точка входа в приложение у ИАРа располагается произвольно и знать ее вовсе не обязательно. Достаточно вычитать адрес начала кода из образа (опять же, см. описание первых 0х40 байтов в кортексе).

Altemir
Попробовал сделать ремап векторов прерываний. Не заводится проц (или не выходит из NXP-шного загрузчика?). sad.gif Что ещё не так мог сделать? Вроде всё просто должно быть.

В коде написал:
Код
VTOR  = 0x400;


В *.icf файле:
CODE
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x00000400;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x00000000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0003FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x10007FFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_heap__ = 0x800;
/**** End of ICF editor section. ###ICF###*/


define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];

define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };

initialize by copy { readwrite };
//initialize by copy with packing = none { section __DLIB_PERTHREAD }; // Required in a multi-threaded application
do not initialize { section .noinit };

place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };

place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK, block HEAP };
Altemir
И ещё. Почему при указании в *.icf файле строки, например:
Код
define symbol __ICFEDIT_region_ROM_start__ = 0x00001100;

всё-равно заполняет область 0x100...0xFFF кодом? В map-файле он явно написал:
Код
"A1":  place at 0x00001000 { ro section .intvec };
"P1":  place in [from 0x00001100 to 0x0003ffff] { ro };
"P2":  place in [from 0x10000000 to 0x10007fff] { rw, block CSTACK, block HEAP };

  Section             Kind        Address    Size  Object
  -------             ----        -------    ----  ------
"A1":                                        0xc4
  .intvec             ro code  0x00001000    0xc4  startup_LPC17xx.o [1]
                             - 0x000010c4    0xc4

"P1":                                      0x675c
  .text               ro code  0x00001100  0x2050  blablabla.o [1]
...

Позиции в области 0x100...0xFFF нигде в map файле не встречаются. Если же в свойствах проекта указать заполнение нулями этой области, тогда да, там чисто, map-ы не отличаются, а код разумно вырастает на 4КБ. Правда, ни векторы, ни код всё-равно линкуются не туда. Где что не так?

P.S. С этим разобрался. Виноват IAR. hex-файл генерит правильно, а в бинарнике отрезает младшую часть неиспользуемых адресов *WALL* Только сильно легче не стало. С ремап-ом всё-равно не запускается код. Неужели никто не делал?

P.P.S. Похоже, догадываюсь, почему ремап не работает. Кто подскажет, чем заменить в icf-файле ранее использованную в xcl-файле директиву типа -KINTVEC=05000,1 ? Подобное позволяло иметь копию векторов прерываний по адресу 0x5000.
gladov
Цитата(Altemir @ Sep 5 2011, 15:38) *
P.P.S. Похоже, догадываюсь, почему ремап не работает. Кто подскажет, чем заменить в icf-файле ранее использованную в xcl-файле директиву типа -KINTVEC=05000,1 ? Подобное позволяло иметь копию векторов прерываний по адресу 0x5000.


А можно поинтересоваться для чего нужны 2 копии таблицы векторов? Вы очень упорно копаете, но создается стойкое ощущение, что немного не туда sm.gif
У Вас же будет бутлоадер? Наверное, он ляжет в один-два сектора в начале ПЗУ, так? А ведь он туда ляжет со своей таблицей, так? Тогда зачем Вам иметь еще и две таблицы у приложения? Его нужно просто сдвинуть на N-е кол-во секторов вперед и все. Только сдвинуть целиком, вместе с таблицей векторов. Например, так:
Код
...
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x00002000;
define symbol __ICFEDIT_region_ROM_end__   = 0x0003FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_RAM_end__   = 0x10007FFF;
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = __ICFEDIT_region_ROM_start__;
/*-Sizes-*/
...
Altemir
Цитата(gladov @ Sep 6 2011, 07:58) *
А можно поинтересоваться для чего нужны 2 копии таблицы векторов? Вы очень упорно копаете, но создается стойкое ощущение, что немного не туда sm.gif

Можно, конечно. Причин было две:
1. Пока не был дан проект от второго программиста, который занимается основной программой, хотел в самом загрузчике обкатать перемещение таблицы векторов прерываний во флэше. Протупил (споткнулся) из-за неправильно генерируемого бинарника сначала, потом понял, что простыми методами из самого загрузчика не сделать такой тест. Надо хотя бы примитивную главную программку залить, или играться с ремапом в ОЗУ, т.к. начальная же область пустая sm.gif
2. Поскольку проекты перетаскиваются с arm7, то ранее на Builder-е была создана спецпрограммка, которая в постбилде отрезала начальный пустой ненужный кусок от главной программы (включая вектора), получала инфу из спецтаблицы, расположенной следом за векторами (и меняла её тоже, всякую инфу добавляя), при этом имелась копия такой таблицы для главной программы по предопределённому адресу (с учётом смещения главной, ессно), из которой оная также получала необходимые сведения. Также постбилдной утилитой проводилось шифрование прошивки. Хотелось перенести такую технологию без изменений, введя копию таблицы через icf-файл, но, поняв в соседней ветке, что это нельзя сделать, пришлось делать через код в главной проге, объявляя две копии по предопределённым адресам. В принципе, несложно, но некрасиво sm.gif Уже всё проверил.

Так что всем спасибо за советы.
Alechek
От сабя скажу следующее:
Я тоже вначале был немного в раздумьях, куда же девать всю эту таблицу и почему я ее должен прописывать статически.
В итоге от всей таблицы в ПЗУ осталось лишь
Код
        DATA
__vector_table
        DCD     sfe(CSTACK)            ; Top of Stack
        DCD     __iar_program_start    ; Reset Handler
        DCD     NMI_Handler            ; NMI Handler
        DCD     HardFault_Handler         ; Hard Fault Handler
        DCD     MemManage_Handler         ; MPU Fault Handler
        DCD     BusFault_Handler          ; Bus Fault Handler
        DCD     UsageFault_Handler        ; Usage Fault Handler
__vector_table_0x1c
        DCD     0                         ; Valid user Code

После первоначального запуска инициализирутся драйвер NVIC, который создает таблицу в ОЗУ. Далее работаем уже исключительно с ней.
Очень удобно (и единственно возможно на данном камне) при динамической инициализации векторов прерываний.
Altemir
Цитата(Alechek @ Sep 6 2011, 11:00) *
В итоге от всей таблицы в ПЗУ осталось лишь...

Хм, тоже неплохое решение, которое вполне имеет право на существование. Возьму на заметку. Благодарю.

Да, ещё вопросик. Использую в сишном коде асмовскую вставку вида:
Код
  asm("mov sp,#0x8400");
  asm("ldr sp,[sp,#0]");


Для сишных файлов константа 0x8400 определена. Есть ли какая-то возможность подставить эту константу для асма? Погуглил. Пишут, что требуется явно указывать sad.gif Оно и понятно, но всё же...
KRS
Я для IAR такой код перехода в программу поставил
Код
                VTOR = (unsigned)__section_begin(".intvect");
                asm ("ldm r1, {r0,r1}\n"
                     "mov r13, r0\n"
                     "mov r15, r1");
                while(1);

Здесь при оптимизации и записи в VTOR, нужная константа уже будет в r1 (можно по листингу проверить) осталось только стек и точку входа считать...
в конце while(1) стоит для оптимизатора.
Altemir
Цитата(KRS @ Sep 6 2011, 18:34) *
Я для IAR такой код перехода в программу поставил...

Очень элегантно! Спасибо! По коду всё понял. Не поделитесь заодно полным описанием набора инструкций для Cortex-M3? Что-то я у ARM на сайте не нашёл pdf-ника нормального.
KRS
Цитата(Altemir @ Sep 7 2011, 08:52) *
Не поделитесь заодно полным описанием набора инструкций для Cortex-M3? Что-то я у ARM на сайте не нашёл pdf-ника нормального.

Вам нужен arm architecture v7m reference manual, посмотрите новости местных закромов sm.gif

Altemir
KRS
Отлично! Ещё раз - благодарю.
Vitaliy_ARM
Пишу спец загрузчик и как раз столкнулся с тем, что мне надо иметь две таблицы векторов прерываний.
Задача загрузчика записать приложение по адресам 0x0-0xFFFF, т.е после чего он уже будет не нужен. И на место него пользовательское приложение будет писать другие данные, но это не важно.
Механизм такого загрузчика предполагается сделать так.
1. Копируются вектора прерываний куда-нибудь (во флешь или озу)
2. Делается ремап.
3. Стартует загрузчик

Можно ли сделать копирование векторов прерываний в другую страницу на этапе линковки загрузчика, скажем по адресу 0x18000?
KRS
Цитата(Vitaliy_ARM @ Sep 16 2011, 16:22) *
Можно ли сделать копирование векторов прерываний в другую страницу на этапе линковки загрузчика, скажем по адресу 0x18000?

Я бы в вашем случае сделал так:
загрузчик пишется как обычно приложение, но только для работы в RAM.
Это можно сделать двумя способами - с помощью __ramfunc и двух таблиц прерываний, но на мой взгляд больно геморно....

Второй вариант переписав стратап код! Для кортекса можно без асма обойтись. Тоже понадобится 2 таблицы прерываний.

Код
// вектора во флеше для первоначального старта
uint32_t const __boot_table[]@".bootvect" =
{
    0x20003FF0, //0
    (uint32_t)bl_main, //1
};

#pragma section=".intvect"
#pragma section=".intvect_init"
#pragma section=".text_init"
static void segment_init(void)
{
    uint32_t *src;
    uint32_t *dst;
    uint32_t len;
    src = __section_begin(".intvect_init");
    len = (uint32_t)__section_end(".text_init");
    len = (len + 3 - (uint32_t)src) & ~3;
    dst = __section_begin(".intvect");
    while(len) {
        *dst++=*src++;
        len-=4;
    }
}

#pragma location=".boot"
__noreturn
void bl_main(void)
{
    segment_init();
              *AT91C_CM3_VTOR = (unsigned)__section_begin(".intvect");
               asm ("ldm r1, {r0,r1}\n"
                     "mov r13, r0\n"
                     "mov r15, r1");
                while(1);
}


А в icf файл добавить
Код
do not initialize { section * };
initialize manually { section .text, section .intvect};

place at start of FLASH { section .bootvect };
place at start of RAM { section .intvect };
place in FLASH          { section .boot*, section .text_init, section .intvect_init};
place in RAM           { readwrite, readonly };


Но тут надо смотреть какие секции у вас используются и т.п.
но принцип - все скопировать в озу и перейти по вектору старта из таблицы уже в озу.
Alechek
Цитата(KRS @ Sep 16 2011, 19:10) *
но принцип - все скопировать в озу и перейти по вектору старта из таблицы уже в озу.

Главное не забывать про выравнивание таблицы прерываний!

KRS
Цитата(Alechek @ Sep 19 2011, 08:50) *
Главное не забывать про выравнивание таблицы прерываний!

это как раз не проблема - кладется в начало области и все, автоматически будет выравнена.
Alechek
Область то тоже должна быть выровнена, причем байт минимум на 256.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.