Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прерывания от одного источника становятся в очередь, если прерывание возникло во время работы обработчика?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Bulat
Прерывания от порта PIO становятся в очередь, если прерывание возникло во время работы обработчика?
Обработчик:
CODE
__ramfunc void irq_Receive()
{
volatile unsigned int dummy;
volatile unsigned int source; //источник прерывания

source = regs->PIOA_PDSR&0x780; //Накладываем маску прерывания

switch(source)
{
case 0x200 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA|0x80000000; break;} //A1
case 0x400 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA&0x7FFFFFFF; break;} //B1

case 0x80 : {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG;
recB = recB>>1; i_shB++; recB = recB|0x80000000; break;} //A2
case 0x100 : {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG;
recB = recB>>1; i_shB++; recB = recB&0x7FFFFFFF; break;} //B2

case 0x280 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA|0x80000000; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1; i_shB++; recB = recB|0x80000000;
break;} //A1,A2
case 0x500 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA&0x7FFFFFFF; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1; i_shB++; recB = recB&0x7FFFFFFF;
break;} //B1,B2

case 0x300 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA|0x80000000; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1; i_shB++; recB = recB&0x7FFFFFFF;
break;} //A1,B2
case 0x480 : {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG;
recB = recB>>1; i_shB++; recB = recB|0x80000000; PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG; recA = recA>>1; i_shA++; recA = recA&0x7FFFFFFF;
break;} //A2,B1

default: {;}
}

dummy = AT91C_BASE_PIOA->PIO_ISR;
}


При изменении уровней порта PIO в соответствии с маской 0x780, возникает прерывание, которое обрабатывается обработчиком irq_Receive(). В зависимости от содержимого источника прерываний source в буфера recA и recB записывается 1 или 0 и происходит их сдвиг, а также запускаются таймеры 1 или 2, которые контролируют паузу между принимаемыми битами. То есть этот обработчик принимает данные от двух каналов. Когда данные поступают на порт PIO от 2-х каналов не одновременно, то возникают сбои при приеме данных и прнимаются не те данные. То есть, возможна ситуация, когда обработчик считывает данные в буфер канала А recA, а в этот момент приходит очередной импульс на порт PIO от канала B, но прерывание занято, следовательно, бит данных пропадает. Такое может быть или же сучествует очередь для одинаковых прерываний?
aaarrr
Т.к. сброс прерывания PIO (чтение PIO_ISR) у вас выполняется в конце обработчика, то любое прерывание PIO, возникшее во время его выполнения, будет потеряно. Никаких очередей, естественно, нет.
Bulat
Цитата(aaarrr @ Dec 11 2009, 14:38) *
Т.к. сброс прерывания PIO (чтение PIO_ISR) у вас выполняется в конце обработчика, то любое прерывание PIO, возникшее во время его выполнения, будет потеряно. Никаких очередей, естественно, нет.


Вот вариант программы реализующей 4 обработчика от 4 источников прерывания: PA7,8,9,10.
CODE
__ramfunc void irq_Receive_7() //A2
{
volatile unsigned int dummy;

PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG;
recB = recB>>1;
i_shB++;
recB = recB|0x80000000;

dummy = AT91C_BASE_PIOA->PIO_ISR;
}

__ramfunc void irq_Receive_8() //B2
{
volatile unsigned int dummy;

PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG;
recB = recB>>1;
i_shB++;
recB = recB&0x7FFFFFFF;

dummy = AT91C_BASE_PIOA->PIO_ISR;
}

__ramfunc void irq_Receive_9() //A1
{
volatile unsigned int dummy;

PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1;
i_shA++;
recA = recA|0x80000000;

dummy = AT91C_BASE_PIOA->PIO_ISR;
}

__ramfunc void irq_Receive_10() //B1
{
volatile unsigned int dummy;

PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1;
i_shA++;
recA = recA&0x7FFFFFFF;

dummy = AT91C_BASE_PIOA->PIO_ISR;
}

//Настройка прерываний
void Receiver_ini()
{

AT91C_BASE_AIC->AIC_SVR[7] = (unsigned int)irq_Receive_7;
AT91C_BASE_AIC->AIC_SMR[7] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | PORT_INTERRUPT_LEVEL;
AT91C_BASE_AIC->AIC_IECR = (0x1 << 7);
AT91C_BASE_SYS->PIOA_IER = 7;

AT91C_BASE_AIC->AIC_SVR[8] = (unsigned int)irq_Receive_8;
AT91C_BASE_AIC->AIC_SMR[8] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | PORT_INTERRUPT_LEVEL;
AT91C_BASE_AIC->AIC_IECR = (0x1 << 8);
AT91C_BASE_SYS->PIOA_IER = 8;

AT91C_BASE_AIC->AIC_SVR[9] = (unsigned int)irq_Receive_9;
AT91C_BASE_AIC->AIC_SMR[9] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | PORT_INTERRUPT_LEVEL;
AT91C_BASE_AIC->AIC_IECR = (0x1 << 9);
AT91C_BASE_SYS->PIOA_IER = 9;

AT91C_BASE_AIC->AIC_SVR[10] = (unsigned int)irq_Receive_10;
AT91C_BASE_AIC->AIC_SMR[10] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | PORT_INTERRUPT_LEVEL;
AT91C_BASE_AIC->AIC_IECR = (0x1 << 10);
AT91C_BASE_SYS->PIOA_IER = 10;
}


Но так прерывания не работают. Как правильно настраивать прерывания от отдельных выводов PIO?
aaarrr
Цитата(Bulat @ Dec 11 2009, 13:40) *
Вот вариант программы реализующей 4 обработчика от 4 источников прерывания: PA7,8,9,10.
...
Но так прерывания не работают.

Естественно не работают. Какая связь между номерами линий PIO и номерами векторов AIC'а?

Цитата(Bulat @ Dec 11 2009, 13:40) *
Как правильно настраивать прерывания от отдельных выводов PIO?

PIO выдает одно прерывание для всех линий. Можно использовать выводы IRQx для получения дополнительных прерываний.
Попробуйте сначала перенести чтение PIO_ISR в самое начало обработчика.
Bulat
Цитата(aaarrr @ Dec 11 2009, 16:07) *
Можно использовать выводы IRQx для получения дополнительных прерываний.

Вы имеете в виду AT91C_ID_IRQ0 и AT91C_ID_IRQ1?
Цитата(aaarrr @ Dec 11 2009, 16:07) *
Попробуйте сначала перенести чтение PIO_ISR в самое начало обработчика.

Я переместил чтение PIO_ISR в начало обработчика. Я могу определять источник при чтении PIO_ISR? Просто у меня пока получается определять источник только при чтении регистра порта PDSR. В коде, приведенном ниже применяю логическое "И" между содержимым PIO_ISR и PIO_PDSR и по результату этой операции делаю switch. Таким образом, я хочу исключить лишнюю обработку при возникновении второго прерывания по спаду.
CODE
__ramfunc void irq_Receive()
{
volatile unsigned int dummy = AT91C_BASE_PIOA->PIO_ISR;
volatile unsigned int source = regs->PIOA_PDSR & 0x780; //источники прерываний - выводы PA7,8,9 или 10

dummy &= source;
switch(dummy)
{
case 0x200 : { PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA|0x80000000; break;} //A1
case 0x400 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA&0x7FFFFFFF; break;} //B1

case 0x80 : {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG;
recB = recB>>1; i_shB++; recB = recB|0x80000000; break;} //A2
case 0x100 : {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG;
recB = recB>>1; i_shB++; recB = recB&0x7FFFFFFF; break;} //B2

case 0x280 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA|0x80000000; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1; i_shB++; recB = recB|0x80000000;
break;} //A1,A2
case 0x500 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA&0x7FFFFFFF; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1; i_shB++; recB = recB&0x7FFFFFFF;
break;} //B1,B2

case 0x300 : {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG;
recA = recA>>1; i_shA++; recA = recA|0x80000000; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1; i_shB++; recB = recB&0x7FFFFFFF;
break;} //A1,B2
case 0x480 : {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG;
recB = recB>>1; i_shB++; recB = recB|0x80000000; PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN;
PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG; recA = recA>>1; i_shA++; recA = recA&0x7FFFFFFF;
break;} //A2,B1

}
}

//Настройка прерывания от PIO
void Receiver_ini()
{
unsigned int REC_MASK = 0x780;

AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOA] = (unsigned int)irq_Receive;
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOA] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | PORT_INTERRUPT_LEVEL;

AT91C_BASE_AIC->AIC_IECR = (0x1 << AT91C_ID_PIOA);
AT91C_BASE_SYS->PIOA_IER = REC_MASK;
}


Так можно делать? И еще возможен вариант одновременного возникновения единиц на 2-х выводах, в этом случае регистр PIO_ISR покажет 2 единицы или одну?
DpInRock
По хорошему, надо сброс всех событий делать по выходу из обработчика. А перед выходом проверять, не возникло ли какое событие, требующее этого обработчика ( и сответственно снова обработать оное). И так до тех пор пока событий не останется. После чего покидать обработчик.
Bulat
Цитата(DpInRock @ Dec 11 2009, 17:48) *
По хорошему, надо сброс всех событий делать по выходу из обработчика. А перед выходом проверять, не возникло ли какое событие, требующее этого обработчика ( и сответственно снова обработать оное). И так до тех пор пока событий не останется. После чего покидать обработчик.

я сброс событий (чтение PIO_ISR) поставил в начале, чтобы поймать прерывание, пришедшее во время работы обработчика.
То есть, мне нужно повторно считывать PIO_ISR при выходе и в случае неравенства нулю его содержимого возвращаться в начало обработчика?
DpInRock
Прерывание - это лишь повод запустить обработчик. Смотрите на состояние информационных выводов. И после их успокоения сбрасывайте все флаги - и на выход.
Bulat
Цитата(DpInRock @ Dec 11 2009, 19:27) *
Прерывание - это лишь повод запустить обработчик. Смотрите на состояние информационных выводов. И после их успокоения сбрасывайте все флаги - и на выход.

так данные на порт по каждому каналу идут с частотой 100 кГц, то есть при их неодновременном приходе на порт частота удваивается, а помимо прерывания от порта мне еще 2 прерывания надо обрабатывать, поэтому ждать "успокоения" я не могу.
DpInRock
Если внутри обработчика прерывания возникают события, которые должны обрабатываться этим же обработчиком, и нет паузы между этими событиями, то вы неверно спроектировали алгоритм или систему. (Т.е. обработчик в принципе не успевает обрабатывать).

Хотя лично я не вижу тут никаких проблем.
defunct
Цитата(Bulat @ Dec 11 2009, 14:37) *
volatile unsigned int dummy = AT91C_BASE_PIOA->PIO_ISR;
volatile unsigned int source = regs->PIOA_PDSR & 0x780;

говорите частота входного сигнала 100khz...

Вы можете обосновать зачем dummy и source объявлены у вас в обработчике как volatile?
Чтобы сделать обработчик более медленным?
DpInRock
Потому что это регистры.
defunct
Цитата(DpInRock @ Dec 11 2009, 17:44) *
Если внутри обработчика прерывания возникают события, которые должны обрабатываться этим же обработчиком, и нет паузы между этими событиями, то вы неверно спроектировали алгоритм или систему. (Т.е. обработчик в принципе не успевает обрабатывать).

Речь идет о pin-change 4-х source'ов. Допустим есть такие теоретические параметры:
- частота источника всегда одинакова и равна 1kHz (интервал между событиями 1000us).
- время выполнения обработчика для одного source в худшем случае равна 100us.

Для 4-х источников Система с четырьмя отдельными обработчиками, будет загружена всего на (4 * 100us / 1000us) * 100% = 40%.

Теперь переложим эту гипотетическую задачу на железо автора ветки. Проблема состоит в том, что здесь нет отдельных IRQ для каждого источника, а имеется один общий INT на все четыре события. События асинхронны - друг от друга не зависят. Соответвенно событие №4 может произойти как раз тогда когда обслуживается одно из событий 1-3.

Будут ли возникать события, которые должны обработаться тем же обработчиком - конечно будут (т.к. IRQ общий для всех событий, а события асинхронны).
Можно ли при этом говорить, что система спроетирована неверно?


Цитата
Потому что это регистры.

Вы Редькина начитались? Какие еще регистры. Я говорю о переменных dummy и status.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.