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

Компиляция прошивки для дальнейшей загрузки bootlodaer'ом

Здравствуйте!

Мне не удаётся скомпилировать прошивку для pic16f1825 компилятором xc8 (PRO mode) после того, как указываю codeoffset на 512 слов (в этой области загрузчик).

При обычной компиляции (без смещения) пишет 85% занято, бутлоадер занимает 7%.

Экспериментировал с различными значениями codeoffset, максимальное смещение при котором он ещё компилируется 340 слов, при чем если посмотреть код программы, то там остаётся куча незанятого места.

 

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

 

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


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

Для начала я бы ушел от процентного представления занятой памяти. Более точно все-таки в байтах в map-файле посмотреть сколько конкретно занимает ваша программа.

Второй момент нужно посмотреть linker файл после того, как вы установили смещение, убедиться, что смещение происходит действительно на нужное количество байт. А потом посмотреть чисто математически укладывается ли программа в предоставленный ей объем.

 

Самое главное: а ошибку-то какую получаете, ошибку компилятора или линковщика, какую конкретно?

 

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

Компилятор не компонует код, он только формиует рабочие куски кода с определенными входными аргументами, выходными параметрами, определенной длины. А вот линковщик уже эти готовые рабочие (100% проверенные) куски размещает в памяти по правилам заданным в линкер-файле и настраивает взаимосвязи между ними.

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

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


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

Спасибо за ценный ответ. Посмотрел map при смещении на 150:

               Name                               Link     Load   Length Selector   Space Scale
C:\Users\NIR\AppData\Local\Temp\s71g.obj
                end_init                            285      285        2      2A8       0
                reset_vec                           150      150        2      2A0       0
                config                             8007     8007        2    1000E       0
dist/default/production\medic.X.production.obj
                cinit                               951      951      6AF     12A2       0
                intentry                            154      154      131      2A8       0
                text54                              764      764       15      2A8       0
                text41                              287      287      4DD      2A8       0
                text12                              858      858       F9     10B0       0
                text11                             1990     1990      670     3320       0
                cstackBANK0                          20       20       33       20       1
                cstackCOMMON                         70       70        B       70       1
                clrtext                             779      779        C      2A8       0
                bssBANK2                            120      120       28      120       1
                bssBANK1                             A0       A0       46       A0       1
                dataBANK0                            6C       6C        4       20       1
                bssBANK0                             53       53       19       20       1
                bssCOMMON                            7B       7B        3       70       1
                stringtext                         1000     1000      6BE       20       0

 Psect      | Contents                       | Memory Range  | Size
------------|--------------------------------|---------------|--------------
            |                                |               |              
reset_vec  | Reset vector                   | 0150h - 0151h |    2 words  
intentry   | Interrupt context entry code   | 0154h - 0284h |  305 words  
end_init   | Initialization code            | 0285h - 0286h |    2 words  
text41     | Program and library code       | 0287h - 0763h | 1245 words  
text54     | Program and library code       | 0764h - 0778h |   21 words  
clrtext    | Memory clearing code           | 0779h - 0784h |   12 words  
text12     | Program and library code       | 0858h - 0950h |  249 words  
cinit     Microchip MPLAB XC8 C Compiler (PRO Mode) V1.33

Program space:
    CONST                used     0h (     0) of  1EB0h words   (  0.0%)
    CODE                 used  144Bh (  5195) of  1EB0h words   ( 66.1%)
    STRCODE              used   6BEh (  1726) of  1EB0h words   ( 22.0%)
    ENTRY                used     0h (     0) of  1EB0h words   (  0.0%)
    STRING               used     0h (     0) of  1EB0h words   (  0.0%)

Memory Summary:
    Program space        used  1B09h (  6921) of  2000h words   ( 84.5%)...

 

Видно, что смещение происходит и на нужную величину. Так же памяти у него достаточно, около 1000 слов, а надо всего 512.

Настораживает строчка:

