Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: BootLoader для LPC1766
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Vitaliy_ARM
Был у меня загрузчик для LPC2378 и прочих.
Теперь стала задача переписать его под LPC1766.

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

Прикладная программа заливается вместе с векторами начиная с адреса 0x1 0000 (16-я страница). Т.е. в ней находятся сначала вектора, а потом все остальное.

Код вызова программы:

Код
#define FIRST_PAGE_ADDR 0x10000
#define NVIC_VectTab_FLASH           (0x00000000)

// код вызова приложения

volatile unsigned long    *p = (volatile unsigned long*)NVIC_VECT_TABLE;
*p = NVIC_VectTab_FLASH | (USER_FLASH_START & 0x1FFFFF80);

void (*App)() =  (void(*)())(FIRST_PAGE_ADDR + 1);
App();            // уходим в прикладную программу


Код вызова брал по аналогии из LPC1700 USB Bootloader.

Сделал прикладную программу, которая настраивает порт светодиода на плате и зажигает его.
Прикладная программа вызывается неправильно. В ассемблерном коде используется BLX на адрес, 10001, хотя должен был быть 10002. И яр отображает код совсем подругому.
В приложенных файлах 001 и 002 показаны скриншоты яра при работе загрузчика и уходе в прикладную программу. На 003 - прикладная программа в отладочном режиме без загрузчика.

Как правильно вызывать?
aaarrr
Цитата(Vitaliy_ARM @ Jan 28 2010, 18:37) *
В ассемблерном коде используется BLX на адрес, 10001, хотя должен был быть 10002.

А почему, собственно, 0x10000 + 0x01 должно быть равно 0x10002?
Vitaliy_ARM
Цитата(aaarrr @ Jan 28 2010, 18:42) *
А почему, собственно, 0x10000 + 0x01 должно быть равно 0x10002?

cranky.gif наверное никак.
Сбил с толку указанный выше пример:

Код
void execute_user_code(void)
{
    void (*user_code_entry)(void);
    
    /* Change the Vector Table to the USER_FLASH_START
    in case the user application uses interrupts */
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, USER_FLASH_START);

      user_code_entry = (void (*)(void))((USER_FLASH_START)+1);
    user_code_entry();

}


А что может находиться по адресу 0x10000 + 0x01? На сколько мне известно при 16 битных инструкциях прыгать нужно на адреса, выровненные под 16 битное пространство (т.е. в последнем бите должен быть 0).
aaarrr
Цитата(Vitaliy_ARM @ Jan 28 2010, 19:04) *
А что может находиться по адресу 0x10000 + 0x01? На сколько мне известно при 16 битных инструкциях прыгать нужно на адреса, выровненные под 16 битное пространство (т.е. в последнем бите должен быть 0).

Младший бит адреса BLX выбирает режим работы процессора. В данном случае он должен быть равен "1", т.к. процессор может работать только в Thumb.

Цитата(Vitaliy_ARM @ Jan 28 2010, 18:37) *
В приложенных файлах 001 и 002 показаны скриншоты яра при работе загрузчика и уходе в прикладную программу. На 003 - прикладная программа в отладочном режиме без загрузчика.

Судя по скриншотам, прикладная программа просто неправильно записана.
Vitaliy_ARM
Цитата(aaarrr @ Jan 28 2010, 20:21) *
Младший бит адреса BLX выбирает режим работы процессора. В данном случае он должен быть равен "1", т.к. процессор может работать только в Thumb.

Теперь понятно.
Цитата(aaarrr @ Jan 28 2010, 20:21) *
Судя по скриншотам, прикладная программа просто неправильно записана.

Да, действительно. smile3046.gif
Спасибо.

Рано обрадовался. Были неправильные скриншоты. После скринов будлодера я несколько изменил прошивку.
Теперь сделал все заново. Прошики совпадают.
Vitaliy_ARM
Правильные скриншоты:
1 - дамп памяти в яре при отладке прикладной программы без загрузчика
2 - бинарь, который генерит яр при компиляции прикладной программы
3 - дамп памяти этой же прошивки, после загрузки ее загрузчиком

