Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Внешнее прерывание AT91SAM7S256.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
vutang
Добрый день всем!
Имеется отладочная плата sam7-mt256 фирмы olimex. На плате имеется джойстик, состоящий из 5 кнопок.
Хочу сделать прерывание по нажатию на одну из этих кнопок, но как-то не выходит. Т.е. по нажатию на кнопку программа уходит в прерывание и крутится в нем, пока не перезагрузишь контроллер. На сколько я понял, за окончание прерывания отвечает запись любого значения в регистр AIC_EOICR, но это тоже не помогает. Может кто делал что-нибудь подобное, подскажите куда копать? Ниже приведена часть кода, в котором производится настройка и описание прерывания.
Используемая среда разработки IAR 5.4.

CODE

#define SW2 BIT27
#define LED1 BIT7
int a = 0;

__irq void int_sw(void){
for(int i=0;i<10000;i++)
{}
a=~a;
if(a!=0)
{
*AT91C_PIOA_CODR |= LED1;
}
else
{
*AT91C_PIOA_SODR |= LED1;
}
AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_PIOA->PIO_ISR;
}

int main(void)
{
InitPeriphery();
InitFrec();

// Initialize interrupts
*AT91C_PIOA_ASR = (1<<SW2);
*AT91C_PIOA_IER = SW2;
*AT91C_PIOA_IMR = SW2;
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_IRQ1] = 0x00;
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_IRQ1] = (unsigned int) int_sw;
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_IRQ1);
while (1)
{

}
}
aaarrr
Почему Вы для прерывания PIO инициализируете источник IRQ1?
AT91C_PIOA_IMR - Read Only, писать его смысла нет.
vutang
Исправил код следующим образом:

Код
  portA->PIO_IFER = SW1;  
  pAic->AIC_IDCR = (1<<AT91C_ID_PIOA);
  pAic->AIC_SMR[AT91C_ID_PIOA] =(AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE|AT91C_AIC_PRIOR_HIGHEST);
  pAic->AIC_SVR[AT91C_ID_PIOA] = (unsigned int) int_sw;
  pAic->AIC_ICCR = (1<<AT91C_ID_PIOA);
  portA->PIO_IER = SW1;
  pAic->AIC_IECR = (1 << AT91C_ID_PIOA);


Теперь программа сразу уходит в обработчик прерывания и висит в нем. Такое ощущение, что условия срабатывания по фронту не работают...
aaarrr
PIO - это не внешний источник, а внутренний. Детектирование фронта производится в самом модуле PIO, так что в SMR можно спокойно прописать level sensetive.

С механизмом "висения" что-то не очень ясно пока. Как организован код вектора прерывания?
vutang
Извините не совсем понял про код вектора прерывания, где его посмотреть можно?
aaarrr
Смотрите startup.s или что-то похожее.
vutang
Часть кода из файла board_cstartup_iar.s. На сколько я понимаю тут на ассемблере написано, а я в нем не силен.
CODE
/*
Handles incoming interrupt requests by branching to the corresponding
handler, as defined in the AIC. Supports interrupt nesting.
*/
irqHandler:
/* Save interrupt context on the stack to allow nesting */
SUB lr, lr, #4
STMFD sp!, {lr}
MRS lr, SPSR
STMFD sp!, {r0, lr}

/* Write in the IVR to support Protect Mode */
LDR lr, =AT91C_BASE_AIC
LDR r0, [r14, #AIC_IVR]
STR lr, [r14, #AIC_IVR]

/* Branch to interrupt handler in Supervisor mode */
MSR CPSR_c, #ARM_MODE_SYS
STMFD sp!, {r1-r3, r4, r12, lr}
MOV lr, pc
BX r0
LDMIA sp!, {r1-r3, r4, r12, lr}
MSR CPSR_c, #ARM_MODE_IRQ | I_BIT

/* Acknowledge interrupt */
LDR lr, =AT91C_BASE_AIC
STR lr, [r14, #AIC_EOICR]

/* Restore interrupt context and branch back to calling code */
LDMIA sp!, {r0, lr}
MSR SPSR_cxsf, lr
LDMIA sp!, {pc}^


/*
After a reset, execution starts here, the mode is ARM, supervisor
with interrupts disabled.
Initializes the chip and branches to the main() function.
*/
SECTION .cstartup:CODE:NOROOT(2)

PUBLIC resetHandler
EXTERN LowLevelInit
EXTERN ?main
REQUIRE resetVector
ARM

resetHandler:

/* Set pc to actual code location (i.e. not in remap zone) */
LDR pc, =label

/* Perform low-level initialization of the chip using LowLevelInit() */
label:
LDR r0, =LowLevelInit
LDR r4, =SFE(CSTACK)
MOV sp, r4
MOV lr, pc
BX r0

/* Set up the interrupt stack pointer. */
MSR cpsr_c, #ARM_MODE_IRQ | I_BIT | F_BIT ; Change the mode
LDR sp, =SFE(IRQ_STACK)

/* Set up the SYS stack pointer. */
MSR cpsr_c, #ARM_MODE_SYS | F_BIT ; Change the mode
LDR sp, =SFE(CSTACK)

/* Branch to main() */
LDR r0, =?main
MOV lr, pc
BX r0

/* Loop indefinitely when program is finished */
loop4:
B loop4

END
aaarrr
Тогда уберите из вашего обработчика модификатор __irq и запись AIC_EOICR, так как все это уже сделано в обертке irqHandler.
vutang
Эффекта нет. Пошагово просмотрел как выполняется программа, сразу после строки "BX r0" в файле board_cstartup_iar.s входит в прерывание. Смотрел примеры на сайте производителя, так там просто в цикле опрашивается состояние пинов. Хочется на прерываниях сделать, не думал, что вылезут такие косяки. Подумываю уже таймер задействовать...
RabidRabbit
Чтение PIO_ISR есть, проглючило меня sm.gif

запись *AT91C_PIOA_CODR |= LED1 можно смело заменить на *AT91C_PIOA_CODR = LED1

BIT7 = это (1 << 7)?
тогда что за странная запись *AT91C_PIOA_ASR = (1<<SW2); ?
а тактирование PIO включено?
aaarrr
Цитата(vutang @ May 24 2013, 16:13) *
Эффекта нет. Пошагово просмотрел как выполняется программа, сразу после строки "BX r0" в файле board_cstartup_iar.s входит в прерывание.

Вот "пошагово" - это и источник всех бед. AIC под отладчиком не сброшен, потому и чудит.
vutang
Короче все заработало. Наверное проблема была в том, что PORTA находился в таком состоянии, что прерывание вызывалось постоянно. Решил проблему добавив в обработчик проверку конкретного бита этого порта.

Инициализация для одной кнопки:
Код
  // Initialize interrupts
  portA->PIO_IFER = SW1;  
  pAic->AIC_IDCR = (1<<AT91C_ID_PIOA);
  pAic->AIC_SMR[AT91C_ID_PIOA] =(AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE|AT91C_AIC_PRIOR_HIGHEST);
  pAic->AIC_SVR[AT91C_ID_PIOA] = (unsigned int) int_sw;
  portA->PIO_IER = SW1;
  pAic->AIC_IECR = (1<<AT91C_ID_PIOA);


Обработчик:
Код
void int_sw(void){  
  if(!((portA->PIO_PDSR) & SW1))
  {
    Delay(5,'m');
    portA->PIO_SODR |= LED1;
  }else if(((portA->PIO_PDSR) & SW1))
  {
    Delay(5,'m');
    portA->PIO_CODR |= LED1;
  }
}


где
Код
#define SW1    BIT29
#define LED1    BIT7
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.