Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вложенные прерываня
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
moonrock
Всем привет, недавно начал разбираться с LPC2132, среда - Keil uVision,
и вот встал вопрос, как сделать, чтобы прерывания с высшим приоритетом могли прерывать исполнение обработчиков прерываний с низшим приоритетом?
DASM
Цитата(moonrock @ Jul 8 2006, 00:39) *
Всем привет, недавно начал разбираться с LPC2132, среда - Keil uVision,
и вот встал вопрос, как сделать, чтобы прерывания с высшим приоритетом могли прерывать исполнение обработчиков прерываний с низшим приоритетом?

А никак. Прерывания всего два IRQ и FIQ. Есть конечно разные приоритеты в VIC - но их смысл только в том, какое из нескольких прерываний (если случилось несколько) будет вызвано при разрешении прерываний.
Andrew2000
Цитата(DASM @ Jul 8 2006, 02:04) *
А никак.

Ну, не правда. Вложенные прерывания возможны. Чтоб приоритеты - надо будет маску прерываний ручками подправлять.
В книге, которая про ARM LPC по-русски (забыл как называется, под рукой нет) это рассматривается (поищите по конфе).

А заодно (почти в тему) - вот попадаю я в обработчик IRQ по умолчанию и хочу перевести бит-флаги в номер прерывания (чтоб по таблице функцию-обработчик найти), т.е. мне надо узнать позицию (номер бита) младщей единицы (в XScale инструкция CLZ есть, а в LPC?).

Написал такое, но асм для ARM я почти не знаю, может кто подчкажет как оптимизировать?

/* in: r3 - bit mask */
/* out: r1 - int num */
MOV r1,#0
findirqstart:
AND r4, a3, #1
CMP r4, #0
BNE findirqend

ADD r1, r1, #1
MOV r3, r3, lsr #1
B findirqstart
findirqend:
moonrock
как я понимаю, такое ограничение накладывает контроллер прерываний филипса, а есть ли вообще контроллеры, которые это позволяют? Ведь, если я не ошибаюсь, такое может делать AVR...
GetSmart
Извращенцы вы тут все. Говорят о том, что не знают. Даже помогать после этого не хочется.

На АРМе это всё делается элементарно. Почитайте в хэлпе об __nested
Может потом на вопросы отвечу.
aaarrr
Читать лучше не абстрактные хелпы, а обратиться к первоисточнику. Сразу отпадут многие вопросы.
DASM
да... был неправ. Всем спасибо, век живи - век учись
moonrock
Всем большое спасибо, а вот тот ответ, который я хотел услышать:
ARM 7 аппаратно НЕ поддерживает вложенные прерывания, но обеспечить их можно софтварным путём, используя следующие асмовые макросы
#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 */ \

#define IDISABLE /* Nested Interrupts Exit */ \
__asm { LDMFD SP!, {LR} } /* Restore LR */ \
__asm { MSR CPSR_c, #0x92 } /* Disable IRQ (IRQ Mode) */ \
__asm { LDMFD SP!, {LR} } /* Restore SPSR_irq to LR */ \
__asm { MSR SPSR_cxsf, LR } /* Copy LR to SPSR_irq */ \

и втыкать их перед и после того кода обработчика прерывания более низким приоритетом, который мы хотим прерывать
ещё раз всем спасибо
yuri_t
IMHO,без крайней необходимости с nested interrupt в ARM7/9 лучше не связываться -
весьма коварная штука. Ну а если все таки без этого никак, рекомендую использовать
код из книги A.Sloss,D.Symes,C.Wright, ARM System Developer's Guide - Designing and
Optimizing System Software
zltigo
Цитата(moonrock @ Jul 8 2006, 12:23) *
ARM 7 аппаратно НЕ поддерживает вложенные прерывания

Осталось выяснить КТО аппаратно подерживает сохранение контекстов для КАЖДОГО из
возможных прерываний :-)). На самом деле достоинством является вообще наличие аппаратно переключаемого стека и собственных регистров FIQ и IRQ. Таким образом "софтовая" организация
вложенных прерываний является абсолютно естественной а не каким-то "извращением" являющимся дурной особенностью ARM7.

Цитата(yuri_t @ Jul 8 2006, 13:17) *
IMHO,без крайней необходимости с nested interrupt в ARM7/9 лучше не связываться -
весьма коварная штука.

