Jump to content

    

[Решено] LPC1788 bootloader переход на адрес приложения

Не получается запустить приложение из загрузчика. Пример из 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.

Share this post


Link to post
Share on other sites
Поделитесь у кого есть реально рабочий код запуска приложения из загрузчика на этом процессоре с gcc.

Делюсь:

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
}

 

Share this post


Link to post
Share on other sites
Не получается запустить приложение из загрузчика. Пример из 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();

 

 

 

 

вызывает сброс в lockup и так по кругу. На следующем старте источник сброса SYSRESET и LOCKUP в RSID.

 

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

Share this post


Link to post
Share on other sites

Спасибо за код и подсказку. Буду внимательнее смотреть корректность приложения.

 

Зачем тут ассемблер применять?

Так было в аппноуте когда делал это на LPC1768. Через указатель на функцию тогда не получалось, видимо по другим причинам, но решив их оставил как было в аппноуте ибо нефик трогать то что работает :)

Share this post


Link to post
Share on other sites

Попробуйте обявить эту функцию с __attribute__((naked))

Share this post


Link to post
Share on other sites
Попробуйте обявить эту функцию с __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() в периферийной библиотеке.

Share this post


Link to post
Share on other sites
Делюсь:

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 по сравнению с запуском приложения без бутлоадера. Ассемблерный вариант работает правильно.

 

 

Share this post


Link to post
Share on other sites

У меня схожая проблема. При переключении из bootloadera в рабочую программу в рабочей программе не стартует Freertos. То есть все, что до запуска планировщика работает, а как только доходит до запуска планировщика все рушится. FreeRtos присутствует и в bootloadere и в рабочей программе. Отладить вообще не представляю как, ибо рабочая программа загружается по с tftp-сервера, только по логам в уарте сужу, что происходит.

ъ
/**
* @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);
            }
...

 

Буду признателен за помощь.

Edited by IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Share this post


Link to post
Share on other sites

Попробуйте отключить systick перед запуском приложения.

В начале функции switchProgram():

SysTick->CTRL &= ~((uint32_t)(1<<0)); // отключает таймер 
SysTick->CTRL &= ~((uint32_t)(1<<1)); // отключает прерывание
SysTick->CTRL &= ~((uint32_t)(1<<16));  // сбрасывает флаг

Share this post


Link to post
Share on other sites

В таблице векторов прерываний по нулевому смещению присутствует адрес стека приложения?

Share this post


Link to post
Share on other sites

Cosmojam

Отключение systick не помогло.

Bass

Не совсем понял Ваш вопрос: речь идет о таблице векторов бутлоадера или рабочей программы?

 

Я выяснил, что в рабочей программе перестает работать FreeRtos, когда я подключаю к проекту бутлоадера драйвер etherneta EMAC_LPC177x_8x.c. Исключаю его из компиляции - все работает, подключает ось в рабочей программе не стартует.

Share this post


Link to post
Share on other sites

Я понял в чем проблема. Все дело в функции systemInit, которая вызывается у меня в начале всех программ. Ошибка конечно глупейшая, я не углядел, что в ней тоже инициализируется регистр VTOR:

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, либо не вызывать второй раз ее, раз уж она в буте используется.

Edited by IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Share this post


Link to post
Share on other sites
Выходит, что вектора надо ремапить либо во второй программе, после systemInit, либо не вызывать второй раз ее, раз уж она в буте используется.

Ремапить в загрузчике и приложении можно так:

SCB->VTOR = (unsigned long)&g_pfnVectors & 0x3FFFFF80;

Сразу после вызова SystemInit(). Так указывается адрес таблицы векторов всегда на фактический её адрес независимо от абсолютного адреса куда линкер её положил.

Share this post


Link to post
Share on other sites
Cosmojam

Где определен указатель g_pfnVectors?

В стартап файле из любого примера NXP. Там таблица векторов определена в этом массиве в виде указателей на функции. Правда это в примерах от NXP под GNU-тые средства разработки. Под другие может иначе сделано.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this