Bascom zu langsam, Brauche Hilfe bei Assembler

herby

Neues Mitglied
18. Feb. 2009
24
0
0
Sprachen
Hi,
mein Problem ist das der Code im Bascom zu langsam ist, und ich Hilfe bei der Umsetzung in Assembler brauche würde.

Folgendes UP möchte ich gerne so schnell wie möglich auf einem
ATMega 644P mit 20 MHz zum laufen haben:

Sub Logger
Portc.1 = 1
Msg = 0
Adr1 = 1
Adr0 = 0
Dold = 255
Portc.0 = 0
Timer1 = 0
Start timer1
Do
D = Pinb
If D <> Dold Then
Rama(adr1) = Timer1
Ramd(adr1) = D
Incr Adr1
Dold = D
End If
' evtl bei Timeroverflow noch weitere Variable Hochzählen
' und in weteren Array abspeichern
' und wenn ovflzähler maxwert erreicht (keine Veränderungen am Port)
' Flag setzen und sub beenden

Loop Until Adr1 > 1000
Stop Timer1
Timestamp = Timer1
Portc.0 = 1
Portc.1 = 0
End Sub

Leider sind meine Assemblerkenntnisse zu tief verschüttet um mich
hieran zu wagen. Vieleicht ist hier jemand so freundich und bringt mich in die Spur.

Gruß
Herbert
 
Hi
Ich bin zwar nicht fit in BASCOM und den Assembler vom 644, aber ich denke, die grobe Richtung wird passen.

Sub Logger Sub_Logger:
Portc.1 = 1
LDS Reg_x, Port_C ; Variable benutzen
ORI Reg_x, 0b00000010 ; Bit 1 setzen
ANDI Reg_x,0b11111110 ; Bit 0 löschen
STS Port_C, Reg_x ; Ich benutze immer eine Variable, dier wirkliche Ausgabe erfolgt in einem eigenen UP am Ende der Programmschleife

Msg = 0
CLR Reg_x ; Register auf 0 setzen
STS msg, Reg_x ; An Variable übergeben
STS Adr0, Reg_x ; und auch die nächste mit gleichem Wert

Adr1 = 1
LDI Reg_x, 1 ; Register mit 1 laden
STS Adr1, Reg_x ; An Variable übergeben

Adr0 = 0 ; ist oben bereits erledigt

Dold = 255
LDI Reg_x, 0xFF ; Register mit 255 laden
STS Dold, Reg_x ; An Variable übergeben

Portc.0 = 0 ; ist oben bereits erledigt
etc.
Im AVR-Studio ist eine Assembler -Hilfe für die einzelnem Mnemonics. Aber hier möchte ich mal stoppen, da mir die Vorgehensweise nicht Sinnvoll erscheint. Eine Initialisierung in einem UP, vermutlich öfters aufgerufen ?
dazu ein Loop im Unterprogramm macht jedes Programm langsam. Wie ich sehe, wartest du auf ein Ergebnis. Das ist natürlich eine Bremse für dein Hauptprogramm und wenn es auch noch abhängig von einem Timer ist, nutzt auch kein Assembler, um den Vorgang zu beschleunigen.
Daher hier mein Tipp:
Der Timer wird anfangs initialisiert und liefert dir einen Interrupt z.B. im ms-Takt. In der ISR zählst du die Takte in eine Variable.
Dein Hauptprogramm ruft in der Schleife zuerst den Input ( Einlesen eines Ports) auf und bekommt in einer Variablen die aktuellen Werte der Portbits. Da ist ein UP.
Danach bearbeitet dein Programm die Werte, überprüft Bits und beschreibt ensprechende Variablen. Zum Schluß kommen dann deine Ausgaben an Anzeige oder Portbits. Auch wieder UP's, die mit Variablenwerten gefüttert werden. So kannst du die entsprechenden UP's prüfen und dann vergessen. Sie werden ihre Arbeit immer auf übergebene Variable stützen. Dein Programm läuft ohne interne Schleifen und Verzögerung. Es ist das klassische EVA - Prinzip: Einlesen -- Verarbeiten -- Ausgeben
Gruß oldmax
 
Hallo Herbert
Meine Antwort ist ja schon ein paar Stunden her und mich wüd's einfach mal interessieren, ob ich dich auf die richtige Spur gebracht habe oder ob du dein Vorhaben in die Tonne gekloppt hast
Gruß oldmax
 
Hi Oldmax,
leider komme ich erstheute dazu mal wieder ins Forum zu schauen (Job und so)und deine Antwort zu lesen, und ich muß sagen :Ja, die Richtung passt. Danke.
Der Looop im Unterprogramm dient dazu 500 Werte ins Memory einzulesen wenn der Wert am Port sich verändert hat. Zu jeder veränderung wird der Timerwert mit abgespeichert, damit sich das Ereignis zeitlich zuordnen lässt.
(Logikanalisator, in anlehnung an einen Artikel aus der Elektor). so bekomme ich unabhängig vom schnellstem Signal auch langsame Vorgänge in den Speicher. Das UP ist nicht vom Timer abhängig, sondern liest ihn nur. In Bascom kann man aber nur Signale mit einer max. Frequenz von ca. 300 KHz erfassen. alles was schneller ist geht einfach durch die Zykluszeiten die Bascom benötigt, verloren. Deshalb mein Wunsch nach Assembler. Ich werde dein ASM einmal Umsetzen und schauen was passiert´. Anschliesen werde ich Dir Bericht erstatten und evtl Dich um weitere Unterstützung bitten.

Für heute erst einmal recht herzlichen Dank für deine Mühe.

Gruß
Herbert
Ps. Ich hatte schon gedacht das ich im falschem Forum gepostet habe, denn es kam doch erst nach einiger Zeit eine Meldung zu diesem Thema.
 
Hi Dino,
danke für deine Antwort. Aber es ist schon schwer ein vernüftiges Zeitmanagent auf die Rille zu bringen, das eine will man und das andere muß man.
Aber das mit dem UP in Assembler ist schon eine für mich vertrackte Sache.
Aber mit 60 fängt das Leben ja erst an und ich werde ASM auch noch knacken.
Wenn mein Projekt erst einmal fertig ist (Logiganalysator und Ossi umschaltbar auf einem Chip und PC als Komandozentrale mit Grafikfenster in VB Basic) ist es sicher für viele hier im Forum interessant, eine Eierlegende Wollmilchsau zum Fahradpreis zu bekommen. Wenn ich dann alles auf der Rille Habe werde ich das Projekt hier posten. Ich denke wenn ich mit dem Assembler noch auf Kriegsfuß stehe werde ich hier einfach weiter Fragen stellen:kiss3: . Denn ich habe festgestellt:
"Hier werden Sie gehelft!!!!" . Danke

Gruß Herbert
 
Hi Herbert,

Wenn mein Projekt erst einmal fertig ist (Logiganalysator und Ossi umschaltbar auf einem Chip und PC als Komandozentrale
nur mit dem SRAM im Mega ? Ob das nich ein büschn knapp ist ?

Stell dir mal vor du willst nen 400kHz I2C-Bus mitlesen ...
Da sollte man mit mindestens 800kSamples/s (besser 1,5-2MSamples/s)
die Leitungen abtasten. Dabei hast du dann zwei entscheidente Probleme.

Ich nehme mal an ... 20MHz Quarz und 1 Takt pro Befehl ...

1. Geschwindigkeit ... bei 800kS/s ... 25 Asm-Befehle pro Sample (im optimalsten
Fall). Das muß reichen für Einlesen, Speichern, Adresse hochzählen, Triggerbedingung
testen, ... :eek: :eek:

2. Speichertiefe ... wieder 800kS/s ... I2C mit Adresse und 1es Byte ...
S01234567A-01234567AP => 21 Bus-Takte => min. 42 Samples. Da
könnten aber schon Ereignisse beim samplen verloren gehen. Vor allem
weil der Sample-Takt ja nicht mit dem gesampleten Signal synchronisiert
ist und dadurch die Samplevorgänge über die Ereignisse hinweg gleiten.
Bei 2MS/s (bessere Auflösung in der Zeitachse) => ca. 105 Samples.
Spätestens wenn man etwas mehr samplen will (Kommunikation auf I2C)
wird der Speicher sehr schnell sehr eng.

Also ich würde den Speicher extern legen (32k*8) und die gesamte
Sample-Logik in Hardware gießen sonst wird wohl bei ca 500kS/s Ende
sein (fürchte ich mal) ... oder du hast da irgendeine tolle Idee gehabt.

Die Daten gleich per USB an den PC leiten wird auch ziemlich viel Zeit
verbraten die du wohl im Sample-Vorgang nicht hast.

Als Analog-Oszilloskop für Audio-Signale sehe ich da kein Problem aber
beim Logikanalysator könnte das verdammt eng werden.

Aber ich laß mich mal überraschen ;)

Gruß
Dino
 
Hi Dino,
die Idee ist folgendermasen:
Triggerbedingung abwarten,
Sample und Timer starten,
bei veränderung am Port (d <> oldd)
portstatus und Timerwert ( und wert des Timerüberlaufs) im Ram speichern
das passiert solange bis 500 samples oder der Timerüberlauf bei maxwert angekommen ist.
fertigmeldung an den PC ausgeben
diese holt die Daten dann ab und stellt sie nach Auswertung grafisch dar.
so kann man schnelle und auch langsame Ereignise mit relativ wenig Speicher erfassen.(siehe Artikel in der Elektor "CC2")
Grundgerippe läuft schon, aber wie bereits gepostet ist mit Bascom bei ca. 300 KHz das Ende der Fahnenstange errreicht. Ich denke da man mit optimiertem UP in Asm ca 1MHz erfassen kann. Mal sehen.
Gruß
Herbert
 
Hi Herbert,

die Idee ist folgendermasen:
Triggerbedingung abwarten,
Sample und Timer starten,
bei veränderung am Port (d <> oldd)
portstatus und Timerwert ( und wert des Timerüberlaufs) im Ram speichern
das passiert solange bis 500 samples oder der Timerüberlauf bei maxwert angekommen ist.
fertigmeldung an den PC ausgeben
diese holt die Daten dann ab und stellt sie nach Auswertung grafisch dar.
so kann man schnelle und auch langsame Ereignise mit relativ wenig Speicher erfassen.(siehe Artikel in der Elektor "CC2") ...
das wird aber dann folgendes ergeben ...

Die Samples fangen erst bei der Triggerbedingung an. Du hast keine Samples
von den Ereignissen, die evtl erst zu der Triggerbedingung geführt haben.
Also nix mit ...
---------#---------- oder ----------------#-- oder --#---------------
(# = Triggerbedingung)
bei dir ist das so ... #------------------
und durch eventuelle Reaktionszeiten fehlen dir Ereignisse von der Erkennung
der Triggerbedingung bis zum ersten geholten Sample. Also eigentlich eher so
#..------------------

Weißt du was ich damit meine ?

Du müßtest eigentlich dauernd samplen, den Triggerzeeitpunkt im Speicher
markieren und dann die halbe Speichertiefe weitersamplen (oder 3/4 Speichertiefe).

Grundgerippe läuft schon, aber wie bereits gepostet ist mit Bascom bei ca. 300 KHz das Ende der Fahnenstange errreicht. Ich denke da man mit optimiertem UP in Asm ca 1MHz erfassen kann. Mal sehen.
1MHz ? :rolleyes:

inc, in, store, branch ... das sind im absolut optimalsten Fall 4 Befehle

inc = 1 Zyklus
in = 1 Zyklus
store = 2 Zyklen
branch = 2 Zyklen (beim Sprung)

Also 6 Zyklen im optimalsten Fall => 20MHz = 50ns/Zyklus => 300ns/Durchhlauf

1/300ns => 3,3MSamples/s im optimalsten aller Fälle bei 20MHz Quarz,
maximal 256 Samples (8Bit-Zähler) und Sample-Bereich im RAM an einer
8Bit-Grenze. Also alles was man optimieren kann rausgeholt.

Bei 512 Samples Tiefe wird sich das erheblich verschlechtern weil man mit
Addition und Überlauf arbeiten muß usw. Also mit dem 1MS/s könnte schon
ungefähr hinkommen.

Du solltest den Anfang des Sample-Bereichs auf jeden Fall an eine 8Bit-Grenze
im SRAM setzen (also zB 0x300 oder 0x400, 0x500 ... irgend so etwas)

Bei 1MS/s würde ich guten Gewissens nur noch Signale mit 250kHz samplen.
Also 250kHz maximaler I2C-Takt (zum Beispiel). Damit man 2 Samples auf dem
high-Bereich des Signals und 2 Samples auf dem low-Bereich hat. Siehe ...

_#_#_-#-#-_#_#_-#-#-_... (#=Samplezeitpunkt)

sonst könnte es zB bei 500kHz Signalen folgendermaßen sein ...

____#_----_#_____#_----_#____ ...

Also man samplet kurz vor dem High-Bereich des Signals und dann wieder
kurz danach. Dann glaubt man, das Signal wär dauernd auf Low aber in
Wirklichkeit sind doch Änderungen vorhanden.

Alles nicht so einfach :rolleyes:

Gruß
Dino
 
Hi Dino,
Deine Auführungen sind richtig und gut.
Aber...
Ich gehe davon aus, das die Triggebedingung am Begeinn der Aufzeichnung erfüllt sein muß, denn dann beginnt doch erst der Signalabschnitt der mich interessiert.
Da ich eigentlich ständig sample, aber nur bei einer Veränderung eines der 8 Signale am Port eine Speicherung des Portzustandes mit einem Zeitstempel zusammen ausführe, muß ich nicht zwischendurch weitere Samples speichern.
Die auswertung und zeitliche zuordnung wird dann im PC erfolgen.
Ich hänge der Einfacheit halber einmal einen Screenshot an.
Kanlal 2 = 4,903Khz
Kanal 3 = 8,000Khz
Beide Signale sind nicht Synchron, somit auf einem Oszi nicht gleichzeitig darstellbar.
Wie man sehen kann, Grundgerüst steht, jetzt an die Feinheiten und mal sehen was dann am Ende machbar ist. Ich denke aber das man alles das was mit normalen Megas machbar ist auch am Logiganalysatuor dann sehen kann.
Einen schönen 2.Advent
Dir und Allen Hier im Forum.
Gruß
Herbert.
Nicht vergessen: Wenns 5. Kerzlein brennt ................:vroam:
 
Sorry, Anlage vergessen!!!:banghead:
Herbert
 

Anhänge

  • Sample 1.png
    Sample 1.png
    21,7 KB · Aufrufe: 7
Hi,
ich will doch einmal zeigen wie ich nir mit meinen stümperhaften ASM Kentnissen die Umsetzung vorstelle :
Code:
Sub Logger

  Msg = 0
  Adr1 = 1
  Adr0 = 0
  Dold = 255
  Portc.0 = 1
  Timer1 = 0
  Ti = 0
  pop r15
  Start Timer1
$asm
Lese:
in R15,portb
cp r15,dold
breq gleich
st ramd(adr1),r15
st rama(adr1),timer1
st ramo(adr1),ti
st dold,r15
Incr Adr1
cp adr1,500
brne LESE
jmp ready
Gleich:
jmp lese
Ready:
$end Asm

''''
'Do
'    D = Pinb
'      If D <> Dold Then
'          Rama(adr1) = Timer1
'          Ramd(adr1) = D
'          Ramo(adr1) = Ti

'          Incr Adr1
'          Dold = D
'      End If
'      If Ti > 2000 Then
'          Adr0 = Adr1
'          Msg = 255
'          Adr1 = 501
'     End If
'Loop Until Adr1 > 500
Stop Timer1
Timestamp = Timer1                                          'letzter Timerwert
Push r15

  Portc.0 = 0
   Put #1 , 99                                              'messung beendet
   Portc.1 = 0
End Sub

Ich weiß das es so sicherlich nicht geht, aber ich denke das micr doch jemand auf die Sprünge helfen kann. (Bascomvariablen nach assembler ?)

Gruß
Herbert
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)