Hallo zusammen,
ich verwende den ATMega328P, SPI läuft über Interrupt im Slave-Modus,
ich muss aber auch eine Software-PWM mit Timer 1 machen, die
zeitkritisch ist.
Dazu habe ich diese Fragen:
Bei
1
reti
werden Interrupts ja wieder aktiviert. Würde bei anliegendem Interrupt
dann trotzdem noch ein Befehl des Hauptprogramms ausgeführt, bevor der
nächste Interrupt kommt?
Wenn das so ist: Zu
1
sei
habe ich gelesen, dass da der unmittelbar folgende Befehl noch vor einem
eventuellen Interrupt ausgeführt wird. Könnte man dann den Interrupt mit
1
sei
2
ret
beenden?
Dann würde man zwar einen Takt für sei einbüßen, aber man spart die bis
zu 4 Takte dauernde Beendigung des nächsten Hauptprogramm-Befehls ein,
und die zuverlässige Beendigung der ISR ist trotzdem noch gewahrt, da
ret der unmittelbar auf sei folgende Befehl ist.
Ist das so oder habe ich dabei einen Denkfehler?
Meine zweite Frage ist: Ich habe beim Atmega 2 Words Platz in der
Interrupttabelle. Kann man da auch beliebige Befehle unterbringen, z.B.
das hier anstelle des üblichen jmp, rjmp oder reti:
Hallo Steffen,
ich würde so, wie du es gerade vorhast, nicht "kämpfen".
Das SPI und I2C dir bekannt sind, kann man einen weiteren Slave AVR µC
für die PWM Erzeugung an den Master anbinden.
Dadurch die Hardware nicht mehr dein Problem und das Schreiben der
Software auch, in meinen Augen, viel einfacher.
Alle Fragen sind zu bejahen.
Aber, um den Begriff des Vorredners aufzugreifen, könnte es sein, dass
Sie an der falschen Front kämpfen? Geht nicht auch Hardware-PWM oder ein
höherer Takt? Oder ein Umgestalten der Software, dazu müsste man aber
mehr wissen.
Vielen Dank erstmal für alle Antworten, das hilft mir weiter!
PWM nur in Hardware ist etwas schwierig, weil ich eine Vollbrücke mit
vier Schaltzuständen mit variabler Frequenz und Einschaltdauer habe. Der
Chip läuft zur Zeit mit 16 MHz, daraus werden in der endgültigen Version
dann sicher noch die maximalen 20 MHz.
An einen separaten µC hatte ich auch schon gedacht, aber so viel hat er
außer der Software-PWM auch nicht zu tun:
- der SPI wird nicht mehr als 50 Byte/s übertragen
- immer wenn Zeit ist werden Spannung und Strom aus je einem externen
A/D-Wandler ausgelesen, 100 Mal in der Sekunde reichen dafür auch, in
der Praxis wird eher 500x pro Sekunde erreicht (dass es so langsam ist
liegt an recht einfachen Optokopplern dazwischen, aber ich brauche auch
nicht mehr)
Was ich erreichen will ist vor allem eine recht kleine minimale
Einschaltdauer der PWM, die ich jetzt auf 18 Takte gebracht habe, d.h.
knapp 1 µs bei 20 MHz, davon nimmt der MOSFET-Treiber nochmal 500 ns zur
Sicherheit weg. Die 18 Takte sind die Zeit zwischen dem Setzen der Ports
in der ersten (Einschalten) und in der zweiten ISR (Ausschalten).
Ich hatte aber durch den Hinweis auf den separaten µC noch die Idee, bei
kleiner Einschaltdauer auf die zweite ISR zu verzichten, und in der
ersten einfach nacheinander ein- und gleich wieder auszuschalten - damit
komme ich dann auf einen einzigen Takt Mindesteinschaltdauer.
Steffen Fuchs schrieb:> Vielen Dank erstmal für alle Antworten, das hilft mir weiter!>> PWM nur in Hardware ist etwas schwierig, weil ich eine Vollbrücke mit> vier Schaltzuständen mit variabler Frequenz und Einschaltdauer habe.
Attiny26 würde sich da anbieten, kann das in Hardware.
Steffen Fuchs schrieb:> SPI läuft über Interrupt im Slave-Modus
SPI-Slave ist bei den AVRs einfach nur krank.
Wenn Du nur 50Byte/s übertragen mußt, könnte der Master ja nach jedem
Byte 1ms warten. Dann hast Du Zeit, das SPI in der Mainloop zu pollen
und brauchst keinen Interrupt, der Dir die SW-PWM zerkloppt.
Alternativ wäre auch I2C oder UART. Die UART hat einen 3 Byte Puffer und
das I2C ist selbst synchronisierend, d.h. verzögert den Master per
Clock-Stretching. Beides ist also lange nicht so zeitkritisch, wie das
SPI.
Steffen Fuchs schrieb:> PWM nur in Hardware ist etwas schwierig, weil ich eine Vollbrücke mit> vier Schaltzuständen mit variabler Frequenz und Einschaltdauer habe.
Was genau ist Dein Problem bei den HW-PWMs?
Falls Du nur eine weitere PWM brauchst, bietet sich vielleicht auch der
zweite SPI an (also per Datenbytes).
> immer wenn Zeit ist werden Spannung und Strom aus je einem externen> A/D-Wandler ausgelesen, 100 Mal in der Sekunde reichen dafür auch, in> der Praxis wird eher 500x pro Sekunde erreicht
in den meisten Fällen ist das nicht gut. Meist ist hier ein Synchrones
Design besser.
> davon nimmt der MOSFET-Treiber nochmal 500 ns zur Sicherheit weg.
?? Meinst Du damit, er schaltet 500ns mehr verzögert ein als aus?
> Ich hatte aber durch den Hinweis auf den separaten µC noch die Idee, bei> kleiner Einschaltdauer auf die zweite ISR zu verzichten
Das ist in jedem Fall vorzuziehen. Auch bei großer Einschaltdauer
(~99%).
Für nähere Tipps wäre es wichtig zu wissen, welche Periodendauer Dein
PWM hat und welche Baudrate Dein Slave-SPI. Wenn Du die Slave-SPI z.B.
auf 1kHz reduzieren kannst (reicht ja für die Datenmenge), dann kommt
vielleicht auch ein rein synchrones Design in Frage.
Vielen Dank an alle für die Antworten!
Ich nehme für die PWM den Timer 1 mit 16 Bit. Der Pin 16 an meinem PDIP,
der als OC1B auch die PWM ausgeben könnte, ist durch den SPI belegt,
aber mit den 8-Bit-Timern komme ich nicht hin, wenn ich Frequenz und
Pulsbreite variabel brauche, da dann bei hoher Frequenz die Pulsbreite
sehr ungenau wird.
Mit dem SPI-Interrupt habe ich auch kein Problem. Das Erste was ich tue
ist Interrupts wieder zuzulassen, so dass die PWM weiterläuft. Dass ich
ein Stack-Problem bekomme ist auch ausgeschlossen, zum einen weil der
Master nur eine kleine Datenrate sendet, zum anderen habe ich noch eine
Routine die bei einem evtl. doch vorkommenden zweiten Aufruf nur eine
kurze Fehlerinformation zurücksendet und sofort wieder aussteigt.
Die Kommunikation mit SPI funktioniert auch einwandfrei, daher würde ich
es jetzt auch nicht ändern wollen.
Bezüglich der Verzögerung durch den MOSFET-Treiber ist es genau wie
vermutet dass aus- und erst nach 500 ns der andere Transistor
eingeschaltet wird.
Spannungs- und Strommessung ist recht unkritisch weil sich der Strom
nicht schneller als innerhalb von ca. 100 ms und die Spannung im Bereich
einiger Sekunden nennenswert ändert - deshalb messe ich sie nur wenn ich
sonst nichts zu tun habe.
Die PWM geht bis max. ca. 60 kHz, das sind bei 16 MHz Takt 267
Taktzyklen, innerhalb derer ich normalerweise 4 Interrupts auslöse,
deren Gesamtlaufzeit inkl. Overhead bei ca. 120 Takten liegt. Die
restliche Hälfte der Laufzeit bleibt für die 50 Byte/s SPI und die
Messungen reicht.
Die SPI-Routine hat auch nicht mehr als 150 Taktzyklen, deren Interrupt
wird max. für 40 Taktzyklen durch die PWM geblockt, die ISR ist damit
innerhalb von max. 30-50 µs nach Auftreten des Interrupts abgearbeitet.
Das nächste Byte kommt frühestens nach 1,5 ms an, der SPI-Takt liegt bei
ca. 5 kHz.
Vielen Dank auch für den Tip, auch bei hohen Tastzyklen in Richtung 99%
auf einen Interrupt zu verzichten, aber der Fall kommt nicht vor.
Viele Grüße,
Steffen
Ein Xmega könnte ebenfalls helfen, deren PWM-Module sind extrem
wandlungsfähig und mit integriertem Totzeitgenerator auch ziemlich
"endstufenfreundlich".