Проблема осталась таже.
prgjz
Для STM32 применяю так:
Загрузчик находится 0х0800 0000
Программа
#define KERNEL_START_APP 0x08004000

__SYSJUMP(KERNEL_START_APP);

;*******************************************************************************
; Function Name : __SYSJUMP
; Description : Assembler function for the jump to App. from Boot
; Input : - r0 : Application Start Addres.
; Return : None
;*******************************************************************************

__SYSJUMP

MOVS R4,R0
CPSID i
LDR R0,[R4, #+0] ; set the stack pointer to app
MSR MSP, R0
LDR PC,[R4, #+4] ; load PC with reset vector from APP

END

Обратите внимание что у кортекса в начале вектора прерывания находится указатель на стек
а +4 начало программы
Vitaliy_ARM
Цитата(prgjz @ Jan 29 2010, 16:52) *
Для STM32 применяю так:
Загрузчик находится 0х0800 0000
Программа
#define KERNEL_START_APP 0x08004000
Обратите внимание что у кортекса в начале вектора прерывания находится указатель на стек
а +4 начало программы


Спасибо за код. Но для начала хочу понять весь механизм. Все знают что в иар по резету происходит переход в __iar_program_start .
Я в прикладной программе нашел адрес этой подпрограммы. И в загрузчике сделал вызов именно по этому адресу, забив адрес в регистр PC. Прошивка заработала!
Однако когда я забиваю в PC в прикладной программе начало таблицы векторов 0x10000 со смещением: 0x00000, 0x00002, 0x00004 и т.д. процессор улетает в хардваре еррор дефаулт хэндл. Т.е. ошибка состоит в том, что в вызове прикладной программы происходит переход "НЕ ТУДА".

Вот кусок яровского стартапа:
Код
        EXTERN  __iar_program_start
        PUBLIC  __vector_table
        PUBLIC  __vector_table_0x1c

        DATA
__vector_table
        DCD     sfe(CSTACK)            ; Top of Stack
        DCD     __iar_program_start    ; Reset Handler
        DCD     NMI_Handler            ; NMI Handler
        DCD     HardFault_Handler         ; Hard Fault Handler
        DCD     MemManage_Handler         ; MPU Fault Handler
        DCD     BusFault_Handler          ; Bus Fault Handler
        DCD     UsageFault_Handler        ; Usage Fault Handler
__vector_table_0x1c
        DCD     0                         ; Reserved
        DCD     0                         ; Reserved
        DCD     0                         ; Reserved
        DCD     0                         ; Reserved
        DCD     SVC_Handler            ; SVCall Handler
        DCD     DebugMon_Handler          ; Debug Monitor Handler
        DCD     0                         ; Reserved
        DCD     PendSV_Handler            ; PendSV Handler
        DCD     SysTick_Handler        ; SysTick Handler
        DCD     WDT_IRQHandler            ; Watchdog Handler
        DCD     TMR0_IRQHandler        ; TIMER0 Handler
        DCD     TMR1_IRQHandler        ; TIMER1 Handler
        DCD     TMR2_IRQHandler        ; TIMER2 Handler
        DCD     TMR3_IRQHandler        ; TIMER3 Handler
        DCD     UART0_IRQHandler          ; UART0 Handler
        DCD     UART1_IRQHandler          ; UART1 Handler
        DCD     UART2_IRQHandler          ; UART2 Handler
        DCD     UART3_IRQHandler          ; UART3 Handler
        DCD     PWM1_IRQHandler        ; PWM1 Handler
        DCD     I2C0_IRQHandler        ; I2C0 Handler
        DCD     I2C1_IRQHandler        ; I2C1 Handler
        DCD     I2C2_IRQHandler        ; I2C2 Handler
        DCD     SPI_IRQHandler            ; SPI Handler
        DCD     SSP0_IRQHandler        ; SSP0 Handler
        DCD     SSP1_IRQHandler        ; SSP1 Handler
        DCD     PLL0_IRQHandler        ; PLL0 Handler
        DCD     RTC_IRQHandler            ; RTC Handler
        DCD     EINT0_IRQHandler          ; EXT Interupt 0 Handler
        DCD     EINT1_IRQHandler          ; EXT Interupt 1 Handler
        DCD     EINT2_IRQHandler          ; EXT Interupt 2 Handler
        DCD     EINT3_IRQHandler          ; EXT Interupt 3 Handler
        DCD     ADC_IRQHandler            ; ADC Handler
        DCD     BOD_IRQHandler            ; BOD Handler
        DCD     USB_IRQHandler            ; USB Handler
        DCD     CAN_IRQHandler            ; CAN Handler
        DCD     GPDMA_IRQHandler          ; General Purpose DMA Handler
        DCD     I2S_IRQHandler            ; I2S Handler
        DCD     Ethernet_IRQHandler    ; Ethernet Handler
        DCD     RIT_IRQHandler            ; Repetitive Interrupt Timer Handler
        DCD     MotorControlPWM_IRQHandler; Motor Control PWM Handler
        DCD     QE_IRQHandler             ; Quadrature Encoder Handler
        DCD     PLL1_IRQHandler        ; PLL1 Handler


Вопрос, на какой адрес прыгает процессор LPC1766 (и т.п.) после сброса?
aaarrr
Цитата(Vitaliy_ARM @ Jan 29 2010, 18:45) *
Вопрос, на какой адрес прыгает процессор LPC1766 (и т.п.) после сброса?

По адресу, записанному в Reset Handler таблицы векторов:
Код
        DCD     __iar_program_start; Reset Handler
Vitaliy_ARM
Запись в даташите:

Цитата
Following a hardware reset, the Boot ROM is temporarily mapped to address 0. This is
normally transparent to the user. However, if execution is halted immediately after reset by
a debugger, it should correct the mapping for the user. See Section 33–6.


В секции 33:

Код
Following chip reset, a portion of the Boot ROM is mapped to address 0 so that it will be
automatically executed. The Boot ROM switches the map to point to Flash memory prior
to user code being executed. In this way a user normally does not need to know that this
re-mapping occurs.

However, when a debugger halts CPU execution immediately following reset, the Boot
ROM is still mapped to address 0 and can cause confusion. Ideally, the debugger should
correct the mapping automatically in this case, so that a user does not need to deal with it.
aaarrr
Цитата(Vitaliy_ARM @ Jan 29 2010, 19:18) *
Понятно, по какому адресу?

Что по какому адресу? После сброса Reset Handler находится по адресу 0x04.
Vitaliy_ARM
Цитата(aaarrr @ Jan 29 2010, 19:21) *
Что по какому адресу? После сброса Reset Handler находится по адресу 0x04.

Забиваю адрес 0x04 в PC при отладке, указатель начинает бежать по векторам подряд и через некоторое время вылетает в аппаратный хендел. Если забить в него адрес __iar_program_start, то программа начинает работать. Может так нельзя делать? Или проблема собственно что резет находится в этот момент не по 0х04 адресу?
aaarrr
PC загружается из 0x04, а не им.
Vitaliy_ARM
Цитата(aaarrr @ Jan 29 2010, 19:47) *
PC загружается из 0x04, а не им.


Немного не понял что это значит. Поясните пожалуйста.
aaarrr
Считывается слово из адреса Reset Handler (0x04), и загружается в PC.
Vitaliy_ARM
Цитата(aaarrr @ Jan 29 2010, 20:14) *
Считывается слово из адреса Reset Handler (0x04), и загружается в PC.


Так и сделал:
Код
// загружаем в указатель значение, находящееся по адресу FIRST_PAGE_ADDR + 0x04
void (*App)() =  (void(*)())(*((DWORD*)(FIRST_PAGE_ADDR + 0x04)));
// запускаем приложение
App();


Все работает, спасибо!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.