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

Внешнее прерывание AT91SAM7S256.

Добрый день всем!

Имеется отладочная плата sam7-mt256 фирмы olimex. На плате имеется джойстик, состоящий из 5 кнопок.

Хочу сделать прерывание по нажатию на одну из этих кнопок, но как-то не выходит. Т.е. по нажатию на кнопку программа уходит в прерывание и крутится в нем, пока не перезагрузишь контроллер. На сколько я понял, за окончание прерывания отвечает запись любого значения в регистр AIC_EOICR, но это тоже не помогает. Может кто делал что-нибудь подобное, подскажите куда копать? Ниже приведена часть кода, в котором производится настройка и описание прерывания.

Используемая среда разработки IAR 5.4.

 

#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)
 {

 }
}

Изменено пользователем vutang

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


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

Почему Вы для прерывания PIO инициализируете источник IRQ1?

AT91C_PIOA_IMR - Read Only, писать его смысла нет.

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


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

Исправил код следующим образом:

 

  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);

 

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

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


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

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

 

С механизмом "висения" что-то не очень ясно пока. Как организован код вектора прерывания?

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


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

Извините не совсем понял про код вектора прерывания, где его посмотреть можно?

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


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

Часть кода из файла board_cstartup_iar.s. На сколько я понимаю тут на ассемблере написано, а я в нем не силен.

/*
  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

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

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


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

Тогда уберите из вашего обработчика модификатор __irq и запись AIC_EOICR, так как все это уже сделано в обертке irqHandler.

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


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

Эффекта нет. Пошагово просмотрел как выполняется программа, сразу после строки "BX r0" в файле board_cstartup_iar.s входит в прерывание. Смотрел примеры на сайте производителя, так там просто в цикле опрашивается состояние пинов. Хочется на прерываниях сделать, не думал, что вылезут такие косяки. Подумываю уже таймер задействовать...

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


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

Чтение PIO_ISR есть, проглючило меня :)

 

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

 

BIT7 = это (1 << 7)?

тогда что за странная запись *AT91C_PIOA_ASR = (1<<SW2); ?

а тактирование PIO включено?

Изменено пользователем RabidRabbit

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


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

Эффекта нет. Пошагово просмотрел как выполняется программа, сразу после строки "BX r0" в файле board_cstartup_iar.s входит в прерывание.

Вот "пошагово" - это и источник всех бед. AIC под отладчиком не сброшен, потому и чудит.

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


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

Короче все заработало. Наверное проблема была в том, что 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

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


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

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

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

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

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

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

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

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

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

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