Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Bootloader. Подскажите.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
vitek101
Написал загрузчик для XMega128, IAR5.20. Переделал его из примера Атмела 1605.
Загрузчик расположен в одном проекте с основным приложением в секции #ifdef. По сбросу стартует загрузчик и проверяет наличие программы в FRAM, если есть заливает ее во флеш.
Определил сегмент в XCL:

-D_..X_FLASH_HUGE_END=21FFF
-D_..X_BOOTSEC_SIZE=2000
-Z(CODE)BOOT_SEGMENT=(_..X_FLASH_HUGE_END-_..X_BOOTSEC_SIZE+1)-_..X_FLASH_HUGE_END

Сам загрузчик:
Код
#pragma segment = "BOOT_SEGMENT"
#pragma location="BOOT_SEGMENT"

#include <eeprom_driver.h>
#include <sp_driver.h>
#include <defines.h>

#define BOOT_F_CPU             2000000UL

........ // определение типов и констант для I2C

boot_TWI_Master_t  twiMaster;   // структура для работы с I2C
uint8_t boot_sBuf[32];

// объявление функций для I2C
__root bool boot_TWI_MasterWriteRead(boot_TWI_Master_t *twi,
                         uint8_t address,
                         uint8_t *writeData,
                         uint8_t bytesToWrite,
                         uint8_t bytesToRead) @ "BOOT_SEGMENT";
__root void boot_TWI_MasterInterruptHandler(boot_TWI_Master_t *twi) @ "BOOT_SEGMENT";

.........


__root void boot(void) @ "BOOT_SEGMENT"; // тело загрузчика
__root void GoToApplication(void) @ "BOOT_SEGMENT"; // переход в приложение

__root void boot(void) @ "BOOT_SEGMENT"
{
  boot_TWI_MasterInit(&twiMaster,                   // инициализирую I2C
                 &TWIF,
                 TWI_MASTER_INTLVL_HI_gc,
                 BOOT_TWI_BAUDSETTING);
  
  PMIC.CTRL |= PMIC_HILVLEN_bm;
  
  boot_sBuf[0] = 0x00;                                   // читаю из FRAM 6 байтов
  boot_sBuf[1] = 0x40;
  boot_TWI_MasterWriteRead(&twiMaster,
                      0xA0,
                      &boot_sBuf[0],
                      2,
                      6);

  while (twiMaster.status != boot_TWIM_STATUS_READY)      // пишу и читаю пока надо
  {
    if ((TWIF.MASTER.STATUS & 0xCC) != 0x00)
    {
      boot_TWI_MasterInterruptHandler(&twiMaster);
    }
  }
  
  // в зависимости от результата что-то делаю
  ............
  
  GoToApplication();
    
}

__root void GoToApplication(void) @ "BOOT_SEGMENT"
{
  cli();
  PMIC.CTRL = 0;
  SP_WaitForSPM();
  SP_LockSPM();
  EIND = 0x00;
  void (*funcptr)( void ) = 0x0000;         // Set up function pointer to RESET vector.
  funcptr();                                // Jump to Reset vector 0x0000 in Application Section.
}

__root bool boot_TWI_MasterWriteRead(boot_TWI_Master_t *twi,
                         uint8_t address,
                         uint8_t *writeData,
                         uint8_t bytesToWrite,
                         uint8_t bytesToRead) @ "BOOT_SEGMENT"
{
    /*Parameter sanity check. */
    if (bytesToWrite > boot_TWIM_WRITE_BUFFER_SIZE) {
        return false;
    }
    if (bytesToRead > boot_TWIM_READ_BUFFER_SIZE) {
        return false;
    }

            ..........................
}


Загрузчик стартует как надо, переход в тело работает.
Теперь собственно в чем проблема:
Инициализация I2C проходит нормально, регистры принимают нужное значение.
При вызове boot_TWI_MasterWriteRead(...) смотрю в отладчике, а там параметр bytesToRead всегда равен 0. Пробовал убрать параметр address, тогда bytesToRead передается как надо. Т.е получается не может передать большое количество параметров. Но дальше все равно не работает чтение из FRAM. Пробовал вставлять этот кусок в основное тело приложения, там все работает хорошо.
Мне кажется или что-то со стеком при работе в области загрузчика или не знаю.

Помогите пожалуйста help.gif


И еще: может проблема быть связана с __root, #pragma и т.д.? Может чего-то не хватает? Просто я в них не особо шарю... laughing.gif
KRS
_root не надо писать у каждой функции!
достаточно у boot

кроме того у вас все функции расопложены "BOOT_SEGMENT",
но первой должна быть функция boot (точка входа), а линкер может их перемешать!
Можно например сделать 2 сегмента -Z(CODE)BOOT_ENTY, BOOT_SEGMENT=....
и boot расположить в BOOT_ENTY, тогда будет гарантировано первой!

А как вы рабоаете с прерываниями в бутлоадере?
Какой cstartup используете?
IMHO в данном случае лучше работать полингом!

Да про cstartup забыл, так что в BOOT_ENTY должен быть startup, который для бутлоадера надо написать простейший - достаточно инициализации стеков. (SP и Y)
V_G
Цитата(KRS @ Nov 11 2009, 19:15) *
А как вы рабоаете с прерываниями в бутлоадере?
Какой cstartup используете?
IMHO в данном случае лучше работать полингом!

Пардон, вопрос не ко мне, но отвечу про себя.
У меня в бутлоадерах традиционно запрещены все прерывания, работа с компортом по опросу состояния (polling).
Ну, и на ассемблере работаю. Одна из попыток перейти на Си в микроконтроллерах как раз и завершилась кривым бутлоадером, полностью ручками перепер его на ассемблер, и с тех пор ему (ассемблеру) не изменяю. А на С, С++ пишу программы под винду, которые общаются с моими же программами из микроконтроллеров.
KRS
Цитата(V_G @ Nov 11 2009, 12:25) *
Ну, и на ассемблере работаю. Одна из попыток перейти на Си в микроконтроллерах как раз и завершилась кривым бутлоадером, полностью ручками перепер его на ассемблер, и с тех пор ему (ассемблеру) не изменяю.

Так вы просто не разобрались smile.gif
Только на асме уже давно глупо писать!
Данный код компилер сделает не хуже!
А вот, например для ARM - работа с периферией, где куча констант, из-за особенностей архитектуры - скомпилируется лучше чем на асме, конечно можно руками за месяцок простчитать все константы и напистаь код оптимальнее wink.gif
vitek101
А я тут и использую полинг. С прерываниями я так и не разобрался (вроде как надо вторую таблицу создавать, а как ее создавать х.з. laughing.gif ).
А про startup можно поподробнее? Че как инициализировать? Просто я в общем язык и структуру понимаю, а в такие дебри еще не лазил. Надо взять готовый стартап и изменить его или свой новый создавать?
За сегменты спасибо smile.gif
KRS
примерно так
Код
EXTERN boot
        RSEG   CSTACK:DATA:NOROOT(0)
        RSEG   RSTACK:DATA:NOROOT(0)
        RSEG   BOOTENTRY:CODE:ROOT(1)

          LDI   R17,LOW(SFE(RSTACK)-1)
          OUT   SPL,R17
          LDI   R17,HIGH(SFE(RSTACK)-1)
          OUT   SPH,R17
          
          LDI   YL,LOW(SFE(CSTACK)-1)
          LDI   YH,HIGH(SFE(CSTACK)-1)

          rjmp boot

кстати на rjmp boot можно сэкономить, если расположить boot сразу за BOOT_ENTRY.

Да здесь не инициализируются переменные! Если надо зполнять 0 и/или копировать контстанты можно добавить
(кстати если переменных нет код автоматически уберется). Общий код примерно такой
Код
EXTERN boot
        RSEG   CSTACK:DATA:NOROOT(0)
        RSEG   RSTACK:DATA:NOROOT(0)
        RSEG   BOOTENTRY:CODE:ROOT(1)

          LDI   R17,LOW(SFE(RSTACK)-1)
          OUT   SPL,R17
          LDI   R17,HIGH(SFE(RSTACK)-1)
          OUT   SPH,R17
          
          LDI   YL,LOW(SFE(CSTACK)-1)
          LDI   YH,HIGH(SFE(CSTACK)-1)
//NEAR_Z initialization
        RSEG   STARTUPCODE:CODE:NOROOT(1)
PUBLIC `?<Segment init: NEAR_Z>`
`?<Segment init: NEAR_Z>`:
          lda   Z, SFB(NEAR_Z)
          lda   X, SIZEOF(NEAR_Z)
          clr   r16
filloop:
          st    Z+, r16
          sbiw XL, 1
          brne filloop

//NEAR_I initialization
        RSEG   STARTUPCODE:CODE:NOROOT(1)
PUBLIC `?<Segment init: NEAR_I>`
`?<Segment init: NEAR_I>`:
          lda   Z, SFB(NEAR_ID)
          lda   Y, SFB(NEAR_I)
          lda   X, SIZEOF(NEAR_I)
          
moveloop:
          lpm r0, Z+
          st Y+, r0
          sbiw XL, 1
          brne moveloop

        RSEG   BOOTENTRY:CODE:ROOT(1)
          rjmp boot
vitek101
На всякий случай прошу прощения за возможно глупый вопрос rolleyes.gif
А BOOTENTRY (в строке RSEG BOOTENTRY:CODE:ROOT(1)) это то же, что и BOOT_ENTY в вашем первом посте?
И че вообще с этим кодом надо сделать? Его надо впихнуть в CSTARTUP, который я взял из avr\src\lib и подключил к своему проекту?
KRS
Цитата(vitek101 @ Nov 11 2009, 14:59) *
На всякий случай прошу прощения за возможно глупый вопрос rolleyes.gif
А BOOTENTRY (в строке RSEG BOOTENTRY:CODE:ROOT(1)) это то же, что и BOOT_ENTY в вашем первом посте?
И че вообще с этим кодом надо сделать? Его надо впихнуть в CSTARTUP, который я взял из avr\src\lib и подключил к своему проекту?

Да это BOOT_ENTRY, там еще, елси переменные инициализировать STARTUPCODE надо на BOOT_ENTRY заменить.
его надо вместо CSTARTUP.
Да boot надо остваить в BOOTCODE.
vitek101
Сделал так:
Код
EXTERN boot
        RSEG   CSTACK:DATA:NOROOT(0)
        RSEG   RSTACK:DATA:NOROOT(0)
        RSEG   BOOT_ENTRY:CODE:ROOT(1)

          LDI   R17,LOW(SFE(RSTACK)-1)
          OUT   SPL,R17
          LDI   R17,HIGH(SFE(RSTACK)-1)
          OUT   SPH,R17
          
          LDI   YL,LOW(SFE(CSTACK)-1)                                  // тут ругается: illegal effective address
          LDI   YH,HIGH(SFE(CSTACK)-1)                                // тут ругается: illegal effective address
//NEAR_Z initialization
        RSEG   BOOT_ENTRY:CODE:NOROOT(1)                      // тут заменил STARUPCODE на BOOT_ENTRY
PUBLIC `?<Segment init: NEAR_Z>`
`?<Segment init: NEAR_Z>`:
          lda   Z, SFB(NEAR_Z)                                                // тут ругается: bad instruction
          lda   X, SIZEOF(NEAR_Z)                                           // тут ругается: bad instruction
          clr   r16
filloop:
          st    Z+, r16
          sbiw XL, 1                                                                // тут ругается: illegal effective address
          brne filloop

//NEAR_I initialization
        RSEG   BOOT_ENTRY:CODE:NOROOT(1)                      // тут заменил STARUPCODE на BOOT_ENTRY
PUBLIC `?<Segment init: NEAR_I>`
`?<Segment init: NEAR_I>`:
          lda   Z, SFB(NEAR_ID)                                           // тут ругается: bad instruction
          lda   Y, SFB(NEAR_I)                                           // тут ругается: bad instruction
          lda   X, SIZEOF(NEAR_I)                                           // тут ругается: bad instruction
          
moveloop:
          lpm r0, Z+
          st Y+, r0
          sbiw XL, 1                                                                // тут ругается: illegal effective address
          brne moveloop

        RSEG   BOOT_ENTRY:CODE:ROOT(1)
          rjmp boot
                                                                                        // тут ругается unexpected end of file encountered


Это все вставил вместо содержимого стандартного CSTARTUP. Что делаю не так?
KRS
Цитата(vitek101 @ Nov 11 2009, 15:33) *
Это все вставил вместо содержимого стандартного CSTARTUP. Что делаю не так?

так надо
Код
    END

в конце написать smile.gif
vitek101
Да, правильно biggrin.gif
Но illegal effective address и bad instruction остались unsure.gif
KRS
А да про макрос забыл smile.gif
Код
//**************************************************************************
// lda - load addr to Z, X, or Y pair
lda MACRO rPtr, Offset
     ldi \1L, LOW(Offset)
     ldi \1H, HIGH(Offset)
    ENDM
vitek101
А можно заменить
Код
          lda   Z, SFB(NEAR_Z)

на
Код
          LD[b]A[/b]   ZL,LOW(SF[b]B[/b](NEAR_Z)-1)
          LD[b]A[/b]   ZH,HIGH(SF[b]B[/b](NEAR_Z)-1)

?
illegal effective address убрались smile.gif

Спросил, а потом увидел ответ smile.gif

Вроде собрал, правда только первую часть (без инициализации переменных. Там ругается invalid syntax на строки с макросом).
Только он теперь говорит undefined external "boot" referred in cstatup wacko.gif



Все, запустил. Но в отладчике нашего стартапа не видно и все не работает по-старому...
KRS
Цитата(vitek101 @ Nov 11 2009, 16:51) *
Все, запустил. Но в отладчике нашего стартапа не видно и все не работает по-старому...

Это значит startup взялся стандартный из библиотеки!
Для начала можно вообще библиотеку отключить! (она тут скорее всего не нужна)

А откуда стартует проц? (под отладчиком)
По исходнику
Код
    RSEG   BOOT_ENTRY:CODE:ROOT(1)

          LDI   R17,LOW(SFE(RSTACK)-1)

т.е. по адресу начала BOOT_ENTRY должны быть эти данные!


что бы отключить стандартный стартап из библиотеки, надо в настройках линкера поставить override default program entry и вписать метку __program_start
а код модифицировать
Код
    RSEG   BOOT_ENTRY:CODE:ROOT(1)
PUBLIC __program_start
__program_start:
          LDI   R17,LOW(SFE(RSTACK)-1)


Но это надо проверить я в основном 3 версию иар использую. В новой были пробелмы что не хотел он стартап стандартный убирать, приходилось ручками из библиотеки моуль удалять!
Вообще надо map файл смотреть - что линкер напихал и куда!
V_G
А фьюзы на запуск с bootloadera поставили? И на тот ли адрес? Это от компилятора не зависит, это программатором определяется (ну, или настройками симулятора). А адресов бутлоадера у 128 меги может быть 4 разных, насколько я помню (для загрузчиков объемом до 256,512,1024,2048 слов)
vitek101
Поставил. Стартует он откуда надо. У XMega только одна область для загрузчика, 8 Кб.

Что-то не получается у меня отключить стандартную библиотеку. Если ее выкинуть, вылезает толпа разных ошибок.
А если взять и в стандартном STARTUPе заменить строки
Код
RSEG    CODE:CODE:NOROOT(1)

на
Код
RSEG    BOОT_ENTRY:CODE:NOROOT(1)

Может так сработает?

И main на boot

Работает!!! 08.gif
В общем поменял CODE на BOOT_ENTRY, а main оставил. Теперь следующая картина:
Стартует с загрузчика, но без STARTUPа. Праметр bytesToRead так и не работает (см. первый пост). Но попробовал опять убрать address и все заработало. Стартап появляет в отладчике в начале основной программы.
Непонятно вылезут дальше косяки какие-нибудь или нет, т.к. проблема с address так и не решена.
Спасибо за помощь! a14.gif

Теперь стартап такой:
Код
;----------------------------------------------------------------------------
; Set up the INTVEC segment with a reset vector
;----------------------------------------------------------------------------
        MODULE    ?RESET

    COMMON  INTVEC:CODE:ROOT(1); Align at an even address

        EXTERN  ?C_STARTUP
        PUBLIC  __program_start
        PUBLIC  ?RESET

    ORG $0
__program_start:
?RESET:
    XJMP    ?C_STARTUP

        ENDMOD

;----------------------------------------------------------------------------
; Forward declarations of segments used in initialization
;----------------------------------------------------------------------------
    RSEG    CSTACK:DATA:NOROOT(0)
    RSEG    RSTACK:DATA:NOROOT(0)

;----------------------------------------------------------------------------
; Perform C initialization
;----------------------------------------------------------------------------
    MODULE  ?C_STARTUP

    EXTERN  __low_level_init
    EXTERN  __segment_init
#ifdef _ECLIB_ECPP
    EXTERN  __call_ctors
#endif /* _ECLIB_ECPP */
    EXTERN  main
    EXTERN  exit
    EXTERN  _exit

;----------------------------------------------------------------------------
; If the return address stack is located in external SRAM, make sure that
; you have uncommented the correct code in __low_level_init!!!
;----------------------------------------------------------------------------
    RSEG    BOOT_ENTRY:CODE:NOROOT(1)
    PUBLIC  ?C_STARTUP
    PUBLIC  __RESTART
    EXTERN ?RESET

__RESTART:
?C_STARTUP:
#if A90_POINTER_REG_SIZE > 2
    PUBLIC  ?zero_reg_initialization

?zero_reg_initialization:
    CLR R15
    OUT RAMPD,R15
#endif

    REQUIRE ?SETUP_STACK
    REQUIRE ?RESET

    RSEG    BOOT_ENTRY:CODE:NOROOT(1)
    PUBLIC  __RSTACK_in_external_ram

__RSTACK_in_external_ram:
    LDI     R16,0xC0
    OUT     0x35,R16   ;Enable the external SRAM with a wait state

    RSEG    BOOT_ENTRY:CODE:NOROOT(1)
    PUBLIC  __RSTACK_in_external_ram_new_way
    EXTERN  __?XMCRA

__RSTACK_in_external_ram_new_way:
    LDI     R16,0x8C       ;SRE=1,SRL2=0,SRL1=0,SRL0=0,SRW11=1,SRW10=1,SRW01=0,SRW00=0
    STS     __?XMCRA,R16   ;Enable the external SRAM with maximum wait state.

;----------------------------------------------------------------------------
; Set up the CSTACK and RSTACK pointers.
;----------------------------------------------------------------------------
    RSEG    BOOT_ENTRY:CODE:NOROOT(1)
?SETUP_STACK:
   ;; Return address stack (RSTACK)
    LDI R16,LOW(SFE(RSTACK)-1)
    OUT 0x3D,R16
#if A90_POINTER_REG_SIZE > 1
    LDI R16,HIGH(SFE(RSTACK)-1)
    OUT 0x3E,R16
#endif

   ;; Data stack (CSTACK)
    LDI Y0,LOW(SFE(CSTACK))
#if A90_POINTER_REG_SIZE > 1
#if MEMORY_MODEL == TINY_MEMORY_MODEL
    LDI Y1,0
#else
    LDI Y1,HIGH(SFE(CSTACK))
#endif
#if A90_POINTER_REG_SIZE > 2
    LDI Z0,HWRD(SFB(CSTACK))
    OUT     RAMPY,Z0
#endif
#endif

#if A90_POINTER_REG_SIZE > 2
; Nothing here, the things previously here has been done earlier.
#else
    REQUIRE ?call_low_level_init

;----------------------------------------------------------------------------
; Clear R15 so that it can be used as zero register by the code generator.
; The compiler will emit a "REQUIRE ?zero_reg_initialization" statement if
; this optimization has been enabled.
;----------------------------------------------------------------------------
    RSEG    BOOT_ENTRY:CODE:NOROOT(1)
    PUBLIC  ?zero_reg_initialization

?zero_reg_initialization:
    CLR R15

;----------------------------------------------------------------------------
; Call __low_level_init to do low level initializatons. Modify the supplied
; __low_level_init module to add your own initialization code or to
; remove segment initialization (by returning 0).
;----------------------------------------------------------------------------
    RSEG    BOOT_ENTRY:CODE:NOROOT(1)
#endif
    PUBLIC  ?call_low_level_init

?call_low_level_init:
    XCALL   __low_level_init

    REQUIRE ?cstartup_call_main

;----------------------------------------------------------------------------
; Call __segment_init to initialize segments.
;----------------------------------------------------------------------------
    RSEG    BOOT_ENTRY:CODE:NOROOT(1)
    PUBLIC  ?need_segment_init

?need_segment_init:
    TST P0
    BREQ    ?skip_segment_init
    XCALL   __segment_init
?skip_segment_init:

;----------------------------------------------------------------------------
;   Call the constructors of all global objects. This code will only
;   be used if any EC++ modules defines global objects that need to
;   have its constructor called before main.
;----------------------------------------------------------------------------
#ifdef _ECLIB_ECPP
    RSEG    DIFUNCT:CODE:NOROOT(0)
    RSEG    BOOT_ENTRY:CODE:NOROOT(1)

    PUBLIC  ?call_ctors

?call_ctors:
#ifdef __HAS_ELPM__
    LDI P0,LOW(SFB(DIFUNCT))
    LDI P1,LOW(SFB(DIFUNCT) >> 8)
    LDI P2,SFB(DIFUNCT) >> 16

    LDI Q0,LOW(SFE(DIFUNCT))
    LDI Q1,LOW(SFE(DIFUNCT) >> 8)
    LDI Q2,SFE(DIFUNCT) >> 16
#else
    LDI P0,LOW(SFB(DIFUNCT))
    LDI P1,SFB(DIFUNCT) >> 8

    LDI P2,LOW(SFE(DIFUNCT))
    LDI P3,SFE(DIFUNCT) >> 8
#endif

    XCALL   __call_ctors
#endif /* _ECLIB_ECPP */

;----------------------------------------------------------------------------
;   Call main
;----------------------------------------------------------------------------
    RSEG    BOOT_ENTRY:CODE:NOROOT(1)

    PUBLIC  ?cstartup_call_main

?cstartup_call_main:
    XCALL   main
    XCALL   exit
    XJMP    _exit

    END

;----------------------------------------------------------------------------
;
KRS
Так у вас просто мешанина получилась, часть стартапа в начале флеша, часть с boot_entry.
причем еще low_level_init вызыватеся, которая берестя из библиотеки по умолчанию.
А когда вы бутлоадером прошьете новую программу вызов low_level_init будет непредсказуемым. Если ее конечно не определить в BOOT сегменте.
Но лучше разобраться с линкером и библиотеками и написать свой простейший стартап.
vitek101
Разобраться конечно неплохо бы smile.gif
KRS
А что за ошибки то возникают если библиотеку отключить?
Вы используете библиотечные функции?
вообще надо map файл смотреть!
не должен бутлоадер содеражть лишних кусков.
vitek101
В том то и дело, что я не могу ее отключить. В свойствах проекта в линкере поотключал что нашел, а он все равно на библиотеку ссылается. Попробовал ее удалить, тогда валятся ошибки, что библиотека не найдена.
KRS
Цитата(vitek101 @ Nov 12 2009, 17:16) *
В том то и дело, что я не могу ее отключить. В свойствах проекта в линкере поотключал что нашел, а он все равно на библиотеку ссылается. Попробовал ее удалить, тогда валятся ошибки, что библиотека не найдена.

Так это в General Options Library Configuration
MDD
Не совсем в тему, но может будет полезно. Недавно тоже делал бутлоадер для Xмеги, только 32-й. Долго не мог побороть вот какую фигню - не смотря на то, что линкеру явно было указано размещать весь код в секции бутлоадера, тем не менее в файле прошивки наблюдалось следующее: весь код действительно сидел в нужной секции. Но стартовый jmp почему-то упорно пихался по нулевому адресу. Причем указывал этот jmp совсем не на начало секции бутлоадера (что можно было бы стерпеть), а куда-то вовнутрь него.
Почитав форум, решил, что причина в стартапе и его нужно править(хотя смутно представлял что именно). Перетащил его исходник в папку проекта и подключил его к проекту. После этого проект пересобрал, чтобы проверить не возникает ли конфликтов с библиотекой. Конфликтов почему-то не возникло. Наверное "своему стартапу" отдается предпочтение. Но самое главное, глюк исчез без всякой правки! Теперь стартовый вектор находился где надо - в начале секции бутлоадера. Компилятор тоже 5.20
vitek101
Цитата(KRS @ Nov 12 2009, 18:22) *
Так это в General Options Library Configuration


А, ну да, там тоже отключал (Library Configuration)
D1ma
Здравствуйте
Впервые пишу будлоадер. (не судите строго)
Пишу в IAR 5.2.1 под АТmega128.

Создал проект, написал свой *.xcl
Вектор ресет на адрес 0x0000
В *xcl указал адрес кода 0хf000-0xffff, в этом пространстве и вектора прерываний.
Тоесть, если есть прога то она запускается если нет то бутлоадер(думаю).

*.xcl :
Код
// The '_..X_' prefix is used by C-SPY as an indication that the label should
// not be displayed in the dissassembly window.
//

// Set up XLINK
-ca90
-w29


/* Code memory - this line is generated with preprocessor.xls */
-Z(CODE)INTVEC,FAR_F,SWITCH,CODE=F000-FFFF
/*EEPROMMEMORY*/
-Z(XDATA)EEPROM_I,EEPROM_N=0-FFF
//////////////////////////////////////////////////////////////////////////////
//SRAM
-D_..X_CSTACK_SIZE=200    /* 512 bytes for auto variables and saved registers. */
-D_..X_RSTACK_SIZE=40     /* 64 bytes for return addresses, equivalent to 32 */
                          /* levels of calls, including interrupts. */
-D_..X_HEAP_SIZE=100      /* 256 bytes of heap. */
-D_..X_SRAM_BASE=100      /* Start of ram memory */
-D_..X_SRAM_TEND=100      /* End of tiny ram memory */
-D_..X_SRAM_END=10FF      /* End of ram memory */
-D_..X_EXT_SRAM_BASE=0    /* Start of exram memory */
-D_..X_EXT_SRAM_SIZE=0    /* End of exram memory */



-Z(DATA)TINY_I,TINY_Z,TINY_N=_..X_SRAM_BASE-_..X_SRAM_TEND
-Z(DATA)NEAR_I,NEAR_Z=_..X_SRAM_BASE-_..X_SRAM_END,_..X_EXT_SRAM_BASE-(_..X_EXT_SRAM_BASE+_..X_EXT_SRAM_SIZE)
-Z(DATA)RSTACK+_..X_RSTACK_SIZE=_..X_SRAM_BASE-_..X_SRAM_END /* ,_..X_EXT_SRAM_BASE-(_..X_EXT_SRAM_BASE+_..X_EXT_SRAM_SIZE) */
-Z(DATA)CSTACK+_..X_CSTACK_SIZE=_..X_SRAM_BASE-_..X_SRAM_END /* ,_..X_EXT_SRAM_BASE-(_..X_EXT_SRAM_BASE+_..X_EXT_SRAM_SIZE) */
-Z(DATA)HEAP+_..X_HEAP_SIZE=_..X_SRAM_BASE-_..X_SRAM_END,_..X_EXT_SRAM_BASE-(_..X_EXT_SRAM_BASE+_..X_EXT_SRAM_SIZE)


Код бутлоадера:
Код
#include <ioavr.h>

#pragma vector=USART1_RXC_vect
__interrupt void irqINT0_vect (void)
{
}
void main()
{
    long address;
    unsigned int temp_int;
    unsigned char val;

    /*Initialization*/    
    void (*funcptr)( void ) = 0x0000; // Set up function pointer to RESET vector.
    /*Body*/
    //.....
    /* Jump to Reset vector 0x0000 in Application Section.*/
    funcptr();
}

Прога которая загружается бутлоадером создана обычно, тоесть вектора сначала, код в адресе 0х0000-0xEFFF.
Да, эта же прога должна и запускать бутлоадер думаю так
Код
void (*pBoot)( void ) = 0xf000;
pBoot();


Вопрос:
В бутлоадера есть свои вектора прерываний по адресу 0xf000 и свой стартап , переменные… в проги свои. Как себя поведет, контролер, если выполнится стартап проги потом будлоадера потом снова проги и так дали? В какие прерывания будет попадать бут.. и прога (по адресу 0х0000 или 0хf000)? Что будет делаться с теми переменами которые были в проге, какая была переписана другой (глобальные, внутренние ?)
KRS
Цитата(D1ma @ Nov 13 2009, 19:27) *
Тоесть, если есть прога то она запускается если нет то бутлоадер(думаю).

Я бы на это не рассчитывал, если конечно FLASH стерт и заполнен 0xFF
до доскачет конечно и до бутлоадера smile.gif. А если нет может где нибудь зависнуть.
Обычно всегда стартует бутлоадер и проверяет либо целостность проги, либо условие запуска бутлоадера, или ... и решает что запускать прогу или себя!

Цитата(D1ma @ Nov 13 2009, 19:27) *
Вопрос:
В бутлоадера есть свои вектора прерываний по адресу 0xf000 и свой стартап , переменные… в проги свои. Как себя поведет, контролер, если выполнится стартап проги потом будлоадера потом снова проги и так дали?

да контроллеру пофиг - стартап обычно инитит стек, заполняет часть памяти 0 и копирует часть памяти из флеша и вызвает main, это можно делать сколько угодно раз!
А вот с переферией могут быть проблемы - ее надо полностью инитить, даже не используемую раз выиспользуете перрывания и там и там, потому что проиниченная переферия с включенными прерываниями не используемая программой или бутлоадером даст глюки.
IMHO лучший вариант переключения между бутлоадером и программой через ресет ( с помощью watchdog). Тем более что причину reset можно определить и память не сбрасывается, можно метку ставить.

