Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: IAR 5.11
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Laurica
Собственно проблема такая - примеры для AT91SAM7A3 компилятся, линкуются и тп. но!, при попытке прогнать их во встроенном симуляторе Cstartup.s с первой точки (reset) улетает куда-то на адрес 6E7C0000, при попытке переписать стартап чтобы он с ресета уходил на lowlevel_init в симуляторе все ОК, однако в железе - мертвяк. все во Flash_DEBUG
sKWO
Цитата(Laurica @ May 16 2008, 18:28) *
Собственно проблема такая - примеры для AT91SAM7A3 компилятся, линкуются и тп. но!, при попытке прогнать их во встроенном симуляторе Cstartup.s с первой точки (reset) улетает куда-то на адрес 6E7C0000, при попытке переписать стартап чтобы он с ресета уходил на lowlevel_init в симуляторе все ОК, однако в железе - мертвяк. все во Flash_DEBUG

Немного непонятно
А файл прошивки должен формироваться в режиме Реалис. Вы так его формировали?
И ещё, где-то было сообщение нащёт версии 5.11 толи В толи А что она вообще не рабочая.
Laurica
Цитата(sKWO @ May 17 2008, 09:41) *
Немного непонятно
А файл прошивки должен формироваться в режиме Реалис. Вы так его формировали?
И ещё, где-то было сообщение нащёт версии 5.11 толи В толи А что она вообще не рабочая.


Теперь мне не понятно...Что значит в режиме Реалис? Дело в том, что моя собственная программа, отлично собиравшаяся в 4.3Х-KS напрочь отказывается компилироваться в 5.11-EV. При попытке переписать startup вроде как адресация после рестарта нормальная - я попадаю в lowlevel init, затем в main - но это все только в симуляторе, а в железе ...
ЛЮДИ, ежели не в падлу, скиньте ссылку на EWARM 4.XX EVALUATION, все-же хочется работать, а не бороться со средствами разработки... help.gif smile3046.gif
zltigo
Цитата(sKWO @ May 17 2008, 07:41) *
И ещё, где-то было сообщение нащёт версии 5.11 толи В толи А что она вообще не рабочая.

- А это правда, что Сидоров выиграл машину в лотерею?
- Правда. Только не машину, а тысячу рублей. И не в лотерею, а в преферанс, и не выиграл, а проиграл...


Цитата(Laurica @ May 17 2008, 08:16) *
...все-же хочется работать, а не бороться со средствами разработки... help.gif smile3046.gif

Боритесь только сами с собой. Разработчики коммпилятров ошибаются несораизмеримо реже, нежели их пользователи smile.gif. тем более на переходе в main(). A EWARM 4.xx, Вы конечно взять можете на сайте iar.com, но незачем.
Laurica
Цитата(zltigo @ May 17 2008, 10:31) *
Боритесь только сами с собой. Разработчики коммпилятров ошибаются несораизмеримо реже, нежели их пользователи smile.gif.

Да я не против бороться, я даже за twak.gif . Но чтобы бороться надо знатьхоть с чем конкретно. Кто нибудь знает где почитать как startup-ы пишуться в 5.11 с примерами/картинками smile.gif. На сайте IAR я посмотрю, но по-моему там уже везде ссылки на 5.10-5.11.
zltigo
Цитата(Laurica @ May 17 2008, 12:53) *
с примерами/картинками smile.gif.

C картинками - это Вам тогда в детский сад надо пойти. А так - базовый вариант startup в комплекте поставки + документация на контроллер/ASM.
Laurica
Цитата(zltigo @ May 17 2008, 18:27) *
C картинками - это Вам тогда в детский сад надо пойти.


Да староват вроде как для сада уже... Зря вы так, наглядный пример лучше трех талмудов.
zltigo
Цитата(Laurica @ May 17 2008, 19:02) *
Зря вы так, наглядный пример лучше трех талмудов.

Повторяю:
Код
..базовый вариант startup в комплекте поставки..

Более, чем нагляден и достаточно универсален. Разве только без картинок smile.gif.
Laurica
Обратился к первоисточнику:
Код
        ARM
__vector:
        ldr  pc,[pc,#+24]            ;; Reset ----------------------------------
__und_handler:                                                                             |
        ldr  pc,[pc,#+24]            ;; Undefined instructions                   |
__swi_handler:                                                                              |
        ldr  pc,[pc,#+24]            ;; Software interrupt (SWI/SVC)        |  
__prefetch_handler:                                                                       |
        ldr  pc,[pc,#+24]            ;; Prefetch abort                              |
__data_handler:                                                                            |
        ldr  pc,[pc,#+24]            ;; Data abort                                   |
        DC32  0xFFFFFFFF             ;; RESERVED                                 |
__irq_handler:                                                                              |
        ldr  pc,[pc,#+24]            ;; IRQ<-----------------------------------
__fiq_handler:                                                                              
        ldr  pc,[pc,#+24]            ;; FIQ                                            
                                                                                                  
        DC32  __iar_program_start                                                  
        DC32  __und_handler
        DC32  __swi_handler
        DC32  __prefetch_handler
        DC32  __data_handler<-------------------------------------- а из IRQ сдесь
        B .
        DC32  IRQ_Handler_Entry
        DC32  FIQ_Handler_Entry


если я правильно понимаю, то вот сдесь
Код
ldr  pc,[pc,#+24]

происходит добавление к текущему адресу числа 24, (смещение на 6 dword) то есть если выполнится первая такая команда, то мы окажемся там, где стрелочка в коде. Так?
Понимаю, что звучит по-дурацки, но... wacko.gif
alexander55
Цитата(Laurica @ May 17 2008, 22:55) *
Код
ldr  pc,[pc,#+24]

происходит добавление к текущему адресу числа 24, (смещение на 6 dword) то есть если выполнится первая такая команда, то мы окажемся там, где стрелочка в коде. Так?
Понимаю, что звучит по-дурацки, но... wacko.gif

В счетчик команд заносится соответствующий хандлер, т.е. осуществляется переход на соответствующую метку .
Laurica
Цитата(alexander55 @ May 19 2008, 09:33) *
В счетчик команд заносится соответствующий хандлер, т.е. осуществляется переход на соответствующую метку .

Это понятно, что обработчик заносится..., но меня интересует вопрос правильно ли я понимаю КАКОЙ обработчик туда заносится. Адресация-то относительная.
zltigo
Цитата(Laurica @ May 17 2008, 20:55) *
если я правильно понимаю, то вот сдесь
Код
ldr  pc,[pc,#+24]

происходит добавление к текущему адресу числа 24, (смещение на 6 dword) то есть если выполнится первая такая команда, то мы окажемся там, где стрелочка в коде. Так?

Нет. "Для разобраться" надо просто слегка посмотреть на архитектуру процессора и на то, что значат в ASM скобочки [].
Хотя написано, конечно от балды. Я так не пишу, дабы не заморачивать голову ненужными магическими числами.
Так читабельнее:
Код
                ldr     pc, (?vect_entry + 4*0); 00
                ldr     pc, (?vect_entry + 4*1); 04
                ldr     pc, (?vect_entry + 4*2); 08
                ldr     pc, (?vect_entry + 4*3); 0C
                ldr     pc, (?vect_entry + 4*4); 10
                dc32    0                     ; 14 Summ of other vectors instructions
                ldr     pc, [pc,#-0xFF0]; 18 Jump directly to the address given by the AIC
                                        ; from [0xFFFFF030] Curent 18h +conveyer
                ldr     pc, (?vect_entry + 4*7); 1C
;----------------------------------------------------------------------------
                ORG     0x20
             ; Constant table entries (for ldr pc) will be placed at 0x20
?vect_entry:
                dc32    ?cstartup            ; Reset
                dc32    ?undf_abort    ; UND
                dc32    vPortYieldProcessor; SWI
                dc32    ?pref_abort    ; P_ABT
                dc32    ?data_abort    ; D_ABT
                dc32    0                    ; ARM-reserved vector
                dc32    0                    ; IRQ (Jump directly!)
                dc32    FIQ_ISR_handler; FRQ
Laurica
За пример - большое спасибо, так и вправду понятнее. Однако, касаемо моей изначальной проблеммы - а именно не_запускания программы в железе - наткнулся на то, что если workspace поставить flash_flash (а не flash_debug), то все несколько меняется. При компиляции во flash_debug при переходе с "0" адреса происходит улет в 0x6E7C (а там вакуум...и не работает не в железе ни в симуляторе), в RAM_debug 0x7B50, а в flash_flash туда же в 0x6E7C, при этом все работает в симуляторе, но в железе глухо как в танке... При этом код не меняелся никак.
Доктор, где у меня ошибка..? crying.gif
Vitaliy_ARM
Столкнулся с такой проблемой.

Не могу в этом IAR експортировать функции (в данном случае __start_firmware()) из startup.s
Прописал:
Код
SECTION .intvec:CODE:NOROOT(2)
        PUBLIC  __vector
        PUBLIC  __iar_program_start
        PUBLIC  __vector_0x14
        PUBLIC  __start_firmware


Тело функции:

Код
__start_firmware:
ldr  r0,=0x0
ldr  r1,=0x0
ldr  r2,=0x0
ldr  r3,=0x0
ldr  r4,=0x0
ldr  r5,=0x0
ldr  r6,=0x0
ldr  r7,=0x0
ldr  r8,=0x0
ldr  r9,=0x0
ldr  r10,=0x0
ldr  r11,=0x0
ldr  r12,=0x0
ldr  r13,=0x0
ldr  r14,=0x0
ldr  pc, =(0x0008000)


пытался вызвать:
Код
extern void __start_firmware();

main()
{
    TargetInit();
    __start_firmware();
}


При компиляции выдается ошибка, что __start_firmware неопределена. В мануале написано, что для экспорта достаточно прописать PUBLIC __start_firmware. Может чего упустил?
Сергей Борщ
Цитата(Vitaliy_ARM @ May 20 2008, 12:03) *
При компиляции выдается ошибка, что __start_firmware неопределена. В мануале написано, что для экспорта достаточно прописать PUBLIC __start_firmware. Может чего упустил?
Самое простое - может забыли подключить startup.s к проекту?

Более сложное - если ваш файл компилится в режиме С++, то надо писать extern "C" void __start_firmware(); Если файл может компилиться как в С так и в С++ варианте, то
Код
#include <yvals.h>
_EXTERN_C
void __start_firmware();
_END_EXTERN_C
Vitaliy_ARM
Цитата(Сергей Борщ @ May 20 2008, 13:44) *
Более сложное - если ваш файл компилится в режиме С++, то надо писать extern "C" void __start_firmware(); Если файл может компилиться как в С так и в С++ варианте, то
Код
#include <yvals.h>
_EXTERN_C
void __start_firmware();
_END_EXTERN_C


Спасибо!!! Второй вариант заработал.
a14.gif
Vitaliy_ARM
Потихоньку разбираюсь с C++. Не пойму один момент.
Как известно, в ARM надо прописать адрес обработчика прерывания в VIC;
Некоторый класс:
Код
typedef class _TIMER
{
   public:
        void Init();
        __arm void Isr();

}TIMER,*pTIMER;

void _TIMER::Init()
{
  -------------------
  OpenIsr(TIMER1,(DWORD*)Isr,HIGH_PR);                       // определяем обработчик прерывания
}

__arm void _TIMER::Isr()
{
----------------------
}

Компилятор ругается, что нельзя сконвертировать тип.
Пробовал и так конвертировать:
Код
  OpenIsr(TIMER1,static_cast<DWORD*>(Isr),HIGH_PR);     // определяем обработчик прерывания


Ошибка таже:
Error[Pa073]: invalid type conversion (from "__code __interwork void ()" to "DWORD*")

Это вообще возможно или я в трех соснах блуждаю?
Сергей Борщ
Цитата(Vitaliy_ARM @ May 22 2008, 11:07) *
Ошибка таже:
Error[Pa073]: invalid type conversion (from "__code __interwork void ()" to "DWORD*")
Странная ошибка. он должен был ругаться на конвертацию адреса функции-члена в указатель, а он ругается на нее как на обычную функцию. Дело в том, что при вызове функции-члена первым параметром неявно передается указатель на объект. Прерывание не может передать этот указатель. Поэтому, или обработчик должен быть статической функцией-членом (которой не нужен this) или надо написать обычную функцию как обертку:
Код
__arm void TIMER1_Isr_wrapper()
{
   TIMER1.Isr();   // Тут мы явно указываем передать адрес TIMER1 как this
}


  OpenIsr(TIMER1,(DWORD*)TIMER1_Isr_wrapper,HIGH_PR);                       // определяем обработчик прерывания
при этом функцию-член-обработчик лучше сделать встраиваимой.

Чтобы было легче понять: Вы объявили 5 экземпляров этого класса (TIMER1, TIMER2, ... TIMER5). Попав в ваш _TIMER::Isr(), откуда он будет знать, какой конкретно из этих 5 таймеров надо обрабатывать? И при инициализации ваш _TIMER:Init() настраивает только первый таймер, а как настраивать остальные? Если вы пишете этот класс под один конкретный таймер, то можно все функции-члены и данные-члены сделать статическими, но тогда появится неудобство - придется явно заводить каждый статический член-данное.

Ой... Вы же передаете TIMER1 в OpenIsr. Видимо где-то дальше оно у вас используется для вызова обработчика. Тогда про статическое не читайте, почитайте это: указатель на функцию-член. И покажите объявление (а лучше и текст) OpenIsr()
Vitaliy_ARM
Цитата(Сергей Борщ @ May 22 2008, 12:40) *
Ой... Вы же передаете TIMER1 в OpenIsr. Видимо где-то дальше оно у вас используется для вызова обработчика. Тогда про статическое не читайте, почитайте это: указатель на функцию-член. И покажите объявление (а лучше и текст) OpenIsr()


Хорошая ссылка. Привожу код для OpenIsr():
Код
void OpenIsr(DWORD IntNum,DWORD Handler, DWORD Priority)
{
    DWORD *vect_addr;
    DWORD *vect_cntl;
    VICIntEnClr = 1 << IntNum;
    if (IntNum < VIC_SIZE )
    {
        vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNum*4);
        vect_cntl = (DWORD *)(VIC_BASE_ADDR + VECT_CNTL_INDEX + IntNum*4);
        *vect_addr =  Handler;    
        *vect_cntl = Priority;
        VICIntEnable = 1 << IntNum;    
    }
}

Немного конкретизирую идею
Думал сделать отдельный класс TARGET, в котором будут находиться функции , а потом все классы сделать наследниками его. Класс, который написал - это просто пример. Наверное удобнее номер таймера передавать в конструкторе, а потом от этого прописывать прерывания в OpenIsr:
Код
typedef class _TIMER
{  
   public:
    _TIMER(DWORD TimerNum);
    void Init();
    void Isr();
}

Собственно на пути всего этого стоит то, что не могу передать функции OpenIsr адрес обработчика превывания (метод этого же класса), который она должна записать в регистр микроконтроллера (LPC2468). По ссылке, указанной вами, попытался создать в классе такой указатель: void (_TIMER::*pFunction) ();
Потом в конструкторе попытался сделать так:
Код
_TIMER::_TIMER(void)
{
  DWORD *p;
  pFunction = &_TIMER::Isr;    
  p = static_cast<DWORD*>(pFunction);
}

На третью строчку в фигурных скобках таже ошибка, не может сконвертировать тип.

Обертку C функции делать не очень хочется, каждый раз при создании класса ее придется тоже создавать.
Сергей Борщ
Ах вот оно как! Я чего-то подумал, что TIMER1 это у вас объект класса _TIMER, а это вы так VIC_TIMER1 переобозвали... Маленькое замечание - не рекомендуется использовать подчеркивание в качестве первого символа в именах, такие имена зарезервированы за компилятором, можете напороться на интересные ошибки. И имена из одних заглавных обычно используются для мароопределений (#define).
Цитата(Vitaliy_ARM @ May 22 2008, 17:29) *
На третью строчку в фигурных скобках таже ошибка, не может сконвертировать тип.
Функция, вызываемая по этому указателю, требует this в качестве неявного параметра. По этому указателю определяется, с каким именно из объектов данного класса идет работа. Как ваш обработчик передаст в функцию этот this? Если бы компилятор разрешил вам это преобразование, то у вас для нескольких прерваний VICVectAddr указывал бы на одну и ту же функцию. И как бы эта функция разгребала, какой из таймеров надо обрабатывать? VIC на каждый источник прерывания хочет вызвать отдельную функцию. И никак вы это не обойдете. Или вам придется сделать на N таймеров N функций-"оберток", или в классе объявить N статических обработчиков, которые отличаются от "оберток" только областью видимости.
Посмотрите дизассемблированный текст обращения к любой функции-члену. В R1 находится указатель на объект Если бы компилятор разрешил вам это преобразование, то, поскольку в момент прерывания у вас R1 может иметь произвольное значение, эта функция-член начала бы править данные не в конкретном объекте, а в произвольном месте памяти.

Нет, есть конечно финт ушами - сделать все классы, имеющие обработчики прерывания, полиморфными наследниками абстрактного базового класса, в VICVectAddr заносить указатели на объекты этих классов, а единый обработчик на векторе IRQ считывает VICVectAddr, преобразовывает его к типу "указатель на этот абстракный базовый класс" и вызывает по нему метод обработчика. Но это будет громоздкое (по сохранению регистров на стеке) и совершенно непереносимое на другие архитектуры решение.

Что-то вроде вот такого:
Код
class interrupt_t
{
    friend __irq void IRQ_Handler();
protected:
    interrupt_t(uint_fast8_t const vector_num, uint32_t const irq_ID);
private:
    virtual void Handler() = 0;
};

class timer_t : private interrupt_t
{
public:
    timer_t(uint_fast8_t const vector_num, uint32_t const irq_ID);
private:
    virtual void Handler();
    uint32_t Time;
};

inline interrupt_t::interrupt_t(uint_fast8_t const vector_num, uint32_t const irq_ID)
{
    uint32_t *Vector = &VICVectAddr0;
    Vector[vector_num] = (uint32_t)this;
    uint32_t *Control = &VICVectCtnl0;
    Control[vector_num] = (1 << 5) | irq_ID;
    VICVectEnable = (1 << irq_ID);
}

inline timer_t::timer_t(uint32_t const vector_num, uint32_t const irq_ID)
    : interrupt_t(vector_num, irq_ID)
{
    // настройка таймера
    .........    
}

timer_t::Handler()
{
    ++Time;
}

timer_t Timer1 (15, VIC_TIMER1);

#pragma vector = 0x18
__irq void IRQ_Handler()
{
    interrupt_t * pSource = (interrupt_t *)VICVectAddr;
    pSource->Handler();
    VICVectAddr = 0;
}
Хм, а интересная мысль. Надо взять ее на заметку для небольших неторопливых безОСевых приложений типа загрузчиков. smile.gif
Vitaliy_ARM
Цитата(Сергей Борщ @ May 22 2008, 22:18) *
Хм, а интересная мысль. Надо взять ее на заметку для небольших неторопливых безОСевых приложений типа загрузчиков. smile.gif

Сложно. Получается, что с оберткой по-проще. Уже делал что-то подобное (прикрепил один из вариантов оберток).

Еще пока не использовал наследование, пользовался подобными конструкциями:
Код
while(1)
{
     if(Emac.CheckRx())
    {
      // определяем указатель на приемный пакет
      Emac.RxData(&Buf,&Len);
      // обрабатываем ответ
      StUdp.EthDataProcess(&Buf,&Len);
      // отправляем ответ
      Emac.TxData(Buf,Len);
     }
}

Хотя, если использовать наследование, то можно это все превратить в одну функцию. Занялся формированием концепции программирования.

Вы сказали для неторопливых, оценивали ли вы размер кода, когда несколько объектов наследуют один и тот же базовый класс? Непонятен момент, как компилируются функции этого базового класса. Для каждого наследника они дублируются или компилятор это как-то оптимизирует?
Сергей Борщ
Цитата(Vitaliy_ARM @ May 23 2008, 12:26) *
Вы сказали для неторопливых, оценивали ли вы размер кода, когда несколько объектов наследуют один и тот же базовый класс? Непонятен момент, как компилируются функции этого базового класса. Для каждого наследника они дублируются или компилятор это как-то оптимизирует?
Объект состоит только из данных. Когда вы обращаетесть к функции-члену, то компилятор по имени объекта определяет, какую именно из функций надо вызвать. Поэтому каждая (невстраиваимая) функция-член встречается в коде ровно один раз. Если это унаследованная функция для данного класса, то будет вызвана функция базового класса. Поэтому накладных расходов по коду при наследовании нет никаких. пример:
Код
class a_t:
{
public:
    void func_1() { data_a ++; }
    void func_2() { data_a --; }
    int data_a;

};

class b_t
{
public:
    void func_2() { data_b += 2; }
    int data_b;
};

a_t a;
/*
    в памяти имеем:
    a = struct a_t
    {
        int data_a;
    };
*/

b_t b;
/*
    в памяти имеем:
    b = struct
    {
        struct a_t
        {
            int data_a;
        };
        int data_b;
    };
*/

void test()
{
     a.func_1();// вызывается a_t::func_1(this = &a), происходит a.data_a++;
     a.func_2();// вызывается a_t::func_2(this = &a), происходит a.data_a--;
     b.func_1();// вызывается a_t::func_1(this = &b), происходит b.data_a++;
     b.func_2();// вызывается b_t::func_2(this = &b), происходит b.data_b+=2;
}
Единственные накладные расходы, которые могут возникнуть - по памяти данных на архитектурах с выравниванием. Размер struct a_t будет округлен в бОльую сторону до параметра выравнивания (чтобы если из них сделать массив, следующий элемент оказался выровненным), и это округление может оставить пустое место между data_a и data_b в b.
Vitaliy_ARM
Цитата(Сергей Борщ @ May 23 2008, 15:27) *
Объект состоит только из данных. Когда вы обращаетесть к функции-члену, то компилятор по имени объекта определяет, какую именно из функций надо вызвать. Поэтому каждая (невстраиваимая) функция-член встречается в коде ровно один раз. Если это унаследованная функция для данного класса, то будет вызвана функция базового класса. Поэтому накладных расходов по коду при наследовании нет никаких.

Единственные накладные расходы, которые могут возникнуть - по памяти данных на архитектурах с выравниванием. Размер struct a_t будет округлен в бОльую сторону до параметра выравнивания (чтобы если из них сделать массив, следующий элемент оказался выровненным), и это округление может оставить пустое место между data_a и data_b в b.


Отлично. Получается можно использовать преимущества ОПП и при этом размер кода практически не увеличивается.
Задам последний вопрос на отвлеченную тему:
Если делать класс например для всех COM портов на контроллере LPC2468. При создании в конструкторе прописывать номер порта. При этом есть проблема, у каждого порта свои регистры. Думал как вариант: создать поля указателей на эти регистры. В конструкторе поставить switch и присваивать здесь этим указателям адреса соответствующих регистров, а в остальных функциях обращаться непосредственно к указателям. Достоинсва: быстродействие, недостатки: лишняя память на поля указателей.

Вариант два: сделать в классе поле номера порта, так же инициализировать его в конструкторе. Потом в каждой функции ставить siwtch() и выбирать соответствующие регистры. Достоинсва: меньше памяти расходуется на поля, недостатки: меньше быстродействие.

Можно ли обойтись (а нужно ли?) без операторов switch() при обращении к регистрам ввода/вывода, которые для каждого COM порта могут находиться в любом месте области памяти?
Сергей Борщ
Цитата(Vitaliy_ARM @ May 26 2008, 10:01) *
Вариант два: сделать в классе поле номера порта, так же инициализировать его в конструкторе. Потом в каждой функции ставить siwtch() и выбирать соответствующие регистры. Достоинсва: меньше памяти расходуется на поля, недостатки: меньше быстродействие.
Насколько я помню, там все порты примерно одинаоквы. Все их регистры можно описать одной структурой. Так почему бы указатель на эту структуру и не передавать конструктору?
Vitaliy_ARM
Цитата(Сергей Борщ @ May 26 2008, 12:45) *
Насколько я помню, там все порты примерно одинаоквы. Все их регистры можно описать одной структурой. Так почему бы указатель на эту структуру и не передавать конструктору?


a14.gif Точно! Как я сразу не догадался. Спасибо за ответы
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.