Сергей Борщ 140 20 сентября, 2012 Опубликовано 20 сентября, 2012 · Жалоба Cortex-M0Тогда нужно: 1) Располагать (линковать) загрузчик с адреса 0x08000000, чтобы он мог продолжать работать после ремапа. 2) Располагать (линковать) приложение с адреса 0x0800хххх, чтобы онo могло работать после ремапа. 2) Копировать вектора приложения в начало ОЗУ. У приложения должно быть "откушено" начало ОЗУ под это дело в скрипте линкера. 3) Из векторов приложения брать адрес начала стека и прописывать его в MSP 4) Делать ремап (SYSCFG, биты MEM_MODE) 5) передавать управление на адрес, взятый из вектора reset_handler Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 1 20 сентября, 2012 Опубликовано 20 сентября, 2012 · Жалоба Если буту прерывания не нужно, то можете посмотреть пример NXP (secondary bootloader) В этом примере предлагают использовать ассемблерные вставки, добавляю их в main() Бутлоадера: __asm volatile("ldr r0, =0x103C"); __asm volatile("ldr r0, [r0]"); __asm volatile("mov pc, r0"); Компиллирую проект, выдает ошибку: aplication\main.c(38): error: #1113: Inline assembler not permitted when generating Thumb code Добавляю в настройках проекта --arm. Появляется ошибка: main.c: Error: C3006E: specified processor or architecture does not support ARM instructions Тогда нужно: 1) Располагать (линковать) загрузчик с адреса 0x08000000, чтобы он мог продолжать работать после ремапа. 2) Располагать (линковать) приложение с адреса 0x0800хххх, чтобы онo могло работать после ремапа. 2) Копировать вектора приложения в начало ОЗУ. У приложения должно быть "откушено" начало ОЗУ под это дело в скрипте линкера. 3) Из векторов приложения брать адрес начала стека и прописывать его в MSP 4) Делать ремап (SYSCFG, биты MEM_MODE) 5) передавать управление на адрес, взятый из вектора reset_handler 1,2) Flash-память микроконтроллера lpc11c24 - 0x0000 0000 - 0x0000 8000 RAM-память - 0х1000 0000 - 0х1000 2000 Адреса 0x08000000 у меня нет. Если загрузчик распологаю не по адресу 0х0000 0000, то у меня МК не стартует. 2) копировать с помощью ассемблерных вставок из NXP примера "secondary bootloader"? Постом ниже я написал о затруднениях, с которыми столкнулся при их использовании. 3,4) также выподняется ассемблерными вставками? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 20 сентября, 2012 Опубликовано 20 сентября, 2012 · Жалоба Компиллирую проект, выдает ошибку:С кейлом не работаю, не подскажу. Пусть другие участники помогутю 1,2) Flash-память микроконтроллера lpc11c24А название ветки - STM32 bootloader. Невнимательно читал ваше первое сообщение и даю советы по STM32F0xx. :laughing: Для LPC11 ремапятся первые 512 байт. Соответственно смотрите по ссылке от _Артем_а - там я приводил кусок запуска приложения для LPC11 2) копировать с помощью ассемблерных вставок из NXP примера "secondary bootloader"? Постом ниже я написал о затруднениях, с которыми столкнулся при их использовании. 3,4) также выподняется ассемблерными вставками? 2 - можно и ассемблером, но зачем? Можно сделать и на С/С++ при помощи цикла и указателей либо библиотечной функцией memcpy() 3) да, ассемблерная вставка либо функция из CMSIS, которая тоже на ассемблерной вставке строится. 4) Обычная сишная запись в регистр. Для LPC это будет регистр SYSMEMREMAP Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 1 20 сентября, 2012 Опубликовано 20 сентября, 2012 · Жалоба 2) а если размещать вектор прерываний не в RAM, а во flash по адресу 0х0000 2000 (сюда у меня рабочая программа линкуется), с помощью встроенных IAP-команд, которые позволяют записывать во флеш страницами по 256 байт? Нужно ли будет в таком случае делать Remap? 3) Не помните названия функции? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 20 сентября, 2012 Опубликовано 20 сентября, 2012 · Жалоба 2) а если размещать вектор прерываний не в RAM, а во flash по адресу 0х0000 2000Разместить вектора вы можете где угодно, но вот процессор читает их с адреса 0x00000000. И никаких способов считывать их из других адресов у Cortex-M0 не предусмотрено (у M3 для этого есть регистр VTOR). Поэтому разработчики процессоров идут на хитрость - делают отражение (remap) на эти адреса других регионов памяти, например RAM. После ремапа вы кладете какие-то данные в начало RAM, а процессор их "видит" не только по "родным" адресам в RAM, но и в начале флеша. И таких мест, которые могут быть отражены на начало адресного пространства всего два - начало ОЗУ и начало ПЗУ со встроенным загрузчиком (ISP). Эти места прибиты гвоздями к своим адресам разработчиками процессора. 3) Не помните названия функции?Нет, я не использую CMSIS (только заголовочный файл с описанием адресов регистров). Поищите поиском по файлам, ключевое слово "MSP" вы уже знаете. Или обратитесь в техподдержку Кейла -они должны быстро отвечать на вопросы покупателей своего продукта. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 1 20 сентября, 2012 Опубликовано 20 сентября, 2012 · Жалоба Т.е., когда я заливаю "Загрузчик" по адресу 0х0000 0000 и "Рабочую программу" по адресу 0х0000 2000 обе программы обращаются к одной и той же таблице векторов, которая расположена по адресу 0х0000 0000. Из-за этого "Рабочая программа" запуститься не может, потому что в ней находятся данные "Загрузчика". Я правильно понял суть проблемы? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 20 сентября, 2012 Опубликовано 20 сентября, 2012 · Жалоба Примерно так. Процессор умеет читать вектора только из одного места. Чтобы и приложение и загрузчик оба могли использовать прерывания надо на время работы приложения подсунуть в это место таблицу векторов приложения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 1 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба А как такое решение проблемы: Проект №1 - "Загрузчик" Проект №2 - "Рабочая программа" После того как мы их скомпилировали, открыть HEX-файлы обоих проектов. В ручную заменить строки в НЕХ-файле "Загрузчика", соответствующие таблице векторов прерываний на аналогичные строки из НЕХ-файла "Рабочей программы" не трогая только первые две ячейки: main stack pointer и reset vector. И поскольку в моем "Загрузчике" не используются прерывания, то передав управление "Рабочей программе" та запустится. Сработает? А как такое решение проблемы: Проект №1 - "Загрузчик" Проект №2 - "Рабочая программа" После того как мы их скомпилировали, открыть HEX-файлы обоих проектов. В ручную заменить строки в НЕХ-файле "Загрузчика", соответствующие таблице векторов прерываний на аналогичные строки из НЕХ-файла "Рабочей программы" не трогая только первые две ячейки: main stack pointer и reset vector. И поскольку в моем "Загрузчике" не используются прерывания, то передав управление "Рабочей программе" та запустится. Сработает? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex19 0 21 сентября, 2012 Опубликовано 21 сентября, 2012 (изменено) · Жалоба Если Вы в загрузчике не используете прерывания - сделайте как в примере от NXP (secondary bootloader) В прерываниях загрузчика сделайте редирект на прерывания приложения. Как-то так можно: (для загрузчика размером 4кб(0x1000) ) #define BOOTLOADER_SIZE 0x1000 #define redirect(address) unsigned long pc = *(unsigned long*)(address) + (BOOTLOADER_SIZE); void (*redirect_handler)(void) = (void(*)(void))pc;\ redirect_handler(); .... void CT16B0_IRQHandler(void) { redirect(0x1080); } void CT16B1_IRQHandler(void) { redirect(0x1084); } void CT32B0_IRQHandler(void) { redirect(0x1088); } ..... Изменено 21 сентября, 2012 пользователем Alex19 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба После того как мы их скомпилировали, открыть HEX-файлы обоих проектов. В ручную заменить строки в НЕХ-файле "Загрузчика", соответствующие таблице векторов прерываний на аналогичные строки из НЕХ-файла "Рабочей программы" не трогая только первые две ячейки: main stack pointer и reset vector. Давайте думать дальше. Вы доработали рабочую программу и ее обработчики прерываний оказались по другим адресам. Вам снова надо брать обе прошивики, снова копировать строки HEX-файлов, программировать уже обновленный загрузчик. Тогда какой в нем смысл, если его надо править и заливать программатором перед каждым обновлением приложения? В чем проблема? Вам жалко 256 байт ОЗУ (а реально меньше, ибо не вся таблица используется)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 1 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба Давайте думать дальше. Вы доработали рабочую программу и ее обработчики прерываний оказались по другим адресам. Вам снова надо брать обе прошивики, снова копировать строки HEX-файлов, программировать уже обновленный загрузчик. Тогда какой в нем смысл, если его надо править и заливать программатором перед каждым обновлением приложения? В чем проблема? Вам жалко 256 байт ОЗУ (а реально меньше, ибо не вся таблица используется)? Пытаюсь сделать с помощью Ремапа, не могу понять в чем дело. Решил идти от простого к сложному. 1)Самое простое в ручную из одного HEX-файла скопировать данные по адресам 0х09-0хС0 (по этим адресам располагается таблица векторов. Не трогаю лишь два первых вектора 0х00 - 0х08). Получилось "Рабочая программа" запустилась. 2) Перешел к более сложному - копирую файлы 0х00 - 0х08 (MSP и Reset handler) программно с помощью чего осуществляю прыжок в "Рабочую программу" и она запускается, если не использует прерываний: #include "LPC11xx.h" #include "core_cm0.h" #include "system_LPC11xx.h" __ASM void __jump_( ) { ldr r0, =0x1000 ldr r0, [r0] mov sp, r0 ldr r0, =0x1004 ldr r0, [r0] mov pc, r0 } nt main(void) { SystemInit(); LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); __jump_( ); while(1); } 3)Перехожу к более сложному - программно копирую всю таблицу прерываний - 0х00 - 0хС0. Текст программы: #include "LPC11xx.h" #include "core_cm0.h" #include "system_LPC11xx.h" __ASM void __jump_( ) { ldr r0, =0x1000 ldr r0, [r0] mov sp, r0 ldr r0, =0x1004 ldr r0, [r0] mov pc, r0 ldr r0, =0x1008 ldr r0, [r0] ldr r1, =0x0008 mov [r1], r0 ldr r0, =0x1008 ldr r0, [r0] ldr r1, =0x0008 mov [r1], r0 ...................... //здесь такие же наборы команд для других адресов ...................... ldr r0, =0x10BC ldr r0, [r0] ldr r1, =0x00BC mov [r1], r0 } int main(void) { SystemInit(); LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); __jump_( ); while(1); } И тут сталкиваюсь с затруднением - компилятор на строке "mov [r1], r0" выдает ошибку: error: A1647E: Bad register name symbol, expected Integer register В чем дело? Эта команда же допускает копирование из РОН в память Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба Эта команда же допускает копирование из РОН в памятьЕсли вы читаете из памяти командной ldr, то писать в нее логично командой str. Но, мама дорогая! Почему на ассемблере, да еще и тупым copy-paste? Это, кажется, называется "индусский код"? uint32_t const * pSrc = (uint32_t const *)0x1000; uint32_t * pDst = (uint32_t const *)0x0000; #define VECTORS_COUNT 64 // подставьте сколько нужно, включая указатель стека и reset handler for(uint_fast8_t i = 0; i < VECTORS_COUNT; ++i) *pDst++ = *pSrc++; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 1 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба Если вы читаете из памяти командной ldr, то писать в нее логично командой str. Но, мама дорогая! Почему на ассемблере, да еще и тупым copy-paste? Это, кажется, называется "индусский код"? uint32_t const * pSrc = (uint32_t const *)0x1000; uint32_t * pDst = (uint32_t const *)0x0000; #define VECTORS_COUNT 64 // подставьте сколько нужно, включая указатель стека и reset handler for(uint_fast8_t i = 0; i < VECTORS_COUNT; ++i) *pDst++ = *pSrc++; Индусский ли пиндосский ли...)) Ваш кусок кода не перепрыгивает в "Рабочую программу". Видимо на STM32 есть возможность напрямую писать во флеш (в lpc11xx это возможно только посредством специальных IAP команд) Написанная мною тоже не пашет: ldr r0, =0x1004 ; загружаем в r0 константу 0х1004 ldr r0, [r0] ; загружаем в r0 содержимое по адресу 0х1004 ldr r1, =0x0004 ; загружаем в r0 константу 0х0004 str r0, [r1] ; загружаем значение r0 в адрес r1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба Видимо на STM32 есть возможность напрямую писать во флешВы и себя запутали и я просто перенес на С ваш код с некоторой оптимизацией. Не нужно писать во флеш. И не нуждно копировать в адрес 0. Надо копировать в начало ОЗУ. И потом ремапом подставлять эту область ОЗУ на нулевые адреса: uint32_t const * pSrc = (uint32_t const *)0x00001000; // начало приложения uint32_t * pDst = (uint32_t *)0x10000000; // начало ОЗУ #define VECTORS_COUNT 64 // подставьте сколько нужно, включая указатель стека и reset handler for(uint_fast8_t i = 0; i < VECTORS_COUNT; ++i) *pDst++ = *pSrc++; // далее надо загрузить указатель стека. не_знаю_как_это_сделать_в_кейле(*(uint32_t const *)0x00001000); // LPC_SYSCON->SYSMEMREMAP = 1; // remap to ram void (*Application)(); Application = *(void (**)())0x10000004; Application(); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Almaz1988 1 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба Вы и себя запутали и я просто перенес на С ваш код с некоторой оптимизацией. Не нужно писать во флеш. И не нуждно копировать в адрес 0. Надо копировать в начало ОЗУ. И потом ремапом подставлять эту область ОЗУ на нулевые адреса: uint32_t const * pSrc = (uint32_t const *)0x00001000; // начало приложения uint32_t * pDst = (uint32_t *)0x10000000; // начало ОЗУ #define VECTORS_COUNT 64 // подставьте сколько нужно, включая указатель стека и reset handler for(uint_fast8_t i = 0; i < VECTORS_COUNT; ++i) *pDst++ = *pSrc++; // далее надо загрузить указатель стека. не_знаю_как_это_сделать_в_кейле(*(uint32_t const *)0x00001000); // LPC_SYSCON->SYSMEMREMAP = 1; // remap to ram void (*Application)(); Application = *(void (**)())0x10000004; Application(); Спасибо за пояснения)) Но с ремапом у меня нивкакую запускаться не хочет)) Продолжу с понедельника. П.с. и все же есть возможность записи во флеш ассемблерными вставками?(Как запасной вариант, если ремап не запустится) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться