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

Написал загрузчик для 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:

 

 

И еще: может проблема быть связана с __root, #pragma и т.д.? Может чего-то не хватает? Просто я в них не особо шарю... :laughing:

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


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

_root не надо писать у каждой функции!

достаточно у boot

 

кроме того у вас все функции расопложены "BOOT_SEGMENT",

но первой должна быть функция boot (точка входа), а линкер может их перемешать!

Можно например сделать 2 сегмента -Z(CODE)BOOT_ENTY, BOOT_SEGMENT=....

и boot расположить в BOOT_ENTY, тогда будет гарантировано первой!

 

А как вы рабоаете с прерываниями в бутлоадере?

Какой cstartup используете?

IMHO в данном случае лучше работать полингом!

 

Да про cstartup забыл, так что в BOOT_ENTY должен быть startup, который для бутлоадера надо написать простейший - достаточно инициализации стеков. (SP и Y)

Изменено пользователем KRS

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


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

А как вы рабоаете с прерываниями в бутлоадере?

Какой cstartup используете?

IMHO в данном случае лучше работать полингом!

Пардон, вопрос не ко мне, но отвечу про себя.

У меня в бутлоадерах традиционно запрещены все прерывания, работа с компортом по опросу состояния (polling).

Ну, и на ассемблере работаю. Одна из попыток перейти на Си в микроконтроллерах как раз и завершилась кривым бутлоадером, полностью ручками перепер его на ассемблер, и с тех пор ему (ассемблеру) не изменяю. А на С, С++ пишу программы под винду, которые общаются с моими же программами из микроконтроллеров.

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


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

Ну, и на ассемблере работаю. Одна из попыток перейти на Си в микроконтроллерах как раз и завершилась кривым бутлоадером, полностью ручками перепер его на ассемблер, и с тех пор ему (ассемблеру) не изменяю.

Так вы просто не разобрались :)

Только на асме уже давно глупо писать!

Данный код компилер сделает не хуже!

А вот, например для ARM - работа с периферией, где куча констант, из-за особенностей архитектуры - скомпилируется лучше чем на асме, конечно можно руками за месяцок простчитать все константы и напистаь код оптимальнее ;)

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


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

А я тут и использую полинг. С прерываниями я так и не разобрался (вроде как надо вторую таблицу создавать, а как ее создавать х.з. :laughing: ).

А про startup можно поподробнее? Че как инициализировать? Просто я в общем язык и структуру понимаю, а в такие дебри еще не лазил. Надо взять готовый стартап и изменить его или свой новый создавать?

За сегменты спасибо :)

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


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

примерно так

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

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


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

На всякий случай прошу прощения за возможно глупый вопрос :rolleyes:

А BOOTENTRY (в строке RSEG BOOTENTRY:CODE:ROOT(1)) это то же, что и BOOT_ENTY в вашем первом посте?

И че вообще с этим кодом надо сделать? Его надо впихнуть в CSTARTUP, который я взял из avr\src\lib и подключил к своему проекту?

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


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

На всякий случай прошу прощения за возможно глупый вопрос :rolleyes:

А BOOTENTRY (в строке RSEG BOOTENTRY:CODE:ROOT(1)) это то же, что и BOOT_ENTY в вашем первом посте?

И че вообще с этим кодом надо сделать? Его надо впихнуть в CSTARTUP, который я взял из avr\src\lib и подключил к своему проекту?

Да это BOOT_ENTRY, там еще, елси переменные инициализировать STARTUPCODE надо на BOOT_ENTRY заменить.

его надо вместо CSTARTUP.

Да boot надо остваить в BOOTCODE.

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


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

Сделал так:

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. Что делаю не так?

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


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

Это все вставил вместо содержимого стандартного CSTARTUP. Что делаю не так?

так надо

    END

в конце написать :)

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


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

А да про макрос забыл :)

//**************************************************************************
// lda - load addr to Z, X, or Y pair
lda MACRO rPtr, Offset
     ldi \1L, LOW(Offset)
     ldi \1H, HIGH(Offset)
    ENDM

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


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

А можно заменить

          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 убрались :)

 

Спросил, а потом увидел ответ :)

 

Вроде собрал, правда только первую часть (без инициализации переменных. Там ругается invalid syntax на строки с макросом).

Только он теперь говорит undefined external "boot" referred in cstatup :wacko:

 

 

 

Все, запустил. Но в отладчике нашего стартапа не видно и все не работает по-старому...

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


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

Все, запустил. Но в отладчике нашего стартапа не видно и все не работает по-старому...

Это значит 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 файл смотреть - что линкер напихал и куда!

Изменено пользователем KRS

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


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

А фьюзы на запуск с bootloadera поставили? И на тот ли адрес? Это от компилятора не зависит, это программатором определяется (ну, или настройками симулятора). А адресов бутлоадера у 128 меги может быть 4 разных, насколько я помню (для загрузчиков объемом до 256,512,1024,2048 слов)

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


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

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

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

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

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

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

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

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

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

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