Forum: Mikrocontroller und Digitale Elektronik AT91-SAM7EX256 External Interrupt


von Kalle N. (Firma: FH-Wolfenbuettel) (pixelkalle)


Lesenswert?

Moin,

ich versuche gerade meinen AT91-Sam7EX256 dazu zu bringen eine bestimmte 
Funktion auszuführen, wenn an einem Pin (PA29) vom PioB ein 
Flankenwechsel von Low auf High bzw. umgekehrt eintritt.
Da der Flankenwechsel evtl. sehr schnell auftritt würde ich das gerne 
mit dem FIQ machen, versuche mich aber erstmal am normalen IRQ. Nur 
leider klappts net. Der Prozi bleibt in der ISR hängen und kommt nicht 
wieder raus. Habe schon den ganzen Vormittag nach HowTo's oder 
Code-Exampeln gesucht, welche aber alle nur über den Timer Counter reden 
- bring mir aber nix. Ich brauch ja den Externen Interrupt. Mein Code 
sieht gerade so aus:
1
void initISR(void){
2
*AT91C_PMC_PCER = (1 << AT91C_ID_PIOA) |  /* Enable Clock for PIO    */
3
      (1 << AT91C_ID_IRQ0);   /* Enable Clock for IRQ */
4
  
5
//First disable IRQ for PIOA
6
AT91C_BASE_AIC->AIC_IDCR = 1 << AT91C_ID_PIOA;
7
//Save interrupt handler routine vector
8
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOA] = (unsigned int)ISR_Test;
9
  
10
  
11
//Store in Source Mode Register, set priority
12
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOA] = AT91C_AIC_SRCTYPE_POSITIVE_EDGE | AT91C_AIC_PRIOR_HIGHEST;
13
  
14
//Enable den Interrupt für Pin29 
15
AT91C_BASE_PIOA->PIO_IER = (AT91C_PIO_PA29);
16
  
17
//Re-enable the interrupt
18
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_PIOA);
19
20
}

Die Aufgerufene Funktion ISR_Test() enthält lediglich eine Debug ausgabe 
für ein FTDI Kabel (bisher). Die Funktion wird aufgerufen sobald die 
initISR(); Funktion aufgerufen wird - allerdings nur einmal. Also nicht 
wiederholt.

Fehlt mir in der ISR sowas wie eine Rücksprungadresse? Register Sichern? 
Macht der ARM das nicht selbst? Ich übernehm jetzt mal keine Garantie 
das alles was da oben steht auch wichtig ist - eigentlich bin ich ja 
mehr HighLevel...

Vielleicht hat ja jemand von euch ein Codebeispiel für eine ISR mit 
externem Interrupt (also ein von einem PIN)

Regards,

Kalle

von embedded-os (Gast)


Lesenswert?

schau mal diesen SAM7... code an (läuft auf S.., XC.. & SE..) - 
vielleicht hilft er dir, auch wenn die org. Register-definition nicht 
verwendet wird.

INIT
-----
    AT91S_PIO_PER        = AT91S_SPI_CD_pin;      // enable GPIO of CD
    AT91S_PIO_ODR        = AT91S_SPI_CD_pin;      // output disable CD
    AT91S_PIO_OWDR       = AT91S_SPI_CD_pin;      // write disable  CD
    AT91S_PIO_PUER       = AT91S_SPI_CD_pin;      // pullup enable  CD
    AT91S_PMC_PCER       = (1 << AT91S_ID_PIO);   // enable clock on 
PIO-interface A for reading

    AT91S_AIC_IDCR       = (1 << AT91S_ID_PIO);   // disable the 
interrupt on the interrupt controller
    AT91S_PIO_IFER       = AT91S_SPI_CD_pin;
    AT91S_PIO_IER        = AT91S_SPI_CD_pin;
    AT91S_PIO_IMR        = AT91S_SPI_CD_pin;
    AT91S_AIC_SVR->s[AT91S_ID_PIO] = (U32)(FFSPort_MMC_ISR);// Save the 
interrupt handler routine pointer and the interrupt priority
    AT91S_AIC_SMR->s[AT91S_ID_PIO] = 
AT91S_AIC_SRCTYPE_INT_HIGHLEVEL_SENSITIVE | PIOPort_INT_PRIO;   // Store 
the Source Mode Register
    AT91S_AIC_ICCR       = (1 << AT91S_ID_PIO);   // Clear the interrupt 
on the interrupt controller
    AT91S_AIC_IECR       = (1 << AT91S_ID_PIO);   // Enable the 
interrupt on the interrupt controller


ISR
------

void FFSPort_MMC_ISR(void)
{
    if(AT91S_PIO_ISR & AT91S_SPI_CD_pin) {
        if(AT91S_PIO_PDSR & AT91S_SPI_CD_pin)     // card-lost or 
card-inserted
            FFSPort_MMC_CDi = 1;                  // remember a 
lost-card interrupt
    }
#ifndef _IAR_SYSTEMS_ICC_
    AT91S_AIC_EOICR = 0;                          // End-of-Interrupt
#endif
}

von Kalle N. (Firma: FH-Wolfenbuettel) (pixelkalle)


Lesenswert?

Hiho.

Danke. Ich war schon ein wenig weitergekommen. Aber über ein Problem bin 
ich noch nicht weggekommen: Selbst wenn ich die "initISR" Funktion 
wieder aufrufe, wird der Interrupt nur einmal ausgeführt - also um 
nochmal in die ISR zu springen muss ich die CPU resetten.

Was muss ich wo wieder auf null drehen damit der Interrupt wieder 
freigeschaltet ist?

MFG

Kalle

von proc (Gast)


Lesenswert?

Habe ein ähnliches Problem (siehe 
Beitrag "Externer Interrupt auf AT91SAM7X-EK mit Eclipse" )

Bei mir wird der Interrupt zur Zeit offenbar einmal mit initISR() 
aufgerufen und verbleibt dann darin ohne je in's Hauptprogramm zu 
gelangen.

Irgendwo im Internet muß es doch ein Beispiel für einen externen 
Interrupt geben oder hier jemanden, der sowas schon mal gemacht hat!?
(Oder wenigstens ein Tutorial außer dem Datenblatt, das aufzeigt, welche 
Register man alle wie setzen muß) !!??



P.S. Am Ende der ISR soll wohl AIC_EOICR gecleart werden um aus dem IR 
wieder herauszukommen (aber was noch?):

void ex_int_handler (void)
{
  volatile unsigned int dummy;

  dummy = AT91C_BASE_PIOA->PIO_ISR;
  ...
  AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_TC0->TC_SR;/*  Interrupt Ack*/
  AT91C_BASE_AIC->AIC_ICCR  = (1 << AT91C_ID_TC0);/*  Interrupt Ack*/
  *AT91C_AIC_EOICR = 0;/* End of Interrupt*/ //bzw.:
  AT91C_BASE_AIC->AIC_EOICR = 0;
}

von Proc P. (proc)


Lesenswert?

Weiß inzwischen woran es liegt (an ethernut; brauche ich leider wegen 
tcpip) kann es aber auch nicht "reparieren".

Ohne ethernut läuft bei mir folgendes Testprogramm:
1
void ex_int_handler (void) 
2
{ 
3
  volatile unsigned int ulDummy;    
4
  AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF; 
5
  AT91C_BASE_AIC->AIC_ICCR = 0x04000000; 
6
  AT91C_BASE_PIOB->PIO_CODR=AT91C_PIO_PB19;  // LED1 im Interrupt zum Test anmachen
7
  asm("mrs r7,CPSR"); 
8
  asm("bic r7,r7,#0x80");
9
  asm("msr CPSR,r7"); 
10
  AT91C_BASE_AIC->AIC_IECR = 0x04000000; 
11
  AT91C_BASE_AIC->AIC_IVR = 0x0;
12
  AT91C_BASE_AIC->AIC_EOICR = 0x0;
13
  ulDummy = AT91C_BASE_PITC->PITC_PIVR;
14
  AT91C_BASE_AIC->AIC_EOICR = ulDummy;
15
16
}
und in
1
main(){
2
 ...
3
  AT91C_BASE_PIOA->PIO_PER=INTTAST;    
4
  AT91C_BASE_PIOA->PIO_ODR =INTTAST; 
5
  AT91C_BASE_PIOA->PIO_CODR=INTTAST; 
6
  AT91C_BASE_PIOA->PIO_PPUER=INTTAST; 
7
  AT91C_BASE_PIOA->PIO_ASR=INTTAST; 
8
  AT91C_BASE_PIOA->PIO_OWDR=INTTAST; 
9
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOA]=AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | 0; 
10
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOA]=(unsigned int)ex_int_handler; 
11
  AT91C_BASE_PIOA->PIO_IFER=INTTAST; 
12
  int io_status = AT91C_BASE_PIOA->PIO_ISR; 
13
  AT91C_BASE_AIC->AIC_IECR=(1 << AT91C_ID_PIOA); 
14
  AT91C_BASE_PIOA->PIO_IER=INTTAST;   
15
 ...
16
  while(1){
17
   ... // hier LED2 blinken lassen
18
  }

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.