|
Приоритет и вложенность прерываний, матчасть |
|
|
|
Jun 5 2007, 03:16
|
Участник

Группа: Новичок
Сообщений: 18
Регистрация: 12-04-07
Пользователь №: 26 989

|
На сколько я понял, в SAM7 уровень прерываний заложен, но чтобы он правильно работал, необходимо написать правильный обработчик прерывания. Или я не прав? В простейшем случае необходимо в начале и в конце обработчика поставить define библиотеки ...: __ENABLE_INTERRUPT(); __DISABLE_INTERRUPT(); Провел несколько простых экспериментов, с использованием таймеров 0 и 1 Код #define TIMER0_INTERRUPT_LEVEL 0 #define TIMER1_INTERRUPT_LEVEL 1
#pragma interrupt_handler Timer0_CIrqHandler void Timer0_CIrqHandler(void) { unsigned int status,r0; __ENABLE_INTERRUPT(); status = TC0_SR; // Read timer status register to clear interrupt PIO_CODR = (1<<0); // LED1 ON for(r0=0; r0<0x5FFF; r0++); PIO_SODR = (1<<0); // LED1 OFF AIC_EOICR = status; __DISABLE_INTERRUPT(); }
#pragma interrupt_handler Timer1_CIrqHandler void Timer1_CIrqHandler(void) { unsigned int status,r1; __ENABLE_INTERRUPT(); status = TC1_SR; // Read timer status register to clear interrupt PIO_CODR = (1<<1); // LED2 ON for(r1=0; r1<0x4FF; r1++); PIO_SODR = (1<<1); // LED2 OFF AIC_EOICR = status; __DISABLE_INTERRUPT(); }
void timer0_init ( void ) { PMC_PCER = (0x1 << AT91C_ID_TC0); TC0_CCR = AT91C_TC_CLKDIS; TC0_IDR = 0xFFFFFFFF; AIC_SVR12 = (unsigned int) Timer0_CIrqHandler; AIC_SMR12 =AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE|TIMER0_INTERRUPT_LEVEL;
AIC_IECR = (0x1 << AT91C_ID_TC0); TC0_CMR = AT91C_TC_CLKS_TIMER_DIV5_CLOCK | AT91C_TC_CPCTRG; TC0_RC = 0x0FF0; TC0_IER = AT91C_TC_CPCS; TC0_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; }
void timer1_init ( void ) { PMC_PCER = (0x1 << AT91C_ID_TC1); TC1_CCR = AT91C_TC_CLKDIS; TC1_IDR = 0xFFFFFFFF; AIC_SVR13 = (unsigned int) Timer1_CIrqHandler; AIC_SMR13 =AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE|TIMER1_INTERRUPT_LEVEL;
AIC_IECR = (0x1 << AT91C_ID_TC1); TC1_CMR = AT91C_TC_CLKS_TIMER_DIV5_CLOCK | AT91C_TC_CPCTRG; TC1_RC = 0x00FF; TC1_IER = AT91C_TC_CPCS; TC1_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; } после использования __ENABLE_INTERRUPT(); __DISABLE_INTERRUPT(); действительно уровень прерывания стал работать как надо. Но вот попробовал подключить ШИМ: Код #define F_PWC 0xFF #define PWMC_INTERRUPT_LEVEL 5
#pragma interrupt_handler PWMC_CIrqHandler void PWMC_CIrqHandler(void) { unsigned int status,rir,ss;
__ENABLE_INTERRUPT(); status = PWM_ISR; AIC_ICCR = (0x1 << AT91C_ID_PWMC); PWM_CMR0 = (0<<10)|0x03; PWM_CUPD0 = F_PWC/3; AIC_EOICR = status; __DISABLE_INTERRUPT(); }
void init_pwm(){ int i; *AT91C_PIOA_PDR = (1<<23); // подключаем выв PA23 к шиму *AT91C_PIOA_BSR = (1<<23);
PMC_PCER = (1<<AT91C_ID_PWMC); AIC_SMR10 = AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | PWMC_INTERRUPT_LEVEL; AIC_SVR10 = (unsigned int) PWMC_CIrqHandler; AIC_IECR = (1 << AT91C_ID_PWMC); // PWM_MR =(0x00<<24)|(0x01<<16)|(0x00<<8) |(0x01<<0); PWM_CMR0 = (0<<10)| (0<<9)| (0<<8) | 0x03; PWM_CPRD0 = F_PWC; PWM_CDTY0 = F_PWC/10; PWM_IER = AT91C_PWMC_CHID0; PWM_ENA = AT91C_PWMC_CHID0; } } В таком виде программа виснет, как только срабатывает прерывание ШИМа, точнее когда оно выходит из него. Пробовал убрать __ENABLE_INTERRUPT(); __DISABLE_INTERRUPT(); из всех прерываний все работает, только без преоритетов. По отдельности так же все работает. В чем дело не пойму. Может необходимо более полный обработчик написать? помогите! Пишу на ICCARM для AT91SAM7S256. Startup стандартный crtat91sam7s.s
Сообщение отредактировал maug - Jun 5 2007, 03:20
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 22)
|
Jun 5 2007, 05:46
|
Участник

Группа: Свой
Сообщений: 45
Регистрация: 19-04-07
Пользователь №: 27 172

|
Может размер стека режима прерываний мал? В стандартных стартап-файлах и в примерах на это внимание не обращают.
|
|
|
|
|
Jun 5 2007, 06:46
|
Участник

Группа: Новичок
Сообщений: 18
Регистрация: 12-04-07
Пользователь №: 26 989

|
Цитата Может размер стека режима прерываний мал? В стандартных стартап-файлах и в примерах на это внимание не обращают Размер стека IRQ сделал 1000 вроде для такой программы это с N кратным запасом Цитата Есть такая штука как вложенные прерывания. Так вот. Чтобы их разрешить в АРМе нужно кое-что особенное. Вобщем пролог и эпилог таких прерываний отличается от обычных. Кстати, в обычных прерываниях нельзя разрешать прерывания. По крац\йней мере в ИАРе так. Для вложенных прерываний существует слово __nested. К примеру так описывается заголвок прерывания: __irq __arm __nested Timer0Interrupt() Я примерно об этом и имел ввиду, говоря об специальном обработчике прерывания. Примерно то и суть действий ясна, да вот только примерно. Может кто знает как правильно написать обработчик прерывания или хотябы где посмотреть?
|
|
|
|
|
Jun 5 2007, 07:59
|
Участник

Группа: Новичок
Сообщений: 18
Регистрация: 12-04-07
Пользователь №: 26 989

|
Нашел вставки в прерывания аналог слово __nested. #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)
#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 */
Вроде все стало работать.
|
|
|
|
|
Jun 5 2007, 10:49
|
Участник

Группа: Свой
Сообщений: 45
Регистрация: 19-04-07
Пользователь №: 27 172

|
Цитата(GetSmart @ Jun 5 2007, 12:30)  Кстати, в обычных прерываниях нельзя разрешать прерывания. По крайней мере в ИАРе так В SAM7 можно, его контроллер прерываний обеспечивает при разрешенных прерываниях обработку только более приоритетных прерываний, чем выполняемое в данный момент. Правда есть нюанс, связанный с армовской архитектурой. Прерывание переключает режим ядра в IRQ. Для того, чтобы не испортить адрес возврата и флаги, сначала нужно сохранить их в стеке IRQ, а затем переключиться в режим USER или SUPERVISOR, и только после этого разрешить прерывания. Обработчик IRQ из IAR'овского cstartup для SAM7 отличается от обработчиков для других ARMов. Код IRQ_Handler_Entry: sub LR, LR, #4 ;Сохранение LR_irq в стеке IRQ stmfd SP!, {LR} mrs R14, SPSR ;Сохранить SPSR в стеке для вложенных прерываний stmfd SP!, {R14} stmfd SP!, {R0} ;Сохранение R0 в стеке IRQ
ldr R14, =AT91C_BASE_AIC ;Считать вектор в R0 ldr R0 , [R14, #AIC_IVR] msr CPSR_c, #ARM_MODE_SVC ;Разрешить прерывания и переключиться в Supervisor Mode stmfd SP!, {R1-R3, R12, R14} ;Сохранить используемые регистры в User-стеке
mov LR, PC ;Выполнить процедуру прерывания по вектору из AIC_IVR bx R0
ldmia SP!, { R1-R3, R12, R14} ;Восстановить используемые регистры из User-стека msr CPSR_c, #I_BIT | ARM_MODE_IRQ;Запретить прерывания и переключиться назад в IRQ mode
ldr R14, =AT91C_BASE_AIC ;Отметить окончание прерывания в регистре AIC_EOICR str R14, [R14, #AIC_EOICR]
ldmia SP!, {R0} ;Восстановление SPSR_irq и R0 из стека IRQ ldmia SP!, {R14} msr SPSR_cxsf, R14 ldmia SP!, {PC}^ ;Восстановление скорректированного LR_irq из IRQ-стека прямо в PC Сишные обработчики при этом оформляются не только без слова __nested, но и без interrupt_handler, то есть как обычные процедуры.
|
|
|
|
|
Jun 5 2007, 11:26
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(Calculator) В SAM7 можно, его контроллер прерываний обеспечивает при разрешенных прерываниях обработку только более приоритетных прерываний, чем выполняемое в данный момент. NO WAY !!! А где не так??? В LPC тоже контроллер прерываний не настолько тупой. Цитата Правда есть нюанс, связанный с армовской архитектурой. Прерывание переключает режим ядра в IRQ. Именно его я и имел ввиду, что дальнейшие мои слова и подтверждают. И именно для этого придумано слово __nested. __nested и для SAM7 подойдёт, если прога для ИАРа Цитата(Calculator) В SAM7 можно Попробуйте объявить простой обработчик прерываний (невложенных) и разрешить в нём прерывания. Проверьте. А потом пишите...
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jun 6 2007, 02:45
|
Участник

Группа: Новичок
Сообщений: 18
Регистрация: 12-04-07
Пользователь №: 26 989

|
Цитата(GetSmart @ Jun 5 2007, 17:45)  А в каком компиляторе пишите на си? Пишу на ICCARM 7 Цитата(Calculator @ Jun 5 2007, 17:49)  Обработчик IRQ из IAR'овского cstartup для SAM7 отличается от обработчиков для других ARMов. Этот код видел вот только из за особенности ICCARM асемблера не могу прикрутить аналогичную. не понимает команды работы ldr R14, =AT91C_BASE_AIC ;Считать вектор в R0 ldr R0 , [R14, #AIC_IVR] ldr R14, =AT91C_BASE_AIC ;Отметить окончание прерывания в str R14, [R14, #AIC_EOICR] Может у кого нибудь есть опыт работы ICC? На сколько я понял с таким обработчиком, все команды (функции) тела прерывания будут использовать не IRQ стек, а общий стек лимитированный лишь размером памяти?
|
|
|
|
|
Jun 6 2007, 05:37
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата На сколько я понял с таким обработчиком, все команды (функции) тела прерывания будут использовать не IRQ стек, а общий стек лимитированный лишь размером памяти? Всё верно. Код ldr R14, =AT91C_BASE_AIC;Считать вектор в R0 ldr R0 , [R14, #AIC_IVR] ldr R14, =AT91C_BASE_AIC;Отметить окончание прерывания в str R14, [R14, #AIC_EOICR] Тут скорее всего косяк. Сбрасывать признак прерывания нужно в самом конце прерывания, а не сразу на входе. И общие прерывания уже должны быть запрещены. Вобщем алгоритм такой: 1. Прочитать вектор возникшего прерывания. 2. Перейти на обработчик 3. Сохранить адрес возврата (LR) и переключиться в SYS Mode 4. Разрешить общие прерывания 5. Обработать процедуру прерывания 6. Запретить общие прерывания 7. Переключиться обратно в IRQ Mode и восстановить LR 8. Сбросить флаг прерывания в AIC (AIC_EOICR) 9. Выйти из прерывания 7 и 8 можно поменять.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jun 6 2007, 07:02
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(maug @ Jun 6 2007, 05:45)  На сколько я понял с таким обработчиком, все команды (функции) тела прерывания будут использовать не IRQ стек, С чего-бы это вдруг? Mode не меняли, указатель стека тоже. Цитата а общий стек лимитированный лишь размером памяти? Понятия "общего стека" вообще нет. Есть конкретные стеки для режимов. Под стеки память по любому выделяется идивидуально программистом. Один (любой) из стеков неизвестного (типа сколько останется (а не вообще сколько есть!) памяти, столько и будет) размера можно конечно сделать, но это верный путь к проблемам.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 6 2007, 08:11
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(GetSmart @ Jun 6 2007, 10:07)  Запутаете всех окончательно. Или почитайте внимательно всё с начала. Если имеется конкретный кусок кода и нему конкретный вопрос ответ на который не меет отношения к этому коду, то это означает только одно - все уже запутались окончательно и без меня  Цитата PS Общий стек = стек основной программы. Ну а что тогда "основная программа" - прерванная? - понимаю. Но ведь разборок с тем, из какого режима вывалились в IRQ Mode я не вижу, есть бездумная установка Supervisor Mode вне зависимости от того, какй прервали. Но основная причина моего коммента была в том, что мене не понравилось некое Ваше с maug совместное утверждение "прерывания будут использовать не IRQ стек, а общий стек лимитированный лишь размером памяти?" не только по причине мутного "общего стека", но в основном по причине того, что он "лимитированный лишь размером памяти".
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 6 2007, 09:49
|
Участник

Группа: Новичок
Сообщений: 18
Регистрация: 12-04-07
Пользователь №: 26 989

|
Эту тему я открыл, чтобы разобраться окончательно в прерываниях их приоритетах, вложениях, отсюда стеках...
Может тема уже стала несколько запутанной, может быть я совсем недавно програмирую под АРМ. Чтобы разобраться прошу поправить если я что, то не так понимаю.
1 Основная программа и ее подпрограммы используют супервизорный стек. 2 При возникновении исключительной ситуации в нашем случае прерывание используется стек IRQ 3 Если тело обработчика использует функции то опять же используется IRQ стек (по умолчанию) 4 Для обработчика ...IRQ_Handler_Entry:... из IAR получается,что из IRQ стека используются только 4 байта (1 указатель), а далее стек переопределяется и используется супервизорный стек. Обработчик прерывания по сути представляется как обычная функция.
Приведенный в самом начале код, это лишь наглядный (осцил) эксперимент, для изучения прерываний.
|
|
|
|
|
Jun 6 2007, 10:47
|
Участник

Группа: Новичок
Сообщений: 18
Регистрация: 12-04-07
Пользователь №: 26 989

|
Цитата(GetSmart @ Jun 6 2007, 17:33)  2. Вообще непонятно, какой такой исключительной ситуации? Эта фраза из документации на SAM7 с gaw.ru пункт 12.2.3 (Режимы работы ARM7TDMI) и 12.2.4.3 Типы исключительных ситуаций Ядро поддерживает пять типов исключительных ситуаций, работающих в привилегированном режиме. Ниже приведен их список: 1 быстрое прерывание (FIQ) 2 обычное прерывание (IRQ) 3 аварийная ситуация при работе с памятью (используется для реализации защищенного режима работы памяти или виртуальной памяти) 4 сбой при выполнении команды или выполнение несуществующей команды 5 программные прерывания (SWI) Я имел ввиду именно это.
|
|
|
|
|
Jun 6 2007, 10:53
|
Участник

Группа: Свой
Сообщений: 45
Регистрация: 19-04-07
Пользователь №: 27 172

|
Цитата(GetSmart @ Jun 6 2007, 11:37)  Код ldr R14, =AT91C_BASE_AIC;Отметить окончание прерывания в str R14, [R14, #AIC_EOICR] Тут скорее всего косяк. Сбрасывать признак прерывания нужно в самом конце прерывания, а не сразу на входе. И общие прерывания уже должны быть запрещены. Здесь нет косяка Общие прерывания запрещены строчкой выше (вот этой) Код msr CPSR_c, #I_BIT | ARM_MODE_IRQ;Запретить прерывания и переключиться назад в IRQ mode Запись в AT91C_BASE_AIC разрешает контроллеру прерываний SAM7 выставить новый запрос прерывания ядру. Ядро запустит обработчик только после выполнения последней команды обработчика, которая сделает возврат и переключит режим ядра из IRQ в USER/SUPERVISOR. Этот обработчик нормально работает в нескольких проектах с активным использованием прерываний
|
|
|
|
|
Jun 6 2007, 11:14
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(Calculator @ Jun 6 2007, 16:53)  Здесь нет косяка Общие прерывания запрещены строчкой выше (вот этой) Код msr CPSR_c, #I_BIT | ARM_MODE_IRQ;Запретить прерывания и переключиться назад в IRQ mode Запись в AT91C_BASE_AIC разрешает контроллеру прерываний SAM7 выставить новый запрос прерывания ядру. Ядро запустит обработчик только после выполнения последней команды обработчика, которая сделает возврат и переключит режим ядра из IRQ в USER/SUPERVISOR. Этот обработчик нормально работает в нескольких проектах с активным использованием прерываний Запись -----//----- разрешает контроллеру прерываний реагировать (сразу исполнять, если разрешены общие прерывания) на прерывания с более низким приоритетом чем текущий. В прерываниях, в которых разрешены вложенные прерывания эту команду ставят в самом конце прерывания перед самым выходом, по вполне очевидным причинам. Запоминает же контроллер все прерывания, вне зависимости от их приоритета и записи в AT91C_BASE_AIC, что бы потом, после выхода из текущего прерывания (или даже внутри него) обработать все запомненные прерывания в порядке приоритета и пожеланий программиста. Цитата(maug @ Jun 6 2007, 16:47)  Эта фраза из документации на SAM7 с gaw.ru пункт 12.2.3 (Режимы работы ARM7TDMI) и
12.2.4.3 Типы исключительных ситуаций Ядро поддерживает пять типов исключительных ситуаций, работающих в привилегированном режиме. Ниже приведен их список: 1 быстрое прерывание (FIQ) 2 обычное прерывание (IRQ) 3 аварийная ситуация при работе с памятью (используется для реализации защищенного режима работы памяти или виртуальной памяти) 4 сбой при выполнении команды или выполнение несуществующей команды 5 программные прерывания (SWI) Я имел ввиду именно это. При возникновении исключительной ситуации используется персональный стек этого исключения. Прочитайте что ли файлик arm7tdmi.pdf А то придётся всё содержимое этого файла вам разжёвывать.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jun 8 2007, 06:22
|
Участник

Группа: Свой
Сообщений: 45
Регистрация: 19-04-07
Пользователь №: 27 172

|
Цитата(GetSmart @ Jun 6 2007, 17:14)  Запись -----//----- разрешает контроллеру прерываний реагировать (сразу исполнять, если разрешены общие прерывания) на прерывания с более низким приоритетом чем текущий. В прерываниях, в которых разрешены вложенные прерывания эту команду ставят в самом конце прерывания перед самым выходом, по вполне очевидным причинам. Могу повторить только то, что уже писал. Запись -----//----- действительно разрешает контроллеру прерываний реагировать, но не исполнять, т.к. сброшен флаг разрешения прерываний IRQ в регистре статуса. Последняя команда обработчика прерывания переключает режим ядра, делает возврат в фоновую програму и разрешает прерывания IRQ. Если они есть, то самое приоритетное из них будет выполнено после выполнения одной инструкции из фоновой программы Цитата(maug @ Jun 5 2007, 17:45) Этот код видел вот только из за особенности ICCARM асемблера не могу прикрутить аналогичную. не понимает команды работы ldr R14, =AT91C_BASE_AIC ;Считать вектор в R0 ldr R0 , [R14, #AIC_IVR] ldr R14, =AT91C_BASE_AIC ;Отметить окончание прерывания в str R14, [R14, #AIC_EOICR]
Может у кого нибудь есть опыт работы ICC?
На сколько я понял с таким обработчиком, все команды (функции) тела прерывания будут использовать не IRQ стек, а общий стек лимитированный лишь размером памяти? Опыта работы с ICC у меня нет, но нужно просто разобраться, почему не понимаются эти команды. Может быть у ассемблера немного отличается синтаксис, может быть нет define на AT91C_BASE_AIC, может быть define есть, но равен не тому же, чему в IAR. На всякий случай вот эти define: Код AT91C_BASE_AIC EQU 0xFFFFF000 ;Базовый адрес контроллера прерываний AIC_IVR EQU 0x100;Регистр вектора IRQ (смещение) AIC_FVR EQU 0x104;Регистр вектора FIQ AIC_EOICR EQU 0x130;Регистр "Окончание прерывания" Стек режима IRQ использоваться будет, но мало и его максимальная длина фиксирована. Для максимум 8 вложенных прерываний (а больше не разрешит контроллер прерываний) длина стека IRQ должна быть 3*4*8 байт (3 двойных слова на 8 уровней приоритетов). Если используется всего пара приоритетов, то соответственно 3*4*2
Сообщение отредактировал Calculator - Jun 8 2007, 06:27
|
|
|
|
|
Apr 10 2010, 18:49
|
Группа: Новичок
Сообщений: 1
Регистрация: 10-04-10
Пользователь №: 56 553

|
Здравствуйте. У меня вопрос. Я работаю с AT91SAM7X. Проиннициализировал таймер и юарт. Через регистр AIC_SMR задал юарту максимальный приоритет а таймеру минимальный. Обработчики обьявляю так: __irq __arm <название> Я все это сделал но вложенные прерывания не срабатывают. При попадании в обработчик таймера и наступлении прерывания от юарта, в обработчик юарта я попадаю только после завершения обработчика таймера. У меня вопрос, что нужно сделать, что бы заработали вложенные прерывания?
|
|
|
|
|
Apr 12 2010, 11:36
|
Группа: Участник
Сообщений: 8
Регистрация: 19-06-07
Пользователь №: 28 558

|
Цитата(telerobot @ Apr 10 2010, 23:04)  что нужно сделать, что бы заработали вложенные прерывания? Бесспорно, их нужно разрешить. Разрешить на уровне ядра и на уровне периферии. Внимательно изучите ассемблеровский код в СтартАпе в части настройки режимов и в части обработки прерывания. В моём примере стартАп-а (ссылка в посте выше), на первый и беглый взгляд, в прерывания IRQ (где у меня запрещены прерывания, метка IRQ_Handler_Entry: ) перед самым скачком в п/п-обработчик периферии ядро переключается в основной режим SYS, где (!была моя проблема) уже разрешены прерывания.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|