PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bascom Inline-Assembler



Che Guevara
18.12.2011, 12:45
Hallo,

möchte nun versuchen, eine ISR von Bascom nach ASM zu übersetzen. Ich denke, der Großteil ist mir auch gelungen, jedoch habe ich auch nach mehrstündigem Suchen im Web keine Tipps gefunden, wie man ein Array KONKRETT in ASM anspricht. Vielleicht kann mir das jemand erklären? Hier mal mein Code:
Bascom:


Isr_int0:
If Channel > 0 And Channel < 6 Then
Empf(channel) = Timer0
End If
Timer0 = 6
Incr Channel
Return

Datentypes:


Dim Empf(5) As Word
Dim Channel As Byte
Dim Empf_tmp As Word

Hier mein Übersetzungsversuch:


Isr_int0:

push r16 'sichere r16

lds r16 , {channel} 'lade channel in r16
cpi r16 , 6 'vergleiche r16 mit 6
brlo _lower 'springe, wenn kleiner
rjmp _out_of_range 'sonst springe nach _out_of_range
_lower: '_lower Label
cpi r16 , 1 'vergleiche r16 mit 1
brge _higher 'springe, wenn größer gleich
rjmp _out_of_range 'sonst springe nach _out_of_range
_higher: '_higher Label
'###
in r16 , tcnt0
sts {empf_tmp} , r16
Empf(channel) = Empf_tmp
'###
_out_of_range: '_out_of_range Label
ldi r16 , 6 'lade 6 in r16
!out tcnt0 , r16 'schreibe r16 in timer0
lds r16 , {channel} 'lade Channel in r16
inc r16 'erhöhe Channel um 1
sts {channel} , r16 'lade r16 in Channel

pop r16 'stelle r16 wieder her

Return


Meint ihr, das würde so funktionieren? Laut Simulation siehts ganz gut aus. Habt ihr noch Tipps, wie ich das ganze noch etwas verschlanken kann? Bin mir nicht sicher, ob die If-Else-Abfrage nicht noch etwas eleganter / kürzer ginge?

Außerdem wollte ich noch fragen, wie das ist, wenn man einem Word ein Byte in ASM zuweist? Soweit ich das verstanden habe, wird das Byte in das untere Byte des Words geschrieben, weil man ja das höherwertige Byte des Words mit {Word+1} anspricht, oder?

Vielen Dank schonmal
Gruß
Chris

MagicWSmoke
19.12.2011, 08:32
Du benötigst die Helperfunktion Loadadr dafür. Wenn das Array von 0 beginnen darf, kann das SBIW entfallen.

Loadadr myArr(1) , Z
!LDS R18, {ArrPtr}
!LDS R19, {ArrPtr+1}
!SBIW ZL, 1
!ADD ZL, R18
!ADC ZH, R19
!LD R16, Z
!STS {Rslt},R16
Der Code ist selbsterklärend und sollte alle Deine Fragen beantworten.
Loadadr benutzt außer dem angegebenen Pointerregister keine weiteren Register, es muss also dafür nichts zusätzlich gesichert werden.

PicNick
19.12.2011, 09:30
http://www.rn-wissen.de/index.php/Assembler_Einf%C3%BChrung_f%C3%BCr_Bascom-User (http://www.rn-wissen.de/index.php/Assembler_Einf%C3%BChrung_f%C3%BCr_Bascom-User)

MagicWSmoke
19.12.2011, 09:58
http://www.rn-wissen.de/index.php/Assembler_Einführung_für_Bascom-User (http://www.rn-wissen.de/index.php/Assembler_Einf%C3%BChrung_f%C3%BCr_Bascom-User)
Unter diesem Link seh' ich aber nix zum absoluten Adressieren von Arrays, Loadadr kommt zwar vor, wird aber zur sequentiellen Adressierung benutzt, einmal bei Strings und einmal um ein Word zu holen.

Der Trick bei der absoluten Adressierung ist dagegen, sich die Basisadresse zu holen und den Index aufzuaddieren. Da im vorliegenden Beispiel der Code in einer ISR ausgeführt wird, muss der Index immer wieder neu geholt werden, sequentielle Adressierung ist nicht brauchbar.

Che Guevara
19.12.2011, 21:11
Hallo,

danke, das hilft mir schon mal sehr weiter :)
ABER:
Wie lade ich denn den Wert wieder ins Array? Im Endeffekt möchte ich folgendes nach ASM umsetzen:


Dim Empf(5) As Word
Dim Channel As Byte
...
ISR:
Empf(channel) = Timer0

Außerdem ist zu beachten, dass Empf() ein Word ist, aber ich denke, das macht nichts!?
Sorry, für meine etwas blöden Fragen, aber ich habe noch nicht viel in ASM gemacht, außer ein paar If-Abfragen und Blink-Programme - ausschließlich mit Byte-Datentypen.

Gruß
Chris

MagicWSmoke
20.12.2011, 08:35
Wie lade ich denn den Wert wieder ins Array?
Mit dem Gegenpart des "LD"-Befehls, dem "ST"-Befehl, das wiederum ist im Tutorial zu finden.
Sinnvollerweise mit postincrement, da wird der X,Y oder Z-Pointer nach Ausführung um 1 erhöht.

dass Empf() ein Word ist, aber ich denke, das macht nichts!?
"Macht nichts" ist der falsche Ausdruck, natürlich muss darauf reagiert werden, die X,Y & Z-Pointerei ist Byte-orientiert, damit entspricht WordArr(3) dem 5. & 6. Byte. Du musst also den Index, bevor Du ihn zur Basisadresse addierst, mal 2 nehmen. Am schnellsten geht's, wenn Du ihn einmal nach links schiebst, das geht mit LSL für das LB und ROL für das HB.
Wenn Dein Array nur 5 Elemente groß ist, kannst Du Dir sparen das HB zu schieben, da immer 0.
Das entspräche dann dem hier:

!LDS R18, {ArrPtr}
!DEC R18 <--- weglassen bei Index 0-4
!CLR R19
!LSL R18
!ADD ZL, R18
!ADC ZH, R19
!ST Z+, Reg(WordVal_LB)
!ST Z, Reg(WordVal_HB)
Würde Dir raten, Du holst Dir das AVR-Studio 4, dort kannst Du die von Bascom erzeugte .obj-Datei laden und Dir den disassemblierten Code ansehen. Indem Du Dir einfache Beispiele in Basic schreibst, kannst Du daraus lernen wie Bascom das umsetzt.

Che Guevara
21.12.2011, 22:56
Hallo,

habe mir gerade das AVR-Studio 4 runtergeladen und mir den Disassemblierten Code angesehen.


1202: Empf(channel) = Timer0

+00001D0E: E4A6 LDI R26,0x46 Load immediate
+00001D0F: E0B0 LDI R27,0x00 Load immediate
+00001D10: 918C LD R24,X Load indirect
+00001D11: E3AF LDI R26,0x3F Load immediate
+00001D12: E0B3 LDI R27,0x03 Load immediate
+00001D13: 90AD LD R10,X+ Load indirect and postincrement
+00001D14: 24BB CLR R11 Clear Register
+00001D15: E1A5 LDI R26,0x15 Load immediate
+00001D16: E0B3 LDI R27,0x03 Load immediate
+00001D17: 0CAA LSL R10 Logical Shift Left
+00001D18: 1CBB ROL R11 Rotate Left Through Carry
+00001D19: 0DAA ADD R26,R10 Add without carry
+00001D1A: 1DBB ADC R27,R11 Add with carry
+00001D1B: 938D ST X+,R24 Store indirect and postincrement
+00001D1C: 2788 CLR R24 Clear Register
+00001D1D: 938C ST X,R24 Store indirect

Manches verstehe ich aber nicht. Warum wird z.b. R26 und R27 dreimal mit einem Wert beschrieben, wenn die Register nach den ersten beiden Malen gar nicht verwendet werden und wieder überschrieben werden? Außerdem wird R11 erst gelöscht und dann um 1 nach links geschoben. Was hat das für einen Sinn?
Ich hoffe, ich stelle mich jetzt nicht zu blöd an und jemand ist bereit, mir das zu erklären?

Gruß & Vielen Dank
Ghris

PicNick
22.12.2011, 07:34
Denk dran', "X" und R26 / R27 ist das Gleiche !

Um das Register R24 mit einem Wert aus einer SRAM -Variablen zu laden, muss man --> :


LDI R26 , LOW (Variable)
LDI R27 , HIGH (Variable)
LD R24 , X X == Registerpaar XL /XH und das ist identisch mit R26/R27


AVR ASM hat drei solcher Pointer-Register
X == XL/XH == R26/R27
Y == YL/YH == R28/R29
Z == ZL/ZH == R30/R31

und für die gibt es die BEfehle
LD reg , X
LD reg , Y
LD reg , Z

MagicWSmoke
22.12.2011, 08:17
Chris.

Außerdem wird R11 erst gelöscht und dann um 1 nach links geschoben. Was hat das für einen Sinn?XL & XH wurde Dir ja bereits von PicNick erklärt. Wobei mir allerdings der Nutzen im gezeigten Code nicht recht klar wird, denn wenn keine variable Adressierung notwendig ist, so verbraucht die Kombination

LDI XL, lbyte(Sram_Adress)
LDI XH, hbyte(Sram_Adress)
LD Rxx, X
deutlich mehr Flash als ein simples

LDS Rxx, {Sram_Adress}

Außerdem wird R11 erst gelöscht und dann um 1 nach links geschoben. Was hat das für einen Sinn?
Das dient zum Übertrag des Carry-Flags, hier in's High-Byte des 16Bit Wertes, mache ich auch so im von mir geposteten Beispielcode, nur dort mit ADD/ADC.
Du könntest keine Additionen oder Schiebeoperationen größer 8Bit ohne Carry durchführen.

Hast Du eigentlich die Bascom-Kommentare aus dem AVR-Studio Listing gezielt entfernt, oder nur das falsche File geladen ?

PicNick
22.12.2011, 08:49
Bascom ist nicht der allergrösste Optimierer. Wenn die Zielvariable ("Empf") ein Word ist, verwendet Bascom eigentlich generell die
LD XL, lbyte ( ..)
LD XH, hbyte( ..)
sequenz, auch wenn das im Einzelfall gar nicht notwendig wäre

Btw: Wenn man Assembler schreibt, sollte man sich auch von der BAscom-od. "höhere-Sprache" Denkweise lösen. z.B
Du füllst ja die "Empf" Tabelle strikt aufsteigend. Also ist das Verwenden eines Index überflüssige Arbeit für den µC.
aber das ist jetzt vielleicht zuviel über-drüber für deine Fragestellung

MagicWSmoke
22.12.2011, 09:21
Bascom ist nicht der allergrösste Optimierer.
Trifft hier zumindest was den Speicherverbrauch betrifft nicht zu.

Wenn die Zielvariable ("Empf") ein Word ist, verwendet Bascom eigentlich generell die
LD XL, lbyte ( ..)
LD XH, hbyte( ..)
sequenz, auch wenn das im Einzelfall gar nicht notwendig wäre
Vom Flashverbrauch her macht's keinen Unterschied, es sind nur mehr Zyklen, ich denke wir sprechen hier über Speicherverbrauch.

LDS Rxx, {Word_Var_Adr_LB} <-- 4 Bytes, 1 Zyklus
LDS Ryy, {Word_Var_Adr_HB} <-- 4 Bytes, 1 Zyklus
' 8 Bytes, 2 Zyklen


LDI XL, lbyte(Word_Var_Adr_LB) <-- 2 Bytes, 1 Zyklus
LDI XH, hbyte(Word_Var_Adr_LB) <-- 2 Bytes, 1 Zyklus
LD Rxx, X+ <-- 2 Bytes, 2 Zyklen
LD Ryy, X <-- 2 Bytes, 1 Zyklus
' 8 Bytes, 5 Zyklen

Ansonsten wär's interessant, woraus das von Chris gezeigte Assemblerlisting erzeugt wurde, meine Version 2.0.7.3 baut aus:

Dim A As Byte , B As Byte
B = A

das hier:

9: B = A
LDS R24,0x0060
9: B = A
STS 0x0061,R24
Egal ob mit oder ohne eingeschaltete Optimierung, und das ist einwandfrei so.

PicNick
22.12.2011, 10:17
Bei Byte = BYte ist es so, wie du sagst

aaaber
Beispiel :

Dim A As Byte
Dim B As Byte
Dim C As Word

B = 165
A = B
C = B
End

Was wird draus:


B = 165

LDI r24,0xA5
STS 0x0061,r24 'ok, besser geht's nicht

A = B
LDS r24,0x0061
STS 0x0060,r24 'ok, ebenfalls das entspricht deinem Beispiel

aber jetzt WORD = BYTE -------------------

C = B

LDI XL,0x61
LDI XH,0x00
LD r24,X jetzt lädt er "B" nicht mehr mit LDS, sondern über X

LDI XL,0x62 ' das Word-speichern ist wohl ok, wenn man nicht erbsen zählt
LDI XH,0x00
ST X+,r24
CLR r24
ST X,r24


-------- er hätte schreiben können
STS 0x0062,r24
CLR r24
STS 0x0063,r24

MagicWSmoke
22.12.2011, 10:33
LDI XL,0x61
LDI XH,0x00
LD r24,X jetzt lädt er "B" nicht mehr mit LDS, sondern über X
Ja, ist jetzt nicht direkt logisch, da dazu keine Notwendigkeit besteht.

PicNick
22.12.2011, 10:48
Ich kann ja nur vermuten. Bascom macht ja ein implizites "Casting" auf die Zielvariable (word), d.h. er wählt zum Registerladen die "X" -Methode.
dann hätt man aber erwarten können


LDI XL,0x61
LDI XH,0x00
LD r24,X
CLR R25

' ab nun wäre "B" ein gecastetes WORD (R24/R25), und Bascom müsste sich nicht mehr drum kümmern.
Das geschieht aber auch wieder nicht. Er muss jedesmal doch wieder dran denken, dass "B" eigentlich nur ein Byte ist

Nun, was soll's

MagicWSmoke
22.12.2011, 11:01
Nun, was soll's
Hab's Mark geschrieben, mal sehen was draus wird.

Che Guevara
23.12.2011, 12:37
Hallo,

erstmal danke für die Erklärungen. Ich habe jetzt mal alles, was ich als nicht relevant empfinde, auskommentiert und wollte euch fragen, obs so passt oder ob man noch was optimieren kann? V.a. gehts um möglichst wenige Taktzyklen.


Isr_int0:

push r16 'sichere r16

Push r10
'Push r11
Push r24
Push r26
'Push r27

lds r16 , {channel} 'lade channel in r16
cpi r16 , 6 'vergleiche r16 mit 6
brlo _lower 'springe, wenn kleiner
rjmp _out_of_range 'sonst springe nach _out_of_range
_lower: '_lower Label
cpi r16 , 1 'vergleiche r16 mit 1
brge _higher 'springe, wenn größer gleich
rjmp _out_of_range 'sonst springe nach _out_of_range
_higher: '_higher Label
'################################################# ################################################## ###################################
'################################################# ################################################## ###################################
'Ldi R26 , 0x46
'Ldi R27 , 0x00
Ld R24 , X
'Ldi R26 , 0x3f
'Ldi R27 , 0x03
Ld R10 , X+
'Clr R11
Ldi R26 , 0x15
'Ldi R27 , 0x03
Lsl R10
'Rol R11
Add R26 , R10
'Adc R27 , R11
St X + , R24
Clr R24
St X , R24
'################################################# ################################################## ###################################
'################################################# ################################################## ###################################
_out_of_range: '_out_of_range Label
ldi r16 , 6 'lade 6 in r16
!out tcnt0 , r16 'schreibe r16 in timer0
lds r16 , {channel} 'lade Channel in r16
inc r16 'erhöhe Channel um 1
sts {channel} , r16 'lade r16 in Channel

'Pop r27
Pop r26
Pop r24
'Pop r11
Pop r10

pop r16 'stelle r16 wieder her

Return

Vielleicht fällt euch ja noch was auf, anderfalls wäre es nett, wenn ihr mir ein OK gebt.

Btw: Bascom Version ist 1.11.9.5 ;)

Vielen Dank & Gruß
Chris

PicNick
23.12.2011, 12:57
Wäre besser, du stelltst dein ganzes Programm da rein. Man kann sonst die Variablen-Adressen nicht verifizieren. Ausserdem, wenn du Zyklen sparen willst, gibt's da ein paar Vorschläge.

Che Guevara
23.12.2011, 13:28
Das ganze Programm ist der Quadrocopter Quellcode von Willa. Leider kann ich ihn nicht hier reinstellen, weil er zu lang ist.

gibt's da ein paar Vorschläge.
Wo ist den da? Hier im Thread?

Gruß
Chris

PicNick
23.12.2011, 13:59
:mrgreen: "DA" ist momentan in meinem Hirn :mrgreen:
Geht darum, dass die 1:1 Übertragung von BASCOM ---> Assembler natürlich nicht das Gelbe vom kolumbus ist.

Nun, wenigstens die (relevanten) Variablen definitionen würd' ma schon noch gerne sehen.
Oder sind das genau die vom 1.Post ?

Und worum geht's eigentlich ? Durchschnitt von 6 Messungen ?

Che Guevara
23.12.2011, 14:47
Definitionen sind (glaube ich) die vom ersten Post:


Dim Empf(5) As Word
Dim Channel As Byte

Hm, das ist mir durchaus klar, aber ich kann nicht den ganzen Code nach ASM übersetzen; Trotzdem möchte ich die ISR "etwas" verschnellern. Momentan (also reines Bascom) sinds 162 Takte, das ist zulange.
Worum gehts?
Mit dieser ISR wird das Summensignal des Empfängers eingelesen (und näturlich mithilfe des Timer0). Es gibt 5 relevante Kanäle, die die Software benötigt. Durchschnittsberechnungen sind keine vorhanden. Hier nochmal der orignale Code:


Getreceiver: 'falling edge detection
If Channel > 0 And Channel < 6 Then 'fill empf(1-5)
Empf(channel) = Timer0
End If
Timer0 = 6 'preload for 4.096 ms
Incr Channel 'if no falling edge was detected for a longer period, channel will increase above 11

Return

(wie gesagt von Willa)
Diesen möchte ich auf ASM umschreiben. Habs auch schon mal so gemacht:


Isr_int0:

push r16 'sichere r16

lds r16 , {channel} 'lade channel in r16
cpi r16 , 6 'vergleiche r16 mit 6
brlo _lower 'springe, wenn kleiner
rjmp _out_of_range 'sonst springe nach _out_of_range
_lower: '_lower Label
cpi r16 , 1 'vergleiche r16 mit 1
brge _higher 'springe, wenn größer gleich
rjmp _out_of_range 'sonst springe nach _out_of_range
_higher: '_higher Label
'################################################# ################################################## ###################################
'################################################# ################################################## ###################################
Empf(channel) = Timer0
'################################################# ################################################## ###################################
'################################################# ################################################## ###################################
_out_of_range: '_out_of_range Label
ldi r16 , 6 'lade 6 in r16
!out tcnt0 , r16 'schreibe r16 in timer0
lds r16 , {channel} 'lade Channel in r16
inc r16 'erhöhe Channel um 1
sts {channel} , r16 'lade r16 in Channel

pop r16 'stelle r16 wieder her

Return

Das waren glaube ich 43 Takte, was auch schon deutlich besser ist. (Als Nosave INT) Aber da geht doch noch mehr, oder nicht?

Gruß
Chris

EDIT:
Bei dem letzten Code habe ich vergessen, die Register, die Bascom für die Anweisung "Empf(channel) = Timer0" braucht, zu sichern. Das sind R10, R11, R24, R26, R27.
Das macht dann nochmal 5(Register) * 2(Push&Pop) * 2(Takte pro Befehl) = 20 Takte mehr.

PicNick
23.12.2011, 15:37
Soweit mal klar.
Ich werd' Dir einen ISR-Vorschlag machen

Btw: Du musst in der ISR auf jeden fall noch SREG pushen und poppen, sonst fängt dein Programm zu spinnen an.

Noch eine Frage:
Timer0 hat doch nur 8-Bit

wieso brauchst du eine Tabelle mit WORD ?

MagicWSmoke
23.12.2011, 15:54
...ob man noch was optimieren kann?
Eher richtig machen, weniger "optimieren".
1) Warum glaubst Du, dass XL/XH nicht durch anderen Code verändert wird ? Du lädst X nicht in der ISR, sondern addierst nur fleissig dazu, das geht so gar nicht.

2) Anderer Code wird nicht mehr arbeiten, wenn Du XL/XH verwendest ohne den beim ISR-Eintritt zu sichern, XH kann verändert werden, wenn eine Bytegrenze überschritten wird.

3) Du kannst Dir nur sparen das Carry per ADC auf XH aufzuaddieren, wenn Du sicher bist, dass die absolute SRam-Adresse des Arrays vom Compiler nicht an eine Bytegrenze gelegt wird. Beispiel für Word:
Index 1: HB/LB = &h01 &hFC
Index 2: &h01 &hFE
Index 2: &h02 &h00

4) SREG wird nicht gesichert.

Abschließend vielleicht noch die Frage an Dich, warum ich Dir denn eigentlich Beispiele geschrieben habe, wenn Du die weitestgehend ignorierst ?

PicNick
23.12.2011, 16:14
so, soweit möglich getestet:

Besonderheiten:
"dummy" dient nur dazu, damit Bascom bei "Loadadr" keinen Index verlangt, verbraucht aber keinen Platz (Overlay) . könnte man auch anders machen, however.
"channel" Bascom verlangt Index 1-5. das ist aber ungünstig zu rechnen. Besser 0-4 . man braucht dadurch nur auf > 4 ( >= 5) zu prüfen




Dim Empf(5) As Word
Dim Dummy As Byte At Empf Overlay
Dim Channel As Byte

Getreceiver: 'falling edge detection
$asm
PUSH r24
PUSH r25
PUSH XL
PUSH XH
!IN r24, SREG
PUSH r24
LDS r24, {channel} ' channel 0-4 ( bascom 1-5)
CPI r24, 5 ' >= 5 --> skipped
BRSH _out_of_range
LSL r24 ' * 2 (wordlength)
CLR r25 ' clear (r24 kann ja nicht grösser als 8 werden)
Loadadr Dummy , X ' addr Empf(0)
ADD XL, r24 ' addr Empf + 2*channel
ADC XH, r25
!IN r24, TCNT0 ' timer0
ST X+ , r24 ' empf(channel) = timer0
ST X , r25
_out_of_range:
LDS r24, {channel} ' channel 0-4 ( bascom 1-5)
INC r24
STS {channel}, r24
LDI r24, 6
!OUT TCNT0, r24
POP r24
!OUT SREG, r24
POP XH
POP XL
POP r25
POP r24
$end Asm
Return



Anders und vermutl. besser geht' sicher auch

Ein bisschen kann man noch sparen, wenn "empf" komplett im adressbereich < 256 liegt.

Che Guevara
23.12.2011, 16:31
Hallo,

erstmal danke für das Beispiel!
@MagicWSmoke:
Ich habe deine Beispiele keinesfalls ignoriert, nur ist es für mich nicht leicht, das zu verstehen. Ich habs mir mehrfach angesehen, nur bin ich eben mit dieser ASM-Denkerei noch nicht so vertraut.
@Picture:
Vielen Dank! Ich werde deinen Code testen, auch auf die Taktzahl werde ich achten. Melde mich dann wieder, wenns funktioniert.

Gruß & Vielen Dank
Chris

EDIT:
Habs gerade im Simulator getestet, mit der Return-Anweisung braucht die komplette ISR (wenn Channel zw. 1 und 5) nur 48 Takte. Das ist im vergleich zu den anfänglichen ca 160 Takten nur ein Viertel. Später, oder auch morgen, werde ich das dann mal auf den Quadro flashen und mal schaun, obs funktioniert.

EDIT2:
Habs gerade getestet, irgendetwas funktioniert nicht. Wenn ich das Programm flashe (mit NUR veränderter ISR, Dummy-Variable und NOsave) blinken schon die LEDs anders, sie zeigen wahrscheinlich einen Fehelrcode.

MagicWSmoke
23.12.2011, 18:35
Habs gerade getestet, irgendetwas funktioniert nicht.
Ohne dass ich jetzt Original und ASM im Detail verglichen hab', ist doch zu sehen dass Ihr das hier aus meinem früheren Post vergessen habt:

!DEC R18 <--- weglassen bei Index 0-4
Im Fall von PicNick's Code wäre das R24.

Überleg' doch mal, was ein Schieben des Index 1 zur Folge hat und welche Adresse angesprochen wird.

Ich habs mir mehrfach angesehen, nur bin ich eben mit dieser ASM-Denkerei noch nicht so vertraut.
Hättest Du halt gefragt...

Michael
24.12.2011, 09:30
Btw: Bascom (http://www.rn-wissen.de/index.php/Bascom) Version ist 1.11.9.5
mach doch erstmal ein Update.

Gruß, Michael

MagicWSmoke
24.12.2011, 11:08
Hi Michael,

mach doch erstmal ein Update.
in diesem Fall ist's egal, da nur ASM betreffend und auch der Fehler offensichtlich ist. Unter Bascom wird im Originalcode mit Index 1..5 gearbeitet, die Adressierung in PicNicks Assemblercode benötigt aber Index 0..4.
Wenn man sich die Basisadresse des Arrays mit LoadAdr holt, dann hat man bereits die erste Zelle im Pointer-Register und darf nicht noch den Index mit 1*2 dazurechnen. Wenn man's trotzdem macht, adressiert man den falschen Arrayinhalt und überschreibt hier sogar nachfolgende Variablen.

PicNick
24.12.2011, 13:42
Zur Info, wer's nicht weiss: Bascom adressiert indizierte Tabellen so: er lädt
Tabellenanfangsadresse - elementlänge
dadurch braucht er den index nicht um 1 zu verringern.
das fällt im generierten Code nur auf, wenn man die Tabellen-adresse im Report (prog.RPT) vergleicht.

Zur Vorsicht, weil wir ja nicht den ganzen Code sehen: Die ISR-Routine darf nur HINTER der "END" anweisung stehen.

Che Guevara
24.12.2011, 14:31
Hallo,

Die ISR-Routine steht fast ganz am Schluss des Programms, hinter dem END. Hier (http://www.villalachouette.de/william/krims/tricopter/Tricopter_02_ShrediquetteDLX.txt) findet man den ganzen Quellcode, meiner ist fast identisch, außer dass ich einen BMA020 ACC über I2C anspreche und ich vier Motoren habe. Ansonsten genau gleich.

Gruß
Chris

MagicWSmoke
24.12.2011, 14:46
PicNick,

Zur Info, wer's nicht weiss: Bascom adressiert indizierte Tabellen so: er lädt
Tabellenanfangsadresse - elementlänge
dadurch braucht er den index nicht um 1 zu verringern.
Ja, ist bekannt. Und was hat das mit Deinem Code zu tun ?
Wenn man mal den original Bascom-Code ansieht:


Isr_int0:
If Channel > 0 And Channel < 6 Then
Empf(channel) = Timer0
End If
Timer0 = 6
Incr Channel
Return
dann wird dort channel 1..5 verwendet, Dein ASM-Code verwendet dagegen channel 0..4. Das würde nur funktionieren, wenn channel nur eine innerhalb der ISR verwendete Variable wäre und vom restlichen Code nicht angesprochen wird. Das ist aber bereits aus dem Code hervorgehend sehr unwahrscheinlich, denn pro Aufruf der Int0-ISR wird channel um 1 hochgezählt. Was ist dann bei channel = 5 ? Hört dann alles auf, oder muss channel erst überlaufen ?

Also wird channel sehr wahrscheinlich woanders im Code auch verwendet und wenn dem so ist, müssten alle entsprechenden Stellen auf channel 0..4 umgestellt werden.
Das macht man doch nicht so, da ist's doch einfacher der ASM-Code bildet channel 1..5 nach, auch wenn's 'nen Takt mehr kostet.

@Chris,

wo kommt eigentlich das Hochzählen von channel her ? Ist im Bascom-Code nicht zu entdecken.

Che Guevara
24.12.2011, 14:56
Hallo,

mit der ISR-Int0 Routine und dem Detectrxpause Interrupt wird das Summensignal des Modellbau-Empfängers ausgelesen:


Detectrxpause:
Channel = 0
Return

Der Timer0 (Detectrxpause-Interrupt) ist auf 4.096ms eingestellt. Das Summensignal beinhaltet ja alle Kanäle der FC (in meinem Fall 8, wovon nur 5 eingelesen werden). Nachdem alle 8 Kanäle übertragen wurden, erfolgt eine kurze Pause, durch welche der Timer0 überläuft. Somit wird Channel auf 0 gesetzt, damit die Signale erneut eingelesen werden können.
Mit diesen 5 Werten wird dann der Copter gesteuert; sie werden im übrigen Programm auf Integer-Zahlen (Bereich: -37 ... +37) umgerechnet. Aber hier gehts nur ums einlesen der Signale.
Ich hoffe, das beantwortet deine Frage?!

Gruß
Chris

MagicWSmoke
24.12.2011, 15:04
Channel = 0

Das ist die einzige Stelle an der auf Channel zugegriffen wird ? Allein daraus ergibt sich aber schon der Unterschied, dass bei einem Index von Channel 1..5 der Int0 wenigstens einmal vorher triggern muss muss, damit Channel auf 1 geht, wobei's bei PicNick's Code sofort losgeht. Und das macht den Unterschied aus.

Che Guevara
24.12.2011, 15:17
Ja, das ist die einzige Stelle. Channel wird nur zum Einlesen benötigt.
Also muss ich doch auf >=1 und <6 abfragen, damits stimmt?!

Gruß
Chris

MagicWSmoke
24.12.2011, 15:25
Also muss ich doch auf >=1 und <6 abfragen, damits stimmt?!
Ich kenne nicht den gesamten Code und damit den kompletten Mechanismus, aber ich kann sagen dass wenn der Basic-Code >= 1 <6 abfragt und der funktioniert, die ASM Routine genau das Gleiche machen sollte.
Du hast mir auch die Frage noch nicht beantwortet, woher das Hochzählen von Channel kommt, da in Deinem zuerst geposteten Basic-Code nicht enthalten.
Zeig doch mal die Basic-Routine genau so, wie sie tatsächlich funktioniert.

Che Guevara
24.12.2011, 15:27
Wie meinst du das mit dem Hochzählen? Hier


Isr_int0: 'falling edge detection
If Channel > 0 And Channel < 6 Then 'fill empf(1-5)
Empf(channel) = Timer0
End If
Timer0 = 6 'preload for 4.096 ms
Incr Channel 'Increase Channel
Return

wird die Variable hochgezählt. Wenn du etwas anderes wissen möchtest, dann verstehe ich deine Frage leider nicht.

Gruß
Chris

MagicWSmoke
24.12.2011, 15:38
Wie meinst du das mit dem Hochzählen?
Ist ok, hab's jetzt gesehen. Selektive Wahrnehmung :D

Che Guevara
24.12.2011, 15:44
Ok :)
Aber jetzt ist meine Frage noch offen?!
Ich frage Channel nach >= 1 und < 6 ab. Wenns in dem Bereich ist, dann lese ich die Timer0 Variable WIE ein?


LSL r24 ' * 2 (wordlength)
CLR r25 ' clear (r24 kann ja nicht grösser als 8 werden)
Loadadr Dummy , X ' addr Empf(0)
ADD XL, r24 ' addr Empf + 2*channel
ADC XH, r25
!IN r24, TCNT0 ' timer0
ST X+ , r24 ' empf(channel) = timer0
ST X , r25

Funktioniert dann trotzdem, oder? Hier wird ja, soweit ich das verstanden habe, nur Channel nach links geschiftet, da Empf ein Word ist. Dann wird der entsprechende Empf-Feld-Bereich addresiert und Timer0 wird dort hineingeschrieben!?
Muss ich außer den normal verwendeten Registern und SREG sonst noch was sichern? Warum muss ich überhaupt SREG sichern?

Gruß
Chris

MagicWSmoke
24.12.2011, 15:54
dann lese ich die Timer0 Variable WIE ein?
So:


!IN r24, TCNT0 ' timer0


Funktioniert dann trotzdem, oder? Hier wird ja, soweit ich das verstanden habe, nur Channel nach links geschiftet, da Empf ein Word ist. Dann wird der entsprechende Empf-Feld-Bereich addresiert und Timer0 wird dort hineingeschrieben!?
Warum brauchst Du ein Wordarray, wenn Du nur einen 8Bit-Timer hast ? Werden da noch Rechnungen im Array durchgeführt ?

Warum muss ich überhaupt SREG sichern?
Weil das SREG Statusflags enthält, die z.B. von INC oder CPI verändert werden.

Che Guevara
24.12.2011, 15:59
Nein, ich meinte, wie ich die Variable dann ins Array schreibe? So, wie ich gerade eben nochmal gespostet habe?

Ja, es werden noch Rechnungen durchgeführt und somit benötigt man ein Word. Ich habs e schon mal als Byte deklariert, aber das wollte dann nicht so recht. Deswegen ists ein Word.
Ok, das verstehe ich.

Gruß
Chris

MagicWSmoke
24.12.2011, 16:07
Nein, ich meinte, wie ich die Variable dann ins Array schreibe? So, wie ich gerade eben nochmal gespostet habe?
Ja.

Ja, es werden noch Rechnungen durchgeführt und somit benötigt man ein Word. Ich habs e schon mal als Byte deklariert, aber das wollte dann nicht so recht. Deswegen ists ein Word.
Werden die Rechnungen innerhalb der Arrayvariable durchgeführt oder in einer extra Variablen ?

Che Guevara
24.12.2011, 16:14
Hier sind die Berechnungen im Code:


'--Noise filter--
For I = 1 To 5
Meanrx(i) = Meanrx(i) * 3
Meanrx(i) = Meanrx(i) + Empf(i) '"lowpass filter" of the RC signal
Shift Meanrx(i) , Right , 2 ' (=divide by 4)
Aempfh(i) = Meanrx(i) + 17 'upper acceptable fluctuation
Aempfl(i) = Meanrx(i) - 17 'lower acceptable fluctuation
If Empf(i) > Aempfh(i) Or Empf(i) < Aempfl(i) Then 'compare allowed fluctuation with current rc reading
Empf(i) = Meanrx(i) 'if fluctuation was too high -> replace with averaged value
Print "Error reading channel: " ; I 'handy to check for RC problems
End If
Next

'Empf(X) are filled in "getreceiver". They usually contain values ranging from 63 - 137.
'Empf(throttlechannel) is the throttle stick. it will be rescaled differently.
If Empf(throttlechannel) > 61 And Empf(throttlechannel) < 139 Then 'don't process values that can't be correct
Sempf(throttlechannel) = Empf(throttlechannel) - 61
Sempf(throttlechannel) = Sempf(throttlechannel) * 3 '==> values ranging from 3 (stick at bottom) to 228 (full throttle)
End If
'Now nick, roll, yaw and idle up switch

If Empf(nickchannel) > 61 And Empf(nickchannel) < 139 Then 'don't process values that can't be correct
Sempf(nickchannel) = Empf(nickchannel) - 100 'convert to values ranging from -37 to +37
End If
If Empf(rollchannel) > 61 And Empf(rollchannel) < 139 Then 'don't process values that can't be correct
Sempf(rollchannel) = Empf(rollchannel) - 100 'convert to values ranging from -37 to +37
End If
If Empf(yawchannel) > 61 And Empf(yawchannel) < 139 Then 'don't process values that can't be correct
Sempf(yawchannel) = Empf(yawchannel) - 100 'convert to values ranging from -37 to +37
End If
If Empf(5) > 61 And Empf(5) < 139 Then 'don't process values that can't be correct
Sempf(5) = Empf(5) - 100 'convert to values ranging from -37 to +37
End If

Eigentlich findet alles nicht im Array statt, trotzdem gehts nicht als Byte. Vielleicht liegt das daran, dass bei Fehlerhaftem Signal die Variable Meanrx in Empf geschrieben wird. Sicher bin ich mir da aber nicht. Vielleicht hast du eine Erklärung?

Gruß
Chris

MagicWSmoke
24.12.2011, 16:43
Hatte mich ein wenig gespielt, mit Testumgebung:

$Regfile = "m32def.dat"
$Crystal = 4000000
$hwstack = 32
$swstack = 8
$framesize = 24

'(
Isr_int0:
If Channel > 0 And Channel < 6 Then
Empf(channel) = Timer0
End If
Timer0 = 6
Incr Channel
Return
')

Dim tmp as Byte

Dim Empf(5) As Word
Dim Channel As Byte
Dim Empf_tmp As Word

Do
channel = 0
For tmp = 0 To 7
TCNT0 = 255 - tmp
Gosub Isr_int0
Next tmp
Loop


Isr_int0: ' cycles in range: 53, out of range: 29
!PUSH R16
!IN R16, SREG
!PUSH R16
!LDS R16, {channel}
!DEC R16
!CPI R16, 5
!BRCC NotInRange
!PUSH R17
!PUSH XL
!PUSH XH
LoadAdr Empf(1) , X
!MOV R17, R16
!LSL R17
!ADD XL, R17
!CLR R17
!ADC XH, R17
!IN R17, TCNT0
!ST X+, R17
!CLR R17
!ST X, R17
!POP XH
!POP XL
!POP R17
!NotInRange:
!INC R16
!INC R16
!STS {channel}, R16
!LDI R16, 6
!OUT TCNT0, R16
!POP R16
!OUT SREG, R16
!POP R16
Return

'(
Isr_int0: ' cycles in range: 51, out of range: 30
!PUSH R16
!IN R16, SREG
!PUSH R16
!LDS R16, {channel}
!DEC R16
!CPI R16, 5
!BRCC NotInRange
!PUSH R17
!PUSH XL
!PUSH XH
LoadAdr Empf(1) , X
!CLR R17
!LSL R16
!ADD XL, R16
!ADC XH, R17
!IN R16, TCNT0
!ST X+, R16
!ST X, R17
!POP XH
!POP XL
!POP R17
!NotInRange:
!LDS R16, {channel}
!INC R16
!STS {channel}, R16
!LDI R16, 6
!OUT TCNT0, R16
!POP R16
!OUT SREG, R16
!POP R16
Return
')

die Variable Meanrx in Empf geschrieben wird
Ich sehe nicht ohne Weiteres, wie groß die werden kann.

Diese Zugriffe dürften übrigens recht "teuer" sein in Bezug auf die Ausführungszyklen:

If Empf(throttlechannel) > 61 And Empf(throttlechannel) < 139 Then 'don't process values that can't be correct
Sempf(throttlechannel) = Empf(throttlechannel) - 61
Wenn Bascom die Arrayadresse nicht zur Compilezeit kennt, wie bei einem durch Variable indizierten Array, so wird zu jedem Vergleich die gleiche Arrayzelle immer wieder neu geladen. Du könntest durch temporäre Variablen eine Beschleunigung der Rechnung erreichen.

Und da Du ein Word nicht atomar verarbeiten kannst, hättest Du auch ein Problem wenn im Wordarray tatsächlich Werte > 255 drinstehen würden.
Du kannst nicht verhindern (außer durch Sperren der Interrupts) dass der Interrupt gerade dann unterbricht, nachdem das erste Byte von Empf(x) zum Vergleich eingelesen wurde, die ISR Empf(x) dann beide Bytes verändert und nach Rückkehr das zweite Byte des nun veränderten Empf(x) zusammen mit dem ersten, nicht veränderten Byte weiterverarbeitet wird.

Che Guevara
24.12.2011, 19:13
Also erstmal möchte ich dir frohe Weihnachten wünschen :)
Das finde ich sehr nett, dass du dir soviel Mühe gibst.

Meanrx liegt zwischen 63 und 137, das sind die beiden maximalen Knüppelstellungen. Allerdings stimmt das nicht ganz, da das ja ein Tiefpass ist und dieser normalerweise diese Extremwerte nicht erreichen kann. Eigentlich sehe ich keinen Grund, warum Empf kein Byte sein kann, aber ich habs mal probeweise eingespielt und da hats nicht funktioniert... Ich werds aber morgen nochmal probieren.

Hm, das habe ich mir schon gedacht. Aber wenns morgen mit einem Byte doch funktionieren sollte, dann ist das ja nicht mehr soooo schlimm, oder?
Also Werte > 255 werden nie im Empf-Array drinstehen.
Was genau meinst du mit temporären Variablen? So:


Dim Tmp1 As Word
Dim Tmp2 As Word
Dim Tmp3 As Word
Dim Tmp4 As Word
Dim Tmp5 As Word

...

Tmp1 = Empf(1)
Tmp2 = Empf(2)
Tmp3 = Empf(3)
Tmp4 = Empf(4)
Tmp5 = Empf(5)

If Tmp1 > 61 And Tmp1 < 139 Then
Sempf(1) = Tmp1 - 61
Sempf(1) = Sempf(1) * 3
End If

Oder so:


Dim Tmp1 As Word
Dim Tmp2 As Word
Dim Tmp3 As Word
Dim Tmp4 As Word
Dim Tmp5 As Word

Dim Stmp1 As Integer
Dim Stmp2 As Integer
Dim Stmp3 As Integer
Dim Stmp4 As Integer
Dim Stmp5 As Integer


...


Tmp1 = Empf(1)
Tmp2 = Empf(2)
Tmp3 = Empf(3)
Tmp4 = Empf(4)
Tmp5 = Empf(5)

If Tmp1 > 61 And Tmp1 < 139 Then
Stmp1 = Tmp1 - 61
Stmp1 = Stmp1 * 3
End If

Sempf(1) = Stmp1


Vielen Dank & Gruß
Chris

MagicWSmoke
24.12.2011, 20:00
Also erstmal möchte ich dir frohe Weihnachten wünschen :)
Danke, das wünsch' ich Dir auch :)

Das finde ich sehr nett, dass du dir soviel Mühe gibst.
Ist auch ein Thema, das mich interessiert.

...aber ich habs mal probeweise eingespielt und da hats nicht funktioniert... Ich werds aber morgen nochmal probieren.
Da ist's dann interessant wie Du das machst, poste doch mal den entsprechenden Code. Würde dann das Byte Empf(x) vor weiterer Verarbeitung einer temporären Word-Variable zuweisen.

Hm, das habe ich mir schon gedacht. Aber wenns morgen mit einem Byte doch funktionieren sollte, dann ist das ja nicht mehr soooo schlimm, oder?
Ist nicht schlimm, da scheinbar kein schädlicher Nebeneffekt auftritt, wenn Highbyte des Words immer 0 ist, gibt's auch kein Problem durch Interruptunterbrechung.
Du verschwendest halt ein paar Bytes SRam und ein paar Zyklen.

Also Werte > 255 werden nie im Empf-Array drinstehen.
Dann kann man die ISR ein wenig kürzer halten, siehe unten.

Was genau meinst du mit temporären Variablen? So:
So:

Empf_Tmp = Empf(throttlechannel)
Sempf_Tmp = Sempf(throttlechannel)
If Empf_Tmp > 61 And Empf_Tmp < 139 Then 'don't process values that can't be correct
Sempf_Tmp = Empf_Tmp - 61
Sempf_Tmp = Sempf_Tmp * 3 '==> values ranging from 3 (stick at bottom) to 228 (full throttle)
Empf(throttlechannel) = Empf_Tmp
Sempf(throttlechannel) = Sempf_Tmp
End If
Und genauso mit nick, roll und yaw.

Du hast bemerkt, dass mein vorher geposteter Code dafür gedacht ist, im Simulator zu laufen ?
So kann ohne großartige Rumprobiererei am lebenden Objekt die ISR auf korrekte Funktion überprüft werden.

Wenn Probleme beim Vergleich Byte mit Word existieren, dann solltest Du Michaels Ratschlag zum Update nachkommen.

Hier der Bytearraycode:

Dim Empf(5) As Byte
' ...
Isr_int0: ' byte-array, cycles in range: 43, out of range: 28
!PUSH R16
!IN R16, SREG
!PUSH R16
!LDS R16, {channel}
!INC R16
!STS {channel}, R16
!SUBI R16, 2
!CPI R16, 5
!BRCC NotInRange
!PUSH XL
!PUSH XH
LoadAdr Empf(1) , X
!ADD XL, R16
!CLR R16
!ADC XH, R16
!IN R16, TCNT0
!ST X, R16
!POP XH
!POP XL
!NotInRange:
!LDI R16, 6
!OUT TCNT0, R16
!POP R16
!OUT SREG, R16
!POP R16
Return

Che Guevara
24.12.2011, 21:41
Also, ich habs gerade nochmal probiert:


Config Pind.2 = Input
Portd.2 = 0
Config Int0 = Rising
On Int0 Getreceiver Nosave
Config Timer0 = Timer , Prescale = 256
On Timer0 Detectrxpause Nosave 'timer overflow = pause in receiver's signal

Dim Empf(5) As Byte

...

Getreceiver: 'byte-array, cycles in range: 43, out of range: 28
!PUSH R16
!IN R16, SREG
!PUSH R16
!LDS R16, {channel}
!INC R16
!STS {channel}, R16
!SUBI R16, 2
!CPI R16, 5
!BRCC NotInRange
!PUSH XL
!PUSH XH
LoadAdr Empf(1) , X
!ADD XL, R16
!CLR R16
!ADC XH, R16
!IN R16, TCNT0
!ST X, R16
!POP XH
!POP XL
!NotInRange:
!LDI R16, 6
!OUT TCNT0, R16
!POP R16
!OUT SREG, R16
!POP R16
Return 'that means that there are problems with the receiver


Detectrxpause:
!PUSH R16
!IN R16, SREG
!PUSH R16
!ldi R16, 0
!sts {channel}, R16
!POP R16
!OUT SREG, R16
!POP R16
Return

Es funktioniert doch, anscheinend hatte ich damals irgendwo einen Fehler...
Habe jetzt auch den Timer0 Interrupt umgeschrieben, wäre nett, wenn du kurz drüberschauen könntest, obs so passt!? Fliegen tut das ganze :)
Meinst du, ich solle jetzt noch die Arrays mit den temporären Variablen verändern? Habs gerade mal probiert, mithilfe der Overlay Funktion würde kein zusätzlicher Speicher verbraucht.


Dim Tmp1 As Byte At Empf(1) Overlay
Dim Tmp2 As Byte At Empf(2) Overlay
Dim Tmp3 As Byte At Empf(3) Overlay
Dim Tmp4 As Byte At Empf(4) Overlay
Dim Tmp5 As Byte At Empf(5) Overlay

Außerdem würde ich mir dann die Zuweisung tmpx <--> empf(x) sparen?!
Hältst du das für sinnvoll?

Gruß
Chris

EDIT:
Hab gerade folgendes eingefügt:


