|
|
  |
Самозагрузчик |
|
|
|
Apr 8 2016, 14:07
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(Непомнящий Евгений @ Apr 8 2016, 08:37)  ...* как тестировали? ..Каждый модуль - как отдельный проект?...у вас код запускался из flash? ...Или не применяли команды, которые работают с фиксированными адресами, только по смещению? * где жила системная библиотека (общая для всех модулей)? ...Или все хранится в куче? ... как позвать функцию из другого модуля? - стандартный отладчик только на уровне азма конечно же, кроме загрузчика. юзается в основном дебажный вывод и мощная система логгирования при фатальных ошибках. - каждый модуль отдельный проект, работает из флэша. - вся адресация относительная. - все библиотеки = модули(фрииртос, фаты, стандартная либа, менеджэр памяти - их вообщето два, но для модулей - так-же в модуле отдельном) - куча используется - загрузчик делает позднее связывание модулей. т.е. есть понятия импортируемых и экспортируемых функций, необходимых аппаратных прерываний, версии модуля и запрос версии. - функции зовутся как обычно (в тексте это имеет маленький префикс - вот и всё отличие) зачем = повышенная отказоустойчивость. и минимум требований к фазе дистанционной апгрэйта кода. (круглый)
|
|
|
|
|
Apr 12 2016, 12:44
|
Знающий
   
Группа: Свой
Сообщений: 524
Регистрация: 25-12-08
Из: Москва
Пользователь №: 42 748

