|
Приоритет и вложенность прерываний, матчасть |
|
|
|
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
|
|
|
|
|
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 указатель), а далее стек переопределяется и используется супервизорный стек. Обработчик прерывания по сути представляется как обычная функция.
Приведенный в самом начале код, это лишь наглядный (осцил) эксперимент, для изучения прерываний.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|