Forum: Mikrocontroller und Digitale Elektronik Interrupt löst dauernd aus


von Peter M. (allforone)


Lesenswert?

Hallo,
Ich habe nur einen Interrupthandler. Dieser ist für drei interrupts 
zuständig. (SPI)
Er löst die ganze Zeit und es kommt zu dem Watchdogfehler, das Programm 
kehrt nicht in die Main zurück. Leider kann ich den Fehler nicht finden.
1
// Includes ----------------------------------------------------------------------------------------
2
#include <hidef.h> /* for EnableInterrupts macro */
3
#include "derivative.h" /* include peripheral declarations */
4
#include "SPIDriver.h"
5
6
7
// Variablen ---------------------------------------------------------------------------------------
8
uint8 c_Data = 0x02;
9
static int sbufferpos = 0;
10
11
// Prototypen --------------------------------------------------------------------------------------
12
void SendeTakt(int takt);
13
14
// Main --------------------------------------------------------------------------------------------
15
void main(void) {
16
17
  
18
19
    spi_init();
20
    spi_setMode(Master, RisingEdge, LeadingEdge, LSBfirst);
21
    spi_selectChip(true);
22
    spi_enableInterrupt(true);
23
    
24
  
25
      for(;;)
26
      {
27
        __RESET_WATCHDOG();
28
        if(spi_checkComplete() == true)
29
        {
30
          c_Data = spi_receiveData();
31
          SendeTakt(27);
32
          
33
        }
34
      }  
35
   } 
36
37
__interrupt VectorNumber_Vspi1 void ISR_SPI() {
38
39
  uint8 Temp;
40
  if(sbufferpos==32) {
41
  sbufferpos = 0;
42
  } 
43
  else{
44
     sbufferpos = sbufferpos +1;
45
46
   if(SPI1S_SPRF == 1) {
47
      c_Data = spi_receiveData();
48
   } 
49
   else if(SPI1S_SPTEF == 1) {
50
      Temp = SPI1D;
51
      SendeTakt(27);    
52
   } 
53
   else{
54
      //Fehler
55
   }
56
   
57
  }
58
}
59
60
// Funktionen -----------------------------------------------------------------------------------------
61
void SendeTakt(int takt) {
62
63
  byte buffer[32];
64
  if(takt== 27) { //Wertzuweisung von buffer
65
 
66
  } 
67
  else if(takt == 26){  //Wertzuweisung von buffer
68
 
69
  } 
70
  else {
71
  }
72
    spi_sendData(buffer[sbufferpos]);
73
   
74
}

von ♪Geist (Gast)


Lesenswert?

Flag nicht gelöscht?

von RS (Gast)


Lesenswert?

Mach doch mal aus dieser Zeile

sbufferpos==32

sbufferpos >= 32

von Peter M. (allforone)


Lesenswert?

Ein Bit bzw. Flag bekomme ich nicht gelöscht.

"This bit is set when there is room in the transmit data buffer. It is 
cleared byreading SPI1S with SPTEF set, followed by writing a data value 
to the transmit buffer at SPI1D. SPI1S must be read with SPTEF = 1 
before writing data to SPI1D or the SPI1D write will be ignored. SPTEF 
generates an SPTEF CPU interrupt request if the SPTIE bit in the SPI1C1 
is also set. SPTEF is automatically set when a data byte transfers from 
the transmit buffer into the transmit shift register. For an idle SPI 
(no data in the transmit buffer or the shift register and no transfer in 
progress), data written to SPI1D is transferred to the shifter almost
immediately so SPTEF is set within two bus cycles allowing a second 
8-bit data value to be queued into the transmit buffer. After completion 
of the transfer of the value in the shift register, the queued value 
from the
transmit buffer will automatically move to the shifter and SPTEF will be 
set to indicate there is room for new data in the transmit buffer. If no 
new data is waiting in the transmit buffer, SPTEF simply remains set and 
no data moves from the buffer to the shifter.
0 SPI transmit buffer not empty
1 SPI transmit buffer empty"

Hier ein auszug aus dem Datenblatt.
Sobald ich keine neuen Daten mehr schreiben will, und das SPTEF Flag 
gesetzt bleibt, löst die ganze Zeit das Interrupt aus.

"SPTEF simply remains set..." Genau das versuche ich eigentlich...

Jemand eine Idee?


#Nachtrag:
1
__interrupt VectorNumber_Vspi1 void ISR_SPI() {
2
3
    uint8 Temp;
4
    uint8 Tempo1;
5
    uint8 Tempo2;
6
    
7
    
8
    
9
  //Flags speichern
10
  Tempo1 = SPI1S_SPRF;
11
  Tempo2 = SPI1S_SPTEF;
12
  
13
  //Flags löschen
14
  SPI1S_SPRF = 0;
15
  SPI1S_SPTEF = 0;
16
17
18
   if(Tempo1 == 1) {
19
      
20
      Temp = spi_receiveData();
21
   } 
22
   else if(Tempo2 == 1) 
23
   {
24
      //schreibbereit    
25
   } 
26
   else{
27
      //Fehler
28
   }
29
30
}

So versuche ich es mittlerweile, leider auch ohne Erfolg. Einfach 0 
setzen geht nicht.

von amateur (Gast)


Lesenswert?

>Mach doch mal aus dieser Zeile

Sollte nichts ändern, wenn der obige Code vollständig ist.

Beinhaltet: "spi_enableInterrupt(true);" auch das obligatorische "sei;"?

von Peter M. (allforone)


Lesenswert?

1
void spi_enableInterrupt(bool b_Option)
2
{
3
  if(b_Option == true)
4
  {
5
    // SPI Interrupt einschalten
6
    SPI1C1 = SPI1C1|(SPI1C1_SPIE_MASK);
7
    SPI1C1 = SPI1C1|(SPI1C1_SPTIE_MASK);
8
9
    // Interrupts freigeben
10
    EnableInterrupts;
11
  }
12
  else
13
  {
14
    // SPI Interrupt abschalten
15
    SPI1C1 = SPI1C1&~(SPI1C1_SPIE_MASK);
16
  }
17
}

EnableInterrupts steht für sei().

von Peter M. (allforone)


Lesenswert?

Irgendjemand noch eine Idee?

Zur Info:
Controller MC9S08AW60 (freescale)

von jojo (Gast)


Lesenswert?

Jan R. schrieb:
> So versuche ich es mittlerweile, leider auch ohne Erfolg. Einfach 0
> setzen geht nicht.

der Flag wird durchs Setzten gelöscht, also nicht 0 sonder 1.


Interrupt: Zeitverhalten eines Timerinterrupts

Beitrag "ATMEGA128: Interruptflag löschen durch setzen?"

von holger (Gast)


Lesenswert?

>der Flag wird durchs Setzten gelöscht, also nicht 0 sonder 1.

Beim AVR, aber bei seinem Freescale?

von M. N. (Gast)


Lesenswert?

Jan R. schrieb:
> Sobald ich keine neuen Daten mehr schreiben will, und das SPTEF Flag
> gesetzt bleibt, löst die ganze Zeit das Interrupt aus.

Das ist ja auch richtig, damit die Übertragung überhaupt gestartet wird.
Nachdem das letzte Byte übertragen wurde, mußt Du den Interrupt 
abschalten.

Das könnte so aussehen:
spi_enableInterrupt(false);

von Amateur (Gast)


Lesenswert?

Ich kenne Deinen Prozessor nicht, aber "Frage an Radio Eriwan"
Wie wichtig ist die Sequenz:

Temp = SPI1D;

eigentlich?

Ein Compiler, der was auf sich hält, streicht diesen Befehl ersatzlos, 
da Temp in der Folge nicht verwendet wird.

Stichwort: volatile.

von Peter D. (peda)


Lesenswert?

Amateur schrieb:
> Stichwort: volatile.

IO-Register werden in der Regel im *.h File als volatile gecastet.
Zum Lesezugriff reicht aus:
1
SPI1D;

von Peter M. (allforone)


Lesenswert?

M. N. schrieb:
> Das ist ja auch richtig, damit die Übertragung überhaupt gestartet wird.
> Nachdem das letzte Byte übertragen wurde, mußt Du den Interrupt
> abschalten.
>
> Das könnte so aussehen:
> spi_enableInterrupt(false);

