Перейти к содержанию
    

вопрос про прерывания

Судя по даташиту, в начале обработки прерывания необходимо прочитать регистр 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 и если да, то в каких случаях?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В связи с этим вопрос: необходимо ли читать регистр AIC_IVR
Да, необходимо.
и если да, то в каких случаях?
Вы же в самом начале привели цитату - как только вошли в обработчик прерывания, чтобы определить источник прерывания. Один раз у вас срабатывает скорее всего потому, что вы не пишете EOICR в конце обработчика.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавлю немного.

 

AIC_IVR лучше читать сразу при переходе на вектор IRQ:

00000018    ldr    pc, [pc, #-0xf20]   ; IRQ

для того контроллер прерываний и положили в верхние адреса.

 

Если не записать AIC_EOICR в конце процедуры обработки прерывания, то AIC перестанет реагировать на прерывания с более низким приоритетом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня почти такая же проблема: второй раз не обрабатывает прерывание и докучи перезаписывает один из существующих массивов (программа не зависает, если это важно).

Камень 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Во-первых, не нужно читать write-only регистры. Во-вторых, какой смысл использовать прерывания по фронту для внутреннего источника в данном случае?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Во-первых, не нужно читать 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 на контроллер это и прерывание по фронту для внутреннего источника так и прерывание по спаду для внешнего прерывания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если это про AIC_IVR...

Нет, это про PIO_SODR, PIO_CODR, AIC_ICCR и т.д.

 

AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED в файле AT91RM9200.h описан как...

Смысл какой? Источник у Вас внутренний, так зачем работать по фронту, рискуя огрести проблемы (что, судя по всему, и случилось)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AT91C_BASE_PIOB->PIO_SODR |= ( DDS_P2_MODULATION ); - установить вывод PB7 в 1.

AT91C_BASE_PIOB->PIO_CODR |= ( DDS_P2_MODULATION ); - установить вывод PB7 в 0.

AIC_ICCR - это на самом деле лишнее.

Вместо |= нужно просто =, дабы не плодить бессмысленные и потенциально опасные действия.

 

Прерывание - внешнее - IRQ2, соответствует выводу PA25.

Да, пардон, меня сбило с толку имя обработчика - PIOA_Handler.

 

Тогда следующий вопрос. Если у Вас в стартапе

__irq_handler:
        ldr PC,[PC,#-0xF20]    ;; IRQ

то где оформление функции как прерывания?

static  void PIOA_Handler( void )

 

Мне лучше, чтобы по фронтуили спаду прерывание обрабатывалось, чем по уровню. Я думаю будет точнее работать (время от появления какого либо фронта до установления PB7 в единичку)

Работать будет одинаково, а вот шанс пропустить событие возрастает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Функция обработчика объявлена как обычная функция, не содержащая необходимых действий по сохранению/восстановлению контекста. Именно поэтому прерывание только один раз и вызывается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Функция обработчика объявлена как обычная функция, не содержащая необходимых действий по сохранению/восстановлению контекста. Именно поэтому прерывание только один раз и вызывается.

Функция (обработчик прерывания) должна выплюнуть последовательный код на ножку 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще void IntInit(void) брал из книги по ARM7, там AIC такой-же.

Уж не Редькина ли книжка?

 

PIOA_Handler должен быть не

void PIOA_Handler( void ), а

__irq void PIOA_Handler(void)

или

void PIOA_Handler(void) __attribute__ ((interrupt ("IRQ")));

или иметь еще какие-нибудь модификаторы, в зависимости от используемого компилятора.

 

Иначе процессор никогда не выйдет из режима IRQ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Книжка может быть и Редькина, точно скажу завтра днем.

При использовании функции 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

При использовании функции AT91F_AIC_ConfigureIt объявляя функцию static __arm __irq void PIOA_Handler( void ), получаю ошибку.

Какую?

 

Ну, напишите там (void*)PIOA_Handler.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...