Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F0 и вызов встроенного бутлодера
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Cosworth
А вот интересно, у кого-нибудь получился вот такой трюк: http://www.youtube.com/watch?v=cvKC-4tCRgw ?
Решил попробовать на f0-дисковери (контроллер stm32f051). Открыл руководство по бутлодеру:
Цитата
3 Kbytes starting from address
0x1FFFEC00, contain the bootloader
firmware.

Сдампил содержимое:
Код
7806 0020 35ee ff1f edec ff1f edec ff1f
00f0 02f8 00f0 40f8 0ca0 30c8 0838 2418
2d18 a246 671e ab46 5446 5d46 ac42 01d1
00f0 32f8 7e46 0f3e 0fcc ...

Здорово, первая чиселка 0х20000678 похожа на адрес из рамы, очевидно - указатель куда надо стек поместить. А дальше, с адреса 0x1FFFEC00 + 4 (как раз куда этот чел с видео прыгает) - мура какая-то (0х1FFFEE35), подозреваю, что это некая таблица с адресами. На видео - тоже самое. Дизассемблер видит в этом месте инструкцию arm режима: " mrc 15, 1, r1, cr5, cr15, {7} " - в доках что-то про сопроцессор (какой нафиг сопроцессор?). Вообшем я сделал вывод, что по адресу System Memory + 4 инструкции нету и, тогда вопрос, зачем туда переходить?
Ну ладно, думаю, почему не попробовать:
Код
void __early_init(void)
{
    uint32_t *key = ( uint32_t * ) SRAM_BASE;
    void ( *BootLoader )( void ) = ( void ( * )( void ) ) 0x1FFFEC04;

    if( *key == 0xDEADC0DE )
    {
        *key = 0;

        __set_PRIMASK( 1 );
        __set_MSP( 0x20000678 );
        __set_CONTROL( 0 );
        BootLoader();
    }

    stm32_clock_init();
}

Как и предполагалось - переход по адресу 1FFFEC04 и на этой самой инструкции mrc - провал в хард фолт.
SSerge
Младший бит в адресах переходов - признак Thumb mode, поэтому команду надо было начинать дизассемблировать с адреса 0х1FFFEE34.

Кроме передачи управления нужно ещё переключить мэппинг памяти, за это отвечают биты MEM_MODE[1:0] в регистре SYSCFG->CFGR1.
scifi
Между прочим, в AN2602 написано следующее:
Цитата
In addition to patterns described below, user can execute bootloader by performing a jump to system memory from user code. Before jumping to Bootloader user must:
• Disable all peripheral clocks
• Disable used PLL
• Disable interrupts
• Clear pending interrupts

Ну и правильно сказал SSerge: нужно добавить 1 к адресу.
SSerge
Цитата(scifi @ Jul 10 2015, 01:00) *
Ну и правильно сказал SSerge: нужно добавить 1 к адресу.

Я, наверное, не совсем точно выразился. Во избежание заблуждений надо бы уточнить.
Специально ничего добавлять не нужно, линкер об этом уже позаботился и по адресу 0x1FFFEC04 положил адрес перехода с установленным в 1 младшим битом. Сами адреса памяти, по которым будет производится выборка команд, естественно будут чётными.

Эту единичку надо учитывать при интерпретации программы "в уме" и при вычислении адресов перехода "вручную" из указателей на память данных.

Это всё досталось в наследство от предыдущих ARM, которые имели два набора команд (32-битные ARM и 16-битные Thumb) и младшим битом загружаемого в PC значения указывалось что нужно переключиться в Thumb.
У кортексов набор команд только один, Thumb-2, переключать нечего, но установленный младший бит в адресах переходов остался "для совместимости".
Cosworth
Цитата(SSerge @ Jul 9 2015, 20:27) *
Младший бит в адресах переходов - признак Thumb mode, поэтому команду надо было начинать дизассемблировать с адреса 0х1FFFEE34.

Кроме передачи управления нужно ещё переключить мэппинг памяти, за это отвечают биты MEM_MODE[1:0] в регистре SYSCFG->CFGR1.


А, ну точно, надо ж не на 0x1FFFEC04 прыгать, а на адрес, который там хранится.

В общем-то, я как делаю: из основной программы по команде выключаю все прерывания, записываю по нулевому адресу рамы ключ, ремаплю нулевой адрес на System Flash (Mem_MODE = 01) и делаю сброс. После сброса - попадаю в __early_init(). Вот поправил указатель:
Код
void __early_init(void)
{
...
    void ( *BootLoader )( void ) = ( ( void * )( void ) ) ( *( ( uint32_t * ) 0x1FFFEC04 ) );
...
}

Хард флотов больше нет, но контроллер после выполнения BootLoader() прыгает то в ресет то в рандомную функцию и через stlink не прогается - приходится стирать прошивку через бутлоадер.
scifi
На всякий случай поделюсь своим рецептом перехода на прошивку по произвольному адресу:
Код
static const uint16_t jump2fw[] =
{
    0x6801, // ldr r1, [r0, #0]
    0x468D, // mov sp, r1
    0x6840, // ldr r0, [r0, #4]
    0x4700, // bx r0
};

((void (*)(int))(1 + (int)jump2fw))(FIRMWARE_ADDRESS);

В данном случае FIRMWARE_ADDRESS - это 0, потому что загрузчик, очевидно, ожидает, что его код замапен на нулевой адрес.
Сергей Борщ
до кучи мой рецепт перехода:
Код
extrn "C" void func();
void test()
{
   func();
}
// В командную строку линкера добавляем -Wl,--defsym,func=адрес

Переход на функцию по указателю (как в вопросе) делал бы так:
Код
extern "C" void (*bootloader)();
void test()
{
    bootloader();
}
// В командную строку линкера добавляем -Wl,--defsym,bootloader=0x1FFFEC04
scifi
Цитата(Сергей Борщ @ Jul 10 2015, 18:49) *
до кучи мой рецепт перехода:

Я имел в виду переход на начало прошивки с загрузкой указателя стека и точки входа (так, как стартует Cortex).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.