Не коварнее организации вложенных прерываний на любом другом процессоре, но проектировать систему со вложенными прерываниями действительно нужно только в случае крайней необходимости.
aaarrr
Цитата(moonrock @ Jul 8 2006, 13:23) *
...но обеспечить их можно софтварным путём, используя следующие асмовые макросы

А вот это не советую. Лучше потратить чуть больше времени, и оформить вход и выход из прерывания в виде ассемблерного модуля. В этом случае результат не будет зависеть от компилятора и степени вашего с ним взаимопонимания.
GetSmart
Те же, кто не хочет использовать много асма, могут писать всё на Си и при этом не бояться что что-то плохо будет работать. Это не так. У меня во многих прогах уровень вложенности может доходить до 5-8 и всё работает стабильнее некуда. На асме написан только стартап файл. Поэтому рекомендую, если в программе полезны вложенные прерывания - используйте их наздоровье. Самые критичные прерывания разумеется должны быть непрерываемыми (без __nested). А так, в АРМ7 всё сделано красиво, если кто не понимает почему, их проблемы. Да, и ещё. Прерывания без __nested работают на стеке IRQ|FIQ. А объявленные с __nested работают на стеке основной программы, и ещё в стеке IRQ|FIQ дополнительно занимают 3-4 слова.
zltigo
Цитата(GetSmart @ Jul 8 2006, 15:14) *
У меня во многих прогах уровень вложенности может доходить до 5-8

Нашли, чем гордится :-(((
Цитата
и всё работает стабильнее некуда.

Ну на принципиальную нестабильность механизма вложенности никто и не жаловался...
Если у Вас простейшая системка, хоть и 8 прерываниями, но простейшая с мало или не зависящими от результатов работы друг друга обработчиками, то проблем не будет особых. Ну а если нужно будет разруливать все нюансы взаимодействия недозавершенных обработчиков с их прервавшими и т.д., то уже потенциальных ошибок много больше :-(. Разруливание опять таки в обработчиках, что есть дополнительный код и время.
Цитата
Да, и ещё. Прерывания без __nested работают на стеке IRQ|FIQ. А объявленные с __nested работают на стеке основной программы, и ещё в стеке IRQ|FIQ дополнительно занимают 3-4 слова.

Ага, и это есть хреново, ибо когда у Вас единственная основная программка с единственным стеком, то
оно и ладно, а если у меня их количество десятками исчисляется? Прикажете в стеке каждой
заложить место для стеков многочисленных ее прервавших? Причем поскольку необходимость вложенности перерываний почти всегда следует из громоздкости обработчика, то и требования к размеру стека скорее всего будут заметными :-(.

В общем случае нужно СИЛЬНО думать и все взвешивать перед тем как использовать вложенные прерывания.
Andrew2000
А на мой вопрос про завменитель CLZ кто-нить может ответить?
aaarrr
Цитата(GetSmart @ Jul 8 2006, 16:14) *
Те же, кто не хочет использовать много асма, могут писать всё на Си...

Я лишь предложил способ, пригодный для использования на любом компиляторе. Слово __nested ADS, например, не знает.

Цитата(Andrew2000 @ Jul 8 2006, 17:00) *
А на мой вопрос про завменитель CLZ кто-нить может ответить?

Могли бы уже и сами посмотреть список команд для архитектуры V4. Нет там прямой замены.

P.S. ztigo: за раскрытие темы подводных камней a14.gif
zltigo
Цитата(Andrew2000 @ Jul 8 2006, 16:00) *
А на мой вопрос про завменитель CLZ кто-нить может ответить?

В ядре ARM7 нет. Если нужна скорость - используйте _сразу_ полную или частичную таблицу.
Andrew2000
Цитата(aaarrr @ Jul 8 2006, 17:06) *
Могли бы уже и сами посмотреть список команд для архитектуры V4. Нет там прямой замены.

Знаю, что нет, поэтому (повторю вопрос)

Написал такое, но асм для ARM я почти не знаю, может кто подскажет как оптимизировать?

/* in: r3 - bit mask */
/* out: r1 - int num */
MOV r1,#0
findirqstart:
AND r4, a3, #1
CMP r4, #0
BNE findirqend

ADD r1, r1, #1
MOV r3, r3, lsr #1
B findirqstart
findirqend:


Про таблицу не понял, ну младшую 1 выделить не сложно, а дальше...
zltigo
Цитата(Andrew2000 @ Jul 8 2006, 16:48) *
Про таблицу не понял, ну младшую 1 выделить не сложно, а дальше...

Таблица содержащая номер бита или _сразу_ указатель на функцию.
Если предполагается работа с полноразрядным числом, то можно для экономии размера таблицы использовать сокращенную 16, 8 или 4 битную.
0x0 ?
0x1 0
0x2 1
0x3 0
0x4 2
0x5 0
0x6 1
0x7 0
0x8 3
0x9 0
......
aaarrr
Цитата(Andrew2000 @ Jul 8 2006, 17:48) *
Написал такое, но асм для ARM я почти не знаю, может кто подскажет как оптимизировать?

Здесь посмотрите. Пост №48 by sergeeff.
GetSmart
Цитата(zltigo @ Jul 8 2006, 16:38) *
Не коварнее организации вложенных прерываний на любом другом процессоре, но проектировать систему со вложенными прерываниями действительно нужно только в случае крайней необходимости.

Ага. Скажите прямо, проектировать систему в которой будут сидеть на прерываниях более одного периферийного устройства крайне опасно. Бог его знает, что может произойти. И если в моей программе вдруг потребовалось одновременно обрабатывать все 8 capture-входов, PWM, два UARTа, RTC и пару вшешних прерываний, то это ну очень крайняя необходимость, которая у других никогда не возникает. Причём всё бы ничего, если бы capture не требовали максимально быстрого отклика. А так пришлось все прерывания кроме них сделать вложенными. Гордится этим? Слишком мелко как-то. Я бы гордился скажем 20-ю вложенными прерываниями. Если у вас ничего интересного нет по поводу смешивания вложенных и невложенных прерываний и как с помощью их комбинаций можно оптипизировать систему в целом, то можете говорить и дальше что это плохо и неразумно. Многие с удовольствием послушают.
zltigo
Цитата(GetSmart @ Jul 8 2006, 18:22) *
И если в моей программе вдруг потребовалось одновременно обрабатывать все 8 capture-входов, PWM, два UARTа, RTC и пару вшешних прерываний, то это ну очень крайняя необходимость, которая у других никогда не возникает. Причём всё бы ничего, если бы capture не требовали максимально быстрого отклика. А так пришлось все прерывания кроме них сделать вложенными.

Ну и где в описанной системе 8 "УРОВНЕЙ ВЛОЖЕННОСТИ" помянутые в ПЕРВОНАЧАЛЬНОМ посте???
В этом черным по белому описан вариант одного уровня, причем его наличие обосновано, хотя и не понятно, почему-бы не использовать для CAP FIQ, если конечно у Вас не дебильноватый контроллер типа STR7..... В принципе именно армовские IRQ+FIQ без дополнительной организации вложенности достаточно хорошо закрывают массу вариантов применения, в том числе и описанный Вами.
DASM
А вот и не подеретесь unsure.gif smile3009.gif
Zltigo - а чего в ентих STR дебильного ? Просто интересно.. Вкратце, пару слов
zltigo
Цитата(DASM @ Jul 8 2006, 19:42) *
Zltigo - а чего в ентих STR дебильного ? Просто интересно.. Вкратце, пару слов

Там на FIQ вешаются _только_ Watchdog и Timer0 - абсолютно необъяснимая дурь.

Да и в остальном контроллер прерываний там заметно примитивнее :-( по отношению к прочим сделанным производителями чипов по ARMовским лекалам.
DASM
a14.gif Да уж... Мне как-то повезло... Ни разу FIQ не надо было и вложенность тоже... Отсюда гигантская дыра в знаниях =)
GetSmart
Цитата(zltigo @ Jul 8 2006, 21:52) *
Ну и где в описанной системе 8 "УРОВНЕЙ ВЛОЖЕННОСТИ" помянутые в ПЕРВОНАЧАЛЬНОМ посте???

Собственно 8 уровней мне не надо было. Они возникают сами по себе при объявлении любого прерывания __nested. Поэтому если в системе 8 прерываний, 2 простых, 6 __nested, то если никак дополнительно не извращаться, будут именно 7 уровней вложенности. А теперь почему они сделаны __nested. Например, после приёма байта по UARTпрямо в прерывании вызывается драйвер связи, который может долго не возвращать управление, ну скажем до 100 мкс. Всё это время он не мешает никаким прерываниям с более высоким приоритетом. А в некоторых случаях (приём полного пакета) он ещё и взводит софтовое прерывание с более низким приоритетом. Так, что как только это прерывание завершится и если ничего более важного не произойдёт, управление вернётся не в основную прогу, а в софтовое прерывание связи. В нём вообще может управление застрять на десятки миллисекунд. И никто не обломается! Никаких критических секций и прочих извращений для этого применять не нужно вообще. Всё продумано и очень просто в применении. Бояться вложенных прерываний - в лес не ходить.

Насчёт FIQ'ов, я всё прекрасно знал. И всё-таки решил сделать так. Всё написано на Си, никаких макросов.
zltigo
Цитата(GetSmart @ Jul 8 2006, 20:38) *
Они возникают сами по себе при объявлении любого прерывания __nested.

Когда что-то "возникает само по себе" это не радует :-(. А реально никто не мешает для описанного Вами случая в __nested запретить прерывание одного __nested другим ввиду ПОЛНОЙ НЕНУЖНОСТИ сего действия. И я не назвал-бы это "извращением" - напротив. Если-бы в ARMообразных контроллерах могли назначаться одинаковые приоритеты для разных источников, то это вообще реализовывалось без каких-либо дополнительных телодвижений.
Цитата
А теперь почему они сделаны __nested.

Это не нуждается в дополнительных объяснениях - "надо быстро реагировать на CAP" было вполне достаточно.
Цитата
Бояться вложенных прерываний - в лес не ходить.

Я не призываю их бояться я сам их использую, просто их не надо использовать без необходимости и уж точно бороться с возникающими "сами по себе" побочными эффектами в виде вложенности в местах, где это без надобности. Ибо, как минимум, ведет к дополнительным затратам временных ресурсов и памяти. При этом можно получить неожиданные проблемы (особенно при дописывании через годик-другой) при работе обработчиков с общими ресурсами. При совсем уже чрезмерном увлечении длинными вложенными обработчиками можно и повторный вызов обработчика схлопотать, от которого тоже надо защиту вписывать. В общем оно это надо без крайней необходимости?
Цитата
Насчёт FIQ'ов, я всё прекрасно знал. И всё-таки решил сделать так.

Т.е. для конкретного описанного случая запутаннее и тормознее :-( без явной на то необходимости, а только по причине наличия в EWARM
удобного ключевого слова __nested :-(.
GetSmart
Цитата
можно и повторный вызов обработчика схлопотать

Повторный вызов не схлопотать. Запрещаются все приоритеты равные и ниже текущего. А то, что нельзя делать одинаковые приоритеты я и сам жалею. Помню как удобно было на 51/52 процах с трёхуровневой системой прерываний. Быстро и удобно.

В данном вопросе только один минус - лишняя многоуровневость. Но гораздо больше плюсов. Особенно быстрое время реакции на все прерывания с учётом приоритетов. А медленные софтверные прерывания вообще не сделать без вложенности.

Цитата
просто их не надо использовать без необходимости

Не-а. Я бы советовал не использовать обычные прерывания без особой необходимости. Особенно длинные или использующие много стека.
moonrock
блин, тут все такие умные, один умней другого, аж страшно задавать следующий глупый вопрос smile.gif , но всё же задам: мой компилятор(keil uVision) не знает ключевое слово __nested, чем вы пользуетесь?
zltigo
Цитата(moonrock @ Jul 8 2006, 22:37) *
мой компилятор(keil uVision) не знает ключевое слово __nested, чем вы пользуетесь?

1. Я не полльзуюсь Keil.
2. А зачем своими руками выдрав и отпостив из кейловских рекомендаций два макроса спрашивать
чем пользоваться в Keil???

Не сильно страшно?





Цитата(GetSmart @ Jul 8 2006, 22:32) *
Не-а. Я бы советовал не использовать обычные прерывания без особой необходимости. Особенно длинные или использующие много стека.

Без коментариев.
GetSmart
Я старым (уже) IAR 4.20
Тут где-то выкладывали ссылку на 4.30, а может даже и на 4.40.


Цитата(zltigo @ Jul 9 2006, 02:02) *
Без коментариев.

Без коментариев.
Andrew2000
Цитата(aaarrr @ Jul 8 2006, 18:12) *
Цитата(Andrew2000 @ Jul 8 2006, 17:48) *

Написал такое, но асм для ARM я почти не знаю, может кто подскажет как оптимизировать?

Здесь посмотрите. Пост №48 by sergeeff.

Спасибо, то, что надо.
Nixon
Цитата(moonrock @ Jul 8 2006, 22:37) *
блин, тут все такие умные, один умней другого, аж страшно задавать следующий глупый вопрос smile.gif , но всё же задам: мой компилятор(keil uVision) не знает ключевое слово __nested, чем вы пользуетесь?

Keil не нужно __nested для описания вложенных прерываний. Достаточно пользоваться макросами IENABLE и IDISABLE в функции обработчика прерывания. Очень хорошие примеры вложенных прерываний (там почти все обработчики сделаны этими макросами с поддержкой вложенных прерываний) есть у филипса в примерах кода к lpc21xx (адрес не знаю, искать "code.bundle.lpc213x.lpc214x.uvision.zip").

В качестве примера
Код
void EINT1_Handler (void) __irq
{
    EXTINT = EINT1;        /* clear interrupt */
        
    IENABLE;            /* handles nested interrupt */
    eint1_counter++;
    if ( eint1_counter & 0x01 )    /* alternate the LED display */
    {
    IOSET1 = 0x000F0000;    /* turn off P1.20~23 */    
    IOCLR1 = 0x00F00000;    /* turn on P1.16~19 */
    }
    else
    {
    IOSET1 = 0x00F00000;    /* turn on P1.20~23 */    
    IOCLR1 = 0x000F0000;    /* turn off P1.16~19 */
    }
    IDISABLE;
    VICVectAddr = 0;        /* Acknowledge Interrupt */
}


Сами макросы тоже просты
Код
// Macros for Interrupt Nesting
#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                 */   \

#define IDISABLE                            /* Nested Interrupts Exit  */   \
  __asm { LDMFD   SP!, {LR}     }           /* Restore LR              */   \
  __asm { MSR     CPSR_c, #0x92 }           /* Disable IRQ (IRQ Mode)  */   \
  __asm { LDMFD   SP!, {LR}     }           /* Restore SPSR_irq to LR  */   \
  __asm { MSR     SPSR_cxsf, LR }           /* Copy LR to SPSR_irq     */   \
Сергей Борщ
Цитата(Nixon @ Jul 10 2006, 19:08) *
В качестве примера
Код
void EINT1_Handler (void) __irq
{
    EXTINT = EINT1;        /* clear interrupt */
        
    IENABLE;            /* handles nested interrupt */
         ....................
    IDISABLE;
    VICVectAddr = 0;        /* Acknowledge Interrupt */
}
Скорее всего я чего-то не понимаю, но все же: как может вызваться в этом примере вложенное прерывание если VICVectAddr = 0; стоит в самом конце обработчика? Ведь пока не сделан VICVectAddr = 0 контроллер не выдаст адрес следующего обработчика?
aaarrr
Цитата(Сергей Борщ @ Jul 10 2006, 20:25) *
Скорее всего я чего-то не понимаю, но все же: как может вызваться в этом примере вложенное прерывание если VICVectAddr = 0; стоит в самом конце обработчика? Ведь пока не сделан VICVectAddr = 0 контроллер не выдаст адрес следующего обработчика?

До записи VICVectAddr может быть вызвано только прерывание с более высоким приоритетом.
zltigo
Цитата(aaarrr @ Jul 10 2006, 19:34) *
До записи VICVectAddr может быть вызвано только прерывание с более высоким приоритетом.

Проверить достаточно легко, можно и о PrimeCell почитать первоисточник. Но по логике вещей так быть не может, ибо в этом случае при возникновении последовательно прерываний от разных источников будут потеряны все низкоприоритетные, если процесс обработки не успеет считать значение из VicVectAddr и оно будет перезаписано более приоритетным адресом обработчика. В общем как ни крути именно процедура произвольной записи в VicVectAddr логично разрешает занесение нового (вне зависимости от его приоритета) значения в этот регистр. Ну а примеры, как это почти всегда :-( бывает просто фуфло.
aaarrr
Цитата(zltigo @ Jul 10 2006, 21:06) *
Проверить достаточно легко, можно и о PrimeCell почитать первоисточник.

Вот и почитайте:
Код
Reading from the Vector Interrupt Address Register,
VICVECTADDR, provides the address of the ISR, and updates the interrupt priority
hardware that masks out the current, and any lower priority interrupt requests. Writing
to the VICVECTADDR Register indicates to the interrupt priority hardware that the
current interrupt is serviced, enabling lower priority or the same priority interrupts to be
removed, and for the interrupts to become active to go active.
zltigo
Цитата(aaarrr @ Jul 10 2006, 20:12) *
Код
Reading from the Vector Interrupt Address Register,
......

Достаточно убедительно и в такой трактовке работоспособно, хотя настораживает фраза "the same priority", которых быть не должно.
Короче желательно проверить электроникой, что и сделаю сегодня.

Проверено!
Действительно, чтение " Vector Interrupt Address Register" несет дополнительную функциональную нагрузку в виде перетасовки приоритетов и даже без последующей записи
позволяет функционировать более приоритетным прерываниям. Это хорошо, обязательно использую!
Эксперимент проводился на LPC2148 у которого контроллер прерываний от ARM прикручен.
Angle
Подскажите, если кто знает, пример кода для обработчика вложенных прерываний для AT91SAM7A3, компилятор Keil.
xelax
Цитата(Angle @ Oct 1 2007, 14:55) *
Подскажите, если кто знает, пример кода для обработчика вложенных прерываний для AT91SAM7A3, компилятор Keil.


Из примеров на сайте atmela wink.gif Исходя из примера вложенность прерываний делается просто.
В филипсах таким вопросом не озадачивался, поэтому не совсем понятно зачем народ здесь копья ломает 07.gif

Код
irq_handler:
/*- Manage Exception Entry */
/*- Adjust and save LR_irq in IRQ stack */
        sub      lr, lr, #4
        stmfd    sp!, {lr}
/*- Save r0 and SPSR in IRQ stack */
        mrs      r14, SPSR
        stmfd    sp!, {r0,r14}

/*- Write in the IVR to support Protect Mode */
/*- No effect in Normal Mode */
/*- De-assert the NIRQ and clear the source in Protect Mode */
        ldr      r14, =AT91C_BASE_AIC
        ldr      r0 , [r14, #AIC_IVR]
        str      r14, [r14, #AIC_IVR]

/*- Enable Interrupt and Switch in Supervisor Mode */
        msr      CPSR_c, #ARM_MODE_SVC

/*- Save scratch/used registers and LR in User Stack */
        stmfd    sp!, {r1-r3, r12, r14}

/*- Branch to the routine pointed by the AIC_IVR */
        mov      r14, pc
        bx       r0

/*- Restore scratch/used registers and LR from User Stack */
        ldmia    sp!, {r1-r3, r12, r14}

/*- Disable Interrupt and switch back in IRQ mode */
        msr      CPSR_c, #ARM_MODE_IRQ | I_BIT

/*- Mark the End of Interrupt on the AIC */
        ldr      r14, =AT91C_BASE_AIC
        str      r14, [r14, #AIC_EOICR]

/*- Restore SPSR_irq and r0 from IRQ stack */
        ldmia    sp!, {r0,r14}
        msr      SPSR_cxsf, r14

/*- Restore adjusted  LR_irq from IRQ stack directly in the PC */
        ldmia    sp!, {pc}^
Tannen
Мои пять копеек вопроса про вложенные прерывания. на LPC2148 делаю захват CAP0 по таймеру TIMER0.
По отдельности от сигнала подаваемого на все 4 входа захвата( синхронный фронт на все 4 входа) - все работает - счетчик импульсов тикает.
Когда все вместе ( захватывается только 1-он первый канал (((
пишу под IAR. мой код прерываний - т.к. инициализация корректна
Код
__irq __nested __arm void irq_handler (void)
{
void (*interrupt_function)();
  unsigned int vector;
   vector = VICVectAddr;                   // Get interrupt vector.
   interrupt_function = (void(*)())vector; // Call MM_TIMER0_ISR thru pointer
  (*interrupt_function)();  // Call vectored interrupt function
  VICVectAddr = 0;          // Clear interrupt in VIC
}

void  MM_TIMER0_ISR()
{
   volatile unsigned int iPR;
  unsigned char PriA;
if(T0IR_bit.CR0INT)
  {
  
    TVK[0]++;
    if(VKN&0x01)
         {
           TCapi[0]=TCap[0];
           TCap[0] =T0CR0;
         }
    if(TVK[0]==1) VKN&=~0x01;
  T0IR_bit.CR0INT=1; // clear interrupt
  }
  
  // CAP_1
  if(T0IR_bit.CR1INT)
  {
    TVK[1]++;
    if (VKN&0x02)
    {
         TCapi[1]=TCap[1];
         TCap[1] =T0CR1;
    }
    if(TVK[1]==1) VKN&=~0x02;
   T0IR_bit.CR1INT=1;  // clear inteerupt
  }
  if(T0IR_bit.CR2INT)
  {  
     TVK[2]++;
    if (VKN&0x04)
    {
      TCapi[2]=TCap[2];
      TCap[2] =T0CR2;
    }
    if(TVK[2]==1) VKN&=~0x04;
  T0IR_bit.CR2INT=1;
  }
  
  if(T0IR_bit.CR3INT)
  {  
     TVK[3]++;
    if (VKN&0x08)
    {
      TCapi[3]=TCap[3];
      TCap[3] =T0CR3;
    }
    if(TVK[3]==1) VKN&=~0x08;
    T0IR_bit.CR3INT=1;
  }

Ну и как здесь будет реализована вложенность прерываний? ято я не так делаю ? (((
Сергей Борщ
Цитата(Tannen @ Jun 18 2009, 16:17) *
Код
  T0IR_bit.CR0INT=1; // clear interrupt

что я не так делаю ? (((
В этой строчке вы сбрасываете не только этот флаг, но и все остальные. Потому что доступ к битовому полю происходит как операция "чтение-модификация-запись" чтобы не испортить остальные поля. Откуда же компилятору знать, что для этого регистра так делать нельзя. Это раз.
Второе - непонятно, зачем вам тут вложенные прерывания. Разрешаются вложенные прерывания только более высокого приоритета, т.е. в этот же обработчик вы не попадете.
Третье - вынесите свой irq_handler в ассемблерный файл в виде команды LDR PC,[PC, #-0x0FF0] прямо на векторе прерывания, а VICVectAddr = 0 и __irq __arm перенесите в каждый обработчик. Вот тут пример для SAM7, для LPC меняются имена регистров. Это позволит компилятору генерить максимально эффективные (короткие) прологи/эпилоги и существенно повысит скорость обработки прерываний, а вам позволит использовать __nested только для тех обработчиков, в которых он действительно нужен (например, в самых приоритетных он не нужен - прервать такой обработчик некому - и только замедляет эти самые важные обработчики).
Четвертое - вам надо в этом обработчике организовать цикл do{}while(T0IR);
KeiserSose
Цитата(GetSmart @ Jul 8 2006, 22:32) *
Повторный вызов не схлопотать. Запрещаются все приоритеты равные и ниже текущего. А то, что нельзя делать одинаковые приоритеты я и сам жалею. Помню как удобно было на 51/52 процах с трёхуровневой системой прерываний. Быстро и удобно.

В данном вопросе только один минус - лишняя многоуровневость. Но гораздо больше плюсов. Особенно быстрое время реакции на все прерывания с учётом приоритетов. А медленные софтверные прерывания вообще не сделать без вложенности.


Не-а. Я бы советовал не использовать обычные прерывания без особой необходимости. Особенно длинные или использующие много стека.


Повторный вызов можно схлопотать элементарно. VicVectAddr=0 открывает ВСЕ прерывания. Нужно явно маскировать и восстанавливать приоритеты.
aaarrr
Цитата(KeiserSose @ Jun 19 2009, 11:30) *
Повторный вызов можно схлопотать элементарно. VicVectAddr=0 открывает ВСЕ прерывания. Нужно явно маскировать и восстанавливать приоритеты.


Ошибаетесь:
Цитата
Writing to the VICVECTADDR Register indicates to the interrupt priority hardware that the
current interrupt is serviced, enabling lower priority or the same priority interrupts to be
removed, and for the interrupts to become active to go active.
KeiserSose
Цитата(aaarrr @ Jun 19 2009, 10:36) *
Ошибаетесь:


Если мы обсуждаем версию ARM PrimeCell, используемую в большинстве LPC, то ошибаетесь Вы. Действительно, при чтении VicVectAddr, контроллер повышает приоритет разрешенных прерываний до уровня текущего прерывания. Это обеспечивает правильный вход в стэк прерываний, но только до первой записи в VicVectAddr, что сбрасывает логику контроллера. Таким образом, незавершенные ISR могут прерываться прерываниямм с более низким приоритетом, если прерывания этого типа разрешены в CPSR. Макросы Keil'a просто открывают прерывания. Никакого "Handle nested interrupt" в них нет. VicSWPriorityMask должен быть использован для правильной реализации вложенности.
aaarrr
Цитата(KeiserSose @ Jun 19 2009, 13:11) *
Если мы обсуждаем версию ARM PrimeCell, используемую в большинстве LPC, то ошибаетесь Вы.

Во-первых, и так понятно, что речь шла о pl190, у pl192 этот регистр называется VICADDRESS.
Во-вторых читаем (pl192):
Цитата
The PrimeCell VIC implements two forms of interrupt priority masking:

Hardware masking
The hardware masking is applied whenever an interrupt is being serviced,
either with a read from the VICADDRESS Register, or by asserting the
VICIRQACK input when the VIC port is used. This prevents other
active interrupts of an equal or lower priority generating a new IRQ while
the interrupt service routine is being executed. When the interrupt routine
has completed and the VICADDRESS Register has been written to, the
interrupt mask is cleared to allow all enabled interrupt sources through.
Note
The VICIRQSTATUS and VICRAWINTR Registers are not affected by
this masking.

Software masking
The software masking is applied using the value programmed into the
VICSWPRIORITYMASK Register. This mask is applied continuously,
and at the same time as the hardware mask when an interrupt is being
serviced.
Note
The values in the VICIRQSTATUS and VICRAWINTR Registers do not
reflect the masking by the VICSWPRIORITYMASK Register.

и еще:
Цитата
Writing to the VICADDRESS
Register indicates to the interrupt priority hardware that the current interrupt is serviced,
enabling the masking of lower priority or the same priority interrupts to be removed and
for the interrupts to become active.

И как получается вывод
Цитата
VicSWPriorityMask должен быть использован для правильной реализации вложенности.

?

Программное управление приоритетами было введено в дополнение к аппаратному, и никак его не отменяет:
Цитата
Software-programmable interrupt priority level masking added, in addition to the
hardware priority level masking.
KeiserSose
Убедил. Был неправ. Вспылил.
Step_ARM
Половину не понял из того, что написано...
Хотя вопрос сильно интересует.
Проц. LPC2364
INT2(Р2.12) & INT3(Р2.13) подключены как счетные входы. Частоты примерно 400-500 Гц и 200-250Гц.

Обработчики такие:

__irq __nested __arm void EINT2_Handler (void)
{
EXTINT|= EINT2; /* clear interrupt */
__enable_interrupt(); /* handles nested interrupt */
//***********************************************************

ssf_o++;

//***********************************************************
VICVectAddr = 0; /* Acknowledge Interrupt */
}
__irq __nested __arm void EINT3_Handler (void)
{

EXTINT|= EINT3; /* clear interrupt */
__enable_interrupt(); /* handles nested interrupt */
//***********************************************************
count_msr++;


//***********************************************************
VICVectAddr = 0; /* Acknowledge Interrupt */
}

Короче работает только один счетчик , прерывание которого имеет больший приоритет.
Если убираю _nested и __enable_interrupt(); дела не меняет, тоже самое.

Тоже самое на 51-х, Меге и NEC работает прекрасно. Вопрос КАК извернуться? Объясните, пожалуйста , что не так...
meister
Цитата(Step_ARM @ Jun 23 2009, 09:43) *
Короче работает только один счетчик , прерывание которого имеет больший приоритет.
Вопрос КАК извернуться? Объясните, пожалуйста , что не так...


Когда ничего не помогает, прочтите, наконец, инструкцию.

This bit is cleared by writing a one to it, except in level sensitive mode when
the pin is in its active state.

и

стандарт языка еще, про операцию |=
Step_ARM
Цитата(meister @ Jun 23 2009, 10:41) *
Когда ничего не помогает, прочтите, наконец, инструкцию.

This bit is cleared by writing a one to it, except in level sensitive mode when
the pin is in its active state.

и

стандарт языка еще, про операцию |=

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