Forum: Mikrocontroller und Digitale Elektronik Programm springt nicht aus ISR


von A. C. (michael1988)


Lesenswert?

Hallo,

ich verwende den LPC2148 auf dem Evaluationsboard MCB2140 von Keil. Zum 
Debuggen verwende ich das Programm Hitop 5.

Mein Problem ist, dass mein Programm nach Aufruf der Startfunktion nicht 
mehr aus der ISR heraus springt, sondern immer wieder nach abarbeiten 
der ISR wieder in die selbige springt.

Hier der Code im wesentlichen:
1
int main (void)
2
{
3
4
  i2cMaster_init();
5
  while(1)
6
  {
7
    start(0x90);  
8
  }
9
  return 0;
10
11
}
12
13
void i2cMaster_init(void)
14
{
15
  MEMMAP = 0x2;
16
  
17
  PINSEL0 = 0;
18
  PINSEL1 = 0;
19
  PCONP |= (1 << I2C_POWER);
20
21
  PINSEL0 |=(1 << SCL0_PINSEL) | (1 << SDA0_PINSEL); //SDA und SCL Pins auf I2C-MOdus
22
23
  I20CONCLR = (1 << STO) | (1 << AA) | (1 << STA) | (1 << SI);
24
  I20CONSET = (1 << I2EN) ;//  //enable the I2C function.
25
26
  I20SCLH = 100;
27
  I20SCLL = 58;
28
29
  VICIntSelect = 0;
30
  temp = VICIntSelect;
31
32
  VICVectCntl0 = (DWORD)(IRQ_SLOT_EN | IE_I2C);
33
  VICVectAddr0 = (DWORD) I2C_ISR;  
34
}
35
36
37
38
void i2c_start(int addr)
39
{  
40
  slaveaddr = addr;  
41
  VICIntEnable = (1 << IE_I2C);  
42
  I20CONSET = (1 << STA) ;      //  set STA  
43
}
44
45
void I2C_ISR(void) 
46
{  int temp1 = 0;
47
  temp1 = I20STAT;
48
  I20CONCLR = (1 << SIC);
49
  
50
  switch(temp1)
51
  {
52
    
53
    case 0x08:
54
    {  
55
      I20DAT = slaveaddr; //addr
56
      temp1 = I20DAT;
57
      
58
      break;
59
    }
60
    case 0x10:
61
    {
62
      I20DAT = slaveaddr;
63
      break;
64
    }
65
  }
66
  VICVectAddr = 0;
67
    
68
}

von jimjack j. (jimjack)


Lesenswert?

Hmmm...

gehören die "breaks" nicht jeweils ausserhalb der geschweiften Klammern?

Ich kennne jetzt den LPC nicht, aber hast Du, wenn benötigt das 
Interrupt-Flag vom I2C zurückgesetzt? Bei manchen Controller ist das 
händisch zu machen.

Steffen

von Karl H. (kbuchegg)


Lesenswert?

M. D. schrieb:

> Mein Problem ist, dass mein Programm nach Aufruf der Startfunktion nicht
> mehr aus der ISR heraus springt, sondern immer wieder nach abarbeiten
> der ISR wieder in die selbige springt.

Üblicherweise bedeutet das, dass die interruptauslösende Bedingung dann 
nicht beseitigt wurde.
Meistens ist es so, dass eine ISR diese Bedingung automatisch 
zurücksetzt. Aber gerade bei Kommunikations-ISR ist es oft so, dass man 
das Datenregister des Bausteins auslesen muss, damit das entsprechende 
Interrupt-Flag gelöscht wird.
Wie das bei deinem Prozessor ist, weiß ich nicht. Aber einen Versuch 
wäre es wert.
Sprich: Wenn dir der Aufruf der ISR schon anzeigt, dass ein Byte 
eingetrudelt ist, dann solltest du es auch abholen. Selbst dann, wenn 
ein anderes Flag dir eine Fehlerbedingung anzeigt.

von A. C. (michael1988)


Lesenswert?

HI Steffen

ja das Interrupt-flag lösche ich mit folgernder Zeile,
I20CONCLR = (1 << SIC);

Gruß Michael

von Gast (Gast)


Lesenswert?


von Johnny (Gast)


Lesenswert?

Hat nur indirekt mit Deinem Problem zu tun, aber dennoch:
Mit festen Zuweisungen solltest Du vorsichtig sein, wenn Du eigentlich 
nur Bitoperationen machen willst. Es funktioniert zwar schon, wenn man 
weiss was man tut. Aber meist gibts weniger Fehler, wenn Du Bits 
folgendermassen setzt oder löschst...

Beispiele:

SIC Bit setzen
I20CONCLR |= (1 << SIC);

SIC Bit löschen
I20CONCLR &= ~(1 << SIC);

von Peter D. (peda)


Lesenswert?

Johnny schrieb:
> Mit festen Zuweisungen solltest Du vorsichtig sein, wenn Du eigentlich
> nur Bitoperationen machen willst.


Ne, das stimmt schon, der ARM7 hat spezielle Löschregister.
Eine 1 löscht, eine 0 hat keinen Effekt.

Das ist als Krücke gedacht, da er nicht wie der ARM-Cortex-M3 
Bitoperationen kann.


Peter

von A. C. (michael1988)


Lesenswert?

Ok ,habe das mit dem break geändert, ändert aber leider nichts
am Programmablauf.

Zu |= kann ich nur sagen, dass ich vor diesem Problem faat 10 Tage an 
einem anderen Problem hing und nichts lief, da ich |= verwendet habe bei 
einem Register dass man nur schreiben kann und ich deswegen Probleme 
ohne Ende hatte. Deswegen bin ich damit vorsichtig.

Aber ich will jetzt nicht in dieses Thema abschweifen.
Habe das Falg schon am Anfang der Rotunie gelöscht, nur habe ich dann 
das Problem, dass das Statusregister, dass ich ja auslesen will, 
verändert wird..

von (prx) A. K. (prx)


Lesenswert?

Ob die breaks in der Klammer sind oder draussen ist hier komplett 
wurscht. Und die {} für die switch cases sind hier sowieso überflüssig, 
werden nur benötigt, wenn man dort lokale Variablen definieren will.

Nur bringt es u.U. nichts, das SI Bit zu löschen, wenn der eigentliche 
Grund für den Interrupt noch da ist. Es gibt ja mehr Zustände, als du in 
der ISR berücksichtigst. Wenn du meinst, die seien sinnlos, dann 
solltest du dennoch darauf reagieren, Daten abholen und wegwerfen, 
Abbruch (Stop) erzwingen, ...

von A. C. (michael1988)


Lesenswert?

Den Inhalt vom Statusregister lasse ich mir im Debugger anzeigen.
Die Werte die vorkamen, werden von meiner ISR abgehandelt.

Gruß

von A. C. (michael1988)


Lesenswert?

Noch etwas ist mir aufgefallen:
Erst wenn ich das SI-Flag lösche, werden die Änderungen sichtbar, sprich 
bei Abhandlung des Falls "0x08" wird erst nach löschen Von Si, die 
gesaendete Adresse am Oszi sichtbar.

von (prx) A. K. (prx)


Lesenswert?

> Die Werte die vorkamen, werden von meiner ISR abgehandelt.

Und wenn mal was anderes vorkommt als im Test soll das Programm qua 
Vorschrift einfach hängen bleiben oder abstürzen?

Normalerweise müssten da auch ohne Fehler noch andere Stati kommen. 
Beispielsweise wenn die Adresse raus ist und Daten fällig werden. Gibt 
dazu ein paar schöne Tabellen im Manual (Tab148+).

von A. C. (michael1988)


Lesenswert?

Nein ,mir ist schon klar, dass das Programm so nicht optimal ist.
Aber ich meine in meinem konkreten Problemfall sehe ich ja, aus welchem 
Interruptgrund die ISR ausglöst wurde und jetzt habe ich eben das 
Problem dass ich nicht mehr aus der ISR heraus komme.

Ich habe auch schonmal was zu dem thema gesehen als ich das Problem noch 
nicht hatte, habe es aber bisher noch nicht wieder gefunden...
dann werde ich mal weiter suchen.

Wäre dankbar für schnelle Hilfe,

Gruß

von (prx) A. K. (prx)


Lesenswert?

M. D. schrieb:

> Erst wenn ich das SI-Flag lösche, werden die Änderungen sichtbar, sprich
> bei Abhandlung des Falls "0x08" wird erst nach löschen Von Si, die
> gesaendete Adresse am Oszi sichtbar.

08/10 heisst ja nur, dass eine Start Condition komplett ist. Solange SI 
nicht gelöscht wird ändert sich am Bus per Definition nichts. Siehe 
Doku, steht da so drin. Und die Adresse hat er ohnehin erst als Reaktion 
auf 08/10, wie sollte die also vorher auf dem Bus sichtbar werden 
können?

von A. C. (michael1988)


Lesenswert?

Was mich auch wundert, ist dass das SI Flag laut Debugger garnicht 
gelöscht wird.
Hat jemand eine Ahnung woran das liegen könnte?

von A. C. (michael1988)


Lesenswert?

Ich entschuldige mihc, ich habe auf die falsche Speicherstelle geschaut.
Also Si-Flag wird gelöscht, und Slaveadresse und Daten werden korrekt 
ausgegeben, aber die ISR wird eben nie beendet.....

von A. C. (michael1988)


Lesenswert?

Ich hab jetzt mal die komplette ISR drin.
Ganz des Hauptproblem ist eigentlich, dass alles bis zum abarbeiten von 
"0x28" Routine funktionert(Slaveadresse übertragen mit ACK), allerdings
ist der Satuscode nach dem abrbeiten der "0x28"-Routine ="0x10" und dass 
die Daten nicht übertragen werden.
Wenn der Statuscode dann 0x10 ist, springt die ISR wieder in die "0x10" 
Behandlung.

char buf_config[]={0xAC,0x00,11};
char buf_start[]={0xEE,11};
char buf_read[]={0xAA,11};
char receice_buf[1];

int count = 0, i = 0;
int slaveaddr = 0;int data = 0;
1
void I2C_ISR(void) __irq
2
{  
3
  int temp1 = 0;
4
  temp1 = I20STAT;
5
  
6
  switch(temp1)
7
  {
8
    
9
    case 0x08:
10
    {  
11
      I20DAT = slaveaddr; //addr
12
      temp1 = I20DAT;
13
        
14
    }
15
    break;
16
17
    case 0x10:
18
    {
19
      I20DAT = slaveaddr;
20
    }
21
    break;
22
23
    case 0x18:
24
    {    
25
      i2c_write(buf_config);
26
      if(*buf != 11)
27
        I20DAT = *buf++;
28
      else
29
        i2c_stop();
30
    }
31
    break;
32
33
    case 0x20:
34
    {
35
      i2c_stop();  
36
    }
37
    break;
38
39
    case 0x28:
40
    {
41
        
42
      if(*buf != 11)
43
        I20DAT = *buf++;
44
      else
45
        i2c_stop();
46
    }
47
    break;
48
49
    case 0x30:
50
    {
51
      i2c_stop();    
52
    }
53
}

von (prx) A. K. (prx)


Lesenswert?

M. D. schrieb:

>     case 0x08:
>       I20DAT = slaveaddr; //addr
>       temp1 = I20DAT;   <============

Wozu ist das denn gut?

Wie sehen i2c_stop() und i2c_write() aus?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

In Beitrag "Re: Programm springt nicht aus ISR" fehlt

  }
  VICVectAddr = 0;

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.