Forum: Mikrocontroller und Digitale Elektronik Fast-PWM und ISR Funktionen gleichzeitig nutzen


von Ano N. (anonym1)


Lesenswert?

Guten Tag,

ich habe ein STK600 Board und einen ATMega2560 MicroController und will 
davon aus ein VGA Signal zu einem normalen Monitor aufbauen.
Ich bekomme bereits das vertikale und horizontale Signal hin und auch 
einzelne Farbsignale gehen schon, sodass der ganze Monitor blau,rot oder 
grün sein kann. Jedoch immer nur eine Farbe auf einmal.
Für das vertikale und horizontale Signale benutze ich separate Timer 
(Timer 0 (8bit) und Timer 1(16bit)) mit jeweils 16MHz. Und ebendiese 
Signale erzeuge ich mit FastPWM.

Das Farbsignal bekommen wir hin, wenn wir eines des RGB Kabel mit an an 
das horizontale Signal klemmen. Vermutlich könnte man einfach einen 3. 
Timer mit einbauen und darüber die Farbsignale laufen lassen.

Damit wir lediglich mal einzelne Pixel mit Farbe befeuern können, will 
ich vom horizontalen und vertikalen Signal auch noch auf die ISR 
Funktionen zugreifen. Doch die Anweisungen in der ISR Funktion führt er 
nicht aus.
Erst wenn ich sei() in den Quellcode mit einfüge, funktionieren die
ISR-Funktionen, aber die PWM-Signale werden dadurch nicht mehr
ausgegeben.

Ich wollte nun fragen, ob es möglich ist, *dass man einen Fast-PWM
und einen Timer-Overflow-Interrupt* (und dann mit der entsprechenden
ISR-Funktion arbeiten) auf dem gleichen Timer konfigurieren kann.

Nur zur Verdeutlichung, damit ihr wisst, wohin das Ganze führen
soll:
Das Endziel sollte irgendwann sein, dass ich farbige einfach Grafiken
darstellen kann. Wie z.B. eine Sonne oder die Uhrzeit oder Ähnliches.
Wenn die Grafiken dann nur 120x60 Pixel haben wäre das auch in Ordnung.


Ich habe mich bisher stark an diese Vorgehensweise hier gehalten:
https://www.gammon.com.au/forum/?id=11608


Hier noch mein aktueller Quellcode:
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
6
int main( void )
7
{
8
  
9
  DDRH=0xff;
10
  DDRB=0xff;
11
  DDRL=0xFF;
12
  PORTL = 0x00;    
13
  DDRE = 0xff;
14
   
15
  TCCR2A = 0;
16
  TCCR2B = 0;
17
  
18
  // Timer Mode 7 
19
  TCCR2A |= (1 << WGM20) | (1 << WGM21);
20
  TCCR2B |= (1 << WGM22);
21
  
22
  //Clear B on Compare Inverted
23
  TCCR2A |= (1<< COM2B1|(1<< COM2B0));
24
  
25
  //Clock Prescaler 8
26
  TCCR2B |= 2;
27
  
28
  OCR2A = 63;
29
  OCR2B = 7;
30
  
31
  TIFR2 =  (1 << TOV2);
32
  TIMSK2 =  (1 << TOIE2);
33
  
34
  //Configuration Timer 1
35
  TCCR1A = 0;
36
  TCCR1B = 0;
37
  
38
  //Timer Mode 15
39
  TCCR1A |=  (1<<WGM10) | (1<<WGM11);
40
  TCCR1B |=  (1<<WGM12) | (1<<WGM13);
41
  
42
  //Clear B on Compare Inverted
43
  TCCR1A |= (1<< COM1B1|(1<< COM1B0));
44
  
45
  // Clock Prescaler 1024
46
  TCCR1B |= 5;
47
  
48
  OCR1A = 259;
49
  OCR1B = 0;
50
  
51
  TIFR1 = (1 << TOV1);
52
  TIMSK1 = (1 << TOIE1);
53
      
54
  //sei();
55
  
56
  while( 1 );
57
}
58
59
ISR (TIMER1_OVF_vect){
60
  
61
  PORTL ^= 0xFF; 
62
  
63
}

: Bearbeitet durch User
von void (Gast)


Lesenswert?

Ano N. schrieb:
> Ich wollte nun fragen, ob es möglich ist, dass man einen Fast-PWM
> und einen Timer-Overflow-Interrupt (und dann mit der entsprechenden
> ISR-Funktion arbeiten) auf dem gleichen Timer konfigurieren kann.

Warum zweifelst du daran?
Steht doch so im DB Figure 17-2 für Mode 14+15:
-TOVn Flag Set on: TOP -> Timer-Overflow-Interrupt
TOP ist wahlweise ICRn (14) oder OCRnA (15)

Für mehr graphisch veranlagte Menschen auch als Timing Diagram: Figure 
17-7
1
ISR (TIMER1_OVF_vect){
2
  PORTL = 0xFF;
3
}

Die Port pins toggeln so aber nicht, oder?

von Ano N. (anonym1)


Lesenswert?

void schrieb:
> Ano N. schrieb:
>> Ich wollte nun fragen, ob es möglich ist, dass man einen Fast-PWM
>> und einen Timer-Overflow-Interrupt (und dann mit der entsprechenden
>> ISR-Funktion arbeiten) auf dem gleichen Timer konfigurieren kann.
>
> Warum zweifelst du daran?
> Steht doch so im DB Figure 17-2 für Mode 14+15:
> -TOVn Flag Set on: TOP -> Timer-Overflow-Interrupt
> TOP ist wahlweise ICRn (14) oder OCRnA (15)

Ok TOVn haben wir bereits für beide Timer gesetzt. Ebenso OCRnA, da wir 
den Timer 1 mit dem Mode 15 benutzen. Müsste jetzt unsere ISR Funktion 
dann nicht anspringen?


> Für mehr graphisch veranlagte Menschen auch als Timing Diagram: Figure
> 17-7
>
>
1
> ISR (TIMER1_OVF_vect){
2
>   PORTL = 0xFF;
3
> }
4
>
>
> Die Port pins toggeln so aber nicht, oder?

Da hatte ich noch einen kleinen Fehler vom Rumspielen im Code drinnen. 
Soll natürlich PORTL ^= 0xFF; heissen.

von spess53 (Gast)


Lesenswert?

Hi

>Müsste jetzt unsere ISR Funktion dann nicht anspringen?

Nrin. Bei Fast PWM gibt es nur den Overflow Interrupt, nämlich wenn 
OCR1A bzw. ICR den Topwert erreicht hat.

>Da hatte ich noch einen kleinen Fehler vom Rumspielen im Code drinnen.
>Soll natürlich PORTL ^= 0xFF; heissen.

PIN-Toggle geht beim ATMega2560 einfacher:

PINL = 0xFF;

MfG Spess

von Ano N. (anonym1)


Lesenswert?

> Nrin. Bei Fast PWM gibt es nur den Overflow Interrupt, nämlich wenn
> OCR1A bzw. ICR den Topwert erreicht hat.

Und die ISR Funktion greift diesen Overflow Interrupt nicht ab? Also der 
Code der ISR Funktion wird nicht bei diesem Interrupt ausgeführt?
1
ISR (TIMER1_OVF_vect)

Wenn Nein, hast du dann eine Idee wie wir unser Vorhaben erreichen 
können? Also Fast PWM auf nem Timer UND zusätzlich noch eine ISR 
Funktion benutzen, die unseren eigenen Code ausführt.

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

HI

>Und die ISR Funktion greift diesen Overflow Interrupt nicht ab? Also der
>Code der ISR Funktion wird nicht bei diesem Interrupt ausgeführt?

Wieso nicht. Sieh dir mal im Datenblatt die Kapitel

Modes of Operation -> Fast PWM Mode in den Timerkapiteln an.

MfG Spess

von Ano N. (anonym1)


Lesenswert?

> Wieso nicht. Sieh dir mal im Datenblatt die Kapitel

Als ich dich fragte ob die ISR Funktion jetzt nicht anspringen müsste 
hast du verneint. Klang für mich so als wäre das dann gar nicht möglich. 
Jetzt sagst du mir, dass es möglich ist. Das Handbuch habe ich schon oft 
zu Rate gezogen, aber es steht für mich noch sehr viel kryptisches 
drinnen.

Kannst du mir konkrete Hinweise geben, warum in meinem Code die ISR 
Funktion nicht ausgeführt wird?

Ich bin noch sehr neu auf dem Gebiet der Elektrotechnik und ich hoffe 
ihr könnt mir meine tölpelhafte Ausdrucksweise verzeihen. Und auch, dass 
ich nicht alles auf Anhieb verstehe oder es gar missverstehe.

von Joachim B. (jar)


Lesenswert?


: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ano N. schrieb:
> TIMSK2 =  (1 << TOIE2);

Mir fällt auf, das dieser Interrupt nicht behandelt wird. Du brauchst 
noch eine ISR (TIMER2_OVF_vect).

von Ano N. (anonym1)


Lesenswert?

Matthias S. schrieb:
> Ano N. schrieb:
>> TIMSK2 =  (1 << TOIE2);
>
> Mir fällt auf, das dieser Interrupt nicht behandelt wird. Du brauchst
> noch eine ISR (TIMER2_OVF_vect).


Ich habe jetzt den ISR für den Timer 2 noch eingerichtet. Leider ändert 
sich dadurch nichts.

Um den ISR zu testen, versuche ich die LED's in den beiden ISR 
Funktionen wieder anzuschalten.

Dafür initialisiere ich den PORTD mit:
1
DDRD=0xFF;
2
PORTD = 0xFF; // 0xFF = LED's aus

Und schalte in den ISR-Funktionen den Port auf 0x00;
1
ISR (TIMER1_OVF_vect){
2
  PORTD = 0x00;
3
}
4
5
ISR (TIMER2_OVF_vect){
6
  PORTD = 0x00;
7
}

Dadurch sollten sich eigentlich die LED's anschalten, diese bleiben aber 
leider dunkel.

Ich bin mir ziemlich sicher, dass die ISR-Funktionen einfach nicht 
getriggert werden.

Fehlt vielleicht noch etwas in der Konfiguration?

von Stefan E. (sternst)


Lesenswert?

Ano N. schrieb:
> Ich bin mir ziemlich sicher, dass die ISR-Funktionen einfach nicht
> getriggert werden.

Nicht weiter verwunderlich bei auskommentiertem sei().

von Ano N. (anonym1)


Lesenswert?

Stefan E. schrieb:
> Ano N. schrieb:
>> Ich bin mir ziemlich sicher, dass die ISR-Funktionen einfach nicht
>> getriggert werden.
>
> Nicht weiter verwunderlich bei auskommentiertem sei().

Das habe ich bereits oben im ersten Beitrag beschrieben.
Sobald sei() aktiviert ist, werden die PWM-Signale nicht mehr 
ausgegeben.

von Peter D. (peda)


Lesenswert?

Ano N. schrieb:
> Sobald sei() aktiviert ist, werden die PWM-Signale nicht mehr
> ausgegeben.

Na das ist doch schonmal ein gutes Zeichen.
Es werden also Interrupts aufgerufen, für die Du keinen Handler 
hinterlegt hast und dadurch startet Dein Programm ständig neu.

von hc (Gast)


Lesenswert?

Früher hat man mal paar Breakpoints gesetzt, und das ganze vernünftig 
debugged....

Geht das heutzutage denn nicht mehr?

ist doch eigentlich viel einfacher und spassiger, als sich hier 
krampfhaft im Forum abzumühen...

von Ano N. (anonym1)


Lesenswert?

Peter D. schrieb:
> Na das ist doch schonmal ein gutes Zeichen.
> Es werden also Interrupts aufgerufen, für die Du keinen Handler
> hinterlegt hast und dadurch startet Dein Programm ständig neu.

Danke für die Info.
Nach meinem Wissen setzte ich nur die Interrupts für Timer1 & Timer2.

Diese fange ich aber mit den beiden Funktionen ab:
1
ISR (TIMER1_OVF_vect){
2
  PORTD = 0x00;
3
}
4
5
ISR (TIMER2_OVF_vect){
6
  PORTD = 0x00;
7
}

Hast du vielleicht irgendwelche Tipps, wie ich die überflüssigen 
Interrupt-Befehle herausfinden und abdecken kann?

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Scheint o.k. zu sein. Schau mal ins .lss-File da müßte sowas drin 
stehen:
1
00000000 <__vectors>:
2
   0:  0c 94 72 00   jmp  0xe4  ; 0xe4 <__ctors_end>
3
   4:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
4
   8:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
5
   c:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
6
  10:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
7
  14:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
8
  18:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
9
  1c:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
10
  20:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
11
  24:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
12
  28:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
13
  2c:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
14
  30:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
15
  34:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
16
  38:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
17
  3c:  0c 94 ea 00   jmp  0x1d4  ; 0x1d4 <__vector_15>
18
  40:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
19
  44:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
20
  48:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
21
  4c:  0c 94 8b 00   jmp  0x116  ; 0x116 <__bad_interrupt>
22
  50:  0c 94 df 00   jmp  0x1be  ; 0x1be <__vector_20>

von Ano N. (anonym1)


Lesenswert?

Peter D. schrieb:
> Scheint o.k. zu sein. Schau mal ins .lss-File da müßte sowas drin
> stehen:

Nochmals vielen Dank. Klappt jetzt alles prima.

Ich habe jetzt einfach zusätzlich den vector_default verwendet, um das 
Problem zu lösen:
1
ISR (__vector_default)

Wäre das so sauber gelöst, oder gibt es noch eine bessere Variante?

Ich habe mir auch mal das .lss-File noch ein wenig genauer angesehen.
Kann ich davon ausgehen das 0xf8 eine Addresse ist?
1
00000000 <__vectors>:
2
   0:  71 c0         rjmp  .+226      ; 0xe4 <__ctors_end>
3
   4:  79 c0         rjmp  .+242      ; 0xf8 <__bad_interrupt>
4
   8:  77 c0         rjmp  .+238      ; 0xf8 <__bad_interrupt>
5
   c:  75 c0         rjmp  .+234      ; 0xf8 <__bad_interrupt>
6
  10:  73 c0         rjmp  .+230      ; 0xf8 <__bad_interrupt>
7
  14:  71 c0         rjmp  .+226      ; 0xf8 <__bad_interrupt>
8
  18:  6f c0         rjmp  .+222      ; 0xf8 <__bad_interrupt>
9
  1c:  6d c0         rjmp  .+218      ; 0xf8 <__bad_interrupt>
10
  20:  6b c0         rjmp  .+214      ; 0xf8 <__bad_interrupt>
11
  24:  69 c0         rjmp  .+210      ; 0xf8 <__bad_interrupt>
12
  28:  67 c0         rjmp  .+206      ; 0xf8 <__bad_interrupt>
13
  2c:  65 c0         rjmp  .+202      ; 0xf8 <__bad_interrupt>
14
  30:  63 c0         rjmp  .+198      ; 0xf8 <__bad_interrupt>
15
  34:  61 c0         rjmp  .+194      ; 0xf8 <__bad_interrupt>
16
  38:  5f c0         rjmp  .+190      ; 0xf8 <__bad_interrupt>
17
  3c:  b1 c0         rjmp  .+354      ; 0x1a0 <__vector_15>
18
  40:  5b c0         rjmp  .+182      ; 0xf8 <__bad_interrupt>
19
  44:  59 c0         rjmp  .+178      ; 0xf8 <__bad_interrupt>
20
  48:  57 c0         rjmp  .+174      ; 0xf8 <__bad_interrupt>
21
  4c:  55 c0         rjmp  .+170      ; 0xf8 <__bad_interrupt>
22
  50:  99 c0         rjmp  .+306      ; 0x184 <__vector_20>

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ano N. schrieb:
> Wäre das so sauber gelöst, oder gibt es noch eine bessere Variante?

Einen Fehler zu verstecken, ist niemals eine Lösung.
Du kannst ja nichtmal feststellen, ob beide Handler überhaupt aufgerufen 
werden.
Laß das Programm dochmal im Simulator laufen.

von Ano N. (anonym1)


Angehängte Dateien:

Lesenswert?

Peter D. schrieb:
> Einen Fehler zu verstecken, ist niemals eine Lösung.

Geb ich dir vollkommen Recht.

Peter D. schrieb:
> Du kannst ja nichtmal feststellen, ob beide Handler überhaupt aufgerufen
> werden.

Warum nicht? Man kann z.B. die Pins auch einzeln ansteuern.
1
ISR (TIMER1_OVF_vect){
2
3
  PORTD ^=1<<PB1;
4
}
5
6
ISR (TIMER2_OVF_vect){
7
8
  PORTD ^=1<<PB0;
9
}

Peter D. schrieb:
> Laß das Programm dochmal im Simulator laufen.

Da passiert bei mir reichlich wenig. Der Simulator ruft nie die 
ISR-Funktionen auf. (Ja, ich habe auch oft genug gedrückt).Ich denke es 
wird eine Option im Debugger geben, aber da werde ich morgen mal drüber 
schauen.

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ano N. schrieb:
> Hast du vielleicht irgendwelche Tipps, wie ich die überflüssigen
> Interrupt-Befehle herausfinden und abdecken kann?

Zu diesem Zweck kann man Dummy ISR in GCC basteln:
1
EMPTY_INTERRUPT(TIMER0_OVF_vect);
2
// ISR stub for  unused irqs. The AVRs sometimes need to fire an interupt and 
3
// execute it before OC registers are  updated
4
EMPTY_INTERRUPT(TIMER0_COMPB_vect);
5
6
ISR(TIMER0_COMPA_vect,ISR_ALIASOF (TIMER0_COMPB_vect));
Ich bin da anscheinend auch mal drüber gestolpert, das die OC Register 
nicht das gemacht haben, was ich wollte. Aus einem Quelltext für ein 
BLDC Projekt.

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.