Ok, dass wusste ich so nicht. Dann muss ich das Interrupt einfach 
ausschalten.

Bei der jetztigen Codeversion habe ich das Interrupt noch nicht 
ausgeschaltet, aber es funktioniert in dem Sinne von es schreibt die 
ganze Zeit.
1
void main(void) {
2
3
    spi_init();
4
    spi_setMode(Master, FallingEdge, LeadingEdge, MSBfirst);
5
    spi_selectChip(true);
6
    spi_enableInterrupt(true);
7
    
8
      for(;;)
9
      {
10
        __RESET_WATCHDOG();
11
12
          if( spi_checkComplete()==true) {
13
            
14
          SendeTakt(27);
15
          }
16
      }  
17
   } 
18
19
__interrupt VectorNumber_Vspi1 void ISR_SPI() {
20
21
    __RESET_WATCHDOG();
22
23
    if(sbufferpos<32) {
24
        sbufferpos = sbufferpos + 1;
25
26
           if((SPI1S&(SPI1S_SPRF_MASK)) == 0) {
27
           } 
28
           else{
29
              SPI1S;
30
              SPI1D;
31
           }
32
           if((SPI1S&(SPI1S_SPTEF_MASK)) == 0){  
33
           } 
34
            else{
35
              SPI1S;
36
              SendeTakt(27);
37
            }
38
    }
39
    else{
40
       sbufferpos = 0;
41
    }  
42
}

Hier die spi_checkComplete:
1
bool spi_checkComplete()
2
{
3
  uint8 Temp;
4
5
  if((SPI1S&(SPI1S_SPTEF_MASK)) == 0)
6
  {
7
    return false;
8
  }
9
  else
10
  {
11
    // SPI Data Buffer lesen um Interrupt Bit zu leeren
12
    Temp = SPI1D;
13
    return true;
14
  }
15
}

Den Watchdog sollte man ja eigentlich nciht im Interrupt feeden. Wenn 
ich es allerdings nicht mache, wird das Watchdoginterrupt nach etwa 20 
Durchläufen des Sendevorgangs ausgelöst. Ziemlich komisch, es werden 
keine Fehler angezeigt -> COP Watchdog caused a Reset

Hat hier noch jemand eine Idee?

Controller: MC9S08AW60 (freescale)
http://www.freescale.com/files/microcontrollers/doc/data_sheet/MC9S08AW60.pdf


Auf jeden Fall schon mal vielen Dank für die hilfreichen Antworten!

von jojo (Gast)


Lesenswert?

Datenblatt Seite 179
"
10.6.1 Clearing Timer Interrupt Flags
TPM interrupt flags are cleared by a 2-step process that includes a read 
of the flag bit while it is set (1)
followed by a write of 0 to the bit. If a new event is detected between 
these two steps, the sequence is reset
and the interrupt flag remains set after the second step to avoid the 
possibility of missing the new event.
"

von Peter M. (allforone)


Lesenswert?

Ok, nur es ist ja ein SPI Interrupt.
Und wieso kommt der Fehler beim ca. 20. Durchlauf und nicht schon beim 
ersten?

von M. N. (Gast)


Lesenswert?

Jan R. schrieb:
> Und wieso kommt der Fehler beim ca. 20. Durchlauf und nicht schon beim
> ersten?

Das wirst Du herausfinden und uns mitteilen :-)

von Peter M. (allforone)


Lesenswert?

Ich kann euch mitteilen, dass es so ist. Wieso wird bei mir leider 
schwer...

Aber sehe ich das richtig, dass man zwangsläufig in der ISR den 
Schreibvorgang starten muss.

Ein solches Konstrukt funktioniert nicht:
1
main(){
2
    while(sbufferpos < buffergöße)
3
    {
4
    SendeData(bufferpos);
5
    }
6
}
7
8
ISR()
9
{
10
    if(Transmissionbuffer == empty)
11
    {
12
    sbufferpos++; 
13
    } 
14
}

Wenn man es so machen würde, würde das Interrupt ja permanent ausgelöst 
werden, da das Transmissionbufferemptyflag nicht acknowledged wird. Sehe 
ich das richtig?

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.