hlink "--edf=C:\Program Files (x86)\Microchip\xc8\v1.33\dat\en_msgs.txt" -cs -h+dist/default/production\medic.X.production.sym --cmf=dist/default/production\medic.X.production.cmf -z -Q16F1825 -oC:\Users\NIR\AppData\Local\Temp\s8m8.6 -Mdist/default/production/medic.X.production.map -ver=XC8#PRO##V1.33 -ASTACK=020C8h-0225fh -pstack=STACK -ACONST=0150h-01FFh,0200h-02FFhx30 -ACODE=0150h-07FFh,0800h-0FFFhx3 -ASTRCODE=0150h-01FFFh -AENTRY=0150h-01FFh,0200h-02FFhx30 -ASTRING=0150h-01FFh,0200h-02FFhx30 -ACOMMON=070h-07Fh -ABANK0=020h-06Fh -ABANK1=0A0h-0EFh -ABANK2=0120h-016Fh -ABANK3=01A0h-01EFh -ABANK4=0220h-026Fh -ABANK5=02A0h-02EFh -ABANK6=0320h-036Fh -ABANK7=03A0h-03EFh -ABANK8=0420h-046Fh -ABANK9=04A0h-04EFh -ABANK10=0520h-056Fh -ABANK11=05A0h-05EFh -ABANK12=0620h-064Fh -ABIGRAM=02000h-023EFh -ARAM=020h-06Fh,0A0h-0EFh,0120h-016Fh,01A0h-01EFh,0220h-026Fh,02A0h-02EFh,0320h-036Fh,03A0h-03EFh,0420h-046Fh,04A0h-04EFh,0520h-056Fh,05A0h-05EFh,0620h-064Fh -AABS1=020h-07Fh,0A0h-0EFh,0120h-016Fh,01A0h-01EFh,0220h-026Fh,02A0h-02EFh,0320h-036Fh,03A0h-03EFh,0420h-046Fh,04A0h-04EFh,0520h-056Fh,05A0h-05EFh,0620h-064Fh -ASFR0=00h-01Fh -ASFR1=080h-09Fh -ASFR2=0100h-011Fh -ASFR3=0180h-019Fh -ASFR4=0200h-021Fh -ASFR5=0280h-029Fh -ASFR6=0300h-031Fh -ASFR7=0380h-039Fh -ASFR8=0400h-041Fh -ASFR9=0480h-049Fh -ASFR10=0500h-051Fh -ASFR11=0580h-059Fh -ASFR12=0600h-061Fh -ASFR13=0680h-06EFh -ASFR14=0700h-076Fh -ASFR15=0780h-07EFh -ASFR16=0800h-086Fh -ASFR17=0880h-08EFh -ASFR18=0900h-096Fh -ASFR19=0980h-09EFh -ASFR20=0A00h-0A6Fh -ASFR21=0A80h-0AEFh -ASFR22=0B00h-0B6Fh -ASFR23=0B80h-0BEFh -ASFR24=0C00h-0C6Fh -ASFR25=0C80h-0CEFh -ASFR26=0D00h-0D6Fh -ASFR27=0D80h-0DEFh -ASFR28=0E00h-0E6Fh -ASFR29=0E80h-0EEFh -ASFR30=0F00h-0F6Fh -ASFR31=0F80h-0FEFh -preset_vec=0150h,intentry=0154h,init,end_init -ppowerup=CODE -pcinit=CODE -pfunctab=CODE -ACONFIG=08007h-08008h -pconfig=CONFIG -DCONFIG=2 -AIDLOC=08000h-08003h -pidloc=IDLOC -DIDLOC=2 -AEEDATA=00h-0FFh/0F000h -peeprom_data=EEDATA -DEEDATA=2 -DCODE=2 -DSTRCODE=2 -DSTRING=2 -DCONST=2 -DENTRY=2 -k C:\Users\NIR\AppData\Local\Temp\s8m8.obj dist/default/production\medic.X.production.obj

 

А именно -ACODE=0150h-07FFh,0800h-0FFFhx3 -ASTRCODE=0150h-01FFFh. Почему то класс кода делится на сегменты, один от 150 до 800, а остальные по 2к. слова далее до конца. При смещении на 200, линковщик после выше указанного текста hlink... выдаёт ошибку 0: (1347) can't find 0x58F words (0x58f withtotal) for psect "text41" in class "CODE" (largest unused contiguous range 0x493). Да, после изменения смещения параметр в линковщике меняется на -ACODE=0200h-07FFh,0800h-0FFFhx3.

 

К сожалению я не знаю, возможно ли вручную задать -ACODE=0200h-1FFF и будет ли это иметь какой то смысл, но это единственная моя догадка на данный момент. Если не сложно, подскажите пожалуйста.

 

Добавлено:

Нашёл такой текст в документации:

The second cause of this message is when the total amount of memory needed by the

psect being positioned is sufficient, but that this memory is fragmented in such a way

that the largest contiguous block is too small to accommodate the psect. The linker is

unable to split psects in this situation. That is, the linker cannot place part of a psect at

one location and part somewhere else. Thus, the linker must be able to find a contiguous

block of memory large enough for every psect. If this is the cause of the error, then

the psect must be split into smaller psects if possible.

To find out what memory is still available, generate and look in the map file, see

Section 4.8.8 “-M: Generate Map File” for information on how to generate a map file.

Search for the string UNUSED ADDRESS RANGES. Under this heading, look for the

name of the segment specified in the error message. If the name is not present, then

all the memory available for this psect has been allocated. If it is present, there will be

one address range specified under this segment for each free block of memory. Determine

the size of each block and compare this with the number of words specified in the

error message.

Psects containing code can be reduced by using all the compiler’s optimizations, or

restructuring the program. If a code psect must be split into two or more small psects,

this requires splitting a function into two or more smaller functions (which may call each

other). These functions may need to be placed in new modules.

Psects containing data may be reduced when invoking the compiler optimizations, but

the effect is less dramatic. The program may need to be rewritten so that it needs less

variables. If the default linker options must be changed, this can be done indirectly

through the driver using the driver -L- option, see Section 4.8.7 “-L-: Adjust Linker

Options Directly”. Section 4.8.8 “-M: Generate Map File” has information on interpreting

the map file’s call graph if the compiler you are using uses a compiled stack. (If

the string Call graph: is not present in the map file, then the compiled code uses a

hardware stack.) If a data psect needs to be split into smaller psects, the definitions for

variables will need to be moved to new modules or more evenly spread in the existing

modules. Memory allocation for auto variables is entirely handled by the compiler.

Other than reducing the number of these variables used, the programmer has little control

over their operation. This applies whether the compiled code uses a hardware or

compiled stack.

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

Я изменил параметр линковщика на -L-ACODE=0200h-07FFh,800h-1FFFh (это вставил в Additional option в настройках проекта XC8 Linker). В map файле проверил что установил правильно, проект скомпилировался. Когда добавил смещение, то получил новую ошибку: 1297: (1357) fixup overflow storing 0x92D in 2 bytes at 0x3254/0x2 -> 0x192A (dist/default/production\medic.X.production.obj 232/0x24)

 

Что это то такое?

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

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


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

Здравствуйте! В своё время сам мучился с бутлоадером, требующим сдвига кода. В конце концов перебрался на загрузчик, который прописывается "на чердаке" программной памяти, позволяя отлаживать и компилировать программу так, как будто бутлоадера нет вовсе, а позже загружать полученный hex через бутлоадер. Могу порекомендовать популярный и хорошо документированный ds30Loader: Home page, Исходники. За пару вечеров изучил и запустил под PIC24. Не обращайте внимание на название, в исходниках коды на ассемблере для PIC12, 16, 18, 24, dsPIC, PIC32 + GUI под Windows (включая консольную версию).

 

P.S. GUI достаточно гибкое и позволяет настраивать, помимо прочего, скорость загрузки (включая autobaud) и способ сброса для загрузки - ручной, по сигналам DTR/RTS, по спец. команде (я, например, вбил модбасовскую команду дистанционного сброса устройства).

 

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

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


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

varostov, к сожалению размещать загрузчик "на чердаке" я не могу, так как эта область не защищается аппаратно и я использую прерывания, которые бы не хотелось передавать через программу.

Загрузчик я писал сам из-за достаточно уникальной задачи.

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


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

Ok, тогда желаю успеха. Подсказать, к сожалению, ничего не смогу (давно это было). На будущее: в PIC24 можно задавать количество защищаемых страниц с начала или конца программной памяти + другие фичи ("CodeGuard Security"). Что-то внедрено и в PIC18, но точно не изучал.

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


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

Спасибо!

Вчера пытался разбить на 20 подфункций. Ничего не получилось, все также ошибка при смещении...

 

Неужели ни у кого не было такой проблемы???

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


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

Здравствуйте! В своё время сам мучился с бутлоадером, требующим сдвига кода. В конце концов перебрался на загрузчик, который прописывается "на чердаке" программной памяти, позволяя отлаживать и компилировать программу так, как будто бутлоадера нет вовсе, а позже загружать полученный hex через бутлоадер.

Дела давно минувших дней... Когда делал загрузчик, для PIC16, то он у меня грузил программу сделанную "так, как будто бутлоадера нет вовсе". Только и сам был, как "обычная программа". Я пиками практчески не занимаюсь, так что разных кошерных загрузчиков не изучал за ненедобностью, а сделал, как сделал :).

Всего делов-то и было, что в нем по вектору сброса были 4 NOP, а при загрузке "программы" он слегка правил образ:

void main(void)
{

.....
.....


#asm
global _application_reset_vector
_application_reset_vector
       nop
       nop
       nop
       nop
#endasm
    // Wait watchdog in case the first four bytes are not a jmp instruction
    for(;; );
}




--------------------

                // The bootloader remaps the first four bytes of the application code into a secondary area.
                // This is done to preserve the initial reset vector that jumps to the bootloader.
                // By doing this, we make sure that the bootloader always fires up before the application
                // code and passes control onto it.
                  if( uhf.cdd_st.address < 0x0004 )
                {    // Remap the reset vector
                    byte len = uhf.cdd_st.len_u8 + uhf.cdd_st.address;
                    if( len > 4 )
                       len = 4;
                    len -= uhf.cdd_st.address;
                    // Write whatever part of the reset vector into our reserved appication_reset_vector.
                    // Write the remaining bytes into their original location.

                    if( flash_block_write( (ushort)&application_reset_vector + uhf.cdd_st.address, uhf.cdd_st.data_word, len )||
                        flash_block_write( uhf.cdd_st.address+len, &uhf.cdd_st.data_word[len], uhf.cdd_st.len_u8-len ) )
                       {

 

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


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

Да, хороший способ. Но очень ненадежный...

 

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

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


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

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

Это ужасно. У меня очевидно по незнанию :) и такой живет с 2007 года в 40 тысячах с гаком экземпляров не выключаясь никогда.

Загрузчик и прошивка делалась для уже готовых, устройств одной юаровской фирмы, которые будучи поставлены на обьект в количестве пары тысяч штук, действительно окирпичивались в темпе 10 штук в день.

А что такое ломающийся загрузчик?. Или, скажем так, не ломающийся :)?

 

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


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

Не ломающийся загрузчик (в моём понимании) - это загрузчик, который не может сам себя перезатереть при программировании И не дать себя перезатереть программе, которой отдал управление. Такой загрузчик если и зависнет при прошивке по каким то обстоятельствам, то передёргивание питания всё должно вернуть на место. Другими совами ему ничего не должно быть страшно и, следовательно, он должен без посредников получать управление чтобы корявый загружаемый код (возможно даже нацеленный на поломку устройства), не смог ничего попортить.

 

Делается такая защита при помощи конфигурационных бит, которые указываются при прошивке программатором. Эти биты защищают какую то часть программы от перезаписи самой программой. Например в pic16f1825 можно либо вообще не защитить, либо защитить 0x200, либо 0x1000, либо всю. У меня стоит защита 0x200, следовательно первые 512 слов сама программа не может перезаписать. Это отдельно проверял, команды на стирание отправляются, а страница остаётся невредима.

 

Но тем ни менее моя проблема так и не решена! Есть загрузчик, но нет возможности сделать прошивку.

Столько про эти загрузчики разговоров в сети, неужели никто не загружал код, который занимает много памяти?

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


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

Прошивка скомпилировалась и слинковалась!

Компилятор: XC8 v1.37 (PRO mode) - бесплатная лицензия от Microchip на 60 дней

Среда разработки: MPLAB X IDE v3.25

 

Проблема была в том, что память в этом микроконтроллере разделена на 4 страницы, каждая страница 2К слова (если нужно перейти по адресу, находящемуся на другой странице, то необходима дополнительная команда смены страницы). Компилятор подготавливает так называемые psect (раздел памяти) в которых объединены функции. Если я правильно понимаю, то это такие своеобразные "чёрные ящики", которые компилятор отдаёт линковщику в виде объектных файлов, чтобы тот их разместил в памяти. Так как эти объектные файлы не могут находиться на стыке двух страниц, то есть пересекать их, то может возникнуть ситуация, когда памяти вроде бы хватает, но линковщик отказывается размещать "чёрные ящики", говоря, что максимальная не занятая область внутри страниц меньше, чем то, что необходимо разместить.

 

Следовательно чтобы решить данную проблему, необходимо разбить "чёрные ящики" на части. Я это сделал при помощи спецификатора __section(), который добавил у больших функций, чтобы компилятор подготовил для них отдельный psect и линковщик мог разместить их в памяти по своему желанию.

 

Да, при использовании данного метода, у меня съелось около 160 слов. Они были использованы компилятором для смены страниц при переходах.

 

Собственно вот пример:

void __section("main") main (void) {
...
}

byte __section("settings") my_settings(byte mod){
...
}

 

Ну и позволю себе привести цитату из документации на компилятор:

The __section() specifier may be used to indicate that an object should be located

in the named section (or psect, using the XC8 terminology). This is typically used when

the object has special and unique linking requirements which cannot be addressed by

existing compiler features.

Use the native keywords discussed in the Differences section to look up information on

the semantics of this specifier.

2.5.13.1 EXAMPLE

The following shows a variable which uses the __section keyword.

int __section("comSec") commonFlag;

2.5.13.2 DIFFERENCES

The 8-bit compilers have used the #pragma psect directive to redirect objects to a

new section, or psect. The operation of the __section() specifier is different to this

pragma in several ways, described below.

Unlike with the pragma, the new psect created with __section() does not inherit the

flags of the psect in which the object would normally have been allocated. This means

that the new psect can be linked in any memory area, including any data bank. The

compiler will also make no assumptions about the location of the object in the new section.

Objects redirected to new psects using the pragma must always be linked in the

same memory area, albeit at any address in that area.

The __section() specifier allows objects that are initialized to be placed in a different

psect. Initialization of the object will still be performed even in the new psect. This will

require the automatic allocation of an additional psect (whose name will be the same

as the new psect prefixed with the letter i), which will contain the initial values. The

pragma cannot be used with objects that are initialized.

Objects allocated a different psect with __section() will be cleared by the runtime

startup code, unlike objects which use the pragma.

You must reserve memory, and locate via a linker option, for any new psect created with

a __section() specifier in the current XC8 compiler implementation.

The 16- and 32-bit compilers have used the section attribute to indicate a different

destination section name. The __section() specifier works in a similar way to the

attribute.

 

Если кто то знает другое решение данной проблемы, прошу сообщить мне об этом.

 

Спасибо большое за помощь zltigo и остальным!

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


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

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

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

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

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

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

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

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

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

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