|
вопрос про прерывания, AT91SAM7X |
|
|
|
Dec 6 2007, 11:06
|
Участник

Группа: Новичок
Сообщений: 49
Регистрация: 14-02-07
Пользователь №: 25 346

|
Судя по даташиту, в начале обработки прерывания необходимо прочитать регистр AIC_IVR, как они выражаются, это the entry point of the interrupt handling.. В конце обработки прерывания необходимо прописать что-нибудь в регистр AIC_EOICR, т.к. это the exit point of the interrupt handling..
Так вот.. до недавнего времени мне удавалось вполне успешно обрабатывать прерывания (TC, CAN, ADC), не читая AIC_IVR, а читая соответствующие статусные регистры перриферии, сбрасывающие флаг, свидетельствующий о произошедшем прерывании и прописывая какое-то значение в AIC_EOICR..
Однако при обработке прерываний от PIO и IRQ0, IRQ1 я натолкнулся на некоторые трудности.. Например, при настройке IRQ0 на срабатывание по высокому уровню без чтения AIC_IVR программа зацикливается на функции прерывания.. Когда же произвожу чтение AIC_IVR, функция прерывания выполняется один раз и больше ни на что не реагирует (кроме ресета..)
В связи с этим вопрос: необходимо ли читать регистр AIC_IVR и если да, то в каких случаях?
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 24)
|
Dec 6 2007, 11:19
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Sergei_K @ Dec 6 2007, 13:06)  В связи с этим вопрос: необходимо ли читать регистр AIC_IVR Да, необходимо. Цитата и если да, то в каких случаях? Вы же в самом начале привели цитату - как только вошли в обработчик прерывания, чтобы определить источник прерывания. Один раз у вас срабатывает скорее всего потому, что вы не пишете EOICR в конце обработчика.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 6 2007, 14:02
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Добавлю немного. AIC_IVR лучше читать сразу при переходе на вектор IRQ: Код 00000018 ldr pc, [pc, #-0xf20] ; IRQ для того контроллер прерываний и положили в верхние адреса. Если не записать AIC_EOICR в конце процедуры обработки прерывания, то AIC перестанет реагировать на прерывания с более низким приоритетом.
|
|
|
|
|
Apr 22 2009, 14:39
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 20-10-08
Из: Нижний Новгород
Пользователь №: 41 078

|
У меня почти такая же проблема: второй раз не обрабатывает прерывание и докучи перезаписывает один из существующих массивов (программа не зависает, если это важно). Камень AT91RM9200 Инициализация (сделана отдельной функцией): Код void IntInit(void) {AT91F_PIO_CfgInput(AT91C_BASE_PIOA, DataInput); AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, DataInput, 0); AT91F_AIC_ConfigureIt (AT91C_BASE_AIC, AT91C_ID_IRQ2, 7, AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED, PIOA_Handler); // prio AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_IRQ2); } Обработчик: Код extern int p[33]; static void PIOA_Handler( void ) { AT91C_BASE_AIC->AIC_IVR; AT91C_BASE_PIOB->PIO_SODR |= ( DDS_P2_MODULATION ); /* PB7 - выв 87 AT91RM9200 */ AT91C_BASE_PIOB->PIO_CODR |= ( DDS_P2_MODULATION ); /* PB7 are output */ AT91C_BASE_AIC->AIC_ICCR |= ( 1UL<<AT91C_ID_IRQ2 );//clear interrupt AT91C_BASE_AIC->AIC_EOICR = 0; } Строки, касающиеся прерывания из main(): Код ... IntInit(); AT91C_BASE_PIOB->PIO_SODR |= ( DDS_P2_MODULATION ); /* PB7 - выв 87 AT91RM9200 */ __enable_interrupt(); delay(5000); AT91C_BASE_PIOB->PIO_CODR |= ( DDS_P2_MODULATION ); /* PB7 are output */ ...
Сообщение отредактировал Antokha - Apr 22 2009, 15:16
|
|
|
|
|
Apr 22 2009, 17:24
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 20-10-08
Из: Нижний Новгород
Пользователь №: 41 078

|
Цитата Во-первых, не нужно читать write-only регистры. Если это про AIC_IVR, то это я наверно на автомате набрал, читая pdf на контроллер. Вообще-то этот регистр уже наверно считался до входа в эту процедуру обработки: cstartup.s: Код ... __irq_handler: ldr PC,[PC,#-0xF20] ;; IRQ .... Цитата Во-вторых, какой смысл использовать прерывания по фронту для внутреннего источника в данном случае? AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED в файле AT91RM9200.h описан как: #define AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED ((unsigned int) 0x1 << 5) // (AIC) Internal Sources Code Label Edge triggered, т.е. в соответствии с pdf на контроллер это и прерывание по фронту для внутреннего источника так и прерывание по спаду для внешнего прерывания.
|
|
|
|
|
Apr 22 2009, 17:32
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Antokha @ Apr 22 2009, 21:24)  Если это про AIC_IVR... Нет, это про PIO_SODR, PIO_CODR, AIC_ICCR и т.д. Цитата(Antokha @ Apr 22 2009, 21:24)  AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED в файле AT91RM9200.h описан как... Смысл какой? Источник у Вас внутренний, так зачем работать по фронту, рискуя огрести проблемы (что, судя по всему, и случилось)?
|
|
|
|
|
Apr 22 2009, 17:52
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 20-10-08
Из: Нижний Новгород
Пользователь №: 41 078

|
AT91C_BASE_PIOB->PIO_SODR |= ( DDS_P2_MODULATION ); - установить вывод PB7 в 1. AT91C_BASE_PIOB->PIO_CODR |= ( DDS_P2_MODULATION ); - установить вывод PB7 в 0. AIC_ICCR - это на самом деле лишнее. Цитата Смысл какой? Источник у Вас внутренний, так зачем работать по фронту, рискуя огрести проблемы (что, судя по всему, и случилось)? Прерывание - внешнее - IRQ2, соответствует выводу PA25. Мне лучше, чтобы по фронтуили спаду прерывание обрабатывалось, чем по уровню. Я думаю будет точнее работать (время от появления какого либо фронта до установления PB7 в единичку)
Сообщение отредактировал Antokha - Apr 22 2009, 17:55
|
|
|
|
|
Apr 22 2009, 18:04
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Antokha @ Apr 22 2009, 21:52)  AT91C_BASE_PIOB->PIO_SODR |= ( DDS_P2_MODULATION ); - установить вывод PB7 в 1. AT91C_BASE_PIOB->PIO_CODR |= ( DDS_P2_MODULATION ); - установить вывод PB7 в 0. AIC_ICCR - это на самом деле лишнее. Вместо |= нужно просто =, дабы не плодить бессмысленные и потенциально опасные действия. Цитата(Antokha @ Apr 22 2009, 21:52)  Прерывание - внешнее - IRQ2, соответствует выводу PA25. Да, пардон, меня сбило с толку имя обработчика - PIOA_Handler. Тогда следующий вопрос. Если у Вас в стартапе Код __irq_handler: ldr PC,[PC,#-0xF20] ;; IRQ то где оформление функции как прерывания? Код static void PIOA_Handler( void ) Цитата(Antokha @ Apr 22 2009, 21:52)  Мне лучше, чтобы по фронтуили спаду прерывание обрабатывалось, чем по уровню. Я думаю будет точнее работать (время от появления какого либо фронта до установления PB7 в единичку) Работать будет одинаково, а вот шанс пропустить событие возрастает.
|
|
|
|
|
Apr 22 2009, 19:00
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 20-10-08
Из: Нижний Новгород
Пользователь №: 41 078

|
Цитата Функция обработчика объявлена как обычная функция, не содержащая необходимых действий по сохранению/восстановлению контекста. Именно поэтому прерывание только один раз и вызывается. Функция (обработчик прерывания) должна выплюнуть последовательный код на ножку PB7. Восстановление контекста - какое именно, в pdf написано что возврат в прерванную функцию производится самостоятельно, ничего дописывать не надо, или я что-то не так понял. У меня поганится один из массивов - такое ощущение, что нормального выхода из прерывания нет и контроллер дальше выполняет инструкции, следующие за кодом прерывания (неизвестно какие -  ). Цитата то где оформление функции как прерывания? Код static void PIOA_Handler( void ) В void IntInit(void): ... AT91F_AIC_ConfigureIt (AT91C_BASE_AIC, AT91C_ID_IRQ2, 7, AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED, PIOA_Handler); ... Вообще void IntInit(void) брал из книги по ARM7, там AIC такой-же. Вырезка из lib_AT91RM9200.h: Код __inline unsigned int AT91F_AIC_ConfigureIt ( AT91PS_AIC pAic, // \arg pointer to the AIC registers unsigned int irq_id, // \arg interrupt number to initialize unsigned int priority, // \arg priority to give to the interrupt unsigned int src_type, // \arg activation and sense of activation void (*newHandler) (void) ) // \arg address of the interrupt handler { unsigned int oldHandler; unsigned int mask; oldHandler = pAic->AIC_SVR[irq_id]; mask = 0x1 << irq_id; //* Disable the interrupt on the interrupt controller pAic->AIC_IDCR = mask; //* Save the interrupt handler routine pointer and the interrupt priority pAic->AIC_SVR[irq_id] = (unsigned int) newHandler; //* Store the Source Mode Register pAic->AIC_SMR[irq_id] = src_type | priority; //* Clear the interrupt on the interrupt controller pAic->AIC_ICCR = mask; return oldHandler; }
Сообщение отредактировал Antokha - Apr 22 2009, 19:15
|
|
|
|
|
Apr 22 2009, 19:16
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Antokha @ Apr 22 2009, 23:00)  Вообще void IntInit(void) брал из книги по ARM7, там AIC такой-же. Уж не Редькина ли книжка? PIOA_Handler должен быть не Код void PIOA_Handler( void ), а
__irq void PIOA_Handler(void)
или
void PIOA_Handler(void) __attribute__ ((interrupt ("IRQ"))); или иметь еще какие-нибудь модификаторы, в зависимости от используемого компилятора. Иначе процессор никогда не выйдет из режима IRQ.
|
|
|
|
|
Apr 22 2009, 19:23
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 20-10-08
Из: Нижний Новгород
Пользователь №: 41 078

|
Книжка может быть и Редькина, точно скажу завтра днем. При использовании функции AT91F_AIC_ConfigureIt объявляя функцию static __arm __irq void PIOA_Handler( void ), получаю ошибку. Пробовал ещё так: - настройка: Код AT91C_BASE_PIOA->PIO_ODR |= ( DataInput ); /* PB27 are input */ AT91C_BASE_PIOA->PIO_ASR |= ( DataInput ); AT91C_BASE_AIC->AIC_IDCR |= ( 1UL<<AT91C_ID_IRQ2 );//disable interrupt IRQ2 AT91C_BASE_AIC->AIC_SVR[AT91C_ID_IRQ2] |= ( AT91_REG )PIOA_Handler; // set isr AT91C_BASE_AIC->AIC_SMR[AT91C_ID_IRQ2] |= ( AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED ) | ( 7 )); // prio 7 AT91C_BASE_AIC->AIC_ICCR |= ( 1UL<<AT91C_ID_IRQ2 );//clear interrupt AT91C_BASE_AIC->AIC_IECR |= ( 1UL<<AT91C_ID_IRQ2 );//enable interrupt функцию PIOA_Handler объявляю как: static __arm __irq void PIOA_Handler( void ); без ошибок компилируется, но работает также.
Сообщение отредактировал Antokha - Apr 22 2009, 19:40
|
|
|
|
|
Apr 22 2009, 19:30
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 20-10-08
Из: Нижний Новгород
Пользователь №: 41 078

|
Про ошибку завтра днём. Компилятор (от IAR 5.11) дома не пашет.
|
|
|
|
|
Apr 22 2009, 20:05
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Antokha @ Apr 22 2009, 18:39)  У меня почти такая же проблема: второй раз не обрабатывает прерывание и докучи перезаписывает один из существующих массивов (программа не зависает, если это важно). Обработчик: Код extern int p[33]; static void PIOA_Handler( void ) { AT91C_BASE_AIC->AIC_IVR; AT91C_BASE_PIOB->PIO_SODR |= ( DDS_P2_MODULATION ); /* PB7 - выв 87 AT91RM9200 */ AT91C_BASE_PIOB->PIO_CODR |= ( DDS_P2_MODULATION ); /* PB7 are output */ AT91C_BASE_AIC->AIC_ICCR |= ( 1UL<<AT91C_ID_IRQ2 );//clear interrupt AT91C_BASE_AIC->AIC_EOICR = 0; } Во-первых как Вам уже сказали нужно оформить правильно функцию прерывания(в зависимости от компилятора). Ну и вообще-то сброс прерывания от PIO делается не записью AIC_ICCR, а чтением PIOx_ISR, при этом нужно иметь в виду что сбросятся все прерывания которые пришли на порт в данный момент времени: When the software reads PIO_ISR, all the interrupts are automatically cleared. This signifies that all the interrupts that are pending when PIO_ISR is read must be handled.
|
|
|
|
|
Apr 22 2009, 20:49
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Antokha @ Apr 22 2009, 17:39)  Код extern int p[33]; static void PIOA_Handler( void ) { AT91C_BASE_AIC->AIC_IVR;
...
__irq_handler: ldr PC,[PC,#-0xF20] ;; IRQ .... AIC_IVR читается дважды. Огласите название книжки.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 23 2009, 04:52
|
Участник

Группа: Участник
Сообщений: 31
Регистрация: 20-10-08
Из: Нижний Новгород
Пользователь №: 41 078

|
Цитата AIC_IVR читается дважды. Огласите название книжки. Это моя отсебятина, начитался pdf-ника. Там сказано регистр считать, а cstartup.s не доглядел. Про ошибку: При использовании функции AT91F_AIC_ConfigureIt объявляя функцию static __arm __irq void PIOA_Handler( void ), получаю ошибку: Error[Pe167]: argument of type "void (__arm __irq *)()" is incompatible with parameter of type "void (*)()" На данный момент сделал так: Инит: Код AT91C_BASE_PIOA->PIO_PPUDR |= ( DataInput ); AT91C_BASE_PIOA->PIO_ODR = ( DataInput ); AT91C_BASE_PIOA->PIO_BSR = ( DataInput ); AT91C_BASE_AIC->AIC_IDCR = ( 1UL<<AT91C_ID_IRQ2 );//disable interrupt IRQ2 AT91C_BASE_AIC->AIC_SVR[AT91C_ID_IRQ2] |= ( AT91_REG )PIOA_Handler; // set isr AT91C_BASE_AIC->AIC_SMR[AT91C_ID_IRQ2] |= ( AT91C_AIC_SRCTYPE_EXT_HIGH_LEVEL ) | ( 7 ); // prio 7 AT91C_BASE_AIC->AIC_ICCR = ( 1UL<<AT91C_ID_IRQ2 );//clear interrupt AT91C_BASE_AIC->AIC_IECR = ( 1UL<<AT91C_ID_IRQ2 );//enable interrupt Обработка: Код static __irq __arm void PIOA_Handler( void ) {AT91C_BASE_PIOB->PIO_SODR = ( DDS_P2_MODULATION ); /* PB7 - выв 87 AT91RM9200 */ AT91C_BASE_PIOB->PIO_CODR = ( DDS_P2_MODULATION ); /* PB7 are output */ AT91C_BASE_AIC->AIC_EOICR = 0; } виснет после команды __enable_interrupt(); P.S. Имя обработчика прерывания осталось от нужного когда-то прерывания, извините уж. А книжка - Это Редькин П.П. "32/16-битные микроконтроллеры ARM7 семейства AT91SAM7 Руководство пользователя"
Сообщение отредактировал Antokha - Apr 23 2009, 05:07
|
|
|
|
|
Apr 23 2009, 11:09
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Antokha @ Apr 23 2009, 08:52)  [code] AT91C_BASE_AIC->AIC_SVR[AT91C_ID_IRQ2] |= ( AT91_REG )PIOA_Handler; // set isr AT91C_BASE_AIC->AIC_SMR[AT91C_ID_IRQ2] |= ( AT91C_AIC_SRCTYPE_EXT_HIGH_LEVEL ) | ( 7 ); // prio 7 Опять |=, да еще и при записи адреса. Цитата(Antokha @ Apr 23 2009, 08:52)  А книжка - Это Редькин П.П. "32/16-битные микроконтроллеры ARM7 семейства AT91SAM7 Руководство пользователя" В печку ее.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|