|
Вложенные прерывания, GCC и ARM7 |
|
|
|
Mar 1 2010, 05:08
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
Доброго времени суток! Работаю с платой LPC2478, требуется реализовать вложенные (nested) прерывания. Нарыл несколько статей на эту тему, но пока ни один метод не запахал. Тестирую прерывания таким образом: Код void TestInterrupts::TestTimers() { myPrintf("\nSTART TestTimers()\n");
Timer0VICInit(Timer0ISR); Timer1VICInit(Timer1ISR); Timer1StartWithInt(1000);
myPrintf("\nEND TestTimers()\n"); }
void TestInterrupts::Timer0ISR() { T0IR = TIR_MR0_INT; // reset interrrupt flags myPrintf("\nTimer0ISR()\n"); // Dummy write to VIC to signal end of interrupt VICVectAddr = 0x00000000; }
void TestInterrupts::Timer1ISR() { IENABLE;
T1IR = TIR_MR0_INT; // reset interrrupt flags myPrintf("\nSTART Timer1ISR()\n"); Timer0StartWithInt(5000); volatile tU8 dummy = 0; while(1) { dummy = 0; } myPrintf("\nEND Timer1ISR()\n"); IDISABLE; // Dummy write to VIC to signal end of interrupt VICVectAddr = 0x00000000; } Где в качестве IENABLE пробовал разные последовательности ассемблерных команд, вычитанных с разных статей: Код // FROM Nesting of interrupts in the LPC2000 (AN10381) #define IENABLE /* Nested Interrupts Entry */ \ __asm__ ("MRS LR, SPSR"); /* Copy SPSR_irq to LR */ \ __asm__ ("STMFD SP!, {LR}"); /* Save SPSR_irq */ \ __asm__ ("MSR CPSR_c, #0x1F"); /* Enable IRQ (Sys Mode) */ \ __asm__ ("STMFD SP!, {LR}"); /* Save LR */ \ Код // FROM Real-time processing with the Philips LPC ARM microcontroller; using GCC and the MicroC/OS-II RTOS. #define IENABLE /* Nested Interrupts Entry */ \ __asm__ ("sub lr, lr, #4"); /* (1) Save IRQ context, including the APCS registers, and r4-6 */ \ __asm__ ("stmfd sp!, {r0-r6, ip, lr}"); \ __asm__ ("mrs r4, spsr"); /* (2) Save the SPSR_irq register */ \ __asm__ ("ldr r5, =0xFFFFFF00"); /* (3) Read the VICVectAddr */ \ __asm__ ("ldr r6, [r5]"); \ __asm__ ("msr cpsr_c, 0x1F"); /* (4) Change to SYS mode and enable IRQ */ \ __asm__ ("stmfd sp!, {lr}"); /* (5) Save the banked SYS mode link register */ \ То есть, на консоли должно появиться Цитата START TestTimers() END TestTimers() START Timer1ISR() START Timer0ISR() А на самом деле последняя строка не выводиться, что говорит о невхождении в обработчик вложенного прерывания Timer0. Так вот, первый мой вопрос, какая же все таки последовательной команд должна быть в прологе и эпилоге обработчика для LPC2478? И еще, во втором случае IENABLE полное описание вхождения и вывода их вложенных прерываний выглядит так: Цитата nested_irq_isr: /* (1) Save IRQ context, including the APCS registers, and r4-6 */ sub lr, lr, #4 stmfd sp!, {r0-r6, ip, lr} /* (2) Save the SPSR_irq register */ mrs r4, spsr /* (3) Read the VICVectAddr */ ldr r5, VICVECTADDR ldr r6, [r5] /* (4) Change to SYS mode and enable IRQ */ msr cpsr_c, #SYS_MODE /* (5) Save the banked SYS mode link register */ stmfd sp!, {lr} /* (6) Call the C-coded handler */ mov lr, pc ldr pc, r6 /* (7) Restore SYS mode link register */ ldmfd sp!, {lr} 36 AR1803 May 10, 2006 /* (8) Change to IRQ mode and disable IRQ */ msr cpsr_c, #IRQ_MODE|IRQ_DISABLE /* (9) Restore the SPSR */ msr spsr, r4 /* (10) Acknowledge the VIC */ mov r0, #0 str r0, [r5] /* (11) Restore IRQ context and return from interrupt */ ldmfd sp!, {r0-r6, ip, pc}^ И это описание натолкнуло меня на дополнительный вопрос, а можно ли в GCC переопределять последовательность операций для вызова функций, например путем создания собственных атрибутов для функций. И дальнейшим их использованием в примерно таком виде: Код static void Timer0ISR() __attribute__ ((my_nested_interrupt))
Сообщение отредактировал Novichok1 - Mar 1 2010, 05:14
|
|
|
|
|
 |
Ответов
|
Mar 4 2010, 23:57
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(GetSmart @ Mar 5 2010, 02:26)  театр одного актёра  Надо помочь, наверное, да пугают длинные копипасты мутного кода. Цитата(Novichok1 @ Mar 4 2010, 08:44)  И еще, если использовать директивы компилятора, указывающими на то что данная функция является обработчиком прерывания, то компилятор сам сохраняет изменяемые регистры, а тут мы это делаем ручками и для всех обработчиков, поэтому возникает вопрос, а достаточно ли сохранение первых семи регистров(stmfd sp!, {r0-r6, ip, lr})? Перед вызовом достаточно сохранить R0-R3, R12, R14, остальное вызываемая подпрограмма трогать не имеет права. R4-R6 портит сама обертка. Кроме того, следует обратить внимание на некорректное выравнивание стека - должно быть четное число слов. Использование одного обработчика для прерываний всех приоритетов - тоже, мягко говоря, не самая светлая идея. Цитата(Novichok1 @ Mar 4 2010, 08:44)  Так, если в обработчике первого прерывания происходит второе прерывания, а в вызванном обработчике второго прерывания происходит первое, то после выхода из обработчика программа глючит. Не происходит такого в нормальных условиях. Пока выполняется один обработчик прерывания с определенным приоритетом, другие прерывания с тем же или меньшим приоритетом маскируются. Иначе какой вообще смысл во вложенности?
|
|
|
|
|
Mar 5 2010, 04:59
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
Цитата(aaarrr @ Mar 5 2010, 02:57)  Перед вызовом достаточно сохранить R0-R3, R12, R14, остальное вызываемая подпрограмма трогать не имеет права. R4-R6 портит сама обертка. Кроме того, следует обратить внимание на некорректное выравнивание стека - должно быть четное число слов. Большое спасибо за разъяснение! А насчет некорректного выравнивания стека - после stmfd sp!, {r0-r6, ip, lr} через некоторое число команд вызывается еще и stmfd sp!, {lr} (на шаге 5), так что в сумме получается четное число сохраненных регистров, так можно рассуждать, или при выполнении ОДНОЙ команды записи в стек должно сохраняться четное число слов? Цитата(aaarrr @ Mar 5 2010, 02:57)  Использование одного обработчика для прерываний всех приоритетов - тоже, мягко говоря, не самая светлая идея. Я наверно не совсем точно выразился, под " ...для вызовов всех прерываний использую..." не имелось ввиду использование одного сишного обработчика для всех прерываний, а подразумевалась последовательность ассемблерных команд для подготовки ко входу в обработчик прерывания, вызова сишной функции обработчика, адрес которой лежит в регистре ViсVectAddr, и восстановления регистров и состояния проца после завершения обработчика. Так что для каждого прерывания у меня свой обработчик, как и положено. Цитата(aaarrr @ Mar 5 2010, 02:57)  Не происходит такого в нормальных условиях. Пока выполняется один обработчик прерывания с определенным приоритетом, другие прерывания с тем же или меньшим приоритетом маскируются. Иначе какой вообще смысл во вложенности? Вот в этом-то и дело! К примеру, если в процессе работы обработчика прерывания с приоритетом 5 (Timer1), происходит прерывание с приоритетом 4 (Timer0), то выставляются флаги прерывания в T0IR, VICIRQStatus, записывается нужный адрес в VicVecAddress, НО перехода в обработчик прерывания Timer0 не происходит до тех пор, пока мы не запишем что-либо в регистр VicVecAddress, что само собой разрешит прерывания всех приоритетов. Хотя ни в "AN10381(Nesting of interrupts in the LPC2000)", ни в "Real-time processing with the Philips LPC ARM microcontroller; using GCC and the MicroC/OS-II RTOS." про необходимость записи в регистр VicVecAddress для разрешения вложенных прерываний ничего не сказано. Там говорится о достаточности применения вышеописанных макросов IENABLE, IDISABLE, либо ассемблерной процедурине для входа и выхода из обработчика. Вот и интересно, что же я упустил? А вообще, рассмотрение сего вопроса началось из-за следующего глюка: вызывается функция, которая допускает появления прерываний, далее походу при появлении этих прерываний, ИНОГДА появляются лишние вызовы функций со странными параметрами. При рассмотрении это было похоже на следующее: 1. Вызвали функцию Func1(param1), 2. В этой функции произошло прерывание, в котором использовалось значение по адресу param_ISR 3. Вышли из прерывания 4. ЛИШНИЙ повторный вызов функции Func1(param_ISR) (прошу обратить внимание на изменившийся параметр!) 5. Дальнейший ход выполнения программы. Обработчик прерывания был отмечен атрибутом __attribute__ ((interrupt)), никаких макросов типа IENABLE не было, вход в обработчик был стандартным. Вот и складывается впечатление, что при входе-выходе из прерывания сохраняются-ресторятся не все регистры. Цитата театр одного актёра Благодарю за участие)
Сообщение отредактировал Novichok1 - Mar 5 2010, 05:17
|
|
|
|
|
Mar 5 2010, 10:04
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Novichok1 @ Mar 5 2010, 07:59)  Большое спасибо за разъяснение! А насчет некорректного выравнивания стека - после stmfd sp!, {r0-r6, ip, lr} через некоторое число команд вызывается еще и stmfd sp!, {lr} (на шаге 5), так что в сумме получается четное число сохраненных регистров, так можно рассуждать, или при выполнении ОДНОЙ команды записи в стек должно сохраняться четное число слов? На шаге 5 пишется уже другой стек (SYS), суммировать эти записи нельзя. Цитата(Novichok1 @ Mar 5 2010, 07:59)  Я наверно не совсем точно выразился, под " ...для вызовов всех прерываний использую..." не имелось ввиду использование одного сишного обработчика для всех прерываний, а подразумевалась последовательность ассемблерных команд для подготовки ко входу в обработчик прерывания Я ее и имел в виду. Для прерывания с высшим приоритетом эта ассемблерная последовательность - пустая трата времени. Цитата(Novichok1 @ Mar 5 2010, 07:59)  Вот и интересно, что же я упустил? Вложенные прерывания предполагают, что выполнение процедуры обработки прерывания с приоритетом 5 может быть прервано прерыванием с приоритетом 6 или выше. Прерывание с меньшим приоритетом (4) может отработать только после записи VicVectAddr.
|
|
|
|
Сообщений в этой теме
Novichok1 Вложенные прерывания, GCC и ARM7 Mar 1 2010, 05:08 sergeeff Про прерывания а форуме для ARM столько уже понапи... Mar 1 2010, 06:57 Novichok1 Цитата1. Заставить VIC вызывать по прерыванию С++ ... Mar 1 2010, 08:07 Novichok1 Может и правда, дело в стартапе, выложу его на вся... Mar 1 2010, 09:12 Novichok1 Хорошо, частично разобрался, для вызовов всех прер... Mar 4 2010, 05:44 Novichok1 И благодаря такому подходу исчезли глюки, которые ... Mar 4 2010, 07:06 GetSmart театр одного актёра Mar 4 2010, 23:26   GetSmart Цитата(aaarrr @ Mar 5 2010, 15:04) Вложен... Mar 5 2010, 12:14    Novichok1 Цитата(GetSmart @ Mar 5 2010, 15:14) Это ... Mar 5 2010, 12:43     GetSmart Цитата(Novichok1 @ Mar 5 2010, 17:43) То ... Mar 5 2010, 12:54      Novichok1 Цитата(GetSmart @ Mar 5 2010, 15:54) То б... Mar 5 2010, 13:12   Novichok1 Цитата(aaarrr @ Mar 5 2010, 13:04) Вложен... Mar 5 2010, 12:23 GetSmart Цитата(Novichok1)Вот и складывается впечатление, ч... Mar 5 2010, 06:44 Novichok1 Ну точнее, там используется два источника прерыван... Mar 5 2010, 07:22 GetSmart Если после команды ldmfd в эпилоге второго ничего ... Mar 5 2010, 07:43 Novichok1 Цитата(GetSmart @ Mar 5 2010, 10:43) Если... Mar 5 2010, 07:47 GetSmart ЦитатаВсе-таки кажется странным, что некорректный ... Mar 5 2010, 12:35 Novichok1 Цитата(GetSmart @ Mar 5 2010, 15:35) Со с... Mar 5 2010, 12:55 aaarrr Цитата(Novichok1 @ Mar 5 2010, 15:23) А н... Mar 5 2010, 12:41 GetSmart Это не свой атрибут, а стандартный. Используется т... Mar 5 2010, 13:03 GetSmart Цитата(Novichok1)Спасибо, а не в курсе,
Не, не в к... Mar 5 2010, 14:03 GetSmart Novichok1, хотел ещё спросить, зачем было делать о... Mar 11 2010, 12:21 Novichok1 А разве к статическим членам нет доступа? Ведь обр... Mar 11 2010, 15:07 GetSmart Я бы всё таки выделил прерывания из класса. ИМХО э... Mar 11 2010, 16:35 Novichok1 Цитата(GetSmart @ Mar 11 2010, 20:35) Зна... Mar 11 2010, 18:22 GetSmart Вообще, излишняя универсальность, которая не понад... Mar 11 2010, 19:02 Novichok1 Цитата(GetSmart @ Mar 11 2010, 22:02) А ч... Mar 12 2010, 04:49 GetSmart Цитата(Novichok1)Но в любом случае, мне не совсем ... Mar 12 2010, 05:50 Aurochs Цитата(GetSmart @ Mar 12 2010, 07:50) Так... Mar 13 2010, 18:30
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|