Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прерывания без ОС на EP9315
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
toykhee_menky
Здравствуйте.

EP9315 на плате Tion-pro v1.
Программа на Си, компилируется WinARM 4.1.1, грузится в RAM при помощи redboot.

Пытаюсь работать с портом UART2, порт, судя по всему, работает - тестовая последовательность туда уходит.

FIFO разрешено, после посылки восьми символов оттуда появляется битик прерывания в VIC1RawIntr, т.е. прерывание до VIC вроде бы доходит.

По адресу 0x18 содержится команда, оставленная там redboot-ом, судя по всему:
00000018: 18 F0 9F E5 - перевожу как ldr r15,[r15,#0x18], т.е. должен взяться адрес процедуры реакции на прерывание с адреса 0x38 (0x18+0x18+0x08).

Подменяю указатель по адресу 0x38 на адрес своей функции. Но управление она не получает (контроль - светодиодами).

Прерывания разрешены, режим супервизора: cpsr=0x00000013
ОЗУ отмаплено само на себя, с адреса 0.

обработчик прерывания IRQ оформлен как
Код
void  __attribute__ ((interrupt ("IRQ"))) handler1();

но управления тоже не получает (источник прерывания 25 для VIC1 выбрал, прерывания разрешил, адрес ISR занес).

Чего-то я еще не сделал... Чего?
aaarrr
VIC, наверное, неправильно инициализировали. Код приведите.

Стоп.
Цитата
Подменяю указатель по адресу 0x38 на адрес своей функции.

А VIC что, оказался совсем не у дел? Процессор будет падать на этот адрес по любому прерыванию.
toykhee_menky
Цитата(aaarrr @ Jun 30 2008, 22:00) *
VIC, наверное, неправильно инициализировали. Код приведите.
Не уверен, что нужно всё подряд, вот части, непосредственно работающие с VIC1:
Код
#define IRQ_SRC 25
volatile unsigned int    *VIC1IRQStatus=(unsigned int *)0x800B0000u;
volatile unsigned int    *VIC1FIQStatus=(unsigned int *)0x800B0004u;
volatile unsigned int      *VIC1RawIntr=(unsigned int *)0x800B0008u;
volatile unsigned int    *VIC1IntSelect=(unsigned int *)0x800B000Cu;
volatile unsigned int    *VIC1IntEnable=(unsigned int *)0x800B0010u;
volatile unsigned int   *VIC1IntEnClear=(unsigned int *)0x800B0014u;
volatile unsigned int            *VIC1protection=(int *)0x800b0020u;
volatile unsigned int     *VIC1VectAddr=(unsigned int *)0x800B0030u;
volatile unsigned int  *VIC1DefVectAddr=(unsigned int *)0x800B0034u;
volatile unsigned int    *VIC1VectAddr0=(unsigned int *)0x800B0100u;
volatile unsigned int    *VIC1VectCntl0=(unsigned int *)0x800B0200u;

volatile int *pedr=(int *)0x80840020u;
unsigned int old_0x38;
unsigned int *ptr_0x38=(unsigned int *)0x38;



Код
  *pedr=3;
  old_0x38= *ptr_0x38;
  *ptr_0x38 = (unsigned int)irq_handler;


пробовал nirq=0 и =4, одинаково:

Код
  VIC1VectAddr0[nirq]=(unsigned int)handler1;
  // 2) chain to 25 source (IRQ_SRC)

  VIC1VectCntl0[nirq]=     IRQ_SRC;
  VIC1VectCntl0[nirq]=0x20|IRQ_SRC;

  // 3) enable it
  *VIC1IntEnable = (1<<IRQ_SRC);
и прибиваю торчащее откуда-то прерывание от источника 3:
Код
*VIC1IntEnClear = 0x08;
*VIC1DefVectAddr=(unsigned int)handler1;

Тексты двух обработчиков:
Код
// -------------- handler1 ----------------------
void __attribute__ ((interrupt ("IRQ"))) handler1()
{
    //volatile unsigned int *VIC1VectAddr=(unsigned int *)0x800B0030;
    //volatile unsigned int *VIC2VectAddr=(unsigned int *)0x800C0030;

    unsigned int s= *VIC1VectAddr;

    while (((*UART2Flag) & 0x10)==0) {
    int k= *UART2Data;
        rs_data_in[rs_h++]=k;
        if (rs_h>=MAX_RS_DT)
           rs_h=0;
    }
    *pedr=2;

    *VIC1VectAddr=0;

};
// --------------- irq_handler ------------------
void irq_handler(void)
{
      asm("stmfd sp!, {r0-r12, lr}");
      void (*interrupt_function)();
      unsigned int vector;
      *pedr=0;
      vector = *VIC1VectAddr;
      interrupt_function = (void(*)())vector;
      (*interrupt_function)();
      *VIC1VectAddr = 0;
      
      asm("ldmfd sp!, {r0-r12, lr}");
      asm("subs pc, lr, #4");
}

В общем, не совсем понятно соотношение обработчиков по адресу 0x18, помещенных в вектор (VIC1VectAddr0..VIC1VectAddr15) и VIC1DefVectAddr.
aaarrr
Цитата(toykhee_menky @ Jun 30 2008, 20:21) *
В общем, не совсем понятно соотношение обработчиков по адресу 0x18, помещенных в вектор (VIC1VectAddr0..VIC1VectAddr15) и VIC1DefVectAddr.

Кто в кого помещен?

Код, если честно, мозг ломает напрочь. Но некоторые моменты могу прояснить:
- Читать и писать VectAddr нужно в одном месте, а не в двух.
- Оформлять процедуру в виде прерывания - тоже.

Т.е. если в irq_handler читается и пишется VectAddr, и оформлен он как irq (в чем я, кстати, не уверен - уж больно дикий микс asm-C), то handler1 должен быть простой процедурой.

Код
// -------------- handler1 ----------------------
void handler1(void)
{
      // Здесь ничего из VIC'а не трогаем
};
// --------------- irq_handler ------------------
void __attribute__ ((interrupt ("IRQ"))) irq_handler(void)
{
      unsigned int vector;

      vector = *VIC1VectAddr;
      ...
      *VIC1VectAddr = 0;
}


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

Только сейчас заметил 07.gif 07.gif 07.gif :
Код
*VIC1DefVectAddr=(unsigned int)handler1;


Внимательно и вдумчиво почитайте мануал на VIC (есть на ARM'овском сайте) и архитектуру ARM.
toykhee_menky
Цитата(aaarrr @ Jun 30 2008, 22:47) *
Кто в кого помещен?

см.внизу
Цитата(aaarrr @ Jun 30 2008, 22:47) *
Код, если честно, мозг ломает напрочь.

Я знаю; но это была Ваша инициатива.

Цитата(aaarrr @ Jun 30 2008, 22:47) *
Но некоторые моменты могу прояснить:
- Читать и писать VectAddr нужно в одном месте, а не в двух.
- Оформлять процедуру в виде прерывания - тоже.

Да, если бы программа работала, так бы и было. Но она не работает, но не потому же, что
тут в двух местах читается VectAddr? Ведь до handler1 управление не доходит, так же как и до irq_handler.
Цитата(aaarrr @ Jun 30 2008, 22:47) *
Т.е. если в irq_handler читается и пишется VectAddr, и оформлен он как irq (в чем я, кстати, не уверен - уж больно дикий микс asm-C), то handler1 должен быть простой процедурой.

Только сейчас заметил 07.gif 07.gif 07.gif :
Код
*VIC1DefVectAddr=(unsigned int)handler1;


Внимательно и вдумчиво почитайте мануал на VIC (есть на ARM'овском сайте) и архитектуру ARM.

Это я от отчаяния.

Читаю:
2.1.6 Vectored interrupts
A vectored interrupt is only generated if the following are true:
• you enable it in the interrupt enable register, VICIntEnable
• you set it to generate an IRQ interrupt in the interrupt select register, VICIntSelect
• you enable it in the relevant vector control register, VICVectCntl[0-15].

В соответствии с этим описанием никаких манипуляций с адресом 0x18 не требуется вообще.
Всего три пункта: правильная маска в VICIntEnable, правильная маска в VICIntSelect,
правильное значение VICVectCntl[0-15].

Код
  VIC1VectCntl0[nirq]=     IRQ_SRC;
  VIC1VectCntl0[nirq]=0x20|IRQ_SRC;

  // 3) enable it
  *VIC1IntEnable = (1<<IRQ_SRC);

AFAIR биты VICIntSelect имеют следующие значения: 0:IRQ, 1:FIQ.
По умолчанию 0, т.е. IRQ.

("кто в кого помещен") Интересно, что здесь даже не сказано о VIC1VectAddr0..VIC1VectAddr15. То есть даже если я не помещу туда никакое ненулевое значение, прерывание всё равно произойдет, и управление передастся по адресу 0. Допустим. Но этого не происходит.

Понимаете, всё, что мне нужно - это понять, что еще нужно включить или выключить, чтобы
прерывание появилось. Оформление процедуры, сохранение регистров/контекста/пр. - это всё технические вопросы, я это выясню сам и потом. Пока мне нужно, чтобы управление попало на адрес, который я укажу - адрес ISR (вернее, хардверного обработчика).

При возникновении прерывания бит в VIC1RawIntr (да и в VIC1IRQStatus), соответствующий прерыванию от UART2 (номер 25) взводится. Да так и остается взведенным.

Вдумчиво читаю и комментирую еще одно положение:
2.2.1 Vectored interrupt flow sequence
The following procedure shows the sequence for the vectored interrupt flow:
1. An interrupt occurs.
- появляется прерывание. Да, появилось
2. The ARM processor branches to either the IRQ or FIQ interrupt vector.
- АРМ-процессор осуществляет переход либо на IRQ либо на FIQ-вектор. К сожалению, тут непонятно, о каком именно векторе идет речь. То ли о том, что определен как 0x18/0x1C, то ли о VICxVectAddr0..VICxVectAddr15.
3. If the interrupt is an IRQ, read the VICVectAddr Register and branch to the
interrupt service routine. You can do this using an LDR PC instruction. Reading the
VICVectorAddr Register updates the interrupt controllers hardware priority
register.

Если прерывание - IRQ (а что делать, если это не так?), прочитай регистр VICVectAddr и осуществи переход на ISR. Вы можете сделать это, используя инструкцию LDR PC. Считывание регистра VICVectorAddr обновляет аппаратный регистр приоритета контроллера прерываний.
о чем здесь идет речь? О процедуре, на которую управление приходит с адреса 0x18/0x1C.

4. Stack the workspace so that you can re-enable IRQ interrupts.
5. Enable the IRQ interrupts so that a higher priority can be serviced.
6. Execute the Interrupt Service Routine (ISR).

Выполнить ISR - коротко и ясно.

7. Clear the requesting interrupt in the peripheral, or write to the VICSoftIntClear
Register if the request was generated by a software interrupt.
8. Disable the interrupts and restore the workspace.
9. Write to the VICVectAddr Register. This clears the respective interrupt in the
internal interrupt priority hardware.
10. Return from the interrupt. This re-enables the interrupts.

Получается следующее. Поправьте меня, если я не прав.
* При возникновении IRQ-прерывания управление попадает по адресу 0x18, далее в процедуру обработки аппаратного прерывания, которая выясняет, было ли прерывание векторизированным или нет, выбирает соответствующий ISR, вызывает его, осуществляет манипуляции по повторному разрешению прерываний.
* Считывание и запись регистра VICVectAddr осуществляется соответственно до и после вызова ISR.
* ISR - обычная процедура

Прекрасно, я сейчас это всё сделаю. Только проблема-то останется - hardware handler не вызывается.

В этом же документе (DDI0181.pdf) описывается механизм быстрой обработки прерываний, когда VIC отмапливается на адрес 0xFFFFF000. Тогда его регистры становятся в пределах досягаемости от адреса 0x18, и можно разместить там команду LDR pc, [pc, #-0xff0]. При выполнении этой команды управление передастся на адрес, который хранится непосредственно в VIC, с учетом отмапливания это будет 0xFFFFF030, т.е. VICVectAddr. И в этом случае дополнительного считывания делать уже не нужно, уже всё прочитано и ушло на исполнение... нет?

У меня было несколько предположений. Рискну изложить их здесь, какими бы глупыми они ни были.
1. Прерывание не возникает, потому что процессор в режиме супервизора.
2. Прерывание возникает, но управление передается не на адрес 0x18.
3. Для того, чтобы изменения в VIC воспринялись, нужны дополнительные действия (аналогично outportb(0x20,0x20) в IBM PC).
4. Прерывание не возникает, потому что активно прерывание с более высоким приоритетом. Но я его не вижу.
sergeeff
Ну я бы под пунктом 0 добавил:
Преравание не возникает, потому что прерывания вообще не разрешены (а они разрешены на уровне процессора?)
toykhee_menky
Цитата(sergeeff @ Jul 1 2008, 11:58) *
Ну я бы под пунктом 0 добавил:
Преравание не возникает, потому что прерывания вообще не разрешены (а они разрешены на уровне процессора?)
Разрешены:
Цитата
Прерывания разрешены, режим супервизора: cpsr=0x00000013

Надо расшифровывать значение cpsr?
sergeeff
Ну я бы, для начала, написал бы тестовую функцию обработчика прерывания типа:

void test_handler(void)
{
LED-ON();
while(1);
}

и убедился бы, что она вызывается.

А еще можо посмотреть в книге "ARM System Developer's Guide" A.Sloss на стр.363 есть пример обработчика на VIC
aaarrr
Цитата(toykhee_menky @ Jul 1 2008, 00:01) *
Получается следующее. Поправьте меня, если я не прав.
* При возникновении IRQ-прерывания управление попадает по адресу 0x18, далее в процедуру обработки аппаратного прерывания, которая выясняет, было ли прерывание векторизированным или нет, выбирает соответствующий ISR, вызывает его, осуществляет манипуляции по повторному разрешению прерываний.
* Считывание и запись регистра VICVectAddr осуществляется соответственно до и после вызова ISR.
* ISR - обычная процедура

Все правильно.

Цитата(toykhee_menky @ Jul 1 2008, 00:01) *
В этом же документе (DDI0181.pdf) описывается механизм быстрой обработки прерываний, когда VIC отмапливается на адрес 0xFFFFF000...
...И в этом случае дополнительного считывания делать уже не нужно, уже всё прочитано и ушло на исполнение... нет?

Да, это самый нормальный способ работы с VIC'ом. В прерывании остается только запись VICVectAddr.

Цитата(toykhee_menky @ Jul 1 2008, 00:01) *
У меня было несколько предположений. Рискну изложить их здесь, какими бы глупыми они ни были.
1. Прерывание не возникает, потому что процессор в режиме супервизора.
2. Прерывание возникает, но управление передается не на адрес 0x18.
3. Для того, чтобы изменения в VIC воспринялись, нужны дополнительные действия (аналогично outportb(0x20,0x20) в IBM PC).
4. Прерывание не возникает, потому что активно прерывание с более высоким приоритетом. Но я его не вижу.

1, Не бывает.
2. Может быть, если в регистре 1 CP15 установлен бит V, тогда вектора будут расположены с адреса 0xffff0000. Но вряд ли это так.
3. Никаких действий не нужно.
4. Попробуйте сбросить VIC шестнадцатикратной записью VICVectAddr.
sergeeff
Можно посмотреть http://www.siwawi.arubi.uni-kl.de/avr_proj...ml#lpc_uart_irq. LPC тоже пользует VIC.
toykhee_menky
Мда. Проблема, однако. Неужели я один такой (или первый?!)

Всё-таки мне кажется, что тут redboot руку приложил. Я его сам не собирал, взял готовый:
G:\Tion\tools\utils\util>md5sum redboot_322D.bin
1450b4be1f8a86b85cd2bf2326d8d906 redboot_322D.bin

при старте:
Код
+EP93xx - no EEPROM, static ESA, or RedBoot config option.
No network interfaces found

RedBoot(tm) bootstrap and debug environment [ROMRAM]
Non-certified release, version UNKNOWN - built 16:31:15, May 28 2007

Platform: Cirrus Logic EDB9312 Board (ARM920T) Rev A
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Copyright (C) 2003, 2004, 2005, 2006 eCosCentric Limited

RAM: 0x00000000-0x04000000, [0x00042e80-0x03fdd000] available
FLASH: 0x60000000 - 0x60800000, 64 blocks of 0x00020000 bytes each.
RedBoot>


Смотрел eCos и eCos-2.0, скачивал с ftp://ecos.sourceware.org/pub/ecos/releases, поскольку redboot является частью екоса.

Не вижу поддержки ep93xx в этих исходниках. Если бы была, то можно было бы найти информацию по прерываниям (например, здесь) и отмапливанию памяти.

Значит, какой-то добрый человек сделал поддержку ep93xx в редбуте минимум, а то и в екосе (официальные релизы по ссылке выше - 2003-й год.) Какое отношение автор этого порта имеет к изготовителям Тиона - мне неизвестно. На сайте ЗАО ЗЕО информации о порте екоса и редбута не вижу.
Остаётся надеяться, что кто нибудь, владеющий информацией, направит меня на путь истинный.

Тем не менее: значение регистра 1 CP15: 0xC000007B. Если считать бит V (high vectors) 13-м, то тут 0.
Посмотрел и отмапливание памяти: рег 2 CP15 содержит значение 0x00004000, дамп этого места в памяти:
Код
00004000: 1E 0C 00 00 1E 0C 10 00  1E 0C 20 00 1E 0C 30 00  |.......... ...0.|
00004010: 1E 0C 40 00 1E 0C 50 00  1E 0C 60 00 1E 0C 70 00  |..@...P...`...p.|
00004020: 1E 0C 80 00 1E 0C 90 00  1E 0C A0 00 1E 0C B0 00  |................|
00004030: 1E 0C C0 00 1E 0C D0 00  1E 0C E0 00 1E 0C F0 00  |................|
00004040: 1E 0C 00 01 1E 0C 10 01  1E 0C 20 01 1E 0C 30 01  |.......... ...0.|
00004050: 1E 0C 40 01 1E 0C 50 01  1E 0C 60 01 1E 0C 70 01  |..@...P...`...p.|
00004060: 1E 0C 80 01 1E 0C 90 01  1E 0C A0 01 1E 0C B0 01  |................|
00004070: 1E 0C C0 01 1E 0C D0 01  1E 0C E0 01 1E 0C F0 01  |................|
00004080: 1E 0C 00 04 1E 0C 10 04  1E 0C 20 04 1E 0C 30 04  |.......... ...0.|
00004090: 1E 0C 40 04 1E 0C 50 04  1E 0C 60 04 1E 0C 70 04  |..@...P...`...p.|
000040A0: 1E 0C 80 04 1E 0C 90 04  1E 0C A0 04 1E 0C B0 04  |................|
000040B0: 1E 0C C0 04 1E 0C D0 04  1E 0C E0 04 1E 0C F0 04  |................|
000040C0: 1E 0C 00 05 1E 0C 10 05  1E 0C 20 05 1E 0C 30 05  |.......... ...0.|
000040D0: 1E 0C 40 05 1E 0C 50 05  1E 0C 60 05 1E 0C 70 05  |..@...P...`...p.|
000040E0: 1E 0C 80 05 1E 0C 90 05  1E 0C A0 05 1E 0C B0 05  |................|
000040F0: 1E 0C C0 05 1E 0C D0 05  1E 0C E0 05 1E 0C F0 05  |................|
00004100: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...тут флеш-память:
00005800: 12 0C 00 60 12 0C 10 60  12 0C 20 60 12 0C 30 60  |...`...`.. `..0`|
... регистры и пр - пропустил, не так интересно.
дальше нули.
Интерпретирую это так: это описание 64-х секций длиной по 1Мб, виртуальная память объемом 64Мб, состоит из двух физических блоков по 32Мб, первый с физического адреса 0x00000000, и отображен сам на себя, второй с физического адреса 0x04000000, отображен на 0x02000000.
Флешь с физического адреса 0x60000000, вирт. адрес также 0x60000000.

Интересно, что в разных местах Интернета разная информация по редбуту:
одни говорят, что редбут не использует прерываний вообще, "It seems easy,because redboot will not use IRQ vector" (правда, там процессор ARM7TDMI), в другом месте сообщается. что "RedBoot uses an interrupt vector table which is located at address 0xA000A004." (IQ80310). Отсюда я делаю вывод, что использование или неиспользование прерываний в redboot - платформенно-зависимое. И надо бы мне найти исходники или документацию по порту редбута на ep93xx. Но... см выше.

Еще момент. redboot кроме загрузчика, еще и отладчик. Звучит фантастически, но может быть, там отладчик перехватывает обращения к адресам 0..0x1C?
aaarrr
Исходники redboot'а, если охота в них ковыряться, найдете на arm.cirrus.com.

Я одного понять не могу: зачем Вам redboot для запуска своей программы? Пишите ее сразу во флеш и запускайте.
sergeeff
Ну вот, осталось посмотреть, что же сидит в таблице прерываний с адреса 0х00000000
toykhee_menky
Цитата(aaarrr @ Jul 2 2008, 17:32) *
Исходники redboot'а, если охота в них ковыряться, найдете на arm.cirrus.com.

Спасибо!
Цитата(aaarrr @ Jul 2 2008, 17:32) *
Я одного понять не могу: зачем Вам redboot для запуска своей программы? Пишите ее сразу во флеш и запускайте.
Вот сейчас, наверное, уже и не так сильно нужен. Я надеялся, что будет некий RedBoot API, что- то вроде PC-шного BIOS. Не оказалось. Ну да ладно, это не фатально.
При использовании редбута можно давать диагностику в консоль практически "из коробки", а если делать флешовую программу, то придется изучать еще кучу вещей - среду разработки, синтаксис всевозможных описателей структуры памяти программы и т.п. В общем, как обычно, прежде, чем решить задачу, нужно решить две других, более сложных. Я хотел этого избежать.

Кроме того, мне показалось, что цикл сборка-загрузка-запуск-падение-отладка-исправление будет быстрее для ОЗУ-шной версии.


Цитата(sergeeff @ Jul 2 2008, 17:33) *
Ну вот, осталось посмотреть, что же сидит в таблице прерываний с адреса 0х00000000

Код
RedBoot> dump -b 0 -l 128
00000000: 0E 00 00 EA 18 F0 9F E5  18 F0 9F E5 18 F0 9F E5  |................|
00000010: 18 F0 9F E5 00 00 00 00  18 F0 9F E5 18 F0 9F E5  |................|
00000020: 48 90 00 00 78 91 00 00  9C 91 00 00 C8 91 00 00  |H...x...........|
00000030: E4 91 00 00 00 00 00 00  FC 92 00 00 C4 92 00 00  |................|
00000040: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050: 17 00 08 00 D0 45 01 00  D0 45 01 00 D0 45 01 00  |.....E...E...E..|
00000060: D0 45 01 00 30 CF 03 00  30 CF 03 00 64 47 01 00  |.E..0...0...dG..|
00000070: 60 47 01 00 D0 45 01 00  D0 45 01 00 D0 45 01 00  |`G...E...E...E..|
Сразу уж и 0x92FC (звиняйте, что не дизассемблировано):
Код
RedBoot> dump -b 0x92fc -l 128
000092FC: F0 D0 9F E5 3F 00 2D E9  04 00 4E E2 00 10 4F E1  |....?.-...N...O.|
0000930C: 06 20 A0 E3 0D 30 A0 E1  00 40 0F E1 1F 40 C4 E3  |. ...0...@...@..|
0000931C: 53 40 84 E3 04 F0 29 E1  0D 50 A0 E1 0E 40 A0 E1  |S@....)..P...@..|
0000932C: 37 00 2D E9 0D 00 A0 E1  00 20 0F E1 C0 10 81 E3  |7.-...... ......|
0000933C: 20 10 C1 E3 01 F0 29 E1  00 7F 20 E9 02 F0 29 E1  | .....)... ...).|
0000934C: 00 D0 A0 E1 3F 00 93 E8  FF 00 2D E9 40 10 9D E5  |....?.....-.@...|
0000935C: 1F 10 01 E2 13 00 51 E3  4C 10 9D 05 34 10 8D 05  |......Q.L...4...|
0000936C: 0D 90 A0 E1 09 00 A0 E1  D7 1F 00 EB 00 40 A0 E1  |.............@..|
sergeeff
А что за процедура вызывается по прерыванию? Как бы все похоже, что это обычная функция для ARM_MODE_USER или ARM_MODE_SVC или ARM_MODE_SYS, а уж никак не для режима прерывания? Там к тому моменты и стек другой и прочие прелести. Ну и VIC'ом тоже не попахивает.

По определению interrupt handler не может иметь параметров!

000092FC E59FD0F0 LDR sp, &000093F4
00009300 E92D003F STMFD sp!, {r0-r5}
00009304 E24E0004 SUB r0, lr, #4
00009308 E14F1000 MRS r1, SPSR
0000930C E3A02006 MOV r2, #6
00009310 E1A0300D MOV r3, sp
00009314 E10F4000 MRS r4, CPSR
00009318 E3C4401F BIC r4, r4, #31
0000931C E3844053 ORR r4, r4, #83
00009320 E129F004 MSR CPSR, r4
00009324 E1A0500D MOV r5, sp
00009328 E1A0400E MOV r4, lr
0000932C E92D0037 STMFD sp!, {r0-r2,r4,r5}
00009330 E1A0000D MOV r0, sp
00009334 E10F2000 MRS r2, CPSR
00009338 E38110C0 ORR r1, r1, #&C0
0000933C E3C11020 BIC r1, r1, #32
00009340 E129F001 MSR CPSR, r1
00009344 E9207F00 STMDB r0!, {r8-lr}
00009348 E129F002 MSR CPSR, r2
0000934C E1A0D000 MOV sp, r0
00009350 E893003F LDMIA r3, {r0-r5}
00009354 E92D00FF STMFD sp!, {r0-r7}
00009358 E59D1040 LDR r1, [sp, #64]
0000935C E201101F AND r1, r1, #31
00009360 E3510013 CMP r1, #19
Desenix
для армов EP9312, S3C2410, LPC2368 всегда писал и инициализировал обработчики прерывания сам, а не полагался на среду разработки, и не имел проблем.
Если вы не хотите изучать тонкости процессора, то зачем вы взялись его программировать ?
Отдайте эту задачу системному программисту, а сами пишите только пользовательский уровень.

Изучите как работает контроллер прерываний, как и что в нем надо инициализировать, как надо построить обработчик прерываний, что надо инициализировать в переферии для разрешения прерываний итд.

На самом деле контроллер в ARM хоть и "крутой", но мне кажется немного не доинтегрирован в ядро, в идеале надо было, чтоб не обработчик обрабатывал переход по адресу, а само ядро аппаратно.

на всякий случай кусок кода, правда там таймер и Ethernet, но думаю суть понятна будет, главное что камень EP9312

Код
// Interrupt handlers.
void TimerInterrupt()
{
  (*timer_function)(); // Call timer callback function.
  Timer3Clear = 0x0; // Clear timer 3 interrupt line.
}

// IRQ interrupt handler.
// Only the timer interrupt is used by this example.
__irq __arm void irq_handler(void)
{
  void (*interrupt_function)();
  unsigned int vector;
  // Called at 1000 Hz rate.
  vector = VIC2VectAddr; // Get interrupt vector.
  interrupt_function = (void(*)())vector;
  (*interrupt_function)(); // Call vectored interrupt function.
  VIC2VectAddr = 0; // Clear interrupt in VIC.
}

// Interrupt functions.
void EP9312InitInterrupt(void(*timer_func)())
{
  // Setup timer callback function.
  timer_function = timer_func;

  // Setup interrupt controller.
  VIC1Protection = 0;
  VIC2Protection = 0;
  // Disable all interrupts
  VIC1IntEnClear = 0xffffffff;
  VIC2IntEnClear = 0xffffffff;

  VIC2IntSelect &= ~TC3OI_bit; // IRQ on timer 3 line.
  VIC2VectAddr0 = (unsigned int)&TimerInterrupt;
  VIC2VectCntl0 = 0x20 | VIC2_TC3OI; // Enable vector interrupt for timer 3.
  VIC2IntEnable |= TC3OI_bit; // Enable timer 3 interrupt.

  VIC2IntSelect &= ~TC39OI_bit; // IRQ on MAC line.
  VIC2VectAddr1 = (unsigned int)&InterruptMac;
  VIC2VectCntl1 = 0x20 | VIC2_INT_MAC; // Enable vector interrupt for MAC.
  VIC2IntEnable |= TC39OI_bit; // Enable MAC interrupt.
}
sergeeff
Все очень здорово, но надо же еще обучить процессор при возникновении прерывания с адреса 0х00000018 уходить на обработку конкретной функции обработки прерывания. А по сути, какая разница ядро как-то разбирается с прерываниями или дополнительный контроллер? По мне, так главное, чтобы бастро, понятно и надежно работало.

Я склоняюсь к тому, что redboot что-то в своих интересах инициализировал (или вовсе не инициализировал). На мой взгляд, если коллега действительно хочет именно с этим процессором работать, ему все равно под себя загузчик так и так придется написать. Тогда он будет владеть ситуацией, а не ситуация иметь его.
Desenix
ну да, еще стандартный startup забыл приложить, забыл сказать, использовал IAR

Код
;-----------------------------------------------------------------------------
; This file contains the startup code used by the ICCARM C compiler.
;
; The modules in this file are included in the libraries, and may be replaced
; by any user-defined modules that define the PUBLIC symbol _program_start or
; a user defined start symbol.
; To override the cstartup defined in the library, simply add your modified
; version to the workbench project.
;
; All code in the modules (except ?RESET) will be placed in the ICODE segment.
;
; $Revision: 1.2 $
;
;-----------------------------------------------------------------------------
    
;
; Naming covention of labels in this file:
;
;  ?xxx      - External labels only accessed from assembler.
;  __xxx  - External labels accessed from or defined in C.
;  xxx      - Labels local to one module (note: this file contains
;           several modules).
;  main      - The starting point of the user program.
;

;---------------------------------------------------------------
; Macros and definitions for the whole file
;---------------------------------------------------------------

; Mode, correspords to bits 0-5 in CPSR
MODE_BITS    DEFINE    0x1F    ; Bit mask for mode bits in CPSR
USR_MODE    DEFINE    0x10    ; User mode
FIQ_MODE    DEFINE    0x11    ; Fast Interrupt Request mode
IRQ_MODE    DEFINE    0x12    ; Interrupt Request mode
SVC_MODE    DEFINE    0x13    ; Supervisor mode
ABT_MODE    DEFINE    0x17    ; Abort mode
UND_MODE    DEFINE    0x1B    ; Undefined Instruction mode
SYS_MODE    DEFINE    0x1F    ; System mode
    
;---------------------------------------------------------------
; ?RESET
; Reset Vector.
; Normally, segment INTVEC is linked at address 0.
; For debugging purposes, INTVEC may be placed at other
; addresses.
; A debugger that honors the entry point will start the
; program in a normal way even if INTVEC is not at address 0.
;---------------------------------------------------------------

        MODULE    ?RESET
        COMMON    INTVEC:CODE:NOROOT(2)
        PUBLIC  __program_start
        EXTERN    ?cstartup
;        EXTERN    undef_handler, swi_handler, prefetch_handler
;        EXTERN    data_handler, fiq_handler
        EXTERN    irq_handler
        CODE32; Always ARM mode after reset    
        org    0x00
__program_start
        ldr    pc,=?cstartup ; Absolute jump can reach 4 GByte
;        ldr    b,?cstartup   ; Relative branch allows remap, limited to 32 MByte
        org    0x04
undef_handler    ldr    pc,=undef_handler
        org    0x08
swi_handler    ldr    pc,=swi_handler
        org    0x0c
prefetch_handler ldr    pc,=prefetch_handler
        org    0x10
data_handler    ldr    pc,=data_handler
        org    0x18
        ldr    pc,=irq_handler
        org    0x1c
fiq_handler    ldr    pc,=fiq_handler

    ; Constant table entries (for ldr pc) will be placed at 0x20
        org    0x20
        LTORG
;        ENDMOD    __program_start
                ENDMOD

;---------------------------------------------------------------
; ?CSTARTUP
;---------------------------------------------------------------
        MODULE    ?CSTARTUP

        RSEG    IRQ_STACK:DATA(2)
        RSEG    SVC_STACK:DATA:NOROOT(2)
        RSEG    CSTACK:DATA(2)
        RSEG    ICODE:CODE:NOROOT(4)
        PUBLIC    ?cstartup
        EXTERN    ?main

; Execution starts here.
; After a reset, the mode is ARM, Supervisor, interrupts disabled.

        CODE32
?cstartup

; Add initialization nedded before setup of stackpointers here


; Initialize the stack pointers.
; The pattern below can be used for any of the exception stacks:
; FIQ, IRQ, SVC, ABT, UND, SYS.
; The USR mode uses the same stack as SYS.
; The stack segments must be defined in the linker command file,
; and be declared above.
                mrs     r0,cpsr                            ; Original PSR value
                bic     r0,r0,#MODE_BITS                   ; Clear the mode bits
                orr     r0,r0,#IRQ_MODE                    ; Set IRQ mode bits
                msr     cpsr_c,r0                          ; Change the mode
                ldr     sp,=SFE(IRQ_STACK) & 0xFFFFFFF8    ; End of IRQ_STACK

                bic     r0,r0,#MODE_BITS                   ; Clear the mode bits
                orr     r0,r0,#SYS_MODE                    ; Set System mode bits
                msr     cpsr_c,r0                          ; Change the mode
                ldr     sp,=SFE(CSTACK) & 0xFFFFFFF8       ; End of CSTACK

#ifdef __ARMVFP__
; Enable the VFP coprocessor.
                mov     r0, #0x40000000                ; Set EN bit in VFP
                fmxr    fpexc, r0                      ; FPEXC, clear others.

; Disable underflow exceptions by setting flush to zero mode.
; For full IEEE 754 underflow compliance this code should be removed
; and the appropriate exception handler installed.
                mov     r0, #0x01000000               ; Set FZ bit in VFP
                fmxr    fpscr, r0                      ; FPSCR, clear others.
#endif

; Add more initialization here

; Continue to ?main for more IAR specific system startup

                ldr     r0,=?main
                bx      r0

                LTORG
                ENDMOD
                END
toykhee_menky
Цитата(sergeeff @ Jul 3 2008, 00:38) *
Все очень здорово, но надо же еще обучить процессор при возникновении прерывания с адреса 0х00000018 уходить на обработку конкретной функции обработки прерывания.
Вообще-то процессор умеет это делать, так как исполняет инструкцию, находящуюся по адресу 0x18. Я уже приводил содержимое этого слова:
Код
00000010: 18 F0 9F E5 00 00 00 00  18 F0 9F E5 18 F0 9F E5  |................|
                                   ^^^^^^^^^^^

Разумеется, информация в таком виде представлена для удобства(или, скорее, возможности) прочтения ее человеком. Процессор же интерпретирует ее как команду. Опять же, невозможно адекватно отобразить, что видит процессор по адресу 0x18, но если представить это слово как команду, получается
Код
   18:    e59ff018     ldr    pc, [pc, #18]; 0x38
Перевожу с ассемблера на русский: загрузить в счетчик программы (фактически, передать управление) на адрес, значение которого хранится на 0x18 (#18) больше, чем текущее значение счетчика. 0x38 здесь образуется из трех слагаемых: 0x18 - адрес инструкции, и начальное значение PC; второй 0x18 - смещение из кода команды; 8 - значение задано неявно особенностями архитектуры ARM (набежало за время прохождения конвейера).

На основании этого не вижу необходимости править команду по адресу 0x18, так как ничего лучше и придумать нельзя. Вместо этого я определяю адрес своего обработчика путем занесения его по адресу 0x38:
Код
unsigned int old_0x38;
unsigned int *ptr_0x38=(unsigned int *)0x38;

old_0x38= *ptr_0x38;
*ptr_0x38 = (unsigned int)irq_handler;

и он заносится, проверено.

Цитата(sergeeff @ Jul 3 2008, 00:38) *
Я склоняюсь к тому, что redboot что-то в своих интересах инициализировал (или вовсе не инициализировал). На мой взгляд, если коллега действительно хочет именно с этим процессором работать, ему все равно под себя загузчик так и так придется написать. Тогда он будет владеть ситуацией, а не ситуация иметь его.
Спасибо на добром слове. Ладно, убью еще неделю...
sergeeff
Уважаемый toykhee_menky!

1. Так про то и речь, что твой обработчик прерывания (судя по дизассемблированному коду) странный и уж сильно не похож на известные примеры.
2. Правильно ли инициализирован VIC? Если неправильно, то и не будет ни хрена вызываться по адресу 0х18.
3. Правильно ли инициализирован Uart2. Разрешено ли ему вырабатывать прерывание?

Я это к тому, что причин много и их надо все последовательно проверить.
aaarrr
Цитата(toykhee_menky @ Jun 30 2008, 19:43) *
FIFO разрешено, после посылки восьми символов оттуда появляется битик прерывания в VIC1RawIntr, т.е. прерывание до VIC вроде бы доходит.

Да, а VICIRQStatus что говорит?
toykhee_menky
Цитата(aaarrr @ Jul 3 2008, 14:25) *
Да, а VICIRQStatus что говорит?

До:
VIC1RawIntr=0x00000008 VIC1IRQStatus=0x00000000 VIC1FIQStatus=0x00000000
После:
VIC1RawIntr=0x02000008 VIC1IRQStatus=0x02000000 VIC1FIQStatus=0x00000000
aaarrr
Значит на ядро прерывание передается, других вариантов нет.
sergeeff
Ну дак и осталось то, про что я уже говорил - написать простейшую функцию:

void fun(void)
{
включить LED - прямой записью "1" на выход соответствующего порта, без вызова всяких других функций, чтобы не трогать стек
while(1);чтобы тут и остаться
}

Эту функцию подставить под адрес 0х38 и тут уж однозначно будет ясно, попадаем мы на это прерывание или нет.
Плевое дело нескольких минут, а многое прояснится.
toykhee_menky
Всем спасибо. Перешел на eCos.
sergeeff
Ну, флаг в руки!

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