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

 
 
> STM32 bootloader, написание собственного бута
ierofant
сообщение Jan 3 2012, 13:31
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 3-02-11
Из: Украина, Киев
Пользователь №: 62 695



Всем привет.

Появилась задача создать бутлоадер, который будет удаленно перепрошивать контроллер. Контроллер работает в связке с gsm-модулем.
Раньше опыта создания бутов не было, поэтому вопросов появилось просто масса.

Во-первых, для себя я вижу 2 концепции бутлоадера, каждый со своими плюсами и минусами.

1. Основная программа качает прошивку, пишет её в определенное место флеша(например, с 16-й страницы флеша), проверяет, все ли правильно записалось, устанавливает в энергонезависимом регистре флаг, что нужно войти в бут, перезагружается, происходит вход в бутлоадер, который очищает основную программу(например, со 2й страницы флеша) и перезаписывает новую прошивку на это место и переходит на выполнение основной программы.

Преимущества(+)/недостатки(-):
+простота бутлоадера, в том числе не нужно инициализировать юарт и модуль из бутлоадера.
+не нужно долго висеть в буте
+перезагружаться в бут можно только после того, как прошивка успешно закачана
-если не верно закачалась прошивка либо же не рабочая прошивка - только вручную перепрошивать
-нужен МК с бОльшим обьемом Flash

2. Основная программа перегружает МК в бут, который удаляет старую прошивку, качает новую и сразу записывает её вместо старой.

Преимущества(+)/недостатки(-):
+бут может сам скачать новую прошивку
+контроллер с меньшим обьемом флеша
-сложность бута - нужно будет иниициализировать юарт, включать и инициализировать gsm модуль.
-долго находиться в бутлоадере

Какой вариант лучше? И, может, есть более совершенные решения?

Теперь вопросы по реализации:
1. Какие подводные камни могут быть в написании бута?
2. Читал на форуме про то, что нужно перезаписывать таблицу векторов(или вектора прерываний?)? Можно об этом подробнее? Как это делается? Где об этом можно подробнее почитать, а то никакой вразумительной инфы не нашел.
3. Бут и основная программа пишуться ведь как 2 разных проекта?


Отадельным вопросом - как заставить программу перейти на выполнение с определенного адреса? Где найти об этом информацию?
Пробывал как в примере от ST:
CODE
#include "common.h"
#define ApplicationAddress 0x08000073

extern pFunction Jump_To_Application;
extern uint32_t JumpAddress;

/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();


Не получилось. На ф-ции Jump_To_Application(); уходит в hardfault
Особенно не понятно, где тело этой функции, нигде в присоединенных файлах эта функция не описана. (файлы примера прикрепил к сообщению)

Был бы очень благодарен, если бы кто-то подсказал, где об этом можно прочитать и где можно найти рабочие и понятные примеры.


И чтобы не плодить сообщения, напишу про еще одну проблему с отладочной платой: на STM32VLDiscovery целевой контроллер работает, прошивается, но невероятно греется. Даже на 2 секунды нельзя на нем задержать палец. Очень горячий. Закороток визуально нет, да и паяльником я не притрагивался к плате , не знаю, с чего все и началось. Тестера под рукой тоже нет. Не работает светодиод LD4. Правда я не знаю, это следствие или причина нагрева, сейчас далеко от цивилизации, протестить и перепаять ничего не могу. (схема : http://www.st.com/internet/com/TECHNICAL_R...CD00267113.pdf)


Прикрепленные файлы
Прикрепленный файл  an2557.rar ( 1.64 мегабайт ) Кол-во скачиваний: 79
 
Go to the top of the page
 
+Quote Post
8 страниц V   1 2 3 > »   
Start new topic
Ответов (1 - 99)
skripach
сообщение Jan 3 2012, 16:12
Сообщение #2


■ ■ ■ ■
*****

Группа: Свой
Сообщений: 1 100
Регистрация: 9-08-06
Пользователь №: 19 443



Я бы делал вариант 2, т.к. в первом варианте во вновь загруженной прошивке может неожиданно вылезти глюк при загрузке новой пошивки и это "конец". sm.gif Да и памяти больше нужно. Хотя конечно глюк может вылезти везде.
Переход на приложение:
Код
void JumpToApplication(Int32U addr)
{
  typedef  void (*pFunction)(void);
  pFunction Jump_To_Application;
  Int32U JumpAddress;
  if(addr>=0x08005000)
  {
    JumpAddress = *(Int32U*) (addr + 4);
    Jump_To_Application = (pFunction) JumpAddress;
    /* Initialize user application's Stack Pointer */
    __MSR_MSP(*(vu32*) addr);
    Jump_To_Application();
  }
}

Цитата
Читал на форуме про то, что нужно перезаписывать таблицу векторов(или вектора прерываний?)?

NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x08005000);
Цитата
Бут и основная программа пишуться ведь как 2 разных проекта?

Да.


--------------------
Делай что должен и будь что будет.
Go to the top of the page
 
+Quote Post
Cosmojam
сообщение Jan 3 2012, 20:52
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182



Цитата(ierofant @ Jan 3 2012, 16:31) *
Пробывал как в примере от ST:
Не получилось. На ф-ции Jump_To_Application(); уходит в hardfault

Внимательно проверьте правильно ли и по правильным ли адресам записывается приложение. Я с этим долго бился на LPC17 из-за банальной ошибке при записи данных.
skripach, Ваш пример ничем не отличается от приведённого ТС. Указания нового положения таблицы векторов нет. Или это фича STM? Я правда пока с ними не работал, но предстоит в ближайшее время. Вы ставите указатель на функцию на адрес ResetISR в приложении и обновляете верхушку стека, но не указываете новое расположение таблицы векторов прерываний. Ведь без этого прерывание в приложении приведёт к попутке перехода на вектор в загрузчике.


--------------------
typedef enum { no, yes, maybe } bool; | блог тут
Go to the top of the page
 
+Quote Post
skripach
сообщение Jan 3 2012, 21:30
Сообщение #4


■ ■ ■ ■
*****

Группа: Свой
Сообщений: 1 100
Регистрация: 9-08-06
Пользователь №: 19 443



Цитата
skripach, Ваш пример ничем не отличается от приведённого ТС.

Возможно, автор вопрошал "как перейти на выполнение с определенного адреса?" я привел функцию из своего загрузчика под stm32.
Цитата
Указания нового положения таблицы векторов нет.

Если правильно помню это сделано в приложении, перед прыжком были выключены все прерывания.


--------------------
Делай что должен и будь что будет.
Go to the top of the page
 
+Quote Post
ierofant
сообщение Jan 3 2012, 21:33
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 3-02-11
Из: Украина, Киев
Пользователь №: 62 695



Спасибо, что откликнулись.

skripach

Пытаюсь в простейшей программке протестировать переход выполнения кода по определенному адресу. Пробывал с вашим примером, опять не получилось.

Вот мой код(для иара, поэтому немного отличается от вашего):
CODE
#include "stm32f10x.h"
#include "core_cm3.h"
#define ApplicationAddress 0x08000081


void JumpToApplication(uint32_t addr)
{
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
//if(addr>=0x08005000)
//{
JumpAddress = *(uint32_t*) (addr + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(uint32_t*) addr);
//__MSR_MSP(*(vu32*) addr);
Jump_To_Application();
//}
}




void init_mk()
{
RCC->APB2ENR |= (RCC_APB2ENR_IOPAEN|RCC_APB2ENR_IOPCEN);

GPIOC->CRH |= (GPIO_CRH_MODE9 | GPIO_CRH_MODE8); //C.8, C.9 OUTPUT
GPIOC->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_CNF8);
GPIOA->CRL&=~GPIO_CRL_MODE0;//A.0 INPUT
}

void test()
{
GPIOC->BSRR = GPIO_BSRR_BS9;
}


int main()
{
init_mk();


JumpToApplication(ApplicationAddress);


GPIOC->BSRR = GPIO_BSRR_BS8;

test();

while(1)
{
}
}



__MSR_MSP - не было, заменил на функцию подобного содержания из своего хидера. Вот такая функция

CODE
void __set_MSP(uint32_t topOfMainStack)
{
  __ASM("msr msp, r0");
  __ASM("bx lr");
}


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

#define ApplicationAddress 0x08000081 - это начальный адрес функции test(). (беру его из map-а)

Т.е. по предположению - код должен выполниться в обход строки : GPIOC->BSRR = GPIO_BSRR_BS8; Верно?

Отладчик после выполнения Jump_To_Application(); матерится на то, что указатель стека находится вне его пределах, причем откуда такое значение - черт знает: The stack pointer for stack 'CSTACK' (currently 0x00F44F28) is outside the stack range (0x20000000 to 0x20000400)

Cosmojam, я пока пытаюсь осуществить просто переход выполнения программы по определенному адресу, таблицу векторов даже не трогаю.sm.gif Выше отписался, что у меня не так.


Кстати, я правильно понимаю алгоритм работы бутлоадера?
После того, как он закончил все свои необходимые действия, нужно:
1. перенести таблицу векторов по адресу в памяти, где начинается основная программа.(т.е. если у меня основная программа записана, начиная с 2й страницы флеша (1 страница - 1кб), то нужно будет сделать так: NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x08000800)wink.gif
2. Перейти к выполнению кода на тот же адрес (0x08000800)

Верно ли я все понял?

P.S. Кстати, skripach, спасибо за приведенный код.

Сообщение отредактировал ierofant - Jan 3 2012, 21:38
Go to the top of the page
 
+Quote Post
skripach
сообщение Jan 4 2012, 00:49
Сообщение #6


■ ■ ■ ■
*****

Группа: Свой
Сообщений: 1 100
Регистрация: 9-08-06
Пользователь №: 19 443



Цитата
Т.е. по предположению - код должен выполниться в обход строки : GPIOC->BSRR = GPIO_BSRR_BS8; Верно?

Разумеется нет. Функция JumpToApplication это не совсем "перейти на выполнение с определенного адреса", это переход на приложение расположенное по адресу [addr].
Если попытаетесь разобраться с содержимым JumpToApplication то многое станет понятно в том числе почему "матерится на то, что указатель стека...". Также советую посмотреть в дизассамблер.
Цитата
Кстати, я правильно понимаю алгоритм работы бутлоадера?
После того, как он закончил все свои необходимые действия, нужно:
1. перенести таблицу векторов по адресу в памяти, где начинается основная программа.(т.е. если у меня основная программа записана, начиная с 2й страницы флеша (1 страница - 1кб), то нужно будет сделать так: NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x08000800)

Близко. Таблицу векторов нужно перенести туда где она находится в приложении. Начало приложения и адрес таблицы векторов могут не совпадать, см настройки линкера.
Цитата
2. Перейти к выполнению кода на тот же адрес (0x08000800)

Нет. Нерейти на начало приложения, в нашем случае адрес начала приложения расположен по адресу (адрес таблицы векторов+4). см. таблицу векторов.


--------------------
Делай что должен и будь что будет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 4 2012, 07:47
Сообщение #7


Гуру
******

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



Как у вас все сложно!
Какова структура "обычной" программы под STM32?
В начале идет блок векторов, он состоит из:
-начальное значение стека
-адрес обработчика исключения Reset
-адреса остальных обработчиков ядра
-адреса обработчиков периферии
Далее за ним идет код.

Ну так и работать надо с этой структурой, а не с какими-то магическими числами и приведением указателей:
CODE
struct application
{
    struct vectors
    {
        typedef void( *handler )( void );
        uint32_t    MSP_init;
        handler     Reset_vector;
        handler     Core_handler[14];
        static const uint_fast8_t MCU_VECTORS =
#if defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL)
        56
#elif   defined(STM32F10X_HD_VL)
        61
#elif defined(STM32F10X_CL)
        68
#elif defined(STM32F10X_LD) || defined(STM32F10X_MD) ||defined(STM32F10X_HD) ||defined(STM32F10X_XL)
        60
#endif
     ;
        handler     MCU_handler[MCU_VECTORS];
    }       Vectors;
    uint32_t Size;                          // application size, 4-byte words
};

extern const application Application;

.......
                if (!CRC->DR)                        // Application Section OK
            {
                // set vectors table to application vectors
                SCB->VTOR = (uintptr_t)&Application.Vectors;
                asm volatile
                (
                    "   MSR   MSP, %0\n" // store App stack init value to MSP
                    :
                    : "r" (Application.Vectors.MSP_init)
                );
                Application.Vectors.Reset_vector();
            }

От линкера требуется лишь предоставить символ Application с адресом начала той области, в которую загружается приложение. Не знаю как в последнем ИАРе, в старом это можно было сделать, вписав в линкерный скрипт или командную строку линкера -DApplication=0x08001000

У меня при сборке приложения линкер сразу за таблицей векторов вписывает размер образа, чтобы загрузчик мог просчитать контрольную сумму загруженного приложения (и только его, не учитывая свободную память).


--------------------
На любой вопрос даю любой ответ
"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
ierofant
сообщение Jan 8 2012, 00:38
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 3-02-11
Из: Украина, Киев
Пользователь №: 62 695



Спасибо всем за помощь.

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

Вот только если я пытаюсь перенести таблицу в программе бутлоадера - не выходит (не работают прерывания), если же в основной программе - все нормально.

Переношу так(т.к. не использую библиотеку для периферии, написал сам) :

CODE
#define vector_table_offset 0xC00   //смещение
#define offset (uint32_t)(vector_table_offset & 0x1FFFFF80)   //выравнивание

SCB->VTOR =  offset;


На приложение перехожу с помощью функции JumpToApplication, которую подсказал skripach.

Сергей Борщ, пытался разобрать вашу программу. Не понятна эта строчка:
CODE
SCB->VTOR = (uintptr_t)&Application.Vectors;

Возвращается адрес Application.Vectors, после чего явно преобразуется в тип указателя. Тут понятно. А что именно содержит Application.Vectors? И как оно туда попало?
Связано это, видимо, с
QUOTE
От линкера требуется лишь предоставить символ Application с адресом начала той области, в которую загружается приложение.

И на сколько я понимаю, линкер предоставляет структуре адрес начала приложения, потом уже в структуре в соотвествии этому начальному адресу всем векторам присваиваются их адреса?

Написана ваша программа, однозначно красивее и четче, единственное, хочется её полностью понять.
А может еще подскажете, где в iar 6.21 линкерный скрипт?
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 19 2012, 09:41
Сообщение #9


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

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



Так же пишу бутлоадер, но для lpc11c24.
Столкнулся с казалось бы элементарной проблемой - не могу прошить даже самую простую программу (моргание светодиодом) по адресу, отличному от нуля.
Т.е. если стартовый адрес во флеш-памяти ставлю 0х00000000, то программа стартует.
Стоит его поменять на, к примеру, 0х00000100 и программа не запускается.
Пишу в Keil. Адрес выставляю следующим образом:
правый клик по проекту-->Options for target-->Linker-->R/O base = 0x00000100.
Попробовал прошить из LPCXpresso, - получил ошибку "vectors still have erased values".
Спасибо за ответы
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 19 2012, 10:09
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(Almaz1988 @ Sep 19 2012, 12:41) *
Столкнулся с казалось бы элементарной проблемой - не могу прошить даже самую простую программу (моргание светодиодом) по адресу, отличному от нуля.

Прошиваться она может и прошивается, но работать не будет.

Цитата(Almaz1988 @ Sep 19 2012, 12:41) *
Пишу в Keil. Адрес выставляю следующим образом:
правый клик по проекту-->Options for target-->Linker-->R/O base = 0x00000100.
Попробовал прошить из LPCXpresso, - получил ошибку "vectors still have erased values".
Спасибо за ответы

Этого недостаточно.
Нужна вторая программа (собственно бутлоадер), которая должна быть расположена по адресу 0, и которая запустит основное приложение. Зашить её нужно до зашивки-отладки основной программы.
Ещё момент: смещение 0x100 может и допустимо, но нежелательно - flash стирается по 4кБ за раз и получается нельзя обновить основную программу, не стирая бут. Стереть его можно, если он будет работать из ОЗУ, но это чревато.
Ставьте смещение кратное 0x1000. Для простого бута 4к достаточно, если нужно больше - увеличивайте.

P.S. ещё про boot на lpc11xx
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 19 2012, 10:55
Сообщение #11


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

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



Спасибо Артем, ваш ответ очень помог)

По адресу 0х0000 2000 залил "Рабочая программа", которая моргает 4 раза.

По адресу 0х0000 0000 тоже залил "Бутлоадер", которая моргает 4 раза, а потом прыгает по адресу 0х2169 (функция main() "Рабочей программы" по MAP-файлу).

Все сработало как и ожидалось - МК моргнул 8 раз. Т.е. МК стартовал с "Бутлоадера" затем передал управление "Рабочей программе".

Но вот на следующем этапе на место "Рабочей программы" я залил программу по сложнее ( которую собственно говоря и пишу). В итоге МК моргнул 4 раза, а "Рабочая программа" не запустилась. Подозрения падают на то, что она работает по прерываниям, о чем, собственно, ваша ссылка.

Не могли вы "на пальцах" объяснить, почему эти прерывания требуют особого отношения и для чего нужен ремап векторов?
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 19 2012, 11:56
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(Almaz1988 @ Sep 19 2012, 13:55) *
Не могли вы "на пальцах" объяснить, почему эти прерывания требуют особого отношения и для чего нужен ремап векторов?

Ремап нужен чтобы и бут и рабочая программа могли использовать прерывания. К тому же вектора расположены по адресам от 4 и получается что приложение хранит адреса своих обработчиков в области бута, что как-то странно (если без ремапа). Если буту прерывания не нужно, то можете посмотреть пример NXP (secondary bootloader). там пример где все обработчики делают jump (или call - не помню точно) в область рабочей программы.



Цитата(Almaz1988 @ Sep 19 2012, 13:55) *
По адресу 0х0000 0000 тоже залил "Бутлоадер", которая моргает 4 раза, а потом прыгает по адресу 0х2169 (функция main() "Рабочей программы" по MAP-файлу).

P.S. Бут должен "прыгать" не на main, а на Reset_Handler.
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 19 2012, 12:36
Сообщение #13


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

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



Исправил на reset handler.

По поводу ремапа, как я понял, если "Бутлоадер" залит по адресу 0х0000 0000, а "Рабочая программа" залита по адресу 0х0000 2000 то:

"Бутлоадер", перед тем как передать управление "Рабочей программе" должен таблицу векторов, размещенную по адресам 0х0000 0000 - 0х0000 00С0 скопировать в адреса 0х0000 0000 - 0х0000 20С0, иначе "Рабочая программа" не сможет запуститься?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 19 2012, 20:15
Сообщение #14


Гуру
******

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



QUOTE (Almaz1988 @ Sep 19 2012, 15:36) *
"Бутлоадер", перед тем как передать управление "Рабочей программе" должен таблицу векторов, размещенную по адресам 0х0000 0000 - 0х0000 00С0 скопировать в адреса 0х0000 0000 - 0х0000 20С0, иначе "Рабочая программа" не сможет запуститься?
Если мы говорим о Cortex-M3 (M4), то нужно записать в регистр VTOR значение 0x00002000, ведь именно по этому адресу начинается таблица векторов вашего приложения (ячека с начальным значением стека также входит в эту таблицу).


--------------------
На любой вопрос даю любой ответ
"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, 04:24
Сообщение #15


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

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



Цитата(Сергей Борщ @ Sep 20 2012, 00:15) *
Если мы говорим о Cortex-M3 (M4), то нужно записать в регистр VTOR значение 0x00002000, ведь именно по этому адресу начинается таблица векторов вашего приложения (ячека с начальным значением стека также входит в эту таблицу).

Cortex-M0
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение 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
Сергей Борщ
сообщение Sep 21 2012, 13:25
Сообщение #31


Гуру
******

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



Возможность записи во флеш есть. Ведь как-то этот bootloader должен записать во флеш вашу основную программу? И делается это вызовом функций встроенного заводского загрузчика (IAP). Что писать и куда писать - ему все равно. И на каком языке вы напишете вызов его функций - ему тоже все равно. Почему с REMAP ом не получится - непонятно. У всех получается. Посмотрите внимательно, на какие адреса попадает ваша команда ремапа. Я обращал внимание Артема в той ветке на этот момет - в момент ремапа содержимое первых 512 байтов флеш "накрывается" содержимым ОЗУ. И если следующая за ремапом команда вашего загрузчика попала в эту область - вместо нее будет выполнен мусор из соответствующих адресов ОЗУ. Поэтому если ваш загрузчик настолько мал, что команда находится в первых 512 байтах флеша - надо как-то ее оттуда отодвинуть. Либо поколдовать со скриптом линкера, либо добавить кода.


--------------------
На любой вопрос даю любой ответ
"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, 14:57
Сообщение #32


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

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



А IAP-команды переводятся же в ассемблерный код при компилляции? Это ведь не отдельный язык программирования.
Go to the top of the page
 
+Quote Post
toweroff
сообщение Sep 21 2012, 16:10
Сообщение #33


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(Almaz1988 @ Sep 21 2012, 18:57) *
А IAP-команды переводятся же в ассемблерный код при компилляции? Это ведь не отдельный язык программирования.

нет, конечно

в разные регистры заносятся команда, номер начального сектора, конечного сектора, адрес блока данных
вызывается IAP, адрес которого заранее известен
из еще одного регистра читается результат операции

какая разница, каким языком это дело описать?

а вот требования к выполнению IAP (как то - отключить PLL, например, или вызов IAP не из области FLASH) нужно выполнять обязательно
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 22 2012, 12:13
Сообщение #34


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(toweroff @ Sep 21 2012, 19:10) *
а вот требования к выполнению IAP (как то - отключить PLL, например

В UM10398 Chapter 26: LPC111x/LPC11Cxx Flash programming firmware PLL не упоминается (или я не нашёл). Ссылку приведёте?


Цитата(toweroff @ Sep 21 2012, 19:10) *
вызов IAP не из области FLASH

В примере от NXP функции IAP вызываются из flash. Наверняка потому, что из bootloader не использует прерываний. В случае испоользования прерываний таблицу векторов и обработчики нужно поместить в RAM или запрещать прерывания на время стирания/записи flash.
Go to the top of the page
 
+Quote Post
toweroff
сообщение Sep 22 2012, 16:05
Сообщение #35


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(_Артём_ @ Sep 22 2012, 16:13) *
Ссылку приведёте?


Цитата(toweroff)
(как то - отключить PLL, например,


где-то это требуется, где-то - нет. Здесь весь смысл в том, что требования выполнения IAP, если они есть, выполнять нужно, а вот на каком языке это делать - никакой принципиальной разницы нет
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 22 2012, 17:00
Сообщение #36


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(toweroff @ Sep 22 2012, 19:05) *
Здесь весь смысл в том, что требования выполнения IAP, если они есть, выполнять нужно,

Ну, если так...
Но всё равно спасибо - просмотрел ещё раз UM и обнаружил требование запрета прерываний на момент записи .
Хотя работало и без запрета - может функции IAP запрещают прерывания, если таблица не в ОЗУ?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Sep 22 2012, 20:02
Сообщение #37


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Кхм...
Господа, а как обсуждение IAP от NXP относится к теме "STM32 bootloader"? sm.gif
Может быть, выделить это обсуждение в отдельную тему? А то путаница получается.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
toweroff
сообщение Sep 22 2012, 20:16
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(AHTOXA @ Sep 23 2012, 00:02) *
Господа, а как обсуждение IAP от NXP относится к теме "STM32 bootloader"? sm.gif

да все как обычно biggrin.gif
Go to the top of the page
 
+Quote Post
Almaz1988
сообщение Sep 24 2012, 08:44
Сообщение #39


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

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



#include "LPC11xx.h"
#include "rom_drivers.h"
#include "gpio.h"
#include "string.h"
#include "type.h"
#include "core_cm0.h"
#include "system_LPC11xx.h"
#include "application_Flash.h"


__ASM void __copy_MSP_( )
{
ldr r0, =0x10000000
ldr r0, [r0]
mov sp, r0
}

__ASM void __copy_reset_handler_( )
{
ldr r0, =0x10000004
ldr r0, [r0]
bx r0
}

/********************************************************** Main function ********************************/
int main(void)
{
SystemInit();

LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);

uint32_t const * pSrc = (uint32_t const *)0x00001000; //копируем первые 200 байт флеша, начиная с адреса 0х1000 в ОЗУ
uint32_t * pDst = (uint32_t *)0x10000000;
#define VECTORS_COUNT 128
for(uint_fast8_t i = 0; i < VECTORS_COUNT; ++i)
*pDst++ = *pSrc++;

__copy_MSP_( ); //загружаем в стек

__disable_irq(); //запрещаем прерывания
LPC_SYSCON->SYSMEMREMAP = 0x01; // remap to ram

__copy_reset_handler_(); //прыгаем на Resrt_handler

while(1);
}


Работает только если в "рабочей программе" не используются прерывания. Если прерывания используются, то "Рабоча программа" нивкакую не стартует.
Go to the top of the page
 
+Quote Post
AndreFF
сообщение Mar 2 2013, 07:01
Сообщение #40





Группа: Новичок
Сообщений: 3
Регистрация: 10-01-11
Пользователь №: 62 117



Здравствуйте!
Просьба откликнуться кто в теме. Пишу загрузчик для своего приложения (IAR 6.40, STM32F103VET). Как можно в процессе линковки вставить размер образа по конкретному адресу? Это точно можно сделать, тому пример пост Сергея Борща :

'У меня при сборке приложения линкер сразу за таблицей векторов вписывает размер образа, чтобы загрузчик мог просчитать контрольную сумму загруженного приложения (и только его, не учитывая свободную память).'

Go to the top of the page
 
+Quote Post
MK2
сообщение Mar 2 2013, 19:40
Сообщение #41


Местный
***

Группа: Свой
Сообщений: 202
Регистрация: 30-10-10
Пользователь №: 60 535



тоже интересовал этот вопрос, но решил следующим образом: зафиксировал длину прошивки контроллера, просто принимаю за максимальный объем флешки контроллера (вернее то что остается от бутлоадера)
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 2 2013, 23:03
Сообщение #42


Гуру
******

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



QUOTE (AndreFF @ Mar 2 2013, 09:01) *
Это точно можно сделать, тому пример пост Сергея Борща :
Я использую gcc. Про ИАР ничего не скажу. Должна быть какая-то директива размещения константы, надо читать описание линкера.


--------------------
На любой вопрос даю любой ответ
"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
AndreFF
сообщение Mar 3 2013, 06:27
Сообщение #43





Группа: Новичок
Сообщений: 3
Регистрация: 10-01-11
Пользователь №: 62 117



Спасибо за ответы.
Пробовал следовать советам официальной техподдержки IAR
http://supp.iar.com/Support/?note=62709&from=note+65473
а именно пункта Alternative solution using checksum-start and checksum-end markers
Всё отлично, есть константы с адресами начала и конца проекта, считается CRC32, только в Нех файл значение CRC не заносится категорически, вместо него там нули. А в дизассемблере нормальное значение. Пока не победил это.
Go to the top of the page
 
+Quote Post
vovanxp
сообщение Dec 11 2014, 08:55
Сообщение #44


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 28-10-11
Пользователь №: 68 026



Хочу сделать загрузку прошивки через веб, но неполучается, не запускается основная программа.

Делаю на основе проекта с STM32CubeF4, LwIP_IAP. Манеул к этому проекту
http://www.st.com/st-web-ui/static/active/.../DM00103145.pdf

Среда Keil uVision, мк STM32f4
------------------------------------------

В бутлоадере выставил начальный адрес с которого будет стартовать основная программа
#define USER_FLASH_FIRST_PAGE_ADDRESS 0x08020000


В основной программе изменил начальный адресс 0x08020000
В основной программе изменил смещение для таблици векторов #define VECT_TAB_OFFSET 0x20000
------------------------------------------
После загрузки прошивок, доходит до Jump_To_Application(); и все, дальше тишина.
Переменная JumpAddress = 0x080201A5

if (((*(__IO uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
{
JumpAddress = *(__IO uint32_t*) (USER_FLASH_FIRST_PAGE_ADDRESS + 4);
Jump_To_Application = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) USER_FLASH_FIRST_PAGE_ADDRESS);
Jump_To_Application();
}

Основная программа начинается с адреса 0x08020000 смотрел через STM32 ST-LINK Utility
На скринах без смещения с со смещением, данные совпадаю, отличие только адресами.

В чем может быть причина?
Спасибо.
Эскизы прикрепленных изображений
Прикрепленное изображение
Прикрепленное изображение
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Dec 12 2014, 10:46
Сообщение #45


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Цитата(vovanxp @ Dec 11 2014, 11:55) *
В чем может быть причина?
Спасибо.

Выглядит более менее, за исключением того что неясно как вы меняете таблицу прерываний с бутлоадера на вашу программу. Вы блинк пробовали прошить?
Go to the top of the page
 
+Quote Post
vovanxp
сообщение Dec 12 2014, 11:12
Сообщение #46


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 28-10-11
Пользователь №: 68 026



Цитата(Kabdim @ Dec 12 2014, 14:46) *
Выглядит более менее, за исключением того что неясно как вы меняете таблицу прерываний с бутлоадера на вашу программу.


А где менять менять? Я с таблицей ничего не делал.
Я думал что таблица прерываний по умолчанию в основной программе будет после адреса 0x08020000

Цитата(Kabdim @ Dec 12 2014, 14:46) *
Вы блинк пробовали прошить?

Я свою прошивку заливаю.


Go to the top of the page
 
+Quote Post
Kabdim
сообщение Dec 12 2014, 13:19
Сообщение #47


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Цитата(vovanxp @ Dec 12 2014, 14:12) *
А где менять менять? Я с таблицей ничего не делал.
Я думал что таблица прерываний по умолчанию в основной программе будет после адреса 0x08020000


Я свою прошивку заливаю.

SCB->VTOR - на этом форуме очень много тем посвященных бутлоадерам.
Залейте простейшую мигалку что бы понять правильно ли вы слинковались и заливаете. Заодно если она заработает, значит дело действительно в таблице прерываний.
Еще стоит отключать прерывания во время смены таблицы и перехода т.к. они могут испортить процесс.

Вдогонку, если у вас thumb, то младший бит адреса по которому переходите должен быть 1.
Go to the top of the page
 
+Quote Post
vovanxp
сообщение Dec 12 2014, 14:56
Сообщение #48


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 28-10-11
Пользователь №: 68 026



Цитата(Kabdim @ Dec 12 2014, 16:19) *
SCB->VTOR - на этом форуме очень много тем посвященных бутлоадерам.
Залейте простейшую мигалку что бы понять правильно ли вы слинковались и заливаете. Заодно если она заработает, значит дело действительно в таблице прерываний.
Еще стоит отключать прерывания во время смены таблицы и перехода т.к. они могут испортить процесс.

Вдогонку, если у вас thumb, то младший бит адреса по которому переходите должен быть 1.


В моей программе(не в загрузчике) я поменял дефайн
//#define VECT_TAB_OFFSET 0x00
#define VECT_TAB_OFFSET 0x20000

В SystemInit() есть такой кусок кода

#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif

Сообщение отредактировал vovanxp - Dec 12 2014, 14:56
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Dec 12 2014, 17:25
Сообщение #49


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Цитата(vovanxp @ Dec 12 2014, 17:56) *
В моей программе(не в загрузчике) я поменял дефайн

Видимо нужно отладится в асемблере. К примеру мой код для кортекса м0
Код
void JumpToMainProgram() {
    __disable_irq();
    memcpy(MEMORY_OFFSET, MAIN_PROG_FLASH_OFFSET, INT_MEM_TO_MAP_SIZE);
    __set_MSP(*MAIN_PROG_FLASH_OFFSET);
    LPC_SYSCON->SYSMEMREMAP = 1;
    __enable_irq();
    ISRPtr application_reset_handler = *((ISRPtr*) (MAIN_PROG_FLASH_OFFSET + 1));
    goto *application_reset_handler;

}


MAIN_PROG_FLASH_OFFSET - указатель на u32

Сообщение отредактировал Kabdim - Dec 12 2014, 17:23
Go to the top of the page
 
+Quote Post
vovanxp
сообщение Dec 17 2014, 07:59
Сообщение #50


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 28-10-11
Пользователь №: 68 026



Только что удалось прошить через веб, причина было совсем капец, инициализацию IWDG закоментировал, а в обработчике прерывания таймера оставил HAL_IWDG_Refresh(&Hiwdg);
При обычном режиме все работало, но если основная программа начиналась с 0x8020000 программа не работала.

Одним словом причина была совсем в ином.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 19 2015, 10:44
Сообщение #51


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



А можно ли утоптать загрузчик в память OTP (512 байтов), которая имеется, например, в STM32F207?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 20 2015, 05:46
Сообщение #52


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



А как туда будет передаваться управление?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 20 2015, 07:53
Сообщение #53


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(AHTOXA @ Feb 20 2015, 08:46) *
А как туда будет передаваться управление?

Это будет автономный проект, загрузчик. Без прерываний, работа только по последовательному порту. После сброса попадаем в него. Если есть признак, что нужно обновить основную программу (или просто ждать сообщения секунды 4), принимаем, программируем, сбрасываемся. Если признака нет уходим на основную программу. Стартовый адрес (тот, что в прошивке по 0x00000000), сохраняем где-то в недрах..., и используем его для перехода. А вместо него при прошивке пишем адрес загрузчика. И не надо перемещать основную программу, удобно для отладки.

Вижу вероятность получить неработающий прибор, когда сектор 0 уже стер, а записать не успел.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 20 2015, 09:17
Сообщение #54


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(ViKo @ Feb 20 2015, 12:53) *
После сброса попадаем в него.

Я вот про это и спрашивал. Как мы попадаем в него? Насколько я знаю, после сброса можно попасть в три места: в начало флеша, в ОЗУ и в заводской загрузчик.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 20 2015, 10:36
Сообщение #55


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(AHTOXA @ Feb 20 2015, 12:17) *
Я вот про это и спрашивал. Как мы попадаем в него? Насколько я знаю, после сброса можно попасть в три места: в начало флеша, в ОЗУ и в заводской загрузчик.

Как обычно. В начале flash записан адрес (загрузчика, в данном случае), по которому переходим... ага, эта часть не отображается на нулевые адреса... и из нее, очевидно, нельзя выполнять программы. Но ведь в System Memory скакнуть, вроде, можно?
Ладно, идею похерим. Займу нулевой сектор под загрузчик. Только разобраться надо, как основную программу создавать. Задать ее расположение с адреса 0x0800_4000, что ли?

Я вот чего не пойму. Программный счетчик когда по программе бегает, он какие значения перебирает? Вижу в отладчике 0x0800XXXX. Тогда при чем тут нулевые адреса вообще?
Или в этом случае (работа из flash) адреса 0x00000000 и 0x08000000 - это одно и то же? И можно задать и так, и так? Скажем, вручную в отладчике?
То есть, старшие биты адреса при старте принудительно выставляются в 0x0800 и погнали...
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Feb 20 2015, 12:20
Сообщение #56


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Цитата(ViKo @ Feb 20 2015, 05:36) *
Я вот чего не пойму. Программный счетчик когда по программе бегает, он какие значения перебирает? Вижу в отладчике 0x0800XXXX. Тогда при чем тут нулевые адреса вообще?
Или в этом случае (работа из flash) адреса 0x00000000 и 0x08000000 - это одно и то же? И можно задать и так, и так? Скажем, вручную в отладчике?
То есть, старшие биты адреса при старте принудительно выставляются в 0x0800 и погнали...


Правильные пацаны просто читают мануаль в таком случае.
Угу, одно и тоже. А вот "задать вручную в отладке" это уже методы юных кулхацкеров.
Неизвестно как оно имплементировано, и гарантии нет что везде одинаково и так и будет.
И не факт что поможет.
http://www.keil.com/forum/20219/stm32-and-interrupts/


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 20 2015, 13:01
Сообщение #57


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(A. Fig Lee @ Feb 20 2015, 15:20) *
Правильные пацаны просто читают мануаль в таком случае.
Угу, одно и тоже. А вот "задать вручную в отладке" это уже методы юных кулхацкеров.
Неизвестно как оно имплементировано, и гарантии нет что везде одинаково и так и будет.
И не факт что поможет.

Чему поможет? Мне ничего не надо. А мануалов я начитался тонны. Просто когда не сталкиваешься, не задумываешься. А кое-кто и столкнувшись, не думает. Просто посылает в мануал. rolleyes.gif
Зачем тогда компилировать в адреса 0x08000000? Кидай сразу в 0, и что из RAM, что из Flash будет работать. Зачем мне Keil демонстрирует адреса 0x08000000?

Глянул в отладчике Memory View. Что по 0x00000000, что по 0x08000000 - одинаковое показывает. Первое слово - стек, второе - стартовый адрес - в обоих вариантах 0x0800EAC5. Куда-то в конец скачет, видимо, загрузка переменных.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 20 2015, 13:29
Сообщение #58


Гуру
******

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



Видимо затем, что программу еще надо во флешку записать. А когда она заливается через встроенный заводской загрузчик, на нулевые адреса отражен этот самый загрузчик. Поэтому скомпилированная в "родные" адреса 0x0800.... программа будет заливаться любым способом.


--------------------
На любой вопрос даю любой ответ
"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
ViKo
сообщение Feb 20 2015, 13:45
Сообщение #59


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



А в чем тогда вообще великий смысл "отображения"? Ну, сказали бы, когда заданы биты (прочитаны ноги) такие-то, процессор запускается оттуда-то, а когда такие - оттуда. И шабаш, как говорил Шариков. Типа, нет по нулевым адресам ничего, и не будет, не ищите. rolleyes.gif Чтобы не пугать людей страшными цифрами адресов?
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Feb 20 2015, 14:06
Сообщение #60


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Цитата(ViKo @ Feb 20 2015, 08:01) *
Чему поможет? Мне ничего не надо. А мануалов я начитался тонны. Просто когда не сталкиваешься, не задумываешься. А кое-кто и столкнувшись, не думает. Просто посылает в мануал. rolleyes.gif
Зачем тогда компилировать в адреса 0x08000000? Кидай сразу в 0, и что из RAM, что из Flash будет работать. Зачем мне Keil демонстрирует адреса 0x08000000?

А как программа/компилятор поймет это РАМ или флаш, если обращение будет к 0х00000100 ?


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 20 2015, 14:08
Сообщение #61


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(A. Fig Lee @ Feb 20 2015, 17:06) *
А как программа/компилятор поймет это РАМ или флаш, если обращение будет к 0х00000100 ?

А им зачем? Сказано, в 100, значит, в 100. Это пусть процессор мучается, он же знает, как его запустили.
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Feb 20 2015, 14:16
Сообщение #62


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Цитата(ViKo @ Feb 20 2015, 09:08) *
А им зачем? Сказано, в 100, значит, в 100. Это пусть процессор мучается, он же знает, как его запустили.


Ну а процессор что делать будет?


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 20 2015, 14:33
Сообщение #63


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(A. Fig Lee @ Feb 20 2015, 17:16) *
Ну а процессор что делать будет?

Он уже включен железно так, как задано. Может, вам мануал почитать? rolleyes.gif

Мысль, что по нулевым адресам ничего нет, мне нравится больше.
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Feb 20 2015, 14:36
Сообщение #64


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Цитата(ViKo @ Feb 20 2015, 09:33) *
Он уже включен железно так, как задано. Может, вам мануал почитать? rolleyes.gif

Да, не надо нашим людям помогать. Тебя же потом и по кумполу.
Зря влез.
До свидания.


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
x893
сообщение Feb 20 2015, 17:06
Сообщение #65


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Особенно когда люди даже прочитать не могут, а сразу строчат в форум в надежде, что им разжуют всё (однокашники).
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 21 2015, 01:22
Сообщение #66


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Может ли Cortex-M3 выполнять программу из внешней памяти?
Go to the top of the page
 
+Quote Post
x893
сообщение Feb 21 2015, 11:08
Сообщение #67


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Да ему пофиг какой адрес - что указано в 8000004 или 20000004 (от BOOT0/1 зависит) туда и перейдет.

Сообщение отредактировал x893 - Feb 21 2015, 11:09
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 21 2015, 11:38
Сообщение #68


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Ой ли? Надо по шинам посмотреть в руководстве.
Go to the top of the page
 
+Quote Post
x893
сообщение Feb 21 2015, 11:52
Сообщение #69


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Без Ой-ли. Только hardfault можно получить, если не туда куда можно.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 22 2015, 12:35
Сообщение #70


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Предыдущий оратор путается в показаниях. То у него "без ой-ли", то HardFault.
Есть у кого-нибудь подтверженное практикой мнение, или и так всем ясно (что нельзя)?
Go to the top of the page
 
+Quote Post
SSerge
сообщение Feb 23 2015, 19:34
Сообщение #71


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(ViKo @ Feb 22 2015, 19:35) *
Есть у кого-нибудь подтверженное практикой мнение, или и так всем ясно (что нельзя)?

Cortex™-M3 Technical Reference Manual от ARM™
утверждает что исполнение кода запрещено только из старших 1/2 Гигабайта адресного пространства (от 0xE0000000 и до упора).
Так что при желании можно поисполнять даже содержимое регистров периферийных устройств.
Т.е. архитектура ARM не запрещает, но конкретно у STM32F1xx не получится, выборка кода запрещена для адресов 0x40000000- 0x5FFFFFFF и от 0xA0000000 до конца памяти.

Под внешнюю память отведен диапазон адресов 0x60000000 - 0x9FFFFFFF, если контроллер внешней памяти настроить соответствующим образом, то можно и из внешней памяти код исполнять.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 24 2015, 10:58
Сообщение #72


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Судя по рисунку, STM32F20X может выполнять программу из внешней памяти. А также и из внутренней OTP Flash, наверное.

А еще под картинкой написано:
S2: S-bus
This bus connects the system bus of the Cortex®-M3 core to a BusMatrix. This bus is used
to access data located in a peripheral or in SRAM. Instructions may also be fetch on this bus
(less efficient than ICode)
. The targets of this bus are the 112 KB & 16 KB internal SRAMs,
the AHB1 peripherals including the APB peripherals, the AHB2 peripherals and the external
memories through the FSMC.

То есть, можно команды выбирать откуда хочешь!? rolleyes.gif
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 25 2015, 13:01
Сообщение #73


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Что-то не выходит у меня запустить скомпилированную со сдвигом программу.
Сделал загрузчик, пока только переход на основную программу. Занял нулевой сектор.
В основном проекте задал в Кейле в свойствах проекта начало ПЗУ 0x8004000, размер 0x3C000 (отобрал нулевой сектор для загрузчика), соответственно задал и диапазон для Flash Download. Скомпилировал, зашил. Вижу в ST-Link Utility свое зашитое. Могу и в отладчике в проекте загрузчика посмотреть память. Вроде, все как надо. Но основной проект не работает. Предполагаю, в загрузчике дело. Что-то не так. Вот фрагмент, переход.
Код
/* Если есть SP для приложения */
  if (((*(__IO uint32_t *)APPL_ADDR) & 0x2FFE0000) == 0x20000000) {
/* Адрес таблицы */
    SCB->VTOR = 0x08004000;
    // NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x4000);
/* Указатель на приложение */
    pFunc_t JumpAppl = (pFunc_t)(*(__IO uint32_t *)(APPL_ADDR + 4));
    __set_MSP(*(__IO uint32_t *)APPL_ADDR);
    JumpAppl();
  }
  while (true);
}

Go to the top of the page
 
+Quote Post
SSerge
сообщение Feb 25 2015, 13:41
Сообщение #74


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(ViKo @ Feb 25 2015, 20:01) *
Но основной проект не работает. Предполагаю, в загрузчике дело. Что-то не так.

NVIC_SetVectorTable() в загрузчике не особо нужен.
Это надо в самой запущенной программе сделать, потому что по умолчанию в SystemInit() регистр SCB->VTOR устанавливается на начало флеша.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 25 2015, 14:00
Сообщение #75


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(SSerge @ Feb 25 2015, 16:41) *
NVIC_SetVectorTable() в загрузчике не особо нужен.
Это надо в самой запущенной программе сделать, потому что по умолчанию в SystemInit() регистр SCB->VTOR устанавливается на начало флеша.

Это я из примеров выше в теме (или подобных) вытянул. Не использую, такой функции в CMSIS и нет. А SystemInit у меня своя, и ничего с VTOR не делает.
Плохо, в отладчике оба проекта не видны. Дохожу в загрузчике до JumpAppl() и улетаю незнамо куда, в 0xBFFFXXXX.
Go to the top of the page
 
+Quote Post
esaulenka
сообщение Feb 25 2015, 15:14
Сообщение #76


Профессионал
*****

Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877



Цитата(ViKo @ Feb 25 2015, 17:00) *
Дохожу в загрузчике до JumpAppl() и улетаю незнамо куда, в 0xBFFFXXXX.

Кайл умеет ходить шагами по дизассемблеру. Рекомендую, сразу будет видно, ОТКУДА улетает.


--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 25 2015, 15:45
Сообщение #77


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(esaulenka @ Feb 25 2015, 18:14) *
Кайл умеет ходить шагами по дизассемблеру. Рекомендую, сразу будет видно, ОТКУДА улетает.

Да вот оттуда и улетает, как JumpAppl() жму. Больше же нет ничего для дизассемблера, проект кончается.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Feb 25 2015, 17:29
Сообщение #78


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(ViKo @ Feb 25 2015, 21:00) *
Дохожу в загрузчике до JumpAppl() и улетаю незнамо куда, в 0xBFFFXXXX.

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


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 25 2015, 17:58
Сообщение #79


Гуру
******

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



Цитата(ViKo @ Feb 25 2015, 17:45) *
Да вот оттуда и улетает, как JumpAppl() жму.
Вот прямо в дизассемблере так и написано JumpAppl()? У меня там обычно что-то вроде BL R0 и чуть выше можно увидеть, откуда в R0 вдруг оказался неправильный адрес перехода.


--------------------
На любой вопрос даю любой ответ
"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
ViKo
сообщение Feb 25 2015, 18:29
Сообщение #80


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(SSerge @ Feb 25 2015, 20:29) *
Надо смотреть куда линкер таблицу векторов засунул, похоже она осталась на прежнем месте.

Я ее (их обеих) вижу в окнах Memory в отладчике. Все, как надо: адрес стека, адрес по сбросу...

Цитата(Сергей Борщ @ Feb 25 2015, 20:58) *
Вот прямо в дизассемблере так и написано JumpAppl()? У меня там обычно что-то вроде BL R0 и чуть выше можно увидеть, откуда в R0 вдруг оказался неправильный адрес перехода.

У меня тоже, естественно. BL R1. И адрес в нем правильный, из таблицы, что находится по адресу 0x08004004.
А дальше - то, что описал.

Здесь вот какая штука - в основной программе использую Keil RTX RTOS. Может, она и меняет что-то, например, VTOR. Надо посмотреть в несдвинутом проекте.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 26 2015, 13:33
Сообщение #81


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Из программы-загрузчика по стартовому адресу основной программы 0x08004000 переходит. Начинает обнулять переменные и когда обращается к внешнему ОЗУ, впадает в HardFault. Устанавливается бит Imprecise data access violation, и всё.
Если же основную программу скомпилировать с адреса 0x08000000, то работает.

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

Еще вижу в отладчике для сдвинутой программы в панели NVIC VTO=0x08004000 (как и должно быть), и TBLOFF=0x100080 (а это что за хрень?). В несдвинутой программе последнее - по нулям.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 27 2015, 15:58
Сообщение #82


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Перенес инициализацию FSMC (заодно и всего остального) в SystemInit. Как и предполагал, переход из загрузчика заработал. И как только до этого инициализировались переменные (массивы-буферы), ума не приложу.
Вот только просто ждать таймаута для перехода - не по человечески. Можно по кнопке оставаться в загрузчике. Так ее еще передать и принять нужно...
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 2 2015, 19:43
Сообщение #83


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(ViKo @ Feb 24 2015, 16:58) *
Судя по рисунку, STM32F20X может выполнять программу из внешней памяти. А также и из внутренней OTP Flash, наверное.
...
То есть, можно команды выбирать откуда хочешь!? rolleyes.gif

Должен выполнять, но возможно нужно настроить MPU предварительно.
По-крайней мере для LPC1788 в UM указано:
Default memory space permissions for the Cortex-M3 do not allow program
execution from the address range that includes the dynamic memory chip selects.
These permissions can be changed by programming the MPU

В реальности если запустить код в SDRAM, то при шагании JTAG видно, что несколько команд (с десяток) код выполняется нормально, но на некоторой команде вдруг улетает в
Memory Management Fault (MMFSR.IACCVIOL = 1).
Я только что прописал конфигурирование MPU и после этого всё заработало - теперь программа нормально выполняется из SDRAM (LPC1788).
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 9 2015, 10:10
Сообщение #84


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Хочу спросить... Что-то не могу после прошивки новой программы перескочить в основную. Если после сброса, и таймер отсчитал 2 с - переходит нормально. За эти 2 с я должен нажать кнопку на панели, тогда дается таймер в 16 с для приема кода прошивки. Так вот, если кода не пришло, тоже не могу перейти в основную программу. Как будто, что-то переинициализировать нужно.

Добавлю информации. После записи во флэш проверяю, что есть новый адрес для стека (т.е., что прошивка записана, и есть куда идти). Этот момент сигнализирую вспышкой светодиода. Дальше перехожу в основную программу.
Сразу после программирования диод не пыхает, т.е., не обнаруживается зашитая прошивка. После сброса - нормально проходит, после 2 с ожидания в загрузчике. Если нажму кнопку в это время, после 16 с светодиод тоже пыхает, но перехода нет. Чудо.
Запросы от USART стираю. Больше никакими прерываниями не пользуюсь.
P.S. Я, собственно, прерываниями от USART не пользуюсь. Проверяю состояние. Постирал pending биты запросов. Еще забыл про таймер. От него тоже стер. Всё то же.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 9 2015, 14:10
Сообщение #85


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



А в отладчике после 16 с перескакивает в основную программу и работает. И после обновления прошивки тоже перескакивает. Что-то я пасую.
Похоже, перескакивает он всегда, только работать, как надо, не хочет.

А еще у меня Keil пишет "*** error 34, line 32: undefined identifier" на строку G, main в файле инициализации отладчика. Конкретно, на main. ?
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 10 2015, 13:27
Сообщение #86


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Так и не могу разобраться, что же не дает загрузчику перейти в основную программу сразу после ее прошивки. Ну, попринимал я что-то USART-ом, посчитал время таймером, пописал во флэш... и хочу выйти. Чего не хватает? После сброса (тот же загрузчик, но без приема нового кода) - все нормально запускается. Может, барьеры нужны?

Про кэши ART почитал.
Цитата
To limit the time lost due to jumps, it is possible to retain 64 lines of 128 bits in an instruction cache memory.
...
data cache ... feature works like the instruction cache memory, but the retained data size is limited to 8 rows of 128 bits.

Неслабые такие кэши? Но в загрузчике я их не включаю. И prefetch тоже.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 10 2015, 14:33
Сообщение #87


Гуру
******

Группа: Модераторы
Сообщений: 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
ViKo
сообщение Mar 13 2015, 13:47
Сообщение #88


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Все, исправил. Кнопка от панели передается двумя байтами, да еще и нажатое и отпущенное состояния. Лезло ненужное в основную программу.
Сбрасываю флаг USART_SR_RXNE, основная программа перестала улетать в прерывание.

Теперь задача - зашифровать-расшифровать прошивку. Думаю, не задействовать ли вычислитель CRC в мк.
Go to the top of the page
 
+Quote Post
veteq
сообщение Mar 19 2015, 13:24
Сообщение #89


Участник
*

Группа: Участник
Сообщений: 28
Регистрация: 5-12-06
Пользователь №: 23 160



Есть проблема со входом в бутлоадер STM32L051 (cortex m0+) из тела программы, микроконтроллер сбрасывается. Тот же код только с другими адресами прекрасно работает на STM32L151 и STM32L401 (cortex m3/m4). Подскажите в чем может быть проблема?

CODE


void (*SysMemBootJump)(void);

SysMemBootJump = (void (*)(void)) (*((unsigned int*) 0x1FF00004));

__disable_irq();
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;

__set_MSP(0x20001000);
SysMemBootJump();



Сообщение отредактировал veteq - Mar 19 2015, 13:25
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 23 2015, 11:29
Сообщение #90


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(ViKo @ Mar 13 2015, 16:47) *
Теперь задача - зашифровать-расшифровать прошивку.

Попробовал XTEA. Пока только закодировал. rolleyes.gif Не знаю, сколько времени будет декодироваться в микроконтроллере.
Есть одно замечание. Поскольку кодируются блоки из двух слов, то и перемешивание битов идет в пределах этих двух слов. Дальше все начинается сначала. То есть, одинаковые последовательности слов в начале двоичного файла прошивки (пустые обработчики прерываний) после кодирования тоже будут выглядеть одинаково. Что наталкивает взломщика на принцип кодирования.

Сделал и декодирование, все по https://ru.wikipedia.org/wiki/XTEA#cite_note-report-1
Декодируется быстро, практически, мгновенно.
Фактически, имеется 4 32-битовых ключа, и количество итераций тоже можно выбрать на свой вкус.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 25 2015, 08:37
Сообщение #91


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Теперь подвис на том, как размер кода задать в самом коде. Как здесь писали, после векторов прерываний разместить, например. С помощью линкера (Кейл).
Вариант 2 - занести в код при расчете CRC и кодировании, внешней программой. Это можно. Нужно только зарезервировать в исходнике место для числа-размера. Может, прямо в стартап добавить?

upd. "Нашел" дыру в стартапе. Как, пойдет?
Код
__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler             ; 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
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVC_Handler               ; SVCall Handler
                DCD     DebugMon_Handler          ; Debug Monitor Handler
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 25 2015, 09:52
Сообщение #92


Гуру
******

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



Цитата(ViKo @ Mar 25 2015, 10:37) *
upd. "Нашел" дыру в стартапе. Как, пойдет?
Пойдет, но я бы не экономил. Потом когда-нибудь будете портировать на более продвинутый кортекс у которого это место в таблице занято и будете долго искать причину неработы. Это раз. Второе - будет довольно сложно заставить линкер класть размер в уже занятое векторами место. А сразу за векторами никто ему мешать не будет.


--------------------
На любой вопрос даю любой ответ
"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
ViKo
сообщение Mar 25 2015, 10:00
Сообщение #93


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Сергей Борщ @ Mar 25 2015, 12:52) *
Пойдет, но я бы не экономил. Потом когда-нибудь будете портировать на более продвинутый кортекс у которого это место в таблице занято и будете долго искать причину неработы. Это раз. Второе - будет довольно сложно заставить линкер класть размер в уже занятое векторами место. А сразу за векторами никто ему мешать не будет.

Полистал книжку по Cortex-M4, там тоже дыра. Можно и после векторов прерываний разместить, но и там сдвиг возможен в новых микроконтроллерах, даже с большей вероятностью.
Линкером класть не умею (вернее, вычислять размер не умею). Буду своей программой записывать, туда же CRC, туда же и серийный номер. STM32 ST-Link Utility умеет перезаписывать флэш (ей серийный номер и обновляю).

Э-э, CRC туда поместить нельзя. Иначе при расчете нужно проскакивать ее. Ее лучше в конец приписать, чтобы полный расчет дал 0.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 25 2015, 13:27
Сообщение #94


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Пробую разместить строки в startup.s, чтобы знать точное место. Добавил после определения векторов:
Код
         EXPORT  Serial
         ALIGN 4
Serial DCB  "0000", 0

Вижу в выходном коде свои строки, если к ним нет обращения. Но не видит программа этих переменных из c-файлов, и не компилируется из-за ошибки!
Поможите, чем можете!
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Mar 26 2015, 05:30
Сообщение #95


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Напишите перед использованием объявление:
extern uint16_t Serial;


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Mar 26 2015, 12:36
Сообщение #96


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(AHTOXA @ Mar 26 2015, 08:30) *
Напишите перед использованием объявление:
extern uint16_t Serial;

Так не пробовал. У меня же строка.
А extern char *Serial; компилируется, но не работает. Потому что не указатель. А extern char[] Serial не компилируется.
Как-то надо создать указатели на строки в ассемблерном файле. Неужели вручную?
Сообразил:
TxBuffer_write((char *)&Serial);
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 26 2015, 13:09
Сообщение #97


Гуру
******

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



Цитата(ViKo @ Mar 26 2015, 14:36) *
А extern char *Serial; компилируется, но не работает. Потому что не указатель. А extern char[] Serial не компилируется.
" А кто из телепатов не догадался, что там у меня в исходнике и как ругается компилятор - я не виноват".

Цитата(ViKo @ Mar 26 2015, 14:36) *
Сообразил:
TxBuffer_write((char *)&Serial);
Какое-то масло масляное. Как теперь объявлен Serial?


--------------------
На любой вопрос даю любой ответ
"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
ViKo
сообщение Mar 26 2015, 13:14
Сообщение #98


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Сергей Борщ @ Mar 26 2015, 16:09) *
" А кто из телепатов не догадался, что там у меня в исходнике и как ругается компилятор - я не виноват".
Какое-то масло масляное. Как теперь объявлен Serial?

Я, вроде, всё описал выше.
В startup.s:
Код
                EXPORT  Serial
                ALIGN   4
Serial          DCB     "0002",0

В Main.h:
Код
extern const char Serial;

Использую:
Код
  TxBuffer_write((char *)&Serial);
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 26 2015, 14:11
Сообщение #99


Гуру
******

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



Цитата(ViKo @ Mar 26 2015, 15:14) *
Я, вроде, всё описал выше.
Про main.h не было. И текста ругани компилятора не было. Вот так должно работать:
Код
extern const char Serial[];

  TxBuffer_write(Serial);



Цитата(ViKo @ Mar 26 2015, 15:14) *
Код
extern const char Serial;
А, тогда понятно, почему потребовалось брать адрес и грубой силой приводить его к другому типу.


--------------------
На любой вопрос даю любой ответ
"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
ViKo
сообщение Mar 26 2015, 14:53
Сообщение #100


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Сергей Борщ @ Mar 26 2015, 17:11) *
Про main.h не было. И текста ругани компилятора не было. Вот так должно работать:
[code]extern const char Serial[];

Это я попутал с C#, не туда скобки присобачил. rolleyes.gif Дал маху. Пишу параллельно шифровщик прошивки на компьютере.

Новая загадка всплыла. Серийный номер нужно же сохранить при обновлении прошивки. И в расчете CRC он не должен участвовать. Эх, что-то криво все выходит...
Можно, конечно, в ту самую OTP его прописать.
upd. Но уже был прецедент - переписали номер на корпусе, чтобы солидней выглядело. Меня в известность не поставили. laughing.gif
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 26th July 2025 - 00:53
Рейтинг@Mail.ru


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