Forum: Mikrocontroller und Digitale Elektronik der Interrupt für xmega256A3 wird nicht ausgelöst


von der Interrupt für xmega256A3 wird nicht ausgelöst (Gast)


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
}

: Bearbeitet durch User
von Alexxx (Gast)


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.

von Leser (Gast)


Lesenswert?

der Interrupt für xmega256A3 wird nicht ausgelöst schrieb im Beitrag

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

Lesen kannst Du schon?

#4272641:
> int main (void)
> {
>
>   sei();
>   funct_clock_init_PLL_60M();

von Ahmed M. (mido)


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.

von Karl H. (kbuchegg)


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)

von Ahmed M. (mido)


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ß

von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Ahmed M. (mido)


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ß

von Karl H. (kbuchegg)


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.

von Alexxx (Gast)


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.

von Ahmed M. (mido)


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ß

von Ahmed M. (mido)


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 :(

von P. M. (mikro23)


Lesenswert?

Ahmed M. schrieb:
> Im Datenblatt habe ich nicht viel über Timer Input capture gefunden,

Das steht auch im xmega A Manual und nicht im datasheet.
Das Manual gilt für alle xmega A1 bis A4.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

serielle Ausgaben haben auch in Interrupts nichts zu suchen. Ein ISR muß 
nur das notwendigste machen. Der Rest wieder in der main().

von Ahmed M. (mido)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> serielle Ausgaben haben auch in Interrupts nichts zu suchen. Ein ISR muß
> nur das notwendigste machen. Der Rest wieder in der main().



Hallo,


ich habe die serielle Ausgabe nur geschrieben, um bei der Termite zu 
gucken, ob überhaupt die interrupt ausgelöst wird oder  nicht.

von Ahmed M. (mido)


Lesenswert?

Peter M. schrieb:
> Ahmed M. schrieb:
>> Im Datenblatt habe ich nicht viel über Timer Input capture gefunden,
>
> Das steht auch im xmega A Manual und nicht im datasheet.
> Das Manual gilt für alle xmega A1 bis A4.



ja das meinte ich auch das Manuel von Atmel, findet man nicht viel

von P. M. (mikro23)


Lesenswert?

Ahmed M. schrieb:
> findet man nicht viel

14.7 Capture Channel, Input Capture, Frequency Capture, Pulse Width 
Capture

Mir ist das ausführlich genug beschrieben.
Wenn Dir das nicht reichen sollte, gibt es bestimmt auch noch eine 
Application Note bei Atmel.

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.