der Interrupt für xmega256A3 wird nicht ausgelöst

Gast #4272641
Lesenswert?

Hallo liebe Freunde,

ich versuche die letzen Tage den xmega256A zu programieren, der µC
soll ein digitales Signal messen. Daher muss die Zeit zwischen zwei 
fallenden Flanken gemessen werden, und dann diese Messungen auswerten.
Alles muss mithilfe von Interrupt gemacht werden.
Mein Problem: Die Interrupt Serviceroutine wird nie ausgelöst, ich habe 
bestimmt fehler bei der Initialisierung. Kann jemand bitte mir den Code
gucken vielleicht findet man den Fehler, ich sitze seit ein paar Tage 
und habe das Problem leider nicht gelöst.
Das Eingangssignal liegt an PIN3 PORTC.


1
#include <avr/io.h>
2
#include "avr/interrupt.h"
3
#include <stdint.h>
4
#include <util/delay.h>
5
#include "avr_compiler.h"
6
#include "function.h"
7
#include "UartHandler.h"
8
#include "usart_driver.h"
9

10

11
/***********************************/
12

13
void funct_port_init (void)
14
{
15
  
16
  /* Port C - digital I/O */
17
  DIGI_PORT.DIRSET =  DIGI_PIN1;              // Port C Pin 1 digital I/O 1 as output PIN7
18
  DIGI_PORT.DIRCLR = DIGI_PIN2;        // Port C Pin 3 digital I/O 2 as input    PIN9
19
  DIGI_PORT.DIRSET = OPTO_PIN;        // Port C Pin 0 opto-coupler as digital output
20

21
    PORTC.PIN0CTRL= PORT_OPC_WIREDANDPULL_gc;
22
  PORTC.INTCTRL =  PORT_INT0LVL_LO_gc | PORT_INT0LVL_MED_gc  | PORT_INT0LVL_HI_gc;
23
  PORTC.PIN3CTRL  = PORT_OPC_PULLUP_gc | PORT_ISC_FALLING_gc;
24
  PORTC.INT0MASK = 0x03;    
25
  
26
}
27

28

29
/**********************************/
30

31

32
void funct_inter_init(void)
33
{
34
  PMIC.CTRL = PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm | PMIC_HILVLEN_bm;
35
}
36

37
/***********************************/
38

39
void funct_timer2_init(void)
40
{
41
  TCD1.CTRLA = TC_CLKSEL_DIV1_gc;
42
  TCD1.CTRLB = TC_WGMODE_NORMAL_gc;
43
  TCD1.INTCTRLA = TC_OVFINTLVL_HI_gc;
44
  TCD1.PER= 0xFFF;
45
}
46

47

48
/***********************************/
49

50

51
float zaehler_auswerten(void)
52
{
53
  float perioden_dauer = 0;
54
  if (PORTC_PIN3CTRL==0) // hier soll der Counter anfangen zu zählen bei fallender Flanke
55
  
56
  {
57
    
58
perioden_dauer = TCD1.CNT*zeit_in_us;
59
TCD1.CNT= 0;
60
    zaehler=true;
61
  }
62
  return perioden_dauer;
63
}
64

65
/***********************************/
66

67

68
ISR(PORTC_INT0_vect) // interrupt für I/O Port
69
{
70
  uart_send_string("\ninterrupt ausgeloest\n"); // Diese serielle Ausgabe wird nicht an Termite angezeigt
71
  
72
perioden_dauer = zaehler_auswerten();
73
  interrupt=true;
74
  
75
  
76
  if (perioden_dauer >= sync_min_1)       // synchronization and Communication
77
  {
78
    synchronisiert_b = true;
79
    clock_tick = perioden_dauer*ticks;
80
    
81
    n_nibble = 0;
82
  }
83
  
84
  
85
}
86

87
/***********************************/
88

89
ISR(TCD1_OVF_vect) // Counter Interrupt
90
{
91
  uart_send_string("\ninterrupt timer ausgeloest\n");
92
  
93
if (interrupt)
94
{
95
TCD1.CNT=0 ;
96
}
97

98

99
}
100

101
/***********************************/
102

103
int main (void)
104
{
105
  
106
  sei();
107
  funct_clock_init_PLL_60M();                // clock initialization 60 MHz
108
  
109
  
110
  
111
  funct_DACB_single0_enable(DAC_REFSEL_AVCC_gc);      // initialize DAC with internal Vcc
112
  
113
  uart_InitUsartDriver();                  // initialize RS232 communication
114
                      
115
  
116
DIGI_PORT.OUTCLR =DIGI_PIN1;    //digital output port pin 1 LOW
117
DIGI_PORT.OUTCLR = OPTO_PIN;  // opto-coupler pin LOW
118
  
119
IdleValue=DEFAULT_IDLE_VAL; // analog output -> 5 V (max.: 0x0FFF, 12 bit)
120
  Port=SER_PORT_AO0;                // set analog output as idle port
121
  errorOut=true;                         // turn on error messages by default
122
  debugOut=true;                      // turn on debug messages by default
123
  
124
  
125
  
126
  if (debugOut)
127
  {
128
    uart_send_string(version);
129
    // send version number via RS232
130
    uart_send_string("\nSignalgenerator laeuft\n");
131
  }
132
  
133

134
  funct_timer2_init();
135
  uart_send_string("\ntimer2 initialisiert\n");
136
  funct_port_init();
137
  funct_inter_init();
138
  
139
  uart_send_string("\nSignalgenerator wurde initialisiert\n");
140

141

142
  uart_send_string("\nENDE INITIALISIERUNGEN\n");
143
    
144
  /* main loop */
145
  while(1)
146
  {
147
  }
148
}
Gast #4272894
Lesenswert?

