PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Assembler in BASCOM verwenden



robodriver
24.08.2008, 13:57
Hallo Leute,

ich arbeite zur Zeit an einem Programm, wo es eine sehr Zeitkritische Operation zu bewerkstelligen gibt.
Mein Problem ist, das BASCOM für folgenden Code:


Daten(1).bitcount = PORTD.2

über 50 Cyclen braucht. So viel Zeit habe ich aber nicht zum Speichern des Pinzustandes. Desshalb wollte ich diesen Teil selbst in Assembler schreiben.
Nun gut, das ganze funktioniert ja Dank $asm sehr gut.
Die Variablenübergabe von bitcount ins ASM geht dank {bitcount} auch sehr gut.
Aber beim Array bleib ich hängen.

Wie kann man ein Array an einen ASM-Code übergeben?
wenn ich {daten(1)} schreibe, kommt die Fehlermeldung "No more Space for BIT"
Also wie kann ich das übergeben? vorallem: Die 1 muss dann später auch noch variabel sein.

Hoffe mir kann jemand weiter helfen.

Vielen Dank schonmal.

Gruß Robodriver

for_ro
24.08.2008, 14:08
Das Problem mit den 50 Cyclen tritt nur dann auf, wenn du über eine Variable (bitcount) ein einzelnes Bit ansprichst. Das gleiche hatte ich auch festgestellt und daher meinen Code so umgestellt, dass ich mit festen Werten arbeite. Bei dir würde das also heißen, dass du z.B. Daten(1).1 = PortD.2 setzen musst.
Schau mal, ob du das ändern kannst, dann brauchst du nicht auf Asm zu gehen.

Gruß

Rolf

robodriver
24.08.2008, 14:18
Naja, das bringt mir nicht viel.
Denn diese ganze Routine liegt in einem Interrupt und schaut komplett so aus:


Daten(1).bitcount = Sda_line
Bitcount = Bitcount + 1
If Bitcount = 8 Then
Ready = 1
Cli 'Globale Interrupts deaktivieren
End If
Return


Sprich, bei jeden Interrupt wir der Pin zustand in ein anders Bit im Byte geschrieben.
Ist quasi ein Byte was seriell eingelesen wird. Und der Interrupt wird immer ausgelöst wenn der Takt eine Positive Flank aufweist.

PicNick
24.08.2008, 15:16
Du hast da mehrere Möglichkeiten, eine davon

Du kannst beliebige (SRAM) Adressen in Pointer-Register laden, z.B.
Loadadr Arr(4) , X
Dann muß Bascom das mit dem Index erledigen, du brauchst dann nur
LD register, X oder
ST X, register
zu machen

Ich persönlich würde aber die ganze ISR-Routine in assembler machen, wenn schon die Zeit knapp ist.

Noch'n Tip:
du kannst dir "ready=1" sparen, weil BitCount ist ja nur ein Byte, das kannst du im Hauptprogramm auch auf BitCount = 8 abfragen, das ist dieselbe arbeit

robodriver
24.08.2008, 15:54
Hi,
danke für deine Antwort.

Naja, das ist jetzt momentan nur ein Test. Das ready könnt ich momentan schon so abfangen. Aber wenn das Byte voll ist, wird der Counter wieder auf 0 gesetzt und schon weiß ich nicht mehr dass das Byte fertig ist ;)
Kommt halt später noch mehr drum herum.

Die komplette ISR in Assembler zu schreiben würd ich ja gern.
Aber in der ISR muss dieses Array gefüllt werden.
Und das Array wird später in der Hauptschleife weiter verarbeitet.

Aber danke für deinen Tipp mit dem Loadadr

PicNick
24.08.2008, 17:07
Ich vermute mal, dass die ein Bytearray bitseriell befüllen willst, mit dem Takt über einen Interrupt.
Das hiesse aber, daß weder der Index noch bitcount irgendwelche beliebigen Werte einnehmen, sondern immer der Reihe nach, d.h. Bit 0-7, schalten auf nächstes Byte und wieder 0-7.

Da ist es effizienter, die Bits nicht einzeln zu setzen, sondern mit shift reinzuschieben
Und nicht mit Array-Index, sondern mit einen Pointer, der nach 8 Bit immer inkrementiert wird

Dazu brauchst du
eine Word-Variable für den pointer und
einen Byte-Zähler für die Bits

die setzt du zu Beginn auf die Anfangsadresse des Array und auf Null
z.B.


DIM array (nn) AS BYTE
DIM pointer AS WORD
DIM Bits AS Byte

Bits = 0
pointer = VARPTR(array(1))


In der ISR:
LOADADR pointer, Z
LDD XL , Z + 0 (low pointer
LDD XH , Z + 1 (hig pointer

LD R24, X aktuelles array-byte
CLC clear carry
SBIC portx , inp-pin ' Input -pin = 0/1 ?
SEC set carry
ROL r24 bit reinschieben
ST X, R24 aktuelles byte speichern
LDD R24, Z + 3 (Bitcounter)
INC R24 bitcounter+1
ANDI R24 , 7 es gilt nur 0-7
BRNZ _next_bit
_next_byte:
ADIW X, 1 pointer+1
STD Z + 0, XL neuen low pointer speichern
STD Z + 1, XH neuen hig pointer speichern
_next_bit:
STD Z + 3, r24 (Bitcounter speichern
-- ISR fertig

Es zahlt sich auch aus, die ISR mit "nosave" zu definieren und nur die Register (und den Status) zu pushen, die du tatsächlich brauchst. Bascom pusht sonst alles von rechts bis links


Was da fehlt, ist die Endebedingung, also ein Signal, wenn es genug ist.
Ich weiss nicht, was du da brauchst

Wenn irgendwas unklar ist, frag nur.

(das ganze mit vorbehalt von Schreibfehlern und anderen Schweinereien)

-tomas-
25.08.2008, 23:49
Hallo PicNick,

ich habe Deinen sehr interessanten Code mal in den Bascom Simulator eingepasst:

$regfile = "m8def.dat"
$framesize = 32 'Stack
$swstack = 32
$hwstack = 64

Dim Array(5) As Byte
Dim Dummy(4) As Byte
Dim Pointer As Word At Dummy(1) Overlay
Dim Bits_ As Byte At Dummy(4) Overlay

Dim I As Byte , J As Byte

Bits_ = 0
Pointer = Varptr(array(1))

For I = 1 To 40
Gosub Shifter 'hier mit Breakpoint PinB.0 auf 0/1 umschalten
For J = 5 To 1 Step -1
Print Bin(array(j));
Next
Print
Next
End

Shifter:
Loadadr Pointer , Z
LDD XL , Z + 0 'low pointer
LDD XH , Z + 1 'hig pointer

LD R24, X ' aktuelles array-byte
CLC ' clear carry
SBIC PINB, 0 ' inp-pin Input -pin = 0/1 ?
SEC ' set carry
ROL r24 ' bit reinschieben
ST X, R24 'aktuelles byte speichern
LDD R24, Z + 3 ' (Bitcounter)
INC R24 ' bitcounter+1
ANDI R24 , 7 ' es gilt nur 0-7
Brne _next_bit
'_next_byte:
ADIW XL, 1 'pointer+1
STD Z + 0, XL ' neuen low pointer speichern
STD Z + 1, XH 'neuen hig pointer speichern
_next_bit:
STD Z + 3, r24 'Bitcounter in Bits_ speichern
Return

Der Code shiftet nicht über die Bytegrenzen hinweg. Einfach mal im Simulator durch Umschaltung des grünen Kreies für PinB.0 mit 10111.. durchspielen.
Ich denke, beim Kopieren ist der Sprung zu _next_byte untergegangen.

Gruß
Tomas

thewulf00
26.08.2008, 12:00
Ober eben einfach das Carry-Flag mit dem Bitwert setzen und dann mit ROL reinshiften. In ASM wären das 3 Befehle mit 3 oder 4 Takten. Ungefähr so:

sec ;Carry-Flag setzen
sbis Sda_line ;Sda_line ersetzen
clc ;Carry-Flag bei Bedarf löschen
rol REG ;REG ersetzen

So wird einfach das Bit von rechts reingeschoben.

PicNick
26.08.2008, 13:05
..Der Code shiftet nicht über die Bytegrenzen hinweg.
Bestreite ich glatt.


Ober eben ..
Wieso oder ? Was steht denn bei mir drin ?

thewulf00
26.08.2008, 13:09
[...] sondern mit shift reinzuschieben [...]

Hatte das so verstanden, dass Du das 1. Bit setzen willst und dann Schiften willst. Ich schifte nicht, ich rolle, und damit nutzt er das Carryflag. War ja auch nur ne Idee. Hab ich mal gemacht und hat echt super geklappt. Man muss nur aufpassen, dass durch das Rollen das Carryflag wieder verändert wird. (Es wird zu dem Wert des "rausgerollten" Bits)

Edit: Ich muss dazu sagen, dass ich den Code nicht angeschaut hatte, weil ich mir dachte, ich verstehe den BASCOM-Code eh nicht.

Alles klar, ich gebe zu, eine Idee wiederholt zu haben, die von Dir stammt. ](*,)

PicNick
26.08.2008, 13:20
.. von Dir..
keine Panik, von mir is das auch nicht. Das wurde schon auf Tontafeln im Mesopotamien gefunden. :-)

thewulf00
26.08.2008, 13:23
Das wurde schon auf Tontafeln im Mesopotamien gefunden.

Tatsächlich? War das aus der Zeit, als der Vorsitzende von Infineon noch Tutanchamun war? Wobei mich dann interessiert: Was Tut Elch-Amun, was Nophre nie täte?

PicNick
26.08.2008, 13:29
..Was Tut Elch-Amun, was Nophre nie täte?
Im Stehen pinkeln ?

-tomas-
26.08.2008, 18:56
@PicNick
zurück zum Thema: Du wolltest ein Bytearray bitseriell befüllen

..Der Code shiftet nicht über die Bytegrenzen hinweg.
Bestreite ich glatt.
Ich habe doch extra den den Code für den Simulator angepasst, damit Du es mit copy&paste ohne Mühe prüfen kannst:
Der Code shiftet nicht über die Bytegrenzen hinweg, d.h. das erste Byte wird geshiftet und ist dann gesperrt, danach wird in das 2. Byte geshiftet usw.

PicNick
27.08.2008, 06:57
Ahso, jetzt weiss ich erst, was du meinst.
Nein, das tut er nicht, denn das wäre ein Fehler
Die Bits kommen 2^^7 first ,
die Bytes lowest first

-tomas-
27.08.2008, 09:39
In dem Codefragment fehlt die Schleife mit Sprung zum vorhandenen Label _next_byte.
Ist wohl beim Ausschneiden draufgegangen.

Wie gesagt, meinen angepassten Code einfach in den Simulator kopieren...

PicNick
27.08.2008, 10:01
....fehlt die Schleife...
Was für eine Schleife, beim Zeus ? Dieser Code wir je Bit/interrupt einmal durchlaufen

Jetzt lassen wir's aber.

-tomas-
27.08.2008, 12:19
Du wolltest ein Bytearray bitseriell befüllen:

Ich dachte dabei an LSL (logical shift left)
76543210 <-- 76543210 <-- 076543210 <-- Input

Du befüllst jedes einzelne Byte im Array mit ROL.

Nach 8*n Takten ist das Array[n] bei beiden Methoden gleich voll.

...ich wollt nicht nerven...