Перейти к содержанию
    

[Решено] 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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поделитесь у кого есть реально рабочий код запуска приложения из загрузчика на этом процессоре с 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
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Делюсь:

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня схожая проблема. При переключении из 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);
            }
...

 

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

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Cosmojam

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

Bass

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я понял в чем проблема. Все дело в функции 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, либо не вызывать второй раз ее, раз уж она в буте используется.

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Cosmojam

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...