>> Daher muss die Zeit zwischen zwei
fallenden Flanken gemessen werden, und dann diese Messungen auswerten.
Alles muss mithilfe von Interrupt gemacht werden.

1.) das mit Interupts zu machen ist idiotisch! (Hast du eine Ahnung 
warum?)
2.) Das macht man beim Xmega:
    mit Timer + Frequency-Capture <= Eventkanal <= Portpin

PS:
Du hast vergessen, global Interrupts zu enablen!
=> sei() !

PPS: Wenn 'was nicht funktioniert, schau im Debugger unter I/O nach.
Da muss das Flag gesetzt sein.
Bei "Prozessor" siehst du dann sicher, dass "I" noch nicht enabled ist.
#4272918
Lesenswert?

Danke Alex für die Antwort,

mein Signal ist eine Impulsfolge, die zeit zwischen zwei fallenden
Flanken liegt in µs Bereich. Außerdem muss jede Periode gemessen und
gleichzeitig mit einem anderen Wert verglichen. Daher ist nutze ich
Interrupt. Es könnte sein, dass die Zeit zum Messen länger dauert als 
die nächste fallende Flanke kommt, und somit wird eine Periode verpasst.


wo muss ich die globale interrupts enablen ??


Danke im Voraus.
#4272927
Lesenswert?

Ahmed M. schrieb:
> Danke Alex für die Antwort,
>
> mein Signal ist eine Impulsfolge, die zeit zwischen zwei fallenden
> Flanken liegt in µs Bereich. Außerdem muss jede Periode gemessen und
> gleichzeitig mit einem anderen Wert verglichen. Daher ist nutze ich
> Interrupt.

Interrupt ist schon ok.
Aber nicht mit selber die Flanke erkennen.

Dazu benutzt man einen Timer, dem man den Input Capture aktiviert.
Denn genau dafür ist er gedacht: um die Zeit zwischen 2 Flanken zu 
messen.

> Es könnte sein, dass die Zeit zum Messen länger dauert als
> die nächste fallende Flanke kommt

was jetzt?
sind die Flanken im µs Bereich oder sind sie so lang, dass der der Timer 
'überläuft'?
(denn in Wirklichkeit setzt man auch den Timer nicht dauernd zurück. Man 
lässt ihn laufen. Zeit = Endstand - Anfangsstand)
#4272940
Lesenswert?

Hallo Karl Heinz,


Timer habe ich schon in meinem Code, aber ich weiß es nicht ob es so
richtig konfiguiert ist oder doch nicht.


Im Prinzip ist die Zeit zwischen zwei fallenden Flanken in meinem Fall
in µs Bereich. Der Counter muss bei jeder Fallenden Flanke zurückgesetzt 
werden (der Counter-Wert muss in array gespeichert werden, bevor er 
zurückgesetzt wird).


Irgendwie wird die fallende Flanke nicht gefunden, obwohl das digitale 
Eingangssignal im Oscilloskop zu sehen ist.



Gruß
#4272979
Lesenswert?

Ahmed M. schrieb:

> Im Prinzip ist die Zeit zwischen zwei fallenden Flanken in meinem Fall
> in µs Bereich. Der Counter muss bei jeder Fallenden Flanke zurückgesetzt
> werden

nein, muss er nicht.

> (der Counter-Wert muss in array gespeichert werden, bevor er
> zurückgesetzt wird).

Der Zeitwert ergibt sich aus Endstand minus Anfangsstand.

Wenn ein Skifahrer um 12:35:12 oben wegfährt und um 12:35:19 im Ziel 
ankommt, dann war er 7 Sekunden unterwegs. Das kannst du mit deiner ganz 
normalen Armbanduhr stoppen, du brauchst keine Stoppuhr dazu, die du 
daernd starten und stoppen musst.

Und genau das willst du mit deinem Timer auch machen. Du willst ihn 
ständig laufen haben. Der Input Capture Mode sichert eigenständig bei 
der Flanke den aktuellen Timerwert in einem speziellen Register und löst 
dann einen Interrupt aus. In diesem Interrupt holst du dir gemütlich den 
Wert aus dem Register und ziehst von ihm den Wert vom letzten Interrupt 
ab. Und schon hast du die Anzahl an Timertakten die seit der letzten 
Flanke vergangen sind. Und zwar hast du die auf den Timertakt genau ohne 
dass du irgendwo etwas hättest starten oder stoppen müssen oder 
irgendwelche Flanken auswerten müssen. etc.

