Hallo zusammen,
ich habe dieses BASCOM Code-Schippsel in einer Interrupt Routine.
Up:
cbi ddrb,1 ' disconnect OC1A
cbi ddrb,2 ' disconnect OC1B
If Portb.0 = 0 Then
If Pwm1a > 0 Then
Decr Pwm1a
Pwm1b = Pwm1a
End If
Else
If Pwm1a < 1100 Then
Incr Pwm1a
Pwm1b = Pwm1a
End If
End If
Return
Es geht soweit, nur ich würde gerne etwas schneller werden.
In BASCOM werden alle Register ge-pushed und ge-popt.
Das verbraucht Zeit.
Kann mir ein ASSEMBLER Spezi etwas aus dem Ärmel schütteln, dass
abhängig von PORTB.0 OCR1A und OCR1B um eins erhöht oder erniedrigt
ohne Null zu unterschreiten bzw. 1100 zu überschreiten.
oder , welche Register muss ich Pushen-Popen um NOSAVE benutzen zu
können.
Danke schon 'mal.
Werner
Das liegt in der Natur einer Interruptroutine. BASCOM muss hier alle
Register retten, die im Anwendungsprogramm benutzt werden könnten. Also
im Prinzip alle.
Wenn du einige Push/Pop sparen willst, musst du mit dem Läusekamm dein
Disassemblerlistung untersuchen und eine Registerbenutzungstabelle
machen. Dann siehst du, welche Register nicht benutzt werden. Die
Prozedur ist bei jeder Sourcecodeänderung und jedem Compilerupdate zu
wiederholen.
Am Disassmblerlisting selbst siehst du aber auch, wie BASCOM den
Abschnitt in Assembler umgesetzt hat. Vielleicht (ohne viel Hoffnung)
sieht man, andere Punkte für eine Handoptimierung.
Wobei stört dich denn die momentane Geschwindigkeit der Routine?
Vielleicht ist der Bremshebel ja woanders angezogen.
Hallo Stefan,
das ist in einem push-pull DC-DC Wandler.
Ich habe eine Weile mit Regelschwingungen ( Unsymetrien ) gekämpft.
Jetzt habe ich einen Code der recht gut geht...
nur ab 3 kHz stolpert er aus Zeitmangel.
Ich berechne OCRnx wenn OC1A und OC1B aus sind , will aber bis nahe 50%
duty cycle, dann bleibt wenig Zeit.
OC1A und OC1B laufen in FastPulseWithModulation.
Das Programm sucht eine Pulsbreite bei der am Ende des Zyklus
U ist (wieder) < U soll
und eine Pulsbreite an deren Ende
U ist (möglichst) = U soll ist.
Mikro ATmega8 , 7,238--- MHz
Grüße
Werner
Hi
>Kann mir ein ASSEMBLER Spezi etwas aus dem Ärmel schütteln,
Nein. Das Problem ist nicht der Code, sondern die 'Verwaltung' der
Variablen unter BASCOM.
Wozu soll das:
>cbi ddrb,1 ' disconnect OC1A>cbi ddrb,2 ' disconnect OC1B
gut sein? Das OC-Register wird erst beim Overflow gesetzt.
MfG Spess
BASCOM ist ziemlich einheitlich in der Codeerzeugung. Wenn man einmal
weiss welche Register wirklich gebraucht werden, wird sich daran normal
nichts mehr ändern. Wenn man ganz sicher gehen will, kann man auch den
erzeugten Code dann als inline ASM einfügen - ggf. kann man da auch noch
was Optimieren.
Spess53 schrieb:>>cbi ddrb,1 ' disconnect OC1A>>cbi ddrb,2 ' disconnect OC1B>>Wozu soll das gut sein? Das OC-Register wird erst beim Overflow gesetzt.
OC1A und OC1B werden alternierend mit einem Zweig des push-pull
Inverters verbunden. "cbi ddrb,x" macht beide definitiv aus um den
"glitch" bei "Ovf1" zu vermeiden. "DDRB,1 und DDRB,2" schalten ein und
aus.
"Ein" eben nur wenn U ist < U soll und dann 1-2-3 CPU Takte nach "Ovf1"
An AIN1 hängt ein Komparator.
Bezug ist die interne "Bandgap"
ACI triggert wenn U ist > U soll wird.
...
Config Aci = On , Compare = Off , Trigger = Falling
Acsr.6 = 1
' select internal reference
...
On Ovf1 Top Nosave
On Oc1b Up
On Aci Reached Nosave
Enable Aci
Enable Ovf1
Enable Oc1b
...
Up:
cbi ddrb,1 ' disconnect OC1A
cbi ddrb,2 ' disconnect OC1B
If Portb.0 = 0 Then
If Pwm1a > 0 Then
Decr Pwm1a
Pwm1b = Pwm1a
End If
Else
If Pwm1a < 1100 Then
Incr Pwm1a
Pwm1b = Pwm1a
End If
End If
Return
Reached:
sbic ddrb,2 ' B still on
cbi portb,0 ' increase PWM
sbic ddrb,1 ' A still on
cbi portb,0 ' increase PWM
cbi ddrb,2 ' voltage has turned high , disconnect OC1B
cbi ddrb,1 ' voltage has turned high , disconnect OC1A
Return
Top:
push r24
in r24,acsr
sbrs r24,5 ' voltage is still high at the end of cycle ?
cbi portb,0 ' yes , reduce PWM
sbrc r24,5
sbi portb,0 ' no , increase PWM
sbis portd,4 ' this is A ?
Rjmp Channela
Channelb:
Cbi portd,4 ' toggle flag A-B
sbi acsr,4 ' reset comparator interrupt
sbrc r24,5
sbi ddrb,2 ' connect B if voltage is low
pop r24
reti
Channela:
sbi portd,4 ' toggle flag B-A
sbi acsr,4 ' reset comparator interrupt
Sbrc R24 , 5
sbi ddrb,1 ' connect A if voltage is low
pop r24
reti
Return
Was ein Sch.. das Denglish.. nur für Eingeweihte :0)
nun Du hast gefragt, warum ich beide Kanäle ausschalte, bevor Ovf1
geschieht.
Mit weniger kann ich das nicht erklären...
ich wollte auch nur fragen wie ich OCRnx um eins erhöhen oder
erniedrigen kann. Abhängig von PORTB.0 ohne Null zu unterschreiten und
1100 zu überschreiten. In einer Interruptroutine (OCR1B) in möglichst
kurzer Zeit.
mfg Werner
Hi
>nun Du hast gefragt, warum ich beide Kanäle ausschalte, bevor Ovf1>geschieht.>Mit weniger kann ich das nicht erklären...
Und was soll das sein? Eigener Code, Disassembliertes BASCOM,...? Aus
irgend einem Zusammenhang gerissen macht es keinen Sinn.
MfG Spess
das ist eigener, funktionierender BASCOM Code.
Alles was mein Teil braucht um einen DC-DC Wandler von 12 auf 0 - 400
Volt
bis zu 50 Watt / max ~ 400mA zu steuern.
Ich bin etwas älter, 7-8-10 kHz nerven akustisch nicht mehr so.
Bis 2-3 kHz geht es ja, nervt aber.
U soll kommt aus einem 16 bit DA Wandler ( AD 7303 )
U ist aus einem Spannungsteiler am Ausgang des DC-DC Wandlers.
U delta aus einem Komparator ( AD 648 ) und geht an AIN1.
Mfg Werner
So recht will ich noch nicht glauben, dass eine Assembler Variante der
ISR da irgendwas ändern würde.
Wenn du die Regelung nicht in den Griff kriegst, dann wird es eher daran
liegen, dass deine 2-Punkt Regelung bei höheren Frequenzen nicht mehr
mitkommt und überschwingt.
Mal etwas rechnen.
Bei 16Mhz Systemtakt, hast du von einem ISR Aufruf zum nächsten
16000000 / 3000 = ~5300 Takte
Zeit. 5300 Takte. Das ist massig. So schlimm kann BASCOM gar nicht sein.
Hallo,
ich habe jetzt den Text nur überflogen und kann mir jetzt gerade noch
nicht vorstellen was nun genau geregelt werden soll.
Ich schreibe aber auch gern mal zeitkritische Interruptroutine in
Assembler und sichere bei "Nosave" nur die Register, die ich in der
Interruptroutine auch benutze. Ich glaube schon, dass man auf diese
Weise schnellere Interruptroutine bekommt. Der Befehl mit dem man die
Adresse einer Variablen im Ram feststellen kann (welcher war das noch?)
ist da sehr hilfreich.
Gruß Oilaf
Karl heinz Buchegger schrieb:> Bei 16Mhz Systemtakt, hast du von einem ISR Aufruf zum nächsten> 16000000 / 3000 = ~5300 Takte
Das Sichern und Wiederherstellen des Registersatzes dauert ~110 Takte,
die Up-ISR benötigt insgesamt nicht mehr als 200 Takte.
Aber im Prinzip macht's keinen Spaß aufgrund des Fetzerlcodes
Hilfestellung zu geben, denn ein paar Dinge sind nur zu erraten.
Die Lösung für die Up-ISR wäre sehr einfach, denn das einzig
Zeitkritische dort scheint das Löschen der DDR-Bits zu sein. Die
Änderungen der Outputcompare-Register scheinen weniger zeitkritisch,
denn sie werden aufgrund des HW-PWM Doublebufferings erst beim nächsten
Timerzyklus bei TOP oder BOTTOM übernommen.
Wenn man also das Löschen der Bits zuerst ausführen will, dann
deklariert man Up-ISR mit Nosave, führt darin zuerst die CBI's aus und
umschließt den Basic-Block mit PUSHALL/POPALL.
Evtl. könnte man nach den CBI's noch die Interrupts freigeben, um der
ACI-ISR Vorrang zu verschaffen.
Mit der Informationsbereitstellung des TO's ist das alles schwierig zu
beurteilen. Nicht einmal der µC-Typ ist genannt, ich hab' da keine Lust
mal eben ein wenig Assembler zu schreiben.
Vor allem wenn's sinnlos ist, weil's woanders klemmt.
Hallo und danke,
es ist ein ATmega8 mit 7,3728 MHz.
Timer1 läuft mit Prescaler = 1.
Timer1 macht FPWM Mode 14.
Im Mode 14 bestimmt ICR1 das TOP und OCRnx wird bei TOP ( = BOTTOM
)gesetzt.
"Up" und "Reached" haben in PORTB.0 hinterlassen was zu tun ist.
Ich brauche kaum mehr als 100 Takte "dead time" zwischen den Kanälen
des "push-pull".
Das Geplänkel bei TOP verbraucht bereits ein paar, beide Kanäle müssen
aus
sein um den "Glitsch" bei OCRnx = 0 zu unterdrücken.
Ein Kanal soll auch nicht losgehen wenn Uist bereits > Usoll.
Zeitkritisch ist die Dauer von "Up".
Das Löschen der DDRB.1 und DDRB.2 ist nicht kritisch, es muss lediglich
vor TOP geschehen.
Dauert "Up" zulange wird der neue Wert für OCRnx nicht mehr rechtzeitig
vor TOP ( ~ TOV1 ~ BOTTOM , mode 14 Sägezahn ) fertig.
Desto länger "Up" dauert um so mehr nutzbare Pulsbreite muss ich
verschenken
( deshalb diese Notbremse: PWM1A < 1100 im Beispiel, ICR1 habe ich
empirisch erniedrigt bis
es stolpert )
PWMmax = ICR1 minus nTakteInUp
ICR1 wird bei höherer Frequenz immer kleiner, die TakteInUp immer
gleich.
Das beschränkt die entnehmbare Leistung unnötig.
mfg Werner
Doch Danke :0)
das habe ich gesucht...
Ich bin ein rechter Assembler dummy, hätte lange gedauert, wenn ich es
überhaupz hinbekäme...
Bis Donnerstag hänge ich auf Dienstreise, dann werde ich es probieren,
Nochmals vielen Dank
Werner
Werner schrieb:> @ MWS:>> das gab einen rasanten Zeitgewinn.>> Es geht nicht gleich, das highbyte muss zuerst geschrieben werden.
Ein Klassiker, hab ich doch glatt übersehen ;-)
> nochmal danke
Bitte.