Цитата(D1ma @ Nov 13 2009, 19:27) *
В какие прерывания будет попадать бут.. и прога (по адресу 0х0000 или 0хf000)?

Есть бит IVSEL управляющий размещением векторов.
Но вот прерывания в бутлоадере IMHO лучше не использовать, вернее обычно они не нужны.
Сергей Борщ
Цитата(D1ma @ Nov 13 2009, 18:27) *
Тоесть, если есть прога то она запускается если нет то бутлоадер(думаю).
Лучше специально заточенным фузом запускать всегда загрузчик. А уже он решит - отдавать управление программе или нет. Скрипт правильный.
Цитата(D1ma @ Nov 13 2009, 18:27) *
Код
    /*Body*/
    //.....
    /* Jump to Reset vector 0x0000 in Application Section.*/
    funcptr();
}
В целом правильно, но я вместо этого после прошивки просто сбрасываю процессор собакой. Он рестартует, попадает в загрузчик, загрузчик (в __low_level_init) проверяет целостность приложения и отдает ему управление. Этот же код работает и при включении, то есть получается максимально быстрый запуск приложения при обычном включении - если надо запускать приложение, то не тратится время на исполнение всего стартапа загрузчика.
Цитата(D1ma @ Nov 13 2009, 18:27) *
Да, эта же прога должна и запускать бутлоадер думаю так
Код
void (*pBoot)( void ) = 0xf000;
pBoot();
Правильно. У меня загрузчик определяет, что его вызвали из приложения по направлению одной из ног, которая штатно используется на вывод (при холодном старте все ноги настроены на ввод).
Цитата(D1ma @ Nov 13 2009, 18:27) *
Вопрос:
В бутлоадера есть свои вектора прерываний по адресу 0xf000 и свой стартап , переменные… в проги свои. Как себя поведет, контролер, если выполнится стартап проги потом будлоадера потом снова проги и так дали? В какие прерывания будет попадать бут.. и прога (по адресу 0х0000 или 0хf000)? Что будет делаться с теми переменами которые были в проге, какая была переписана другой (глобальные, внутренние ?)
Стартап на то и стартап, что подготавливает окружение для работы проги. То есть инициализирует указатель стека, переменные, настраивает периферию (в __low_level_init). Грамотная программа не должна полагаться на неинициализированные значения, а инициализированные будут подготовлены стартапом. Естественно, старые значения, оставшиеся от прги/загрузчика будут затерты. Если вам надо сохранять какие-то переменные - вынесите их в отдельный сегмент и на его месте в скрипте загрузчика зарезервируйте память. Для определения таких переменных вам понадобится квалификатор __no_init. Вектора вы переключаете сами - для этого есть специальный битик.

P.S. В будущем не стоит встревать с отдельным вопросом в активную тему.
D1ma
как написать свой стартап и ловлевелинит?
щас у меня IAR генерит свои автоматически.
если можно, пример, желательно на С
KRS
Цитата(D1ma @ Nov 14 2009, 13:05) *
как написать свой стартап и ловлевелинит?

просто определить
int __low_level_init( void )
в своей программе.
если функция возвращает 0 то инициализация сегментов пропускается!
Сергей Борщ
Цитата(D1ma @ Nov 14 2009, 12:05) *
как написать свой стартап
Зачем? Что вас не устраивает в библиотечном? Если очень необходимо - в папке с примерами есть его ассемблерный исходник. Копируйте файл в папку своего проекта и подключайте его к проекту. На C написать его будет затруднительно - компилятор формирует прологи/эпилоги для функций, которые в данном случае будут только мешать.
Цитата(D1ma @ Nov 14 2009, 12:05) *
и ловлевелинит?
Определяете функцию int __low_level_init(). Она подменяет библиотчную. Если проект собирается в режиме С++, то объявите ее с квалификатором extern "C"
vitek101
Почему может постоянно забиваться CSTACK?
Читаю загрузчиком программу из FRAM, пишу ее во флеш страницами по 512 байт, когда дохожу до последней страницы выдается сообщение, что CSTACK забит на 98 процентов и все перестает работать (меняются многие переменные на кривые значения).
Пробовал менять размер стека, все время забивается на 98 процентов. От размера загружаемой программы не зависит... laughing.gif
Да, загрузчик сделал отдельным проектом

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