реклама на сайте
подробности

 
 
8 страниц V  < 1 2 3 4 > »   
Reply to this topicStart new topic
> STM32 bootloader, написание собственного бута
Сергей Борщ
сообщение Sep 20 2012, 06:20
Сообщение #16


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Almaz1988 @ Sep 20 2012, 07:24) *
Cortex-M0
Тогда нужно:
1) Располагать (линковать) загрузчик с адреса 0x08000000, чтобы он мог продолжать работать после ремапа.
2) Располагать (линковать) приложение с адреса 0x0800хххх, чтобы онo могло работать после ремапа.
2) Копировать вектора приложения в начало ОЗУ. У приложения должно быть "откушено" начало ОЗУ под это дело в скрипте линкера.
3) Из векторов приложения брать адрес начала стека и прописывать его в MSP
4) Делать ремап (SYSCFG, биты MEM_MODE)
5) передавать управление на адрес, взятый из вектора reset_handler


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 20 2012, 07:18
Сообщение #17


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Цитата(_Артём_ @ Sep 19 2012, 15:56) *
Если буту прерывания не нужно, то можете посмотреть пример 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


Цитата(Сергей Борщ @ Sep 20 2012, 10:20) *
Тогда нужно:
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) также выподняется ассемблерными вставками?




Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 20 2012, 09:23
Сообщение #18


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Almaz1988 @ Sep 20 2012, 10:18) *
Компиллирую проект, выдает ошибку:
С кейлом не работаю, не подскажу. Пусть другие участники помогутю
QUOTE (Almaz1988 @ Sep 20 2012, 10:18) *
1,2) Flash-память микроконтроллера lpc11c24
А название ветки - STM32 bootloader. Невнимательно читал ваше первое сообщение и даю советы по STM32F0xx. laughing.gif
Для LPC11 ремапятся первые 512 байт. Соответственно смотрите по ссылке от _Артем_а - там я приводил кусок запуска приложения для LPC11
QUOTE (Almaz1988 @ Sep 20 2012, 10:18) *
2) копировать с помощью ассемблерных вставок из NXP примера "secondary bootloader"? Постом ниже я написал о затруднениях, с которыми столкнулся при их использовании.

3,4) также выподняется ассемблерными вставками?
2 - можно и ассемблером, но зачем? Можно сделать и на С/С++ при помощи цикла и указателей либо библиотечной функцией memcpy()
3) да, ассемблерная вставка либо функция из CMSIS, которая тоже на ассемблерной вставке строится.
4) Обычная сишная запись в регистр. Для LPC это будет регистр SYSMEMREMAP


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 20 2012, 11:01
Сообщение #19


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



2) а если размещать вектор прерываний не в RAM, а во flash по адресу 0х0000 2000 (сюда у меня рабочая программа линкуется), с помощью встроенных IAP-команд, которые позволяют записывать во флеш страницами по 256 байт?
Нужно ли будет в таком случае делать Remap?
3) Не помните названия функции?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 20 2012, 11:21
Сообщение #20


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Almaz1988 @ Sep 20 2012, 14:01) *
2) а если размещать вектор прерываний не в RAM, а во flash по адресу 0х0000 2000
Разместить вектора вы можете где угодно, но вот процессор читает их с адреса 0x00000000. И никаких способов считывать их из других адресов у Cortex-M0 не предусмотрено (у M3 для этого есть регистр VTOR). Поэтому разработчики процессоров идут на хитрость - делают отражение (remap) на эти адреса других регионов памяти, например RAM. После ремапа вы кладете какие-то данные в начало RAM, а процессор их "видит" не только по "родным" адресам в RAM, но и в начале флеша. И таких мест, которые могут быть отражены на начало адресного пространства всего два - начало ОЗУ и начало ПЗУ со встроенным загрузчиком (ISP). Эти места прибиты гвоздями к своим адресам разработчиками процессора.
QUOTE (Almaz1988 @ Sep 20 2012, 14:01) *
3) Не помните названия функции?
Нет, я не использую CMSIS (только заголовочный файл с описанием адресов регистров). Поищите поиском по файлам, ключевое слово "MSP" вы уже знаете. Или обратитесь в техподдержку Кейла -они должны быстро отвечать на вопросы покупателей своего продукта.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 20 2012, 12:36
Сообщение #21


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Т.е., когда я заливаю "Загрузчик" по адресу 0х0000 0000 и "Рабочую программу" по адресу 0х0000 2000 обе программы обращаются к одной и той же таблице векторов, которая расположена по адресу 0х0000 0000. Из-за этого "Рабочая программа" запуститься не может, потому что в ней находятся данные "Загрузчика".
Я правильно понял суть проблемы?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 20 2012, 15:26
Сообщение #22


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Примерно так. Процессор умеет читать вектора только из одного места. Чтобы и приложение и загрузчик оба могли использовать прерывания надо на время работы приложения подсунуть в это место таблицу векторов приложения.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 21 2012, 06:37
Сообщение #23


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



А как такое решение проблемы:
Проект №1 - "Загрузчик"
Проект №2 - "Рабочая программа"

После того как мы их скомпилировали, открыть HEX-файлы обоих проектов.
В ручную заменить строки в НЕХ-файле "Загрузчика", соответствующие таблице векторов прерываний на аналогичные строки из НЕХ-файла "Рабочей программы" не трогая только первые две ячейки: main stack pointer и reset vector.

И поскольку в моем "Загрузчике" не используются прерывания, то передав управление "Рабочей программе" та запустится.

Сработает?

А как такое решение проблемы:
Проект №1 - "Загрузчик"
Проект №2 - "Рабочая программа"

После того как мы их скомпилировали, открыть HEX-файлы обоих проектов.
В ручную заменить строки в НЕХ-файле "Загрузчика", соответствующие таблице векторов прерываний на аналогичные строки из НЕХ-файла "Рабочей программы" не трогая только первые две ячейки: main stack pointer и reset vector.

И поскольку в моем "Загрузчике" не используются прерывания, то передав управление "Рабочей программе" та запустится.

Сработает?
Go to the top of the page
 
+Quote Post
Alex19
сообщение Sep 21 2012, 07:11
Сообщение #24


Участник
*

Группа: Участник
Сообщений: 21
Регистрация: 14-05-09
Из: Тула
Пользователь №: 49 063



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

Сообщение отредактировал Alex19 - Sep 21 2012, 07:42
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 21 2012, 07:51
Сообщение #25


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Almaz1988 @ Sep 21 2012, 09:37) *
После того как мы их скомпилировали, открыть HEX-файлы обоих проектов.
В ручную заменить строки в НЕХ-файле "Загрузчика", соответствующие таблице векторов прерываний на аналогичные строки из НЕХ-файла "Рабочей программы" не трогая только первые две ячейки: main stack pointer и reset vector.
Давайте думать дальше. Вы доработали рабочую программу и ее обработчики прерываний оказались по другим адресам. Вам снова надо брать обе прошивики, снова копировать строки HEX-файлов, программировать уже обновленный загрузчик. Тогда какой в нем смысл, если его надо править и заливать программатором перед каждым обновлением приложения?
В чем проблема? Вам жалко 256 байт ОЗУ (а реально меньше, ибо не вся таблица используется)?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 21 2012, 10:00
Сообщение #26


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Цитата(Сергей Борщ @ Sep 21 2012, 11:51) *
Давайте думать дальше. Вы доработали рабочую программу и ее обработчики прерываний оказались по другим адресам. Вам снова надо брать обе прошивики, снова копировать строки 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
В чем дело?
Эта команда же допускает копирование из РОН в память




Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 21 2012, 10:12
Сообщение #27


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Almaz1988 @ Sep 21 2012, 13:00) *
Эта команда же допускает копирование из РОН в память
Если вы читаете из памяти командной ldr, то писать в нее логично командой str.
Но, мама дорогая! Почему на ассемблере, да еще и тупым copy-paste? Это, кажется, называется "индусский код"?

CODE
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++;



--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 21 2012, 12:30
Сообщение #28


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Цитата(Сергей Борщ @ Sep 21 2012, 14:12) *
Если вы читаете из памяти командной 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

Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 21 2012, 12:45
Сообщение #29


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Almaz1988 @ Sep 21 2012, 15:30) *
Видимо на STM32 есть возможность напрямую писать во флеш
Вы и себя запутали и я просто перенес на С ваш код с некоторой оптимизацией. Не нужно писать во флеш. И не нуждно копировать в адрес 0. Надо копировать в начало ОЗУ. И потом ремапом подставлять эту область ОЗУ на нулевые адреса:

CODE
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();


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 21 2012, 13:14
Сообщение #30


Частый гость
**

Группа: Участник
Сообщений: 100
Регистрация: 19-09-12
Пользователь №: 73 602



Цитата(Сергей Борщ @ Sep 21 2012, 16:45) *
Вы и себя запутали и я просто перенес на С ваш код с некоторой оптимизацией. Не нужно писать во флеш. И не нуждно копировать в адрес 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();


Спасибо за пояснения)) Но с ремапом у меня нивкакую запускаться не хочет))
Продолжу с понедельника.
П.с. и все же есть возможность записи во флеш ассемблерными вставками?(Как запасной вариант, если ремап не запустится)
Go to the top of the page
 
+Quote Post

8 страниц V  < 1 2 3 4 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 10:32
Рейтинг@Mail.ru


Страница сгенерированна за 0.01519 секунд с 7
ELECTRONIX ©2004-2016