Der Timer Input Capture ist dein Freund. Genau dafür, um die Zeit 
zwischen 2 Flanken zu messen, ist er perfekt geeignet. Genau dafür wurde 
er gemacht.
#4272990
Lesenswert?

Hallo Karl Heinz,


klar verstehe ich Zeit = Endstand - Anfangsstand, das Problem
jetzt in meiner timer Funktion:


void funct_timer2_init(void)
{
  TCD1.CTRLA = TC_CLKSEL_DIV1_gc;
  TCD1.CTRLB = TC_WGMODE_NORMAL_gc;
  TCD1.INTCTRLA = TC_OVFINTLVL_HI_gc;
  TCD1.PER= 0xFFF;
}

wie muss ich noch diese Funktion erweitern damit ich den Timer Input 
Capture hinkriege.

Ich bin leider neu beim Assembler Programmieren.



Gruß
#4273001
Lesenswert?

Ahmed M. schrieb:
> Hallo Karl Heinz,
>
>
> klar verstehe ich Zeit = Endstand - Anfangsstand, das Problem
> jetzt in meiner timer Funktion:
>
>
> void funct_timer2_init(void)
> {
>   TCD1.CTRLA = TC_CLKSEL_DIV1_gc;
>   TCD1.CTRLB = TC_WGMODE_NORMAL_gc;
>   TCD1.INTCTRLA = TC_OVFINTLVL_HI_gc;
>   TCD1.PER= 0xFFF;
> }
>
> wie muss ich noch diese Funktion erweitern damit ich den Timer Input
> Capture hinkriege.

AUch wenn ich keine XMega benutze, bin ich sicher, die Antwort findet 
sich im Datenblatt zu deinem XMega.

> Ich bin leider neu beim Assembler Programmieren.

brauchst du auch nicht.
Du brauchst nur im Datenblatt beim Timer nachsehen, welche Bits in 
welchem Register zu setzen sind. Was anderes machst du ja jetzt auch 
nicht. Nur eben andere Bits.
Assembler braucht dazu kein Mensch können. Auch weil die Atmel 
Datenblätter sehr gut gemacht sind.
Gast #4273098
Lesenswert?

OK, sei() ist schon da!

Aber was soll/macht die "funct_clock_init_PLL_60M(); "??
Wie hoch ist die Fsys?

Man kann zwar die PLL mit 60MHz laufen lassen, muss aber dann Teiler für 
den Sytemclock einstellen. Xmega (CPU & Timer!) können nur max. 32MHz.
(Das HIRES-Zeug ist nur ein "Schummelmodus")
Es hat anscheinend jemand geschafft ihn mit 40 (48??)MHz zu übertakten.
Bei Fsys= 60MHz macht er aber nur noch komische Sachen.
#4273132
Lesenswert?

Alexxx schrieb:
> OK, sei() ist schon da!
>
> Aber was soll/macht die "funct_clock_init_PLL_60M(); "??
> Wie hoch ist die Fsys?
>
> Man kann zwar die PLL mit 60MHz laufen lassen, muss aber dann Teiler für
> den Sytemclock einstellen. Xmega (CPU & Timer!) können nur max. 32MHz.
> (Das HIRES-Zeug ist nur ein "Schummelmodus")
> Es hat anscheinend jemand geschafft ihn mit 40 (48??)MHz zu übertakten.
> Bei Fsys= 60MHz macht er aber nur noch komische Sachen.

hallo Alex,

bei 32 Mhz funktionierte der Interrupt auch nicht.

irgendwie die fallende flanke wird nicht gefunden.

Gruß
#4273143
Lesenswert?

> AUch wenn ich keine XMega benutze, bin ich sicher, die Antwort findet
> sich im Datenblatt zu deinem XMega.
>
Im Datenblatt habe ich nicht viel über Timer Input capture gefunden,
hier was auf dem Datenblatt steht:


"Selecting the input capture event action makes the enabled capture 
channel perform an input capture on an event. The
interrupt flags will be set and indicate that there is a valid capture 
result in the corresponding CC register. At the same
time, the buffer valid flags indicate valid data in the buffer 
registers.
The counter will continuously count from BOTTOM to TOP, and then restart 
at BOTTOM, as shown in Figure 14-11."

> brauchst du auch nicht.
> Du brauchst nur im Datenblatt beim Timer nachsehen, welche Bits in
> welchem Register zu setzen sind. Was anderes machst du ja jetzt auch
> nicht. Nur eben andere Bits.
> Assembler braucht dazu kein Mensch können. Auch weil die Atmel
> Datenblätter sehr gut gemacht sind.

Ja aber Beispiele finde ich leider nicht :(

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren