Discussion:
Immer noch Probleme mit Arrays zum erzeugen eines PWM Signals
(zu alt für eine Antwort)
Andreas Bause
2003-12-03 16:01:36 UTC
Permalink
Bin jetzt etwas weiter mit meinem Problem, hab es aber noch nicht
getestet (gehe sowieso davon aus das es so noch nicht läuft :-))
Also ich will 600 Schleifen durchlaufen. In jeder dieser Schleifen
werden 2 weitere Schleifen durchlaufen. Eine, die HIGHSCHLEIFE, soll
mir ein HIGH Signal am Parallelport bringen, die andere, die
LOWSCHLEIFE, soll ein LOW Signal bringen.

Die Hauptschleife (PIXELSCHLEIFE) wird immer 600 mal durchlaufen. Die
Anzahl der Durchläufe für die HIGH und LOWSCHLEIFE steht jeweils in
einem Array. Beim ersten Durchlauf der PIXELSCHLEIFE die HIGHSCHLEIFE
so oft durchlaufen werden wie es in dem Array HIGHSignal[1] steht, und
die LOWSCHLEIFE so oft wie es in dem Array LOWSignal[1] steht usw...
Die Array sind also beide auch genau von 1-600 und enthalten Integer
Zahlen von 1 bis max 2000.

Daraus soll später mal ein PWM Signal am Ausgang werden (hoffe ich
zumindenst). Die asm Routine soll in Delphi 6.0 laufen. Da ich mich
mit Assembler erst seit ca einer Woche beschäftige bin ich darin noch
alles andere als standfest.
Wäre schön wenn mal einer über den Code drüberschauen könnte und ein
paar Tips geben könnte oder Fehler aufzeigen.


begin
asm
PUSH EAX // die 32 bit Register
PUSH EBX // EAX bis EDX
PUSH ECX // werden auf dem
PUSH EDX // Stack gesichert
CLI // alle Interrupts werden gesperrt
MOV ECX,600 // ECX wird auf 600 geladen
MOV DX,$378 // Adresse des Parallelport in DX
@PIXELSCHLEIFE

MOV BX,byte PTR[ECX+HIGHSignal] // <--ich denke mal das hier
noch
@HIGHSCHLEIFE // ein Fehler drin steckt
MOV AL,192
OUT DX,AL
DEC BX
CMP BX,0
JNZ @HIGHSCHLEIFE

MOV BX,byte PTR[ECX+LOWSignal]
@LOWSCHLEIFE
MOV AL,64
OUT DX,AL
DEC BX
CMP BX,0
JNZ @LOWSCHLEIFE

STI // Alle Interrupts werden wieder
zugelassen
POP EDX // Alle vier
POP ECX // Register werden
POP EBX // wieder vom
POP EAX // Stack heruntergeholt
end; //end of asm
Vinzent 'Gadget' Hoefler
2003-12-03 16:36:04 UTC
Permalink
Post by Andreas Bause
Die Hauptschleife (PIXELSCHLEIFE) wird immer 600 mal durchlaufen. Die
Anzahl der Durchläufe für die HIGH und LOWSCHLEIFE steht jeweils in
einem Array. Beim ersten Durchlauf der PIXELSCHLEIFE die HIGHSCHLEIFE
so oft durchlaufen werden wie es in dem Array HIGHSignal[1] steht, und
die LOWSCHLEIFE so oft wie es in dem Array LOWSignal[1] steht usw...
Die Array sind also beide auch genau von 1-600 und enthalten Integer
Zahlen von 1 bis max 2000.
[...]
Post by Andreas Bause
Wäre schön wenn mal einer über den Code drüberschauen könnte und ein
paar Tips geben könnte oder Fehler aufzeigen.
begin
asm
PUSH EAX // die 32 bit Register
PUSH EBX // EAX bis EDX
PUSH ECX // werden auf dem
PUSH EDX // Stack gesichert
CLI // alle Interrupts werden gesperrt
^^^

Ich weiss, dass Du das willst, um ein besseres Timing zu erreichen, es
ist aber trotzdem nicht nett, zumal Du die Interrupts hier locker fuer
einige Millisekunden sperren wuerdest (wenn Windows das aus dem
Userspace heraus ueberhaupt zulaesst).
Post by Andreas Bause
MOV ECX,600 // ECX wird auf 600 geladen
MOV DX,$378 // Adresse des Parallelport in DX
@PIXELSCHLEIFE
MOV BX,byte PTR[ECX+HIGHSignal] // <--ich denke mal das hier
noch
@HIGHSCHLEIFE // ein Fehler drin steckt
Ja, richtig. Mit ECX = 600 + HIGHSignal ergibt das den Eintrag 599 des
Arrays. (Egal, was Du fuer einen Index angibst, auf Maschinenebene
beginnen "Arrays" eigentlich immer mit dem nullten Element.)

Besser waere in dem Fall wohl eher ein XOR ECX, ECX (= auf Null
setzen) und weiter unten dann nach oben zaehlen.

Ausserdem ist BX natuerlich ein 16-Bit-Register, waehrend Du einen
8-Bit-Operanden angibst,

| movzx ebx, BYTE PTR [HIGHSignal + ecx]

duerfte besser klappen und erloest Dich von den erzeugten
Operand-Size-Prefixes beim DEC...
Post by Andreas Bause
MOV AL,192
OUT DX,AL
DEC BX
...genau hier. DEC EBX.
Post by Andreas Bause
CMP BX,0
Das zusaetzliche CMP ist ohnehin unnoetig, DEC setzt bereits das
Zero-Flag.
Post by Andreas Bause
MOV BX,byte PTR[ECX+LOWSignal]
@LOWSCHLEIFE
MOV AL,64
OUT DX,AL
DEC BX
CMP BX,0
Dito.
Der Ruecksprung in @PIXELSCHLEIFE fehlt und damit auch die komplette
Schleife an sich.

Hier sollte also noch etwas wie

| INC ECX
| CMP ECX, 600
| JNE @PIXELSCHLEIFE

rein.

Warum schreibst Du die Schleifen eigentlich nicht gleich in Delphi?
Portzugriffe sind so schweinelangsam, dass dieses ganze ASM technisch
ohnehin so gut wie nichts bringt.

Insofern duerfte

|asm cli end {asm};
|
|for p := 1 to 600 do
|begin
| for i := 1 to HIGHSignal[p] do
| asm
| mov dx, 0378h
| out dx, 192
| end {asm};
|
| for i := 1 to LOWSignal[p] do
| asm
| mov dx, 0378h
| out dx, 64
| end {asm};
|end {for};
|
|asm sti end {asm};

in etwas dasselbe leisten. BTW, kennt Delphi die schoenen Port-Arrays
aus Turbo-Pascal nicht mehr? Hat das moeglicherweise den Grund, dass
direkte Hardwarezugriffe nur fuer Code zugelassen ist, der im
Kernelspace laeuft (aka. Treiber)? Abgesehen davon sehe ich da noch
ein paar grundlegende Design-Ideen. a) Windows ist kein
Realtime-System und das, was Du machst, erfordert zumindest ein
sauberes garantiertes Timing und b) Dein Code macht nicht viel mehr
als ein Busy-Wait, denn der einmal auf den Port geschriebene Wert
bleibt sowieso bis zum naechsten Schreibzugriff erhalten, das dauernde
Schreiben in der Schleife waere /eigentlich/ unnoetig, wenn Du nicht
versuchen wuerdest, damit das Timing zu kontrollieren.


Vinzent.
Vinzent 'Gadget' Hoefler
2003-12-04 07:37:58 UTC
Permalink
Post by Vinzent 'Gadget' Hoefler
Ja, richtig. Mit ECX = 600 + HIGHSignal ergibt das den Eintrag 599 des
Arrays.
Das ist natuerlich Quatsch. Verdammte Off-By-One-Fehler. 600 ist
natuerlich bereits ausserhalb des definierten Arrays, 599 waere hier
der richtige Index fuer Element 600 (wenn Zaehlung 1 .. 600).


Vinzent.

Lesen Sie weiter auf narkive:
Loading...