I_am_Lexx 0 18 января, 2019 Опубликовано 18 января, 2019 · Жалоба Доброго дня. Делаю bootloader. PIC24F. XC16. MPLAB 5.00. Увертюра: Архитектура такая, что в одном проекте размещаю bootloader и application. В линкере секции разбиты так, что стирается только определенная область памяти. В эту область записывается приложение, которое разрабатывается в этом же проекте, а не отдельно от загрузчика. Все, как мне казалось сделал, но не работает. Если залить это же приложение, то работает. Если добавить в приложение хотя бы один Nop(), то перестает работать. При запуске программы с 0x00 адреса программа переходит не в функцию main(), а инициализирует стек, переменные, возможно, еще что-то. Эти команды формируются автоматически (компилятором) в стираемой мною области программы (во время перепрошивки). MOV #0x1BBA, W15 MOV #0x6FF0, W14 MOV W14, SPLIM NOP MOV #0x0, W0 CP0 W0 BRA Z, CORCON_RESET MOV #0x10, W0 MOV W0, CORCON RCALL __psv_init RCALL __crt_start_mode, __crt_start_mode_normal CP0 W0 BRA NZ, 0x4072 MOV #0x6F6C, W0 MOV #0x0, W1 BRA 0x4076 MOV #0x0, W0 MOV #0x0, W1 IOR W0, W1, [W15] BRA Z, 0x407C RCALL __data_init, __data_init_da MOV #0x0, W0 CP0 W0 BRA Z, 0x4086 CALL 0x0 NOP CALL main NOP Мне нужно разместить эту часть программы (автоматически формируемую инициализацию) по жестко указанному адресу, т.к. в эту область переходит контроллер из адреса 0x0 при запуске, а код по адресу 0x0 я не меняю при перепрошивке. Задача: "прибить гвоздями" эту часть кода. Что и куда приписать в линкере? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aaron 1 21 марта, 2019 Опубликовано 21 марта, 2019 · Жалоба RCALL __psv_init RCALL __crt_start_mode, __crt_start_mode_normal RCALL __data_init, __data_init_da и ещё сам код верхнего уровня - тоже название функции надо знать - типа reset_handler, __reset, __crt_reset - map-файл посмотреть. Про синтаксис компилятора не подскажу, но судя по всему вы знаете что и как делать. Первый момент. Вам надо в линковщике все эти функции явно объявить внутри секции, относящейся к бутлодеру. Второй момент. Если вы всё делаете в рамках одного проекта, то у вас секция .bss и .data будут содержать сведения как о загрузкике, так и о приложении. Переписывая приложение, размер занимаемого места секциями может измениться - вы всё равно влиять будете на загрузчик. Чтобы это исключить, вам надо в явном виде все константы и переменные, относящиеся к приложению, определять в коде в секцию приложения. Имхо это слишком большой гемор, лучше сделать два независимых проекта bootloader и app. Могу предположить, что вы хотели сэкономить место на общих функциях - типа, в бутлодере есть инициализация и функции по работе с периферией, которые в основной проге тоже используете. В таком случае выделите в отдельную секцию в явном виде по конкретному адресу место под структуру, которая будет хранить ссылки на ваши "общие библиотечные" функции. Тогда в основном приложении вам достаточно объявить просто прототипы этих функций, взять ссылки на них из предопределённой структуры - вот и будет экономия места. Других причин создавать загрузчик и приложение в одном проекте я не вижу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 124 21 марта, 2019 Опубликовано 21 марта, 2019 · Жалоба В 18.01.2019 в 13:24, I_am_Lexx сказал: В эту область записывается приложение, которое разрабатывается в этом же проекте, а не отдельно от загрузчика. Как вы планируете выдрать приложение из общей прошивки, чтобы обновить его в уже отгруженном заказчику приборе? Про остальные минусы Aaron все верно расписал - в какой-то момент вы обнаружите, что очередное обновление или не заливается, или наглухо вешает прибор с самой первой или самой второй версией загрузчика и сделать это обновление совместимым со старой версией загрузчика будет гораздо сложнее, чем сразу делать два отдельных проекта. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
I_am_Lexx 0 26 июня, 2019 Опубликовано 26 июня, 2019 · Жалоба В целом у меня получился бутлодер. Но не все. Структуру бутлодера я не выбирал. Делал, как коллега по работе. Но он на Ассемблере пишет с пустого листа. Стек сам инициализирует: mov mov mov #__SP_init,w15 #__SPLIM_init,w0 w0,_SPLIM ; initialize w15 ; ; initialize SPLIM У меня на Си стек инициализируется сам. Точно механизм я не знаю. Код приведенный ниже формируется сам с адреса 0x00100. Первые 3 строки - это инициализация стека. И только с строки 12 переход в main(). 1 00100 226B6F MOV #0x26B6, W15 2 00102 26FF0E MOV #0x6FF0, W14 3 00104 88010E MOV W14, SPLIM 4 00106 200301 MOV #0x30, W1 5 00108 E00001 CP0 W1 6 0010A 320002 BRA Z, 0x110 7 0010C 202001 MOV #0x200, W1 8 0010E 880191 MOV W1, DSRPAG 9 00110 200000 MOV #0x0, W0 10 00112 E00000 CP0 W0 11 00114 320002 BRA Z, 0x11A 12 00116 020000 CALL 0x0 13 00118 000000 NOP 14 0011A 023000 CALL main 15 0011C 000000 NOP 16 0011E DA4000 BREAK 17 00120 FE0000 RESET 18 00122 FFFFFF NOPR Как я понял это дело находится по адресу C:\...\pic30\crt0_extended24.s. Кусок кода ниже. ;; Initialize stack and PSV window ;; ;; registers used: w1 ;; (w0 is cleared by device reset, so ARGC = 0) ;; ;; Inputs (defined by user or linker): ;; __SP_init = initial value of stack pointer ;; __SPLIM_init = initial value of stack limit register ;; Inputs (defined by linker): ;; __const_length = length of section .const ;; __const_psvpage = PSVPAG setting for section .const ;; ;; Outputs: ;; (does not return - resets the processor) ;; ;; Calls: ;; _main ;; .weak __user_init, __has_user_init mov #__SP_init,w15 ; initialize w15 mov #__SPLIM_init,w14 Значения __SP_init и __SPLIM_init вычисляются автоматически при компиляции. Системные константы. Это вершина стек и размер стека. При изменении программы они меняются. А мой бутлодер не меняет эту область. Чтобы обойти эту проблему я хочу явно указать начало и размер стека и не менять их от версии к версии. На Ассемблере это можно сделать так. .section my_stack, stack, address(0x1800) .space 0x100 Прошу объяснить, 1) как это можно сделать в Си, учитывая, что код формируется до вызова main() или 2) как указать в линкере, чтобы стек был в нужном месте, нужного размера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
I_am_Lexx 0 26 июня, 2019 Опубликовано 26 июня, 2019 · Жалоба Точнее не файл "C:\...\pic30\crt0_extended24.s" а исходя из кода линкера "crt1_extended24.o". Т.е. исходники уже скомпилированы. OUTPUT_ARCH("24FJ128GA606") #if __XC16_VERSION__ > 1027 CRT0_STARTUP(crt0_extended24.o)CRT1_STARTUP(crt1_extended24.o) #else CRT0_STARTUP(crt0_extended.o) CRT1_STARTUP(crt1_extended.o) #endif #if __XC16_VERSION__ > 1027 /* * Define how to startup, by default we initialize * everything as normal; change to crt_start_mode to * preserve preserved data on a restart * * Or define your own __crt_start_mode fucntion */ CRT_STARTMODE(crt_start_mode_normal) #endif Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aaron 1 1 июля, 2019 Опубликовано 1 июля, 2019 · Жалоба > 1) как это можно сделать в Си, учитывая, что код формируется до вызова main() Вам надо написать функцию reset handler (точное имя определено в crt..s). Вы её можете написать на Си. Или возьмите исходник crt ассемблерный и под себя его перепишите. > 2) как указать в линкере, чтобы стек был в нужном месте, нужного размера. Вы же уже ответили сами строчкой выше: .section my_stack, stack, address(0x1800) .space 0x100 Определите глобальные константы исходя из этой секции, аналогичные __SP_init и __SPLIM_init - и используйте свои константы в своём файле инициализации. в gcc это всё можно задать .ld файлом, в keil - scatter. Для pic надо мануалы курить, наверняка тоже есть нечто аналогичное. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться