Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: [Решено] LPC1788 bootloader переход на адрес приложения
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Cosmojam
Не получается запустить приложение из загрузчика. Пример из AN10866 работает на LPC1768, но на LPC1788
Код
static void boot(uint32_t a)
{
    __asm volatile (
    "LDR SP, [R0]\n"
    "LDR PC, [R0, #4]\n"
            );
}

вызывает сброс в lockup и так по кругу. На следующем старте источник сброса SYSRESET и LOCKUP в RSID.
Посмотреть отладчиком что там происходит крайне затруднительно по причине его тормознутости и глючности (китайский j-link, кое-как с openocd рабоает и вообще никак с фирменной софтиной)

Код
__disable_irq();
__disable_fault_irq();

delay_loop(3000000u);
SCB->VTOR = (start_address & 0x1FFFFF80);
__asm volatile (
            "dmb\n"
            "dsb\n"
            "isb\n"
        );
boot(start_address);


Приложение записано с помощью IAP и судя по содержимому памяти записано верно. На LPC1768 помню приходилось перед модификацией PC переключаться на встроенный RC генератор и отключать PLL Тут это тоже пробовал - не помогает, либо я не правильно читаю даташит.

Поделитесь у кого есть реально рабочий код запуска приложения из загрузчика на этом процессоре с gcc.
Axel
Цитата(Cosmojam @ Aug 15 2013, 15:11) *
Поделитесь у кого есть реально рабочий код запуска приложения из загрузчика на этом процессоре с gcc.

Делюсь:
CODE
typedef void (*pFunction)(uint32_t app_start);

void JumpToApp (uint32_t app_start)
{
pFunction jump_to_app = (pFunction)(*(volatile uint32_t *) (app_start + 4));

LPC_SC->CCLKSEL = 0x01; // set sysclk (12MHz) as clock source
LPC_SC->PLL0CON = 0; // disable PLL
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;

SCB->VTOR = (uint32_t)app_start; // Change the Vector Table to the APP_CODE_START
__ASM volatile ("MSR psp, %0" : : "r" (*(volatile uint32_t *)app_start)); // Load new stack pointer address
jump_to_app(app_start); // Jump to application code
}

_Артём_
Цитата(Cosmojam @ Aug 15 2013, 15:11) *
Не получается запустить приложение из загрузчика. Пример из AN10866 работает на LPC1768, но на LPC1788
Код
static void boot(uint32_t a)
{
    __asm volatile (
    "LDR SP, [R0]\n"
    "LDR PC, [R0, #4]\n"
            );
}
Зачем тут ассемблер применять?




Код
typedef void (*IsrHandler_t) (void);

if (CrcOk()) {
    __set_MSP(*(uint32_t *)APPLICATION_MSP_ADDRESS);
    IsrHandler_t application_reset_handler=(IsrHandler_t)(*(uint32_t *)APPLICATION_RESET_ISR_ADDRESS);
    goto *application_reset_handler;
}
else
    NVIC_SystemReset();





Цитата(Cosmojam @ Aug 15 2013, 15:11) *
вызывает сброс в lockup и так по кругу. На следующем старте источник сброса SYSRESET и LOCKUP в RSID.


Видимо вы что-то не то запускаете и нет обработчика HardFault и получаете переход в lockup-state.
Cosmojam
Спасибо за код и подсказку. Буду внимательнее смотреть корректность приложения.

Цитата(_Артём_ @ Aug 15 2013, 15:55) *
Зачем тут ассемблер применять?

Так было в аппноуте когда делал это на LPC1768. Через указатель на функцию тогда не получалось, видимо по другим причинам, но решив их оставил как было в аппноуте ибо нефик трогать то что работает sm.gif
Fedor
Попробуйте обявить эту функцию с __attribute__((naked))
Cosmojam
Цитата(Fedor @ Aug 16 2013, 11:29) *
Попробуйте обявить эту функцию с __attribute__((naked))

Уже без надобности.

Разобрался. Похоже это было из-за прерываний, вставших в очередь. Помогло явное отключение всех прерываний и очистка очереди перед переходом
Код
    NVIC->ICER[0] = 0xFFFFFFFF;
    NVIC->ICER[1] = 0x00000001;
    /* Clear all pending interrupts */
    NVIC->ICPR[0] = 0xFFFFFFFF;
    NVIC->ICPR[1] = 0x00000001;
    /* Clear all interrupt priority */
    uint8_t tmp = 0;
    for (tmp = 0; tmp < 32u; tmp++)
    {
        NVIC->IP[tmp] = 0x00;
    }

Функция NVIC_DeInit() в периферийной библиотеке.
ar__systems
Цитата(Axel @ Aug 15 2013, 07:44) *
Делюсь:
CODE
typedef void (*pFunction)(uint32_t app_start);

void JumpToApp (uint32_t app_start)
{
pFunction jump_to_app = (pFunction)(*(volatile uint32_t *) (app_start + 4));

LPC_SC->CCLKSEL = 0x01; // set sysclk (12MHz) as clock source
LPC_SC->PLL0CON = 0; // disable PLL
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;

SCB->VTOR = (uint32_t)app_start; // Change the Vector Table to the APP_CODE_START
__ASM volatile ("MSR psp, %0" : : "r" (*(volatile uint32_t *)app_start)); // Load new stack pointer address
jump_to_app(app_start); // Jump to application code
}


Этот метод не работает, точнее работает неправильно. При заходе в main() стэк оказывается сдвинут на 0x680 по сравнению с запуском приложения без бутлоадера. Ассемблерный вариант работает правильно.

yanvasiij
У меня схожая проблема. При переключении из bootloadera в рабочую программу в рабочей программе не стартует Freertos. То есть все, что до запуска планировщика работает, а как только доходит до запуска планировщика все рушится. FreeRtos присутствует и в bootloadere и в рабочей программе. Отладить вообще не представляю как, ибо рабочая программа загружается по с tftp-сервера, только по логам в уарте сужу, что происходит.
CODE
ъ
/**
* @brief Переключиться в программу
*
* @param address адрес где расположенна программа
*
*/
__asm void boot_jump( uint32_t address )
{
LDR SP, [R0] ;Load new stack pointer address
LDR PC, [R0, #4] ;Load new program counter address
}


/**
* @brief переключить программу
*
* @param address адрес, куда переключаться
*/
void switchProgram (uint32_t address)
{
NVIC->ICER[0] = 0xFFFFFFFF;
NVIC->ICER[1] = 0x00000001;
/* Clear all pending interrupts */
NVIC->ICPR[0] = 0xFFFFFFFF;
NVIC->ICPR[1] = 0x00000001;
/* Clear all interrupt priority */
uint8_t tmp = 0;
for (tmp = 0; tmp < 32u; tmp++)
{
NVIC->IP[tmp] = 0x00;
}
SCB->VTOR = address;
boot_jump(address);
}


Вот вырезка из места, где все это вызывается:

Код
...
            else if(memcmp("switch\r", str, strlen("switch\r")) ==0 )
            {
                taskEXIT_CRITICAL();
                vTaskEndScheduler();
                switchProgram(0x10000);
            }
...


Буду признателен за помощь.
Cosmojam
Попробуйте отключить systick перед запуском приложения.
В начале функции switchProgram():
Код
SysTick->CTRL &= ~((uint32_t)(1<<0)); // отключает таймер
SysTick->CTRL &= ~((uint32_t)(1<<1)); // отключает прерывание
SysTick->CTRL &= ~((uint32_t)(1<<16));  // сбрасывает флаг
Bass
В таблице векторов прерываний по нулевому смещению присутствует адрес стека приложения?
yanvasiij
Cosmojam
Отключение systick не помогло.
Bass
Не совсем понял Ваш вопрос: речь идет о таблице векторов бутлоадера или рабочей программы?

Я выяснил, что в рабочей программе перестает работать FreeRtos, когда я подключаю к проекту бутлоадера драйвер etherneta EMAC_LPC177x_8x.c. Исключаю его из компиляции - все работает, подключает ось в рабочей программе не стартует.
yanvasiij
Я понял в чем проблема. Все дело в функции systemInit, которая вызывается у меня в начале всех программ. Ошибка конечно глупейшая, я не углядел, что в ней тоже инициализируется регистр VTOR:
CODE
void SystemInit (void)
{
#if (CLOCK_SETUP) /* Clock Setup */
LPC_SC->SCS = SCS_Val;
if (SCS_Val & (1 << 5)) { /* If Main Oscillator is enabled */
while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready */
}

LPC_SC->CLKSRCSEL = CLKSRCSEL_Val; /* Select Clock Source for sysclk/PLL0*/

#if (PLL0_SETUP)
LPC_SC->PLL0CFG = PLL0CFG_Val;
LPC_SC->PLL0CON = 0x01; /* PLL0 Enable */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & (1<<10)));/* Wait for PLOCK0 */
#endif

#if (PLL1_SETUP)
LPC_SC->PLL1CFG = PLL1CFG_Val;
LPC_SC->PLL1CON = 0x01; /* PLL1 Enable */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & (1<<10)));/* Wait for PLOCK1 */
#endif

LPC_SC->CCLKSEL = CCLKSEL_Val; /* Setup Clock Divider */
LPC_SC->USBCLKSEL = USBCLKSEL_Val; /* Setup USB Clock Divider */
LPC_SC->EMCCLKSEL = EMCCLKSEL_Val; /* EMC Clock Selection */
LPC_SC->PCLKSEL = PCLKSEL_Val; /* Peripheral Clock Selection */
LPC_SC->PCONP = PCONP_Val; /* Power Control for Peripherals */
LPC_SC->CLKOUTCFG = CLKOUTCFG_Val; /* Clock Output Configuration */
#endif

#if (FLASH_SETUP == 1) /* Flash Accelerator Setup */
LPC_SC->FLASHCFG = FLASHCFG_Val|0x03A;
#endif

#ifdef __RAM_MODE__
SCB->VTOR = 0x10000000 & 0x3FFFFF80; /* <<< ВОТ ЗДЕСЬ ОН ИНИЦИАЛИЗИРУЕТСЯ ПОВТОРНО */
#else
SCB->VTOR = 0x00000000 & 0x3FFFFF80;
#endif

}


Выходит, что вектора надо ремапить либо во второй программе, после systemInit, либо не вызывать второй раз ее, раз уж она в буте используется.
Cosmojam
Цитата(yanvasiij @ Nov 7 2013, 10:56) *
Выходит, что вектора надо ремапить либо во второй программе, после systemInit, либо не вызывать второй раз ее, раз уж она в буте используется.

Ремапить в загрузчике и приложении можно так:
SCB->VTOR = (unsigned long)&g_pfnVectors & 0x3FFFFF80;
Сразу после вызова SystemInit(). Так указывается адрес таблицы векторов всегда на фактический её адрес независимо от абсолютного адреса куда линкер её положил.
yanvasiij
Cosmojam
Где определен указатель g_pfnVectors?
Cosmojam
Цитата(yanvasiij @ Nov 7 2013, 13:02) *
Cosmojam
Где определен указатель g_pfnVectors?

В стартап файле из любого примера NXP. Там таблица векторов определена в этом массиве в виде указателей на функции. Правда это в примерах от NXP под GNU-тые средства разработки. Под другие может иначе сделано.
Dunduk
Цитата(ar__systems @ Sep 30 2013, 21:17) *
Этот метод не работает, точнее работает неправильно. При заходе в main() стэк оказывается сдвинут на 0x680 по сравнению с запуском приложения без бутлоадера. Ассемблерный вариант работает правильно.

Интересно почему это происходит? И что за магическое число 0x680
Я вижу у себя ту же картину. То есть, переход происходит совсем не туда куда я хочу (0x2000) Мой код:
Код
__asm void boot_jump( uint32_t address ){
   LDR SP, [R0]    ;Load new stack pointer address
   LDR PC, [R0, #4];Load new program counter address
}

void execute_user_code(void)
{
    uint8_t tmp;

    NVIC->ICER[0] = 0xFFFFFFFF;    //Disable all interrupts
    NVIC->ICER[1] = 0x00000001;
    
    NVIC->ICPR[0] = 0xFFFFFFFF;    //Clear all pending interrupts
    NVIC->ICPR[1] = 0x00000001;
    for(tmp = 0; tmp < 32; tmp++)    // Clear all interrupt priority
    {
            NVIC->IP[tmp] = 0x00;
    }
    
    LPC_SC->CCLKSEL = 0x01;     // set sysclk (12MHz) as clock source
    LPC_SC->PLL0CON = 0;             // disable PLL
    LPC_SC->PLL0FEED = 0xAA;
    LPC_SC->PLL0FEED = 0x55;

    SCB->VTOR = (0x2000) & 0x1FFFFF80;
    boot_jump(0x2000);
}
Dunduk
Oops...
Сам себя обманул :-)
У меня в проекте там задан адрес старта 0x2000. При этом я собственными руками писал scatter file для линкера, где указа адрес старта 0x0000. И поставил галочку "верить скеттеру" :-)
Щас все работает.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.