Forum: Mikrocontroller und Digitale Elektronik Problem bei PWM mit TC1 auf AT90CAN128


von Philipp L. (philipp_l89)


Lesenswert?

Hallo zusammen,

ich hänge momentan an einem Problem bei der PWM Erzeugung auf einem 
AT90CAN128 fest. Programmiert wird in C unter dem Atmel Studio 6.1, per 
ISP oder JTAG. Die Fuses sind alle passend beim AT90 gesetzt (läuft mit 
externen 16MHz), es läuft soweit (UART, andere Timer/Counter usw.) 
alles. Erzeugen will ich mit dem Timer/Counter 1 eine PWM mit ca. 40KHz 
und über die Pulsbreite ein Sinussignal. Dafür hab ich das ICR-1 als 
max. Timer/Counter Value benutzt. Jeder Overflow wird also bei 40KHz 
ausgelöst und in diesem Interrupt der jeweils nächste Wert für das OCR1A 
Register aus einem Array geladen und PA1 auf High gesetzt. Im Compare 
Match Interrupt wird der Pin dann auf low gesetzt.

Die Register sind folgendermaßen Initialisiert:
1
DDRA = 0xff;
2
TCCR1A = 0b00000010;
3
TCCR1B = 0b00011001; //Fast PWM Mode und Prescaler 1
4
TCCR1C = 0b00000000; 
5
ICR1   = 405; //Im Fast PWM Mode, führt dies zu Interrupts mit ~40KHz
6
TIMSK1 = 0b00000011;

Die Interrupt Vektoren wie folgt:
1
ISR(TIMER1_OVF_vect)
2
{
3
  PORTA = PORTA | 0b00000001;
4
5
  temp_divider++; //"Verlangsamung" der PWM
6
  if(temp_divider >=200)
7
  {
8
    PWM_step=PWM_step + 1;
9
    
10
    sei();
11
    if(PWM_step > 1020)
12
    {
13
      PWM_step=0;
14
    }
15
    
16
    else if(PWM_step <= 255)
17
    {
18
      //OCR1A  = PWM_1[PWM_step];
19
      OCR1AH = (uint8_t) (PWM_1[PWM_step] >> 8);
20
      OCR1AL = (uint8_t) PWM_1[PWM_step];
21
    }
22
    
23
    else if((PWM_step > 255) && (PWM_step <510))
24
    {
25
      //OCR1A  = PWM_2[PWM_step-255];
26
        OCR1AH = (uint8_t) (PWM_2[PWM_step-255] >> 8);
27
        OCR1AL = (uint8_t) PWM_2[PWM_step-255];
28
    }
29
    
30
    else if ((PWM_step >510) && (PWM_step<765))
31
    {
32
      //OCR1A  = PWM_3[PWM_step-510];
33
      OCR1AH = (uint8_t) (PWM_3[PWM_step-510] >> 8);
34
      OCR1AL = (uint8_t) PWM_3[PWM_step-510];
35
    }
36
    
37
    else if ((PWM_step > 765) && (PWM_step <1020))
38
    {
39
      //OCR1A  = PWM_4[PWM_step-765];
40
      OCR1AH = (uint8_t) (PWM_4[PWM_step-765] >> 8);
41
      OCR1AL = (uint8_t) PWM_4[PWM_step-765];
42
    }
43
    cli();
44
    temp_divider = 0;
45
  }
46
47
}
48
49
50
ISR(TIMER1_COMPA_vect)
51
{
52
  PORTA = PORTA & 0b11111110;
53
}

In den Arrays PWM_1 bis PWM_4 sind Werte von 1 bis 399 für die Breite 
der PWM hinterlegt. Das Problem, welches ich habe ist, dass die PWM 
Breite nicht unter einen Wert im OCR1A von ca. 50 geht und auch nicht 
über ca. 360. Sprich ich seh auf dem Oszi zu lange bzw. zu kurze 
Pulsbreiten. Ich habe auch schon versucht die OCR1A Werte fix zu setzen, 
kein Unterschied. Unter einem Wert von 50 bleibt der Port einfach 
trotzdem bis ca. 50 auf einem High Pegel.

Ist das dem AT90 einfach zu schnell, was ich mir eigentlich nicht 
vorstellen kann? Oder liegt mein Fehler wo anders?

Grüße,

Philipp

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Philipp L. schrieb:

> Breite nicht unter einen Wert im OCR1A von ca. 50 geht

D.h. vom einschalten des Pins hier
1
ISR(TIMER1_OVF_vect)
2
{
3
  PORTA = PORTA | 0b00000001;
4
5
  ...

bis zum ausschalten des Pins hier
1
ISR(TIMER1_COMPA_vect)
2
{
3
  PORTA = PORTA & 0b11111110;

vergehen etwa 50 Takte.

da ist einmal der Epilog vom verlassen der Overlfow ISR und einmal der 
Prolog beim betreten der Compare-ISR. (Und natürlich fallweise das 
bischen rechnen in der Overflow-ISR).

50 kommt mir jetzt dafür ehrlich gesagt ein wenig hoch vor. Hast du den 
Optimizer eingeschaltet?
Aber selbst dann wirst du kaum unter sagen wir mal 20 oder 25 kommen.

Warum versuchst du selber die PWM zu erzeugen und lässt das nicht die 
Hardware machen? Die kommt problemlos auf Taktzyklenauflösung 
(allerdings auch nicht auf exakt 0). Dazu hast du ja die PWM Hardware, 
damit die dir diesen Teil abnimmt. Einzige Einschränkung: du bist an 
bestimmte Pins gebunden. Das muss man eben beim Hardware Design 
berücksichtigen und ist nicht so schlimm, wie es sich am Anfang anhört.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

PS:
1
    if(PWM_step > 1020)
2
    {
3
      PWM_step=0;
4
    }
5
    
6
    else if(PWM_step <= 255)

den Wert PWM_1[0] gibst du nie aus. Aber das ist jetzt nicht das 
Problem.

von Philipp L. (philipp_l89)


Lesenswert?

Karl Heinz schrieb:
> 50 kommt mir jetzt dafür ehrlich gesagt ein wenig hoch vor. Hast du den
> Optimizer eingeschaltet?

Habe es schon sowohl mit, als auch ohne probiert. Musste Leider auch 
feststellen, dass entweder mein JTAGICE3 entweder nicht so wunderbar zum 
debuggen geeignet ist oder ich irgendwas komplett falsch mache. Einige 
Varbiablen sind beim durchsteppen nicht "auslesbar" bzw. "uexpexted 
typedef" oder "optimized away".

Die Hardware ist leider, wie so oft, schon vorgegeben und, daher wird es 
schwierig die OCPs zu verwenden und irgendwo muss ich ja so oder so 
rechtzeitig den neuen Wert ins OCR laden.

von Philipp L. (philipp_l89)


Lesenswert?

Karl Heinz schrieb:
> PS:    if(PWM_step > 1020)
>     {
>       PWM_step=0;
>     }
>
>     else if(PWM_step <= 255)
>
> den Wert PWM_1[0] gibst du nie aus. Aber das ist jetzt nicht das
> Problem.

Ja, ich weiß bzw. ist zwischen allen Array wechseln jeweils ein Schritt 
der nicht ausgeführt wird. Denke aber auch, dass das nicht das Problem 
ist.

von Rudolph (Gast)


Lesenswert?

Mal von den Problemen die Du gerade hast abgesehen, ich würde sagen, das 
ist einfach ein klein wenig zu hart für den 90CAN128.

Alle 405 Taktzyklen ein Interrupt - selbst wenn das funktioniert, der 
wird kaum noch irgendetwas anderes machen können.

Gibt es für sowas nicht spezielle Chips?


>ISR(TIMER1_COMPA_vect)
>{
>  PORTA = PORTA & 0b11111110;
>}

Macht das irgendwas anderes als Taktzyklen zu fressen?

von Karl H. (kbuchegg)


Lesenswert?

Philipp L. schrieb:

> Die Hardware ist leider, wie so oft, schon vorgegeben und, daher wird es
> schwierig die OCPs zu verwenden und irgendwo muss ich ja so oder so
> rechtzeitig den neuen Wert ins OCR laden.

Es hat nichts mit dem Laden der OCR Register zu tun.

Auch ein 90CAN128 braucht seine Zeit um aus der einen ISR auszusteigen 
und in die andere ISR einzusteigen. Das sind deine ca. 50 Takte.

> Die Hardware ist leider, wie so oft, schon vorgegeben

Dann lass sie ändern oder such dir einen PWM Pin, der noch frei ist. 
Aber das ist Unsinn eine PWM selbst zu erzeugen, wenn du einen 
Mords-Prozessor hast, der das locker in Hardware machen kann. Und zwar 
ohne Probleme.

von Rudolph (Gast)


Lesenswert?

Rudolph schrieb:
> Macht das irgendwas anderes als Taktzyklen zu fressen?

Oh, autsch, ich ziehe die Frage zurück, das ist quasi eine Soft-PWM auf 
PA0 was so noch weniger Aussicht auf Erfolg haben wird wenn man 
überlegt, dass dann ja offensichtlich noch mehr im Controller passieren 
soll.

von Philipp L. (philipp_l89)


Lesenswert?

Gut, dann werde ich wohl die "Baustelle eröffnen" :D Danke für die Hilfe 
und Meinungen soweit!

von Karl H. (kbuchegg)


Lesenswert?

Philipp L. schrieb:
> Gut, dann werde ich wohl die "Baustelle eröffnen"

Na ja.
2 Pins zu tauschen, sollte jetzt aber nicht das große Problem sein. Da 
hat derjenige, der das gezeichnet hat nicht aufgepasst.
Auf deinem Entwicklungsbaurd ist die Sache mit einem scharfen Messer und 
ein wenig Fädeldraht schnell soweit behoben, dass du nicht auf eine neue 
Platinenversion warten musst.

von Philipp L. (philipp_l89)


Lesenswert?

Naa, ein großes Problem ist es nicht, erst recht nicht, da ich es 
einfach selbst routen werde, aber die 15 Platinen "umzurüsten" wird ein 
bisschen dauern. Auf den ersten Blick sieht das Oszibild auf jedenfall 
schon mal wesentlich besser aus! ;)

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.