|
|
  |
Стартовый загрузчик, с нуля |
|
|
|
Sep 5 2014, 07:49
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(ДЕЙЛ @ Sep 3 2014, 14:34)  Есть ещё вопрос по безусловному переходу. если написать такой код: Код int i; void main (void) { for (i = 0; i<20; i++) { asm (" nop "); } asm (" B 0x???? "); } то по какому адресу нужно сделать безусловный переход, чтобы программа стала заново выполняться и возможно ли это? МК LPC1778, среда IAR. С этим разобрался, для программного сброса перезапуска программы и соответственно для передачи управления по какому-либо адресу младший бит этого адреса должен быть всегда установлен, если используется Cortex-M3. Т.е. для программного перезапуска нужно написать: Код asm (" B 1 "); Для меня этот эксперимент принципиален для уяснения принципа передачи управления по конкретному адресу флеш, т.к. бутлоадер таким способом запускает программу, как я представляю.
|
|
|
|
|
Sep 5 2014, 10:08
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(menzoda @ Sep 4 2014, 09:33)  2. Если используется стандартный шаблон проекта, то в обработчике прерывания сброса обычно идет вызов процедуры SysInit, которая выполняет инициализацию некоторого оборудования (PLL например). А если у меня в проекте никакие библиотеки не подключены? Просто имеется такой код: Код void main (void) { while(1) { } } и ещё вопрос Если я участок памяти программы, начиная с нулевого адреса, полностью скопирую в ОЗУ по адресу ADRES, затем после процедуры копирования сделаю перескок ассемблерной инструкцией asm (" B ADRES ");, то это будет равносильно выполнению программы заново? Работать будет? Пока в матчасть вникаю, до железа руки не доходят. Вот ещё непонятность. в описании ядра CM3 есть такие слова: "Таблица векторов прерываний может быть перемещена по другому адресу в области кода или в области ОЗУ" и далее имеется описание регистра смещения таблицы векторов VTOR. Как выглядит участок программы, который перемещает эту таблицу векторов? Нужно просто в регистр смещения записать новый адрес? Какие-то дополнительные действия нужны? Хотелось бы посмотреть пример исходника.
Сообщение отредактировал ДЕЙЛ - Sep 5 2014, 10:43
|
|
|
|
|
Sep 5 2014, 10:45
|
Участник

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

|
Цитата(ДЕЙЛ @ Sep 5 2014, 14:08)  А если у меня в проекте никакие библиотеки не подключены? Просто имеется такой код: Код void main (void) { while(1) { } } SysInit находится до этого кода. Есть ли он или нет надо смотреть в стартап-файле, но даже если его нет, все остальное остается в силе и не зависит от того используешь ты библиотеки или нет. Цитата(ДЕЙЛ @ Sep 5 2014, 14:08)  Если я участок памяти программы, начиная с нулевого адреса, полностью скопирую в ОЗУ по адресу ADRES, затем после процедуры копирования сделаю перескок ассемблерной инструкцией asm (" B ADRES ");, то это будет равносильно выполнению программы заново? Работать будет? В общем случае нет. На этапе компоновки вместо вызовов функций и обращений к переменным подставляются абсолютные адреса, то есть необходимо заранее знать где будет исполняться программа. Если ты переместишь программу в другое место, то все сломается. Однако, компоновщик может поддерживать генерацию кода, инвариантного к расположению в памяти (position independent). По крайней мере в тулчейне от ARM я видео такую опцию, но подробно не интересовался. Кроме того, как я уже говорил - кто будет сбрасывать состояние оборудование перед началом выполнения программы? Все это реализуемо, но требует понимания проблемы и дополнительных телодвижение. Поэтому, подытожив, еще раз отвечу на твой вопрос: Цитата будет равносильно выполнению программы заново? Работать будет? В общем случае нет. Цитата Пока в матчасть вникаю, до железа руки не доходят. Мне кажется ты немного не с той стороны начал. Сейчас тебе на каждый вопрос надают кучу ответов, что можно, что нельзя, нужно то, нужно это, только запутают. Вон, хотя бы посмотреть на мои ответы - вроде как нельзя, но в принципе можно. Сейчас как зароешся во всем этом... Может лучше исходить из конечной цели? Например, сделать загрузчик для такого-то МК, который должен то-то и то-то, а не "что будет, если я вызову инструкцию перехода". Так сказать от общего к частному, сначала по советам сделаешь работающий загрузчик, а потом будешь разбираться почему именно так. Цитата Вот ещё непонятность. в описании ядра CM3 есть такие слова: "Таблица векторов прерываний может быть перемещена по другому адресу в области кода или в области ОЗУ" и далее имеется описание регистра смещения таблицы векторов VTOR. Как выглядит участок программы, который перемещает эту таблицу векторов? Нужно просто в регистр смещения записать новый адрес? Какие-то дополнительные действия нужны? Хотелось бы посмотреть пример исходника. Сначала скопировать таблицу векторов в нужное место, а потом в регистр смещения записать новый адрес. Скопировать можно как угодно, таблица векторов прерываний это просто числа в памяти. Никаких дополнительных действий не нужно.
Сообщение отредактировал menzoda - Sep 5 2014, 11:05
|
|
|
|
|
Sep 5 2014, 11:09
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(menzoda @ Sep 5 2014, 14:45)  Может лучше исходить из конечной цели? конечная цель такая: имеется LPC1778, имеется скомпилированный файл proga.bin. Нужно сделать так, чтобы я мог по какому-нибудь интерфейсу с ПК этот файл побайтно отправить своей программой, а в контроллере эти байты встретит чуть ранее загруженный самопальный бутлоадер, который всё принятое разложит в памяти и запустит на выполнение. С написанием программы для ПК проблем не вижу, больше вопросов по принимающей стороне, т.е. с организацией записи прошивки в МК самопальным загрузчиком. Далее предполагаю передавать прошивку по радиоканалу и тем самым иметь возможность удалённо перепрошивать девайс.
|
|
|
|
|
Sep 5 2014, 13:25
|
Участник

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

|
В кратце опишу, как я это вижу. Подробности поведения загрузчика опускаю, это уже на твоей совести.
- Думаем сколько секторов памяти (начиная с первого) выделить под загрузчик. - Настраиваем проект1 загрузчика так, чтобы его таблица векторов прерываний располагалась по нулевому адресу2, а остальной код не выходил за рамки отведенной памяти. - Настраиваем проект основного ПО так, чтобы его образ не выходил за рамки отведенной области, а таблица векторов прерываний находилась в начале области. - Загрузчик может работать с файлами формата Intel HEX. Файл состоит из простых текстовых строк с данными и адресом, куда эти данные записать. Это стандарт де-факто для прошивки различных устройств. Генерируется всеми средствами разработки. Можно использовать и другие форматы. - Для простоты передача управления от загрузчика к основному ПО будет происходить через безусловный переход. При необходимости этот механизм можно заменить чем-нибудь другим. - Цель безусловного перехода - обработчик прерывания сброса основного ПО. Адрес обработчика находится в известном векторе прерывания. Таблица векторов прерываний находится в начале области, отведенной под основное ПО. - Для перехода к основному ПО необходимо (именно в такой последовательности): 1. запретить все прерывания 2. привести состояние использованной периферии к начальному 3. задать в регистре смещения новое положение таблицы векторов прерываний основного ПО 4. совершить переход - Загрузчик может получать файл прошивки по любому интерфейсу. При получении файла он разбирает его формат и записывает содержимое в соответствующую область памяти. Если используется формат Intel HEX, то мы имеем явное указание куда записывать данные3. Если используется простой бинарный образ, то записываем его последовательно в начало области, отведенной под основное ПО. - Перед переходом к основному ПО загрузчик должен убедиться, что оно существует. Для этого при записи ПО подсчитываем его контрольную сумму, результат записываем в заранее определенное место. Перед переходом пробегаемся по области основного ПО и сверяем контрольную сумму. Если все хорошо - переходим, если не сошлось - остаемся в загрузчике4. - Чтобы перейти из основного ПО в загрузчик - программно сбрасываем контроллер.
Вроде все верно. Если что - другие поправят.
1 Настраивать придется скрипт компоновщика (линкера). 2 Имеется ввиду адрес, к которому обращается ядро после сброса. Он обычно (но необязательно) численно равен нулю. 3 При этом все-равно нужно проверять, что мы попадаем в область основного ПО, чтобы при получении неправильного файла случайно не перетереть загрузчик. 4 Можно придумать какой-нибудь другой алгоритм определения наличия ПО.
Сообщение отредактировал menzoda - Sep 5 2014, 13:27
|
|
|
|
|
Sep 30 2014, 10:35
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Пока в исходник загрузчика глубоко не влазил. Хочу попробовать что-либо записать во флеш из программы. т.е. если написать вот так: Код adres = (unsigned int*)0x20000200; //область оперативной памяти *adres = 0x12345678; то всё нормально - в ячейку с указанным адресом записывается число, а если написать вот так Код adres = (unsigned int*)0x1000; //область флеш-памяти *adres = 0x12345678; то ничего не записывается. Тут нужно предварительно какие-то настройки делать. В мануале что-то написано, но нет примеров. Хотелось бы увидеть самый простой пример включения возможности записи в ячейку флеш. МК LPC1778
|
|
|
|
|
Sep 30 2014, 12:50
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(Сергей Борщ @ Sep 30 2014, 15:36)  У них нет возможности записи в ячейку. Вы можете записать только блок. Пример там писать не стали - вся запись сводится к загрузке 4 регистров и вызвове одной функции IAP. Читайте раздел Flash Memory до просветления. Но ведь хочется спросить и тут разжёваный ответ получить  Спасибо за направляющий ответ, буду копать. Как в общих чертах происходит запись блока? Какие шаги нужно проделать?
Сообщение отредактировал ДЕЙЛ - Sep 30 2014, 13:08
|
|
|
|
|
Sep 30 2014, 14:00
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Цитата(ДЕЙЛ @ Sep 30 2014, 16:50)  Но ведь хочется спросить и тут разжёваный ответ получить  Спасибо за направляющий ответ, буду копать. Как в общих чертах происходит запись блока? Какие шаги нужно проделать? Прочитать сраницу из flash, изменить байтик, (возможно очистить flash), записать станицу во flash. Все подробности в application note (а такой есть 99%) на ваш процессор.
|
|
|
|
|
Oct 6 2014, 21:21
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Покопался в настройках линкера, нашёл настройки линкера: Config->Edit->Linker configuration file editor->Vector Table-> .intvec start = 0x7000 Config->Edit->Linker configuration file editor->Memory Regions-> ROM = 0x7000 - 0x7FFFF После компилирования и запуска в пошаговом режиме видно, что программа раположена по адресу, начиная с 0x7000, на этом этапе всё работает нормально - данные бегут из UART0. Получается, что программа уже нормально записана в память и работоспособна. Далее пробую написать маленькую программу, расположенную в обычном месте, т.е. в начальном секторе флеш. Пишу такой текст: Код main() { asm ("B 0x7000"); } Перебрал несколько возможных адресов, но всегда зависает в Hard Fault. Цитата(menzoda @ Sep 5 2014, 17:25)  - Для простоты передача управления от загрузчика к основному ПО будет происходить через безусловный переход. ...... - Цель безусловного перехода - обработчик прерывания сброса основного ПО. Адрес обработчика находится в известном векторе прерывания. Таблица векторов прерываний находится в начале области, отведенной под основное ПО. В каком известном векторе прерывания находится адрес обработчика? Как узнать этот адрес? Цитата(menzoda @ Sep 5 2014, 17:25)  - Для перехода к основному ПО необходимо (именно в такой последовательности): 1. запретить все прерывания 2. привести состояние использованной периферии к начальному 3. задать в регистре смещения новое положение таблицы векторов прерываний основного ПО 4. совершить переход Написал маленькую тестовую программу без подключения библиотек и лишних файлов Код unsigned int *VTOR int main() { VTOR = (unsigned int*)0xE000ED08; //адрес регистра смещения таблицы *VTOR = 0x7000; //смещение адреса таблицы веторов прерываний asm ("B 0x7000"); //адрес перехода } Т.е. 1. Прерывания не разрешал, близко к ним не подходил в этом коде. 2. Переферию не трогал 3. С этим вопрос - как узнать адрес? 4. По какому адресу переходить? Как его узнать? UP1: в прикреплённом архиве проект основного ПО и второй проект тестовой программы, которая должна запускть основное ПО
Сообщение отредактировал ДЕЙЛ - Oct 6 2014, 21:23
Эскизы прикрепленных изображений
|
|
|
|
|
Oct 8 2014, 05:17
|
Участник

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

|
Цитата В каком известном векторе прерывания находится адрес обработчика? Как узнать этот адрес? Первый вектор таблицы содержит адрес вершины стека, второй - адрес обработчика прерываний сброса, подробнее смотри в документации ARM на своё ядро (искать по словам vector table). Цитата Написал маленькую тестовую программу без подключения библиотек и лишних файлов Во-первых, ты переходишь по адресу в первом векторе таблицы, а это адрес вершины стека, так что надо переходить по второму. Во-вторых, ты переходишь в этот вектор, а надо прочитать значение из этого вектора и перейти уже по нему. Исходя из твоего третьего скриншота, тебе надо прочитать содержимое по адресу 0x7004, судя по скриншоту оно было равно 0x8105, и перейти в этот самый 0x8105.
Сообщение отредактировал menzoda - Oct 8 2014, 05:22
|
|
|
|
|
Oct 8 2014, 18:57
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(menzoda @ Oct 8 2014, 09:17)  Во-первых, ты переходишь по адресу в первом векторе таблицы, а это адрес вершины стека, так что надо переходить по второму. Во-вторых, ты переходишь в этот вектор, а надо прочитать значение из этого вектора и перейти уже по нему.
Исходя из твоего третьего скриншота, тебе надо прочитать содержимое по адресу 0x7004, судя по скриншоту оно было равно 0x8105, и перейти в этот самый 0x8105. Написал две строки Код *VTOR = 0x380000; //смещение таблицы относительно начала области кода (0x0000) 0x7000 передвинуты на 7 бит влево, т.к. смещение записывается в битах 28:7 asm ("B 0x8105"); Нивкакую не работает. Что ещё упустил и как правильно написать для перехода к программе, начинающейся с адреса 0x7000?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|