Dim Tmp1 As Byte At Empf(1) Overlay
Dim Tmp2 As Byte At Empf(2) Overlay
Dim Tmp3 As Byte At Empf(3) Overlay
Dim Tmp4 As Byte At Empf(4) Overlay
Dim Tmp5 As Byte At Empf(5) Overlay
Dim Stmp1 As Integer At Sempf(1) Overlay
Dim Stmp2 As Integer At Sempf(2) Overlay
Dim Stmp3 As Integer At Sempf(3) Overlay
Dim Stmp4 As Integer At Sempf(4) Overlay
Dim Stmp5 As Integer At Sempf(5) Overlay

Der Code funktioniert. Ich werde jetzt mal im Simulator testen, ob der Code dadurch schneller läuft. Melde mich dann wieder ;)

EDIT2:
Hab gerade im Simulator folgendes probiert:


If Sempf(1) > -37 And Sempf(1) < 37 Then
!nop
End If

If Stmp1 > -37 And Stmp1 < 37 Then
!nop
End If

Beide IF-Abfragen brauchen incl. dem !Nop genau 34 Takte. Habe ich etwas anderes gemacht, als du gemeint hast oder bringts doch keine Besserung?

MagicWSmoke
24.12.2011, 22:12
Es funktioniert doch, anscheinend hatte ich damals irgendwo einen Fehler...
Schön :-)

Habe jetzt auch den Timer0 Interrupt umgeschrieben, wäre nett, wenn du kurz drüberschauen könntest, obs so passt!? Fliegen tut das ganze :)
Speziell in diesem Fall kannst Du Dir das Sichern des SREGs sparen, denn weder LDI noch STS verändert das SREG. Würdest Du statt dessen !CLR R16 schreiben, wär's etwas anderes.

Detectrxpause:
!PUSH R16
!LDI R16, 0
!STS {channel}, R16
!POP R16
Return

Habs gerade mal probiert, mithilfe der Overlay Funktion würde kein zusätzlicher Speicher verbraucht.
Hältst du das für sinnvoll?
Ich seh' jetzt nicht so recht, wie Du im gezeigten Noise-Filter Code mit Overlay arbeiten willst.

Wie sieht's den mit der Aufrufrate dieses Noise-Filter Codes aus ? Normalerweise sind solche Filter an ein Timing gebunden. Oder läuft der da so schnell er kann ?
Müsstest mal den Code extrahieren und alleine laufen lassen, um zu sehen wie viel Rechenleistung der frisst und ob es lohnt da viel Arbeit reinzustecken.

Edit:
Das hier kann der Compiler zur Compilezeit auflösen und es ist deshalb genauso schnell wie die Adressierung einer einzelnen Variable.

If Sempf(1) > -37 And Sempf(1) < 37 Then
Das kann der Compiler nicht vorher auflösen, da er den Wert von "i" nicht kennt, das kostet mehr Code und Ausführungszeit:

If Sempf(i) > -37 And Sempf(i) < 37 Then

Che Guevara
24.12.2011, 22:18
Ok, habs jetzt ohne Sichern des SREG. Danke!

Nein, beim Noise-Filter-Code verwende ich die Overlays nicht, da hier die Schleife einfach einfacher ist :D
Die Overlays werden nur im restlichen Programm verwendet, z.b. bei den darauffolgenden Zeilen:


If Tmp1 > 61 And Tmp1 < 139 Then 'don't process values that can't be correct
Stmp1 = Tmp1 - 61
Stmp1 = Stmp1 * 3 '==> values ranging from 3 (stick at bottom) to 228 (full throttle)
End If
'Now nick, roll, yaw and idle up switch

If Tmp3 > 61 And Tmp3 < 139 Then 'don't process values that can't be correct
Stmp3 = Tmp3 - 100 'convert to values ranging from -37 to +37
End If
If Tmp2 > 61 And Tmp2 < 139 Then 'don't process values that can't be correct
Stmp2 = Tmp2 - 100 'convert to values ranging from -37 to +37
End If
If Tmp4 > 61 And Tmp4 < 139 Then 'don't process values that can't be correct
Stmp4 = Tmp4 - 100 'convert to values ranging from -37 to +37
End If
If Tmp5 > 61 And Tmp5 < 139 Then 'don't process values that can't be correct
Stmp5 = Tmp5 - 100 'convert to values ranging from -37 to +37
End If

Hm, also der Code wird so schnell wie möglich aufgerufen:


Do
Acc
Gyro
Mixer
Send_mots
Led
Voltage
Failsave
Guiconnection
Loop
End

Die Mixer-Sub beinhaltet den Noise-Filter Code. Meinst du den Filter-Code? Das werde ich gleich mal machen.

Gruß
Chris

MagicWSmoke
24.12.2011, 22:48
Die Mixer-Sub beinhaltet den Noise-Filter Code. Meinst du den Filter-Code?
Ja, weil man dann sieht, wo's sich lohnt zu optimieren und wo nicht.
Mein Edit hast Du gelesen ?
Ob Du über Array(1) oder über Overlay Array(1) adressierst bleibt sich gleich. Nur Array(Variable) = Array(Variable) + andere Variable macht einen deutlichen Unterschied.

Che Guevara
24.12.2011, 23:00
Das Edit habe ich gerade eben gelesen. Das leuchtet natürlich ein.
Was meinst du mit


Nur Array(Variable) = Array(Variable) + andere Variable macht einen deutlichen Unterschied.

?
Meinst du, dass


Stmp1 = Stmp1 + Tmp1

schneller als


Sempf(1) = Sempf(1) + Tmp1

ist?

Gruß
Chris

MagicWSmoke
24.12.2011, 23:07
Meinst du, dass


Stmp1 = Stmp1 + Tmp1

schneller als


Sempf(1) = Sempf(1) + Tmp1

ist?
Nein, gleich schnell.
Das ist langsamer:

Sempf(i) = Sempf(i) + Tmp1

Che Guevara
24.12.2011, 23:13
Oh, na klar! Du hast es ja vorher schon geschrieben...

Werde jetzt mal das Programm durchforsten und mal schauen, wo noch was zu machen ist. Melde mich dann wieder.

Gruß
Chris

EDIT:
Hab jetzt mal den Noise-Filter durch den Simulator gejagt. Herausgekommen ist folgendes:


'( 1439
For I = 1 To 5
Meanrx(i) = Meanrx(i) * 3
Meanrx(i) = Meanrx(i) + Empf(i) '"lowpass filter" of the RC signal
Shift Meanrx(i) , Right , 2 ' (=divide by 4)
Aempfh(i) = Meanrx(i) + 17 'upper acceptable fluctuation
Aempfl(i) = Meanrx(i) - 17 'lower acceptable fluctuation
If Empf(i) > Aempfh(i) Or Empf(i) < Aempfl(i) Then 'compare allowed fluctuation with current rc reading
Empf(i) = Meanrx(i) 'if fluctuation was too high -> replace with averaged value
End If
Next
')

'( 635
Meanrx(1) = Meanrx(1) * 3
Meanrx(1) = Meanrx(1) + Empf(1)
Shift Meanrx(1) , Right , 2
Aempfh(1) = Meanrx(1) + 17
Aempfl(1) = Meanrx(1) - 17
If Empf(1) > Aempfh(1) Or Empf(1) < Aempfl(1) Then
Empf(1) = Meanrx(1)
End If

Meanrx(2) = Meanrx(2) * 3
Meanrx(2) = Meanrx(2) + Empf(2)
Shift Meanrx(2) , Right , 2
Aempfh(2) = Meanrx(2) + 17
Aempfl(2) = Meanrx(2) - 17
If Empf(2) > Aempfh(2) Or Empf(2) < Aempfl(2) Then
Empf(2) = Meanrx(2)
End If

Meanrx(3) = Meanrx(3) * 3
Meanrx(3) = Meanrx(3) + Empf(3)
Shift Meanrx(3) , Right , 2
Aempfh(3) = Meanrx(3) + 17
Aempfl(3) = Meanrx(3) - 17
If Empf(3) > Aempfh(3) Or Empf(3) < Aempfl(3) Then
Empf(3) = Meanrx(3)
End If

Meanrx(4) = Meanrx(4) * 3
Meanrx(4) = Meanrx(4) + Empf(4)
Shift Meanrx(4) , Right , 2
Aempfh(4) = Meanrx(4) + 17
Aempfl(4) = Meanrx(4) - 17
If Empf(4) > Aempfh(4) Or Empf(4) < Aempfl(4) Then
Empf(4) = Meanrx(4)
End If

Meanrx(5) = Meanrx(5) * 3
Meanrx(5) = Meanrx(5) + Empf(5)
Shift Meanrx(5) , Right , 2
Aempfh(5) = Meanrx(5) + 17
Aempfl(5) = Meanrx(5) - 17
If Empf(5) > Aempfh(5) Or Empf(5) < Aempfl(5) Then
Empf(5) = Meanrx(5)
End If
')

Also 635 im Vergleich zu 1439 ist doch schon etwas :)
Vielen Dank für den Tipp!

Gruß
Chris

EDIT:
Mit den Tmpx-Overlay Variablen von Empf(x) kann man ja, wenn ich jetzt keinen Mist erzähle, die ISR nochmal verkürzen?!


'in range: 33
'out of range: 34

!PUSH R16
!IN R16, SREG
!PUSH R16
!PUSH R18

!in r18, tcnt0
!lds r16, {channel}
!cpi r16, 1
!breq channel1
!cpi r16, 2
!breq channel2
!cpi r16, 3
!breq channel3
!cpi r16, 4
!breq channel4
!cpi r16, 5
!breq channel5
!rjmp outofrange
Channel1:
!sts {tmp1}, r18
!rjmp outofrange
Channel2:
!sts {tmp2}, r18
!rjmp outofrange
Channel3:
!sts {tmp3}, r18
!rjmp outofrange
Channel4:
!sts {tmp4}, r18
!rjmp outofrange
Channel5:
!sts {tmp5}, r18
Outofrange:
!inc r16
!sts {channel}, r16
!LDI R16, 6
!OUT TCNT0, R16

!POP R18
!POP R16
!OUT SREG, R16
!POP R16

Stimmt das soweit oder fällt dir etwas auf?

MagicWSmoke
25.12.2011, 00:30
Mit den Tmpx-Overlay Variablen von Empf(x) kann man ja, wenn ich jetzt keinen Mist erzähle, die ISR nochmal verkürzen?!
Das was Du machst, nennt sich Code-Unrolling, hilft Dir hier aber nicht viel.

Ich messe so, dass ich 'nen Haltepunkt auf die Gosub und dann auf dem Gosub nächsten Befehl setze, vorher die Zyklen auf 0 setze und dann beim zweiten Haltepunkt ablese, da kommt bei Deinem ungerollten Code raus:
41, 36, 38, 40, 42, 42 Takte
Bei einem out of range und 5 in range sind das Gesamt 239, mein letzter Code war 43 x 5 + 28 = 243. Viel hast Du nicht gewonnen, außer Erfahrung :D

Che Guevara
25.12.2011, 00:43
Hm, ok... Aber Erfahrung ist ja auch sehr viel Wert! :D
Und meinen Code verstehe ich wenigstens zu 100%.

Ich werde jetzt noch alle > durch >= austauschen, das bringt auch noch ein paar Takte :)
Fällt dir sonst noch ein BASCOM-typischer Taktfresser ein, den ich vermeiden könnte?

Gruß
Chris

MagicWSmoke
25.12.2011, 01:07
Ich werde jetzt noch alle > durch >= austauschen, das bringt auch noch ein paar Takte :)
Hast Du Dir das auch im Disassembler auch mal angesehen ?

Fällt dir sonst noch ein BASCOM-typischer Taktfresser ein, den ich vermeiden könnte?
Berechnungen in Schleifen, Multiplikationen, Divisionen. Wenn ich 'nen Blick auf den gesamten Code werfen würde, könnt' ich vielleicht noch etwas sehen. Aber heut nicht mehr, wird jetzt Zeit Schluss zu machen, hab' morgen Einiges zu erledigen.
In der Zwischenzeit viel Spaß beim Kürzen und vor allem nicht zuviel auf einmal ;)

Ludwig

Che Guevara
25.12.2011, 01:13
Hm nein, habe ich nicht. Aber ich weiß, dass es keinen ASM Befehl für > gibt, nur für >=. Somit sollte doch auch in Bascom ein >= kürzer sein, oder nicht? Ich werds mir mal disassembliert ansehen...

Berechnungen in Schleifen gibts keine mehr, die einzige war glaube ich der Noise-Filter. Multiplikationen gibts schon einige, die meisten mit Single Variablen. Das ist zu hoch für mich.
Divisionen sind fast alle durch die Singles vermieden, lediglich ein paar Integer / Word Divisionen gibt es. Aber es sind nicht sehr viele.

Ja, ist e schon relativ spät. Vielen Dank schonmal für all deine Bemühungen :)

Gruß
Chris

flyer_5
31.01.2012, 11:48
Hallo,

Ich klinke mich mal hier ein,da ich ein ähnliches Problem habe,und hier auf ähnliche Lösungen gestoßen bin ...
Ich will eine Art Servomischer bauen mit größtmöglicher Auflösung,und dann die Servosignale parallel wieder ausgeben. Mit 8 Mhz habe ich jetzt zum einlesen 140 Schritte und zum ausgeben 1000. Timer0 zum einlesen,Timer1 für die Ausgabe.



'================================================= =====
'System-Einstellungen
'================================================= =====
$regfile "m8def.dat"
$crystal = 8000000
$framesize = 64
$swstack = 64
$hwstack = 64
$baud = 57600

'================================================= =====
'Konfigurationen
'================================================= =====

Config Timer1 = Timer , Prescale = 8
Config Timer0 = Timer , Prescale = 64
Config Int0 = Falling

Config Portb = Output
Config Portc.0 = Output
Config Portd.4 = Output
Config Portd.5 = Output
Config Portd.6 = Output
Config Portd.7 = Output
Rc_kanal1 Alias Portd.4
Rc_kanal2 Alias Portb.6
Rc_kanal3 Alias Portb.7
Rc_kanal4 Alias Portd.5
Rc_kanal5 Alias Portd.6
Rc_kanal6 Alias Portd.7
Rc_kanal7 Alias Portb.0



Dim Servo(10) As Word
Dim Empf(10) As Byte
Dim Empf_mw(10) As Byte
Dim Meanrx(10) As Word
Dim Kanal As Byte
Dim Channel As Byte


Dim Kanal1 As Integer
Dim Kanal2 As Word
Dim Kanal3 As Word
Dim Kanal4 As Word
Dim Kanal5 As Word
Dim Kanal6 As Word
Dim Kanal7 As Word

Dim X As Word
Dim R As Word
Dim N As Byte
Dim I As Byte

'-------------------------------------------------------------------------------
Enable Interrupts
Timer1 = 63000

Enable Timer0
Enable Timer1
Enable Int0
Start Timer0
Start Timer1

On Timer1 Rc
On Timer0 Sync Nosave
On Int0 Messen Nosave
'-------------------------------------------------------------------------------

Do



For I = 1 To 5
Meanrx(i) = Meanrx(i) * 3
Meanrx(i) = Meanrx(i) + Empf(i) '"lowpass filter" of the RC signal
Shift Meanrx(i) , Right , 2 ' (=divide by 4)
Empf_mw(i) = Meanrx(i)
Next



Kanal1 = Empf_mw(1) - 100
Kanal1 = Kanal1 * 7

Servo(1) = 64000 + Kanal1
Servo(2) = 63500 + X
Servo(3) = 64500
Servo(4) = 64100


Waitms 10



If X = 1000 Then R = 1
If X = 0 Then R = 0

If R = 1 Then X = X - 5 Else X = X + 5

'(

Print Empf(1) ; " CH1"
Print Empf(2) ; " CH2"
Print Empf(3) ; " CH3"
Print Empf(4) ; " CH4"
Print Empf(5) ; " CH5"
Print Empf(6) ; " CH6"
Print " "
Waitms 100
')


Loop

End


Messen: 'Timer0 läuft bei jedem Kanal über (Preload 150)
!PUSH R16
!IN R16, SREG 'Dadurch höhere Auflösung (100+-70 Schritte -> 140)
!PUSH R16
!LDS R16, {channel}
!INC R16
!STS {channel}, R16
!SUBI R16, 2
!CPI R16, 8
!BRCC NotInRange
!PUSH XL
!PUSH XH
Loadadr Empf(1) , X
!ADD XL, R16
!CLR R16
!ADC XH, R16
!IN R16, TCNT0
!ST X, R16
!POP XH
!POP XL
!NotInRange:
!LDI R16, 0
!sts {N},r16
!LDI R16, 150
!OUT TCNT0, R16
!POP R16
!OUT SREG, R16
!POP R16
'( So sieht der asm Teil in Basccom aus
If Channel > 0 And Channel < 8 Then
Empf(channel) = Timer0
End If

Timer0 = 150
Incr Channel
N = 0
')

Return

Sync: 'Synchronimpuls Auswertung
Push r24
in r24,sreg
push r24
lds r24,{N}
inc r24
cpi r24,2 'wennkleiner 2 ist
BRLO no_sync
Channel = 0
No_sync:
sts {N},r24
pop r24
!out sreg,r24
pop r24
Return


Rc: 'Servosignalausgabe

Incr Kanal

Rc_kanal1 = 0
Rc_kanal2 = 0
Rc_kanal3 = 0
Rc_kanal4 = 0

Timer1 = Servo(kanal)

Select Case Kanal
Case 1 : Rc_kanal1 = 1
Case 2 : Rc_kanal2 = 1
Case 3 : Rc_kanal3 = 1
Case 4 : Rc_kanal4 = 1
Case 5 : Timer1 = 50000
Kanal = 0
End Select

Return


So. Und das alles funktioniert dank Inline asm fast Jitterfrei. Jetzt würde ich aber gerne die Servoausgabe auch in asm schreiben - in der Hoffnung das dann die sporadischen Zucker (alle 3-5s) weg sind.


Rc: 'Servosignalausgabe

Incr Kanal

Rc_kanal1 = 0
Rc_kanal2 = 0
Rc_kanal3 = 0
Rc_kanal4 = 0

Timer1 = Servo(kanal)

Select Case Kanal
Case 1 : Rc_kanal1 = 1
Case 2 : Rc_kanal2 = 1
Case 3 : Rc_kanal3 = 1
Case 4 : Rc_kanal4 = 1
Case 5 : Timer1 = 50000
Kanal = 0
End Select

Return


Ich habe auch schon eine Idee und würde das mit meinen begrenzten asm Kenntnissen auch irgendwie hinbekommen,nur habe ich bei der Übersetzung folgender Zeile Probleme (Word Array) und weiß nicht wie ich vorgehen soll:



Timer1 = Servo(kanal)f. programme bitte "CODE"-Tags verwenden (QUoTE ist für Zitate)PicNick Mod


Gruß

Andreas

MagicWSmoke
31.01.2012, 13:26
...,nur habe ich bei der Übersetzung folgender Zeile Probleme (Word Array) und weiß nicht wie ich vorgehen soll:

Timer1 = Servo(kanal)
Wenn Du Assembler programmierst und den Thread auch durchgelesen hast (wobei's bereits auf der ersten Seite steht), dann sollte sich die Frage gar nicht mehr stellen.

flyer_5
01.02.2012, 12:13
Hallo,

Entschuldige,ich habe den Thread zwar gelesen,aber die Cdes am Anfang nur überflogen. Mit begrenzten asm Kenntnissen meinte ich wirklich begrenzt ;) Also 2 Byte Variablen bekomm ich verglichen und ich kann auch dann entsprechend wohin springen...





!PUSH ZL
!PUSH ZH
Loadadr Servo(1) , z
!LDS R18, {Kanal}
!LDS R19, {Kanal+1}
!SBIW ZL, 1 'Kanal fängt bei 1 an
!ADD ZL, R18
!ADC ZH, R19
!LD R16, Z
!STS {Rslt},R16
!OUT TCNT1L, ZL
!OUT TCNT1H, ZH


Entspricht das ungefähr dem hier? Ich weiß leider nicht so genau in welchem Register dann was und wie reingeladen wird,und wie ich es an den Timer1 übergebe...



Timer1 = Servo(kanal)



Gruß

Andreas

PicNick
01.02.2012, 12:48
Schau,


!OUT TCNT1L, ZL ' das ist TImer1 (LSB)
!OUT TCNT1H, ZH ' das ist Timer1 (MSB)

Wenn du die ganze ISR mit assembler ersetzen willst, darfst du das Sichern und Wiederherstellen aller verwendeten Register (+ SREG) aber nicht vergessen

flyer_5
01.02.2012, 13:00
Hallo und Danke,

Das mit dem Sichern und Wiederherstellen ist klar.Also sehe ich es richtig, dass der Asm-Teil in meinem letzten Post stimmt und so auch der Wert vom Array in den Timer geladen wird?

Als Ergänzung : Servo(10) ist ein Word-Array , Kanal wird nicht größer als 10 (Byte)

Gruß

MagicWSmoke
01.02.2012, 13:09
Hallo Andreas,



!PUSH ZL
!PUSH ZH
Loadadr Servo(1) , z
!LDS R18, {Kanal}
!LDS R19, {Kanal+1}
!SBIW ZL, 1 'Kanal fängt bei 1 an
!ADD ZL, R18
!ADC ZH, R19
!LD R16, Z
!STS {Rslt},R16
!OUT TCNT1L, ZL
!OUT TCNT1H, ZH
Entspricht das ungefähr dem hier? Ich weiß leider nicht so genau in welchem Register dann was und wie reingeladen wird,und wie ich es an den Timer1 übergebe...

Timer1 = Servo(kanal)
nein, das stimmt so nicht. Du hast Servo() als Word deklariert, da muss der Index nach Abzug der 1 noch mit 2 multipliziert werden, Du willst auch nicht den Wert des angesprochenen Arrayelements in Rslt haben, sondern in Timer1. Im Moment schreibst Du die Adresse des ge-indexten Bytes in den Timer.

Außerdem kannst Du Timer1 TCNT1L/H nicht mehr mit !OUT erreichen, denn das Timerregister ist beim ATM8 an &h2C/2D, das solltest Du zumindest wissen, wobei hier Bascom eine Ersetzung durch !STS durchführen wird, ohne dass Du's merkst.

Auch ist Kanal ein Byte, als geht !LDS R19, {Kanal+1} nicht, sondern R19 wird einfach auf 0 gesetzt.

Es muss also nach dem !SBIW , 1 mal 2 multipliziert werden, das geht per Linksschieben mit !LSL für das Lowbyte und !ROL für das Highbyte. Dann stimmt die Adresse für das ge-indexte Word schon mal, von welchem dann dann erst das Lowbyte per !LD Rx, Z+ und dann das Highbyte per !LD Ry, Z gelesen wird. Dann speicherst Du Rx/y nach TCNT1L/H, wobei Du zuerst das Highbyte des TCNT1 schreiben musst und dann das Lowbyte, siehe ATM8 Datenblatt unter Accessing 16-bit Registers.

flyer_5
07.02.2012, 10:35
Danke für die kompetente Antwort,das hat mich schon etwas weiter gebracht...Ich habe leider wenig Zeit,daher erfolgt meine Antwort erst jetzt!
Wenn ich ehrlich bin war mir das mit dem Array zu komplitziert. Ich hab jetzt einfach meherere Word Variablen (K1 bis K7 + Pause als Word)



Rc:

!PUSH R16
!in R16 , Sreg
!push r24
!push r25
!PUSH R16
!LDS R16, {Kanal}
!INC R16 'Kanal um 1 erhöhen
!STS {Kanal}, R16

cbi portd,4 'Alle Ports=0
cbi portB,6
cbi portB,7
cbi portD,5
cbi portD,6
cbi portD,7
cbi portB,0



cpi r16,1
Brne K2 ' wenn ungleich 1 -> weiterspringen
Sbi portd,4 'Ansonsten-> Port einschalten ,Timer mit Kanalwert vorladen
LDS R24, {k1} 'holen Byte 1 (bits 0-7)
LDS R25, {k1+1} 'holen Byte 2 (bits 8-15)
!Out Tcnt1H , R25
!Out Tcnt1l , R24

K2:
cpi r16,2
Brne K3 ' wenn ungleich 2 -> weiterspringen
Sbi portB,6 'Ansonsten-> Port einschalten ,Timer mit Kanalwert vorladen
LDS R24, {k2} 'holen Byte 1 (bits 0-7)
LDS R25, {k2+1} 'holen Byte 2 (bits 8-15)
!Out Tcnt1H , R25
!Out Tcnt1l , R24


K3:
cpi r16,3
Brne K4
Sbi portB,7
LDS R24, {k3} 'holen Byte 1 (bits 0-7)
LDS R25, {k3+1} 'holen Byte 2 (bits 8-15)
!Out Tcnt1H , R25
!Out Tcnt1l , R24

K4:
cpi r16,4
Brne K5
Sbi portd,5
LDS R24, {k4} 'holen Byte 1 (bits 0-7)
LDS R25, {k4+1} 'holen Byte 2 (bits 8-15)
!Out Tcnt1H , R25
!Out Tcnt1l , R24

K5:
cpi r16,5
Brne K6
Sbi portd,6
LDS R24, {k5} 'holen Byte 1 (bits 0-7)
LDS R25, {k5+1} 'holen Byte 2 (bits 8-15)
!Out Tcnt1H , R25
!Out Tcnt1l , R24

K6:
cpi r16,6
Brne Pause
Sbi portb,0
LDS R24, {k6} 'holen Byte 1 (bits 0-7)
LDS R25, {k6+1} 'holen Byte 2 (bits 8-15)
!Out Tcnt1H , R25
!Out Tcnt1l , R24


Pause:
cpi r16,7
Brne Ende ' wenn ungleich 7 -> weiterspringen
LDS R24, {Pause} 'holen Byte 1 (bits 0-7)
LDS R25, {Pause+1} 'holen Byte 2 (bits 8-15)
!Out Tcnt1H , R25
!Out Tcnt1l , R24

!LDI R16, 0 'Kanal=0
!STS {Kanal}, R16

Ende:

pop r24
pop r25
pop r16
!out sreg,r16
pop r16

Return




Das ist nun meine neue Timer1 ISR. Die Ausgabe der Kanäle funktuioniert auch.Nur scheint es ein Problem zu geben ,welches mir nicht ersichtlich ist.... Sobald ich den Interrupt als Nosave definiere,läuft mein Hauptprogramm nicht mehr,wobei die letzten Servowerte weiterhin ausgegeben werden (Timer1 Int läuft also noch).

Theoretisch ist das dann doch was ganz offensichtliches? Vlt. kann mir da jemand helfen,denn ich stehe quasi fast vor dem Ziel ;)

Nur zur Info:
K1 - K7 werden mit 64000+-500 vorgeladen
Pause ist im Moment ein Fixwert : 50000


Gruß

MagicWSmoke
07.02.2012, 10:50
Wenn ich ehrlich bin war mir das mit dem Array zu komplitziert. Ich hab jetzt einfach meherere Word Variablen (K1 bis K7 + Pause als Word)
Auch ok.



Rc:

!PUSH R16
!in R16 , Sreg
!push r24
!push r25
!PUSH R16
' ...
pop r24
pop r25
pop r16
!out sreg,r16
pop r16

Theoretisch ist das dann doch was ganz offensichtliches?
Der Stack ist ein LiFo, last in - first out, also muss in der richtigen Reihenfolge, genau umgekehrt wie ge-PUSH-t wurde, auch wieder ge-POP-ed werden.

flyer_5
07.02.2012, 14:22
Funktioniert ;) Hätte nicht gedacht, dass die Reihenfolge eine Rolle spielt. Aber ich bin nur ein Bascommer auf zeitkritischen Abwegen.
@ MagicWsmoke : Nochmals Danke.Hätte den Mischer ohne deine Hilfe nicht jitterfrei bekommen...

Der komplette Code wird folgen.Wahrscheinlich in einem neuen Thread!

MagicWSmoke
07.02.2012, 19:00
Ok, gern geschehen.
Das wäre übrigens die Lösung gewesen:

Loadadr Servo(1) , Z
!LDS R18, {Kanal}
!LDI R19, 0
!DEC R18
!LSL R18
!ROL R19
!ADD ZL, R18
!ADC ZH, R19
!LD R18, Z+
!LD R19, Z
!OUT TCNT1H, R19
!OUT TCNT1L, R18