|
Сделал, но чего то не получается запустить основную программу в чем может быть проблема? утилитой ST Link проверяю - файл записался и лежит правильно в памяти Загрузчик у меня такой: CODE #define FILE_NAME "loader.bin" #define APP_ADDRESS (uint32_t)0x08008000
do { /* Монтируем. Если нет файла - выходим на загрузку */ if ((rc = f_mount(0, &fatfs)) == 0) { PRINTF("INFO: mount OK\r\n"); } else { PRINTF("ERROR: mount fs\n"); break; }
/* Открыть на чтение */ rc = f_open(&fil, FILE_NAME, FA_READ); if (rc == 0) { PRINTF("INFO: Loader file %s open OK\n", FILE_NAME); } else { PRINTF("INFO: Loader file %s doesn't exist. Continue booting", FILE_NAME); break; }
/* стираем секторы 2...4*/ FLASH_Unlock(); delay_ms(50);
if(FLASH_COMPLETE == FLASH_EraseSector(FLASH_Sector_2, VoltageRange_3)) { PRINTF("Erase sector OK\n"); led_toggle(LED3); } if(FLASH_COMPLETE == FLASH_EraseSector(FLASH_Sector_3, VoltageRange_3)) { PRINTF("Erase sector OK\n"); led_toggle(LED3); }
if(FLASH_COMPLETE == FLASH_EraseSector(FLASH_Sector_4, VoltageRange_3)) { PRINTF("Erase sector OK\n"); led_toggle(LED3); }
/* Читаем файл и записываем в секторы flash */ bytes = 0; addr = APP_ADDRESS; do { bw = 0; rc = f_read(&fil, buf, sizeof(buf), &bw); if (rc == 0 && bw > 0) { bytes += bw; for(i = 0; i < bw; i++) { FLASH_ProgramByte(addr, buf[i]); addr++; } PRINTF("%d bytes written\n", bytes); led_toggle(LED4); delay_ms(50); } } while (bw);
rc = f_close(&fil); // Стираем файл /* Если файл существует - удалим его */ // rc = f_unlink(FILE_NAME); } while (0);
/* Disable all interrupts */ RCC->CIR = 0x00000000; /* Делаем старт по адресу */ JumpAddr = *(__IO uint32_t*) (APP_ADDRESS + 4); Jump_To_App = (pFunction) JumpAddr;
/* Initialize application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APP_ADDRESS); Jump_To_App();
Я вижу отладчиком, что до джампа он доходит - а дальше аут основная прога использует такой скрипт линкера, где установлены адреса: define symbol __ICFEDIT_intvec_start__ = 0x08008000; define symbol __ICFEDIT_region_ROM_start__ = 0x08008000; + сделал коментарий в вызове из ассемблера SystenInit() - так это уже сделано в загрузчике компилю образ проги и получаю бинарник program.binCODE ;Reset_Handler
; LDR R0, =SystemInit ; BLX R0 LDR R0, =__iar_program_start BX R0
В чем может быть еще засада?
|
|
|
|
|
Apr 12 2016, 13:12
|
Знающий
   
Группа: Свой
Сообщений: 524
Регистрация: 25-12-08
Из: Москва
Пользователь №: 42 748

|
Цитата(scifi @ Apr 12 2016, 15:52)  А поподробнее? В окне дизассемблера нашли инструкцию, которая делает не то, что нужно? Посмотрели значения соответствующих регистров? делает branch BLX R8 тока в R8 почему то 0x08009f85
|
|
|
|
|
Apr 12 2016, 14:26
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(inventor @ Apr 12 2016, 15:44)  Код /* Disable all interrupts */ RCC->CIR = 0x00000000; /* Делаем старт по адресу */ JumpAddr = *(__IO uint32_t*) (APP_ADDRESS + 4); Jump_To_App = (pFunction) JumpAddr;
/* Initialize application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APP_ADDRESS); Jump_To_App(); Так делать некорректно! Во первых не устанавливается новый адрес таблицы векторов ( VTOR ) Во вторых указатель стека будет модифицирован и не будет соответствовать тому что лежит по APP_ADDRESS И если хотите отлаживать приложение без бутлоадера (если это разные проекты) то надо у IAR в макросах установить запись VTOR - тогда можно без проблем отлаживать.
|
|
|
|
|
Apr 12 2016, 14:49
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(KRS @ Apr 12 2016, 17:26)  Во первых не устанавливается новый адрес таблицы векторов ( VTOR ) По-моему, это все же дело приложения, а не загрузчика. Цитата(KRS @ Apr 12 2016, 17:26)  Во вторых указатель стека будет модифицирован и не будет соответствовать тому что лежит по APP_ADDRESS Где?
|
|
|
|
|
Apr 12 2016, 15:03
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(aaarrr @ Apr 12 2016, 17:49)  Где? Строго говоря, компилятору разрешается крутить указатель стека в любой момент, причём в любую сторону. Так что я бы сказал, что такой способ установки указателя стека предполагает некое везение. Ассемблерный код здесь идеологически более правильный. Как обычно, агитирую за свой вариант Код static const uint16_t jump2fw[] = { 0xF850, 0xDB04, /* LDR.W SP, [R0], #4 */ 0x6800, /* LDR.W R0, [R0] */ 0x4700, /* BX R0 */ }; ((void (*)(int))(1 + (int)jump2fw))(0x08010000);
|
|
|
|
|
Apr 12 2016, 16:49
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(KRS @ Apr 12 2016, 18:41)  Нет - загрузчика! Потому что старт приложения происходит по RESET вектору который лежит в таблице прерываний, соотв. VTOR обязан указывать туда... Как минимум спорно. Приложение может и не придерживаться этих правил, т.к. не предназначено для непосредственного исполнения после аппаратного сброса. Цитата(scifi @ Apr 12 2016, 18:03)  Как обычно, агитирую за свой вариант  А я - за свой  Код __set_MSP(*((uint32_t *)IMAGE_START)); (*((void (**)(void))(IMAGE_START + 4)))();
|
|
|
|
|
Apr 13 2016, 07:54
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(inventor @ Apr 13 2016, 07:49)  вот мой загрузчик грузит только то, что есть на внутренней flash как быть с теми функциями и данными, которые должны располагаться на RAM памяти? кто должен их располагать правильно? надо ли так же перераспределить и память RAM, между загрузчиком и основной программой? Ничего специально делать не нужно. Если у Вас основная программа не bare bones (иными словами, написана в рамках среды разработки и с использованием стандартных библиотек среды), то перед переходом в main() втихую вызывается инициализация RAM. Она прочищает/устанавливает необходимые области/переменный RAM. Все, что пользовал загрузчик, будет бесследно "перезатерто". Цитата(aaarrr @ Apr 12 2016, 17:49)  Код __set_MSP(*((uint32_t *)IMAGE_START)); (*((void (**)(void))(IMAGE_START + 4)))(); Вставлю свои 5 копеек: в ассемблерном стартовом файле я дописал: Код VTOR EQU (0xE000E000 + 0x0D08) StartMainApp PROC ; R0 - parameter with the APP vector table address EXPORT StartMainApp [WEAK] LDR R1, =VTOR ; Load VTOR register address STR R0, [R1] ; Store to VTOR to relocate the vector table LDR SP, [R0] ; Reinit the user stack LDR R0, [R0, #4] ; Get the user entry point... BX R0 ; ... and jump to it ENDP В С-шном файле вызов выглядит как: Код extern StartMainApp(uint32_t vector); ... StartMainApp(0x08000000 + 0x4000); // для моего случая программы с 16К
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|