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)
Hi
>Was ein Sch.. das Denglish.. nur für Eingeweihte :0)
Richtig. Was sollen diese Codeschnipsel?
MfG Spess
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
Bitte sehr, nichts zu danken :D Laufzeit Routine <= 45 Takte, zzgl. ISR JMP & RETI 7 Takte
1 | Const PWM_Upper = 1100 |
2 | |
3 | Up: |
4 | !cbi ddrb, 1 |
5 | !cbi ddrb, 2 |
6 | !PUSH R16 |
7 | !IN R16, SREG |
8 | !PUSH R16 |
9 | !PUSH R24 |
10 | !PUSH R25 |
11 | !IN R24, {PWM1A} |
12 | !IN R25, {PWM1A +1} |
13 | !SBIC PortB, 0 |
14 | !RJMP Incr_PWM |
15 | !Decr_PWM: |
16 | !SBIW R24, 1 |
17 | !BRMI Up_End |
18 | !OUT {PWM1A}, R24 |
19 | !OUT {PWM1A +1}, R25 |
20 | !OUT {PWM1B}, R24 |
21 | !OUT {PWM1B +1}, R25 |
22 | !RJMP Up_End |
23 | !Incr_PWM: |
24 | !ADIW R24, 1 |
25 | !LDI R16, lbyte(PWM_Upper) |
26 | !CP R16, R24 |
27 | !LDI R16, hbyte(PWM_Upper) |
28 | !CPC R16, R25 |
29 | !BRCS Up_End |
30 | !OUT {PWM1A}, R24 |
31 | !OUT {PWM1A +1}, R25 |
32 | !OUT {PWM1B}, R24 |
33 | !OUT {PWM1B +1}, R25 |
34 | !Up_End: |
35 | !POP R25 |
36 | !POP R24 |
37 | !POP R16 |
38 | !OUT SREG, R16 |
39 | !POP R16 |
40 | Return |
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
@ MWS: das gab einen rasanten Zeitgewinn. Es geht nicht gleich, das highbyte muss zuerst geschrieben werden. Dann klappt alles.
1 | !OUT {PWM1A +1}, R25 |
2 | !OUT {PWM1A}, R24 |
3 | !OUT {PWM1B +1}, R25 |
4 | !OUT {PWM1B}, R24 |
nochmal danke
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.