Forum: Mikrocontroller und Digitale Elektronik CoIDE LPC11C24 Cortex M0, wie ISR ausfrufen?


von Matthias R. (maro0007)


Lesenswert?

Hallo zusammen,

Ich programmiere mit CoIde ein selbst zusammengestelltes Board mit 
LPC11C24 Controller. Ich will mittels eines Timer Interrupts LEDs 
pulsen.
Hierfür nehme ich den 16_Bit_Timer_0. Mein Problem ist,dass mein 
Programm nicht in die ISR springt. Warum? Woher weiß der Controller, 
welche ISR er ausführen muss?

Meine Code sieht folgendermaßen aus:


#include "lpc11xx_gpio.h"
#include <system_LPC11xx.h>
#include "lpc_types.h"
#include "lpc11xx_iocon.h"
#include "lpc11xx_tmr.h"
#include<My_functions.h>
#define _LPC11xx_H_
#define Sysclock_16_Bit_0 0x40




void TIMER_16_0_IRQHandler(void)   // ISR für Interrupt durch 
16-Bit-Timer
{ein();//LEDs werden eingeschalten
 LPC_TMR16B0->IR&=~0x3F; // Timer Interrupt löschen
 }

 void wait (void)

 { int i=0;
   for(i =0;i<=100000;i++)
   {}

 }



int main(void)

{ NVIC_EnableIRQ(TIMER_16_0_IRQn ); // 16 - Bit - Timer Interrupt 
einschalten

  SYSCON_AHBPeriphClockCmd(Sysclock_16_Bit_0,ENABLE); // Clock für 16 
Bit Time ein

  LPC_SYSCON->MAINCLKSEL = 0x01;
  LPC_TMR16B0->TCR |= 0x01; //16-Bit Counter ein
  LPC_TMR16B0->TC |= 0xFFFF;// Overflow bei 0xFFFF
  LPC_TMR16B0->PR |= 0x0FF; //Prescale 0xFF;
  LPC_TMR16B0->MCR |= 0x01; // Match Register Interrupt enable
  LPC_TMR16B0->MR0 |= 0xFFFF; // Interrupt, wenn Timer 1 FFFF erreicht

  ledinit(); // Pins für LED werden initialisiert
  wait();
  aus();// LEDs werden ausgeschalten


  while(1)
    {

    }

}


Meine Leds schalten sich nicht wieder ein, was heißt, das er nicht in 
die ISR springt. warum?

von Dr. Sommer (Gast)


Lesenswert?

Matthias R. schrieb:
> Woher weiß der Controller,
> welche ISR er ausführen muss?
Am Namen - typischerweise ist im Startupcode oder so der ISR-Vektor 
hinterlegt, welcher die ISR's nach ihrem Namen abfragt und auflistet. 
Daher muss deine ISR genau den richtigen Namen haben - keine Ahnung ob 
das bei dir der Fall ist.

von old man (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Matthias R. schrieb:
>> Woher weiß der Controller,
>> welche ISR er ausführen muss?
> Am Namen - typischerweise ist im Startupcode oder so der ISR-Vektor
> hinterlegt, welcher die ISR's nach ihrem Namen abfragt und auflistet.
> Daher muss deine ISR genau den richtigen Namen haben - keine Ahnung ob
> das bei dir der Fall ist.

Wie wird die Datei übersetzt? als C oder C++? Sollte es C++ sein, dann 
geht es so nicht. Da muss die Interrupt-Routine als extern "C" 
deklariert werden.

Dann  machst du alles irgendwie verkehrt rum. Ich würde zuerst die Leds 
initialisieren, die Timer-Register setzen, dann den Interrupt im NVIC 
enablen und zum Schluss erst den Timer mit Enable im TCR loslaufen 
lassen. Hast du keinen Debugger?

von Jojo S. (Gast)


Lesenswert?

der Code sieht erstmal nicht so verkehrt aus. Die ISR Namen sind 
üblicherweise im startup code zu finden. Darin ist eine Tabelle mit den 
Sprungvektoren abgelegt. Die sind mit defaults belegt die meist in einer 
Endlosschleife enden. Durch das Attribut 'weak' nimmt der Linker aber 
einen anderen IRQ-Handler wenn vorhanden.
Von der Reihenfolge her würde ich den timer erst starten (TCR=1) wenn 
die restliche Timerconfig gesetzt ist.

von Stefan (Gast)


Lesenswert?

Und mit die Interrupts müssen nochmal global freigegeben werden.

von old man (Gast)


Lesenswert?


von Matthias R. (maro0007)


Lesenswert?

Danke für die schnellen Antworten!!

ich programmiere in C.

Habe die Header Datei mit den Namensbezeichnung der ISRs gefunden und 
den Ablauf des Programms geändert.
Jetzt springt es ins Interrupt, aber nicht mehr heraus. Habe es mit 
return probiert, funktioniert aber nicht.
Wie kann ich die ISR beenden?

Mein Code sieht jetzt so aus:


#include "lpc11xx_gpio.h"
#include <system_LPC11xx.h>
#include "lpc_types.h"
#include "lpc11xx_iocon.h"
#include "lpc11xx_tmr.h"
#include <My_functions.h>
#define _LPC11xx_H_
#define Sysclock_16_Bit_0 0x40




void TIMER16_0_IRQHandler(void)   // ISR für Interrupt durch 
16-Bit-Timer
{ein();//LEDs werden eingeschalten
 LPC_TMR16B0->IR&=~0x3F; // Timer Interrupt löschen
 return(0);
 }

 void wait (void)

 { int i=0;
   for(i =0;i<=100000;i++)
   {}

 }

int main(void)

{ ledinit(); // Pins für LED werden initialisiert
  LPC_SYSCON->SYSAHBCLKCTRL|=0x80;//// Clock für 16 Bit Time ein
  LPC_SYSCON->MAINCLKSEL = 0x01;
  LPC_TMR16B0->TC |= 0xFFFF;// Overflow bei 0xFFFF
  LPC_TMR16B0->PR |= 0x001; //Prescale 0xFF;
  LPC_TMR16B0->MCR |= 0x01; // Match Register Interrupt enable
  LPC_TMR16B0->MR0 |= 0xFFFF; // Interrupt, wenn Timer 1 FFFF erreicht
  NVIC_EnableIRQ(TIMER_16_0_IRQn ); // 16 - Bit - Timer Interrupt 
einschalten
  LPC_TMR16B0->TCR |= 0x01; //16-Bit Counter ein
  wait();
  aus();// LEDs werden ausgeschalten


  while(1)
    {

    }

}

von generic (Gast)


Lesenswert?

wieder einer, der nicht begriffen hat, dass ein c-programm nicht mit 
main() beginnt. Schau dir den startup-code an, dann sollte alles klar 
sein.

von Dr. Sommer (Gast)


Lesenswert?

Matthias R. schrieb:
> Jetzt springt es ins Interrupt, aber nicht mehr heraus. Habe es mit
> return probiert, funktioniert aber nicht.
return braucht man nicht - und return (0) sollte auch einen Fehler geben 
bei einer Funktion mit Rückgabetype "void"... Vermutlich wird sofort die 
ISR nochmal aufgerufen.

von Matthias R. (maro0007)


Lesenswert?

Scheinbar wird das Interrupt schon wieder ausgelöst, bis die ISR zu Ende 
ist, da wenn ich das Interrupt innerhalb der ISR aussschalte, der 
Controller aus der ISR geht.


#include "lpc11xx_gpio.h"
#include <system_LPC11xx.h>
#include "lpc_types.h"
#include "lpc11xx_iocon.h"
#include "lpc11xx_tmr.h"
#include <My_functions.h>
#define _LPC11xx_H_
#define Sysclock_16_Bit_0 0x40



 void wait (void)

 { int i=0;
   for(i =0;i<=100000;i++)
   {}

 }

int main(void)

{ ledinit(); // Pins für LED werden initialisiert
  LPC_SYSCON->SYSAHBCLKCTRL|=0x80;//// Clock für 16 Bit Time ein
  LPC_SYSCON->MAINCLKSEL = 0x01;
  LPC_TMR16B0->TC |= 0xFFFE;// Overflow bei 0xFFFF
  LPC_TMR16B0->PR |= 0xFFFF; //Prescale 0xFF;
  LPC_TMR16B0->MCR |= 0x03; // Match Register Interrupt enable
  LPC_TMR16B0->MR0 |= 0xFFFF; // Interrupt, wenn Timer 1 FFFF erreicht
  NVIC_EnableIRQ(TIMER_16_0_IRQn ); // 16 - Bit - Timer Interrupt 
einschalten
  LPC_TMR16B0->TCR |= 0x01; //16-Bit Counter ein

  ein();//LEDs werden eingeschalten
  wait();
  aus();// LEDs werden ausgeschalten


  while(1)
    {

    }

}

void TIMER16_0_IRQHandler(void)   // ISR für Interrupt durch 
16-Bit-Timer
{ein();//LEDs werden eingeschalten

 }

von old man (Gast)


Lesenswert?

Matthias R. schrieb:
> void TIMER16_0_IRQHandler(void)   // ISR für Interrupt durch
> 16-Bit-Timer
> {ein();//LEDs werden eingeschalten
>  LPC_TMR16B0->IR&=~0x3F; // Timer Interrupt löschen
>  return(0);
>  }

Zuallererst richtig im Handbuch lesen:

Interrupt Register (TMR16B0IR and TMR16B1IR)
The Interrupt Register (IR) consists of four bits for the match 
interrupts and one bit for the
capture interrupt. If an interrupt is generated then the corresponding 
bit in the IR will be
HIGH. Otherwise, the bit will be LOW. Writing a logic one to the 
corresponding IR bit will
reset the interrupt. Writing a zero has no effect.


Das heißt wenn schon dann so: LPC_TMR16B0->IR=0x1F

Zusätzlich:
Glückwunsch! Hier bist du schon bei deinen ersten Zeilen auf ein paar 
Fallstricke gestoßen die so nicht in den Dokumentationen auftauchen.
Die Hardware (Timer u.s.w.) sind über einen Bus an die CPU angekoppelt. 
Das hat zur Folge, wenn du am Ende der Interruptroutine erst das IR-Flag 
löscht, ist dieser Zustand noch garnicht beim NVIC angekommen, aber dein 
Interrupt schon zu Ende. Danach wird er sofort neu gestartet. Wenn du 
das Flag vor deiner ein()-Funktion löscht sollte die Zeit ausreichen.

von Matthias R. (maro0007)


Lesenswert?

Habe jetzt 'LPC_TMR16B0->IR=0x1F' vor ein() und jetzt geht er wieder aus 
dem Interrupt raus. Was mich jedoch wundert ist, nachdem der Timer 
gestartet wurde , 2 Steps im Debug-Modus später schon das Interrupt 
auslöst und er das Interrupt nicht mehr aufruft. Warum?  Ich kann den 
Timer Value währenddes debuggens leider nicht auslesen.

Hat jemand ein Code Beispiel mit einem funktionierenden Timer-Interrupt 
,welches immer wieder in gewissen Zeitabständen aufgerufen wird?

Mein Code sieht jetzt so aus:

#include "lpc11xx_gpio.h"
#include <system_LPC11xx.h>
#include "lpc_types.h"
#include "lpc11xx_iocon.h"
#include "lpc11xx_tmr.h"
#include <My_functions.h>
#define LPC11xx_H
#define Sysclock_16_Bit_0 0x40



 void wait (void)

 { int i=0;
   for(i =0;i<=100000;i++)
   {}

 }

int main(void)

{ ledinit(); // Pins für LED werden initialisiert
  LPC_SYSCON->SYSAHBCLKCTRL|=0x80;//// Clock für 16 Bit Time ein
  LPC_SYSCON->MAINCLKSEL = 0x01;
  LPC_TMR16B0->TC |= 0xFFFE;// Overflow bei 0xFFFF
  LPC_TMR16B0->PR |= 0xFFFF; //Prescale 0xFFFF;
  LPC_TMR16B0->MCR |= 0x03; // Match Register Interrupt enable
  LPC_TMR16B0->MR0 |= 0xFFFF; // Interrupt, wenn Timer 1 FFFF erreicht
  NVIC_EnableIRQ(TIMER_16_0_IRQn ); // 16 - Bit - Timer Interrupt 
einschalten
  LPC_TMR16B0->TCR |= 0x01; //16-Bit Counter ein

  ein();//LEDs werden eingeschalten
  wait();
  aus();// LEDs werden ausgeschalten


  while(1)
    {

    }

}

void TIMER16_0_IRQHandler(void)   // ISR für Interrupt durch16-Bit-Timer
{LPC_TMR16B0->IR|=0x1F;
  ein();//LEDs werden eingeschalten

 }

von old man (Gast)


Lesenswert?

Den ersten Interrupt kriegst du, weil du TC mit dem selben Wert 
initialisierst wie MR0. Normalerweise braucht TC nicht gesetzt zu 
werden, das ist ja der eigentliche Zähler. Zusammen mit dem Prescaler 
von 0xffff ergibt das einen Überlauf nach 2^32 Takten. Macht bei 48Mhz 
rund 89 Sekunden. Hast du überhaupt solange gewartet?

von Matthias R. (maro0007)


Lesenswert?

Achso. Hab gedacht TC gibt den Wert an, bis den der Counter zählt.
Hab den Befehl gelöscht, jetzt funktionierts :)
Vielen Dank!

von old man (Gast)


Lesenswert?

Die Beschreibung der relativ einfachen Timer der LPC11xx Serie ist 
eigentlich ganz gut. Dein Hauptproblem war wohl sich zu wenig mit der 
Doku beschäftigt zu haben. Das wäre aber dringen angeraten wenn du 
tiefer einsteigen willst ohne jedesmal frustriert hängen zu bleiben...

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.