Ich muss auf einem Microcontroller eine ganze Menge ASCI-Hex Daten nach
Binär wandeln.
Leider dauert das alles noch zu lange. Mit Libary-Funktionen dauert es
ewig.
Ich habe nun Zeichen für Zeichen genommen, geguckt ob es zwischen 0-9
oder A-F liegt, entsprechend abgezogen und das High-Nibble um 4
geschoben. Das geht schon viel schneller, ist aber immer noch zu
langsam.
Kennt jemand eine tolle und extrem schnelle Methode (C-Code)? Mir fällt
nicht mehr viel ein, auch in ASM würde ich es nicht anders machen als
das, was der Compiler aus meinem C-Code macht.
Thx,
Regatti
Arithmetik und Fallunterscheidung je nach ASCII-Wert gar nicht mehr
machen. Große Tabelle für ASCII-Werte von 0x00 bis 'f' resp. 'F' anlegen
(Platz sollte nicht das Problem sein), und ASCII-Wert direkt als Offset
für die Tabelle benutzen. Nicht benutzte Tabellenwerte interessieren
dann nicht.
Tabelle doppelt anlegen für High- und Low-Nibble, dann musst Du nur noch
die beiden Nibbles addieren.
Wo kommen die Daten her, wo gehen sie hin, was für ein MC ?
Ich kann mir nicht vorstellen, daß das Wandeln gegenüber den weiteren
Tasks merkbar viel Zeit beansprucht. Es sind ja nur wenige Vergleiche,
Additionen.
Ob die Tabellenmethode wirklich ein klein wenig schneller ist, hängt vom
MC ab, erheblich aufwendiger ist sie auf jeden Fall.
Peter
Aufwändiger ist eine Tabellenmethode nicht, aber schneller. Wenn man
"dünn besiedelte" Tabellen zulässt, spart man jede
Indizierungsarithmetik... schneller geht es dann nicht mehr.
Matthias L. wrote:
> Wenn ich richtig gezählt habe, sind das 25Befehle, bei 2Takten je Befehl> und 16MHz sollten das etwa ~3,1µsek...
Das ist aber reichlich viel Holz
und dieser Befehl dauert drei Takte, statt zwei wie ein RAM-Zugriff.
Das würde bedeuten, der aus den ~3,1µsek werden dann vielleicht
2,9µsek..
Ich glaube nicht, dass es das bringt..
Hilft das eventuell?
Hier gibt es jedoch eine Einschränkung, A-F müssen als Großbuchstaben
vorhanden sein. Wenn sie als Kleinbuchstaben vorhanden sind, ist
entweder zusätzlich ein bit zu löschen oder "subi register, 0x61-0x3a"
zuverwenden
; zu wandelnder Wert '4F'
anfang:
ldi r16,'4' ;r16 enthält 0x34
ldi r17,'F' ;r17 enthält 0x46
call beginn_ascii_nach_binaer
nop
rjmp anfang
beginn_ascii_nach_binaer:
sbrs r16,5
subi r16,0x41-0x3a
subi r16,0x30
swap r16
sbrs r17,5
subi r17,0x41-0x3a
subi r17,0x30
add r16,r17 ;Ergebnis in r16
ret
Im ungünstigsten Fall sind 8 Befehle abzuarbeiten im günstigsten Fall
nur 6
;Ende
MfG
wb1
Die Vorschläge sind ja alle ganz nett, aber vielleicht sollte man den
Hintergrund des Problems erstmal beleuchten.
Wieviele Daten sollen in welcher Zeit gewandelt werden? Wo kommen die
her? Etc.
Dann kann man sicher noch ganz andere Lösungen in Betracht ziehen.
Think global, act local.
MFG
Falk
= 20 Befehle
Das Problem mit der Tabelle ist, dass die Indizierung selbst auch
einige Befehle braucht. Die Berechnungsmethode ist da schneller.
PS: Ich geh von der Annahme aus, dass nur Grossbuchstaben vorkommen
Karl heinz Buchegger wrote:
> Runter auf 13
Bei so trivialen Aufgaben ist es wirklich besser ohne Tabelle. Hätte ich
nicht gedacht.
Hier mal eine (fast) vollständig auf Tabelle basierende Lösung:
PS: Man könnte die Tabelle mit 48 Nullen in x und y Richtung am Anfang
erstellen, dann könnte man sich die Subtraktion mit '0' sparen. Dann
wird die Tabelle aber 5kb groß :D
Simon Küppers wrote:
> Karl heinz Buchegger wrote:>> Runter auf 13>> Bei so trivialen Aufgaben ist es wirklich besser ohne Tabelle. Hätte ich> nicht gedacht.
Die Assembler Lösung von weiter oben hängt uns immer noch kräftig
ab. Das wurmt :-)
holger wrote:
> Man ignoriert mich hier scheinbar :(
Du hast nur keinen Beweis für die Länge des Assemblercodes geliefert.
Ich denke darum ging's ja hier
gibt die beste Lösung. Nicht ganz so kurz wie das Original,
aber dafür werden die gcc Konventionen eingehalten :-)
Interessant finde ich, dass der Compiler die Subtraktion von '0'
vom Byte 1 rausoptimiert, da der andi etwas weiter unten das
überflüssig macht.
Nochmal in 'schöner' C-Form
>Oops. Du hast recht.
Danke !
Und wenn man jetzt bedenkt das er für die Parameterübergabe
in zwei Bytes in einer übergeordneten Funktion schieben muss
könnte das Ergebnis auch noch anders aussehen.
holger wrote:
>> Und wenn man jetzt bedenkt das er für die Parameterübergabe> in zwei Bytes in einer übergeordneten Funktion schieben muss> könnte das Ergebnis auch noch anders aussehen.
Ja klar.
Kommt allerdings darauf an, wo die Zeichen herkommen.
Ich sehe da im meiner Glaskugel:
Er liest ein Hexfile von ner Speicherkarte, wandelt in Bytes und brennt
damit den Flash.
Das Brennen dürfte mit Abstand die meiste Zeit verbraten. Es ist also
völlig unsinnig um ein paar popelige Zyklen beim Byte wandeln zu
feilschen.
Peter
@Peter
Deine Glaskugel hat recht.
Aber mit deiner Einschätzung liegst du falsch. Das flashen geht im
moment wesentlich schneller als das Wandeln (Faktor 4).
Es war schon spät, und ich brauchte das G....
Ich sollte mir wieder angewöhnen, Programme zumindest einmal
durchlaufen zu lassen, egal wie einfach sie sind :-)
Die von Matthias vorgeschlagene Schiebeoperation kann man sich auf
Kosten einer zweiten Tabelle übrigens sparen:
1
uint8_tascii2hex(uint8_t*data)
2
{
3
staticuint8_tHex0x[]=
4
{0,1,2,3,4,5,6,7,8,9,
5
0,0,0,0,0,0,0,
6
0x0A,0x0B,0x0C,0x0D,0x0E,0x0F
7
};
8
staticuint8_tHexx0[]=
9
{0,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,
10
0,0,0,0,0,0,0,
11
0xA0,0xB0,0xC0,0xD0,0xE0,0xF0
12
};
13
14
uint8_tResult;
15
16
Result=Hexx0[*data-'0'];
17
Result|=Hex0x[*(data+1)-'0'];
18
19
returnResult;
20
}
... manche Prozessoren sind beim Schieben langsam. Wenn aber ein
Swap-Befehl existiert (der beide Nibbles vertauscht), dann ist der
Aufwand natürlich geringer, sofern der Optimizer des Compilers den auch
nutzt.
Interessant ist allerdings, wozu der OP die hier geforderte
Funktionalität überhaupt braucht.
Rufus t. Firefly wrote:
>> Interessant ist allerdings, wozu der OP die hier geforderte> Funktionalität überhaupt braucht.
Hast du das mal im Listfile begutachtet? Würde mich interessieren
wieviele Takte da drauf gehen.
@ Regatti (Gast)
>Aber mit deiner Einschätzung liegst du falsch. Das flashen geht im>moment wesentlich schneller als das Wandeln (Faktor 4).
Sicher? Richtig gemessen? Bei einer Page Size von 512 Byte und einer
Brenndauer von 10ms sind das ~20us pro Byte. Macht bei 16 MHz 320 Takte.
huh, wenn DAS nicht reicht?
MFg
Falk
Eigentlich gelesen, was ich zu Anfang schrieb?
Große, dünn besiedelte Tabelle verwenden, die das ganze verwendete
ASCII-Alphabet abdeckt - Platzbedarf dürfte hier interessieren. Tabelle
für Low- und High-Nibble anlegen. Von 0x0 bis klein 'f' sind das 103
Werte, mal zwei = 206 Bytes, keine 5kB! Weil in der Tabelle Groß- und
Kleinbuchstaben drin sind, braucht es keine Fallunterscheidung. Nicht
benutzte Tabelleneinträge setzt man zu 0.
Dann DIREKT indizieren, ohne jede Arithmetik... das schlägt alles an
Geschwindigkeit.
1
tab1 [103] = {Initialisierung für Lownibble};
2
tab2 [103] = {Initialisierung für Highnibble); /* Wert wie für tab1 aber * 16 */
Tcf Kat wrote:
> Dann DIREKT indizieren, ohne jede Arithmetik... das schlägt alles an> Geschwindigkeit.>
1
> tab1 [103] = {Initialisierung für Lownibble};
2
> tab2 [103] = {Initialisierung für Highnibble); /* Wert wie für tab1 aber
3
> * 16 */
4
>
5
> val = tab1[low_nibble] + tab2[high_nibble];
6
>
>> Geht es noch schneller?
Hast du das ausprobiert, durch den Compiler gejagt und das List-
File studiert? Du wirst dich wundern.
Array-Indizierung kriegst du nicht gratis.
Auf einem AVR heist das:
Z Pointer mit der Startadresse laden 2 Befehle
Index dazuaddieren 2 Befehle
Byte holen 1 Befehl
macht für einen Array Zugriff 5 Befehle. Das ganze dann ein
2-tes mal für den 2. Zugriff, macht 10 Befehle. Noch ein bischen
drumherum für die Addition, Registerkonventionen für den
Funktionsaufruf und du bist ganz schnell bei 13 oder 14.
Die beste Lösung die es bisher gibt, liegt aber bei 10 und
die beruht nicht auf Array Indizierung.
Dazu dann noch der Speicherplatz für die Tabelle. Auch wenn
das nur 206 Bytes sind, so ist das zb. für einen Mega8 schon
reichlich viel.
Tcf Kat wrote:
> Von 0x0 bis klein 'f' sind das 103> Werte, mal zwei = 206 Bytes, keine 5kB!
Richtig, aber diese Methode ist verschieden von meiner oben genannten.
Da sind es 5kB. Dafür fällt aber eine Addition flach (Ok, es kommen ein
paar Befehle für die 2D-Array Indizierung hinzu)
> Die beste Lösung die es bisher gibt, liegt aber bei 10 und> die beruht nicht auf Array Indizierung.
Immernoch erstaunlich, wo doch meistens Tabellen benutzt werden um
Berechnungen im Voraus zu machen und nicht während der Laufzeit.
Hier aber eben wirkt es sich gegenteilig aus.
> Immernoch erstaunlich, wo doch meistens Tabellen benutzt werden um> Berechnungen im Voraus zu machen und nicht während der Laufzeit.> Hier aber eben wirkt es sich gegenteilig aus.
Yep.
Liegt daran, dass ein Nibble mit 3 Befehlen abgehandelt
werden kann. Da kommt eine Array-Indizierung einfach nicht
mit.
Wobei ich der Fairness halber auch sagen muss, dass ich
zunächst auch auf die Array-Lösung geschworen hätte, bis
mir dann der Assembler Code weiter oben das Stichwort geliefert
hat.
@kbuchegg; Nein, ich gebe zu, ich habe das nicht ausprobiert, und ich
kenne die Adressierungsmodi der AVR nicht. Hätte aber gedacht, dass die
Indizierung effizienter ist... Regatti hat aber immer noch nicht gesagt,
um welchen µC es sich handelt. Anstatt also von AVR auszugehen, sollte
man sich die Möglichkeiten der verwendeten Kiste angucken.
Den Funktionsaufruf würde ich mir sparen, sondern das direkt in den Code
schreiben.
@simon: Die Idee ist ja richtig, durch das zweidimensionale Array wird
das aber aufgebläht; und die Indexierung wird aufwändiger. Ist hier
nicht nötig, da die beiden Nibble getrennt betrachtet werden können.
Tcf Kat wrote:
> Den Funktionsaufruf würde ich mir sparen, sondern das direkt in den Code> schreiben.
Genau das würde ich wieder nicht tun :-)
Compiler beherrschen schon seit langer Zeit das Funktions-inlining.
Hier nochmal was in Assembler.
Der Tabellenzeiger wird aus dem umzurechnenden Wert und dem Highteil der
Tabelle gebildet.
Die eigentliche Umrechnung sind noch vier Befehle.
Es geht auch mit drei Befehlen, wenn man je eine Tabelle für den high
und lowteil benutzt. (zb ldi yh, high(highnibbletabelle), ldi xh,
high(lownibbletabelle, wobei highnibbletabelle auf zb 0x330 liegt). Der
swap-Befehl kann dann entfallen.
Schneller kann es dann nur noch gehen, wenn man Prozessoren benutzt, die
einen gezeigerten Wert direckt zu einem Registerwert addieren können,
ich glaube der Z80 konnte sowas.
tabelle1:
ldi xh,high(tabelle)
mov yh,xh
tabelle1a:
ldi xl,'4'
ldi yl,'F'
call beginn
rjmp tabelle1a
beginn:
ld r16,x
ld r17,y
swap r16
add r16,r17
ret
.dseg
.org 0x230
tabelle:
.db 0,1,2,3,4,5,6,7,8,9
.org 0x241
.db 10,11,12,13,14,15
.org 0x261
.db 10,11,12,14,14,15
MfG
wb1
Tcf Kat wrote:
> @wb1: Wenn ich das richtig sehe, ist das nach meinem Vorschlag von> 16:00?> Fehlt da aber nicht ein *16 für das highnibble?
Nein. Das erledigt der swap
Allerdings hat der Code natürlich ein paar Annahmen, die man
in C so nicht treffen kann :-)
* die Indexregister x und y werden vorgeladen und verändern
ihren Wert während der Wandlung mehrere Werte nicht
* die Tabelle ist sorgfältig so in den Speicher positioniert
worden, dass kein Offset berechnet werden muss
In Assembler kann man das natürlich machen, aber in C ist
das so afaik nicht möglich :-)
@tcf Ja
Die multiplikation mit 16 ist in dem Fall das gleiche wie swap
Im Highnibble des umzurechnenden ascii-codes (hier 4F) steht ja hex34
im lownibble steht hex46.
Aus der Tabelle auf Platz hightabelle (hex02) lowtabelle (hex34), also
hex0234 wird 4 gelesen.
Also im Register r16 0b00000100, swap des Registers = 0b01000000.
Dann braucht man nur den lownibbleteil den man aus der tabelle liest zu
addieren.
Wenn du eine zweite Tabelle aufmachst, z.B ab 0x300 und legst das
Ergebnis dort bereits mit 16 multipliziert ab, brauchst du kein swap
mehr und der Programmschnipsel verkürzt sich um einen weiteren Befehl.
Also an der Tabellenstelle 0x334 würde dann der Wert 0b01000000
hinterlegt sein.
MfG
wb1
Karl heinz Buchegger wrote:
> Nein. Das erledigt der swappatsch Ja, wie dumm von mir... :(
> Allerdings hat der Code natürlich ein paar Annahmen, die man> in C so nicht treffen kann :-)> * die Indexregister x und y werden vorgeladen und verändern> ihren Wert während der Wandlung mehrere Werte nicht> * die Tabelle ist sorgfältig so in den Speicher positioniert> worden, dass kein Offset berechnet werden muss>> In Assembler kann man das natürlich machen, aber in C ist> das so afaik nicht möglich :-)
Egal, das erscheint mir die kürzeste Lösung... wie ich sagte, dünn
besetzte Tabelle, und damit keine Fallunterscheidung und/oder
Indizierungsarithmetik... ;)))
Richtigen schnellen Code muss man also immer noch von Hand
programmieren, allen tollen Compiler-Optimierungen zum Trotze... grins
Edit @ wb1: Ok, alles klar!
Ich weiß nicht was du mit offset meinst.
Wenn du damit meinst, das die tabelle bei C in jedem Bereich liegen kann
und bei assembler nicht, ist das nicht richtig.
Es wird nur eine Startadresse benötigt. Das ich das hier auf eine
geraden Wert positioniert habe, ist meiner Faulheit zu verdanken und
natürlich dem bestreben nach kompaktem code.
Angenommen ich lege die Startadresse der Tabelle auf hex123
Dann ändert sich der code folgendermaßen:
ldi yh,high(0x123)
mov xh,yh
neuwert_holen:
ldi xl,'4'
ldi yl, 'F'
addiw x,low(0x123)
addiw y,low(0x123)
call beginn
rjmp neuwert_holen
An der eigentlichen Rechenroutine ändert sich nichts.
MfG
wb1
W. Bl wrote:
> ldi yh,high(0x123)> mov xh,yh> neuwert_holen:> ldi xl,'4'> ldi yl, 'F'> addiw x,low(0x123)> addiw y,low(0x123)> call beginn> rjmp neuwert_holen>> An der eigentlichen Rechenroutine ändert sich nichts.
ok. du benutzt einen addiw
Aber: jetzt ändere das ganze mal so ab, dass du auch 2 Umwandlungen
hintereinander machen kannst. 2 register enthalten die Character
die Aufrufe sollen also so aussehen
ldi r16, '4'
ldi r17, 'F'
call ToHex
....
ldi r16, '3'
ldi r17, '2'
call ToHex
....
Wie muss jetzt ToHex aussehen.
Denk aber daran, zwischen den Aufrufen könnte sich X und Y
verändern :-)
Wenn ich das jetzt richtig überschlagen habe, dann kommst du
mit 7 Befehlen durch. Nicht schlecht, aber der adiw benötigt
ja 2 Taktzyklen, damit sind wir bei 9 : 10
Karl heinz Buchegger wrote:
> Wenn ich das jetzt richtig überschlagen habe, dann kommst du> mit 7 Befehlen durch. Nicht schlecht, aber der adiw benötigt> ja 2 Taktzyklen, damit sind wir bei 9 : 10
Ich glaube ich hab mich verzählt. Das müssten 8 Befehle
sein. Mit den 2 zusätzlichen Takten für die beiden adiw
steht es wieder 10:10, wobei du noch zusätzlich Speicher
für eine Tabelle verbrauchst.
Wenn man davon ausgehen kann, dass die Register X und Y
unangetastet bleiben, dann gewinnst du 8:10. Nur ist
diese Annahme in einem C-Programm eine schlechte Annahme :-)
W. Bl wrote:
> Angenommen ich lege die Startadresse der Tabelle auf hex123> Dann ändert sich der code folgendermaßen:>> ldi yh,high(0x123)> mov xh,yh> neuwert_holen:> ldi xl,'4'> ldi yl, 'F'> addiw x,low(0x123)> addiw y,low(0x123)> call beginn> rjmp neuwert_holen>> An der eigentlichen Rechenroutine ändert sich nichts.
Da fällt mir gerade auf:
Da sollte sich aber was ändern. Leg die Startadresse der Tabelle
mal auf 0x01FF
(du kriegst dann einen Überlauf inach xh, was sich beim
nächsten Durchlauf als fatal erweisen wird)
Irgendwo müssen die Daten ja herkommen, eventuell als stream von einer
UART, oder sie stehen im speicher.
Wie auch immer, wir betrachteten bisher nicht die Datenquelle.
Ich mach es mir jetzt einfach:
Die register xl und yl kommen mit dem geladenen, umzuwandelden Wert
angeschwirrt und der Rückgabewert ist in r16.
yh und xh sind vorgeladen
Das ganze wird als subroutine ausgeführt.
Mit dem Überlauf des highteils hast du recht, ich muß im ungünstigem
fall noch ein register verwenden oder den stack bemühen. Hab ich mal in
Klammern beim ersten aufruf eingefügt.
Eventuell bekommst du es in C auch hin, wenn du vereinfachende
Festlegungen triffst, oder geht das nicht?
Noch was, ich kann C nur ansatzweise, es war mir immer suspekt weil ich
nicht genau wußte was da passiert. Ich find Assembler einfach besser,
bilde mir ein, dadurch die volle Kontrolle zu haben. Allerdings muß ich
zugeben bekommt man dabei leicht Kopfschmerzen und graue Haare. Aber was
solls
ldi xh,high(0x123)
mov yh, yh
ldi xl, '4'
ldi yl, 'F'
(push xh)
call ToHex
(pop yh
mov xh,yh)
....
ldi xl, '3'
ldi yl, '2'
(hier mit register
ld r18,xh)
call ToHex
(ld xh,r18
ld yh,r18)
....
ToHex:
addiw x,low(0x123)
addiw y,low(0x123)
ld r16,x
ld r17,y
swap r16
add r16,r17
ret
W. Bl wrote:
> Mit dem Überlauf des highteils hast du recht, ich muß im ungünstigem> fall noch ein register verwenden oder den stack bemühen. Hab ich mal in> Klammern beim ersten aufruf eingefügt.
Oder du lässt die Annahme der vorgeladenen xh, yh auf. Ist in Summe
schneller als push/pop
Aber:
> ToHex:> ldi xh,high(0x123)> mov yh, yh> addiw x,low(0x123)> addiw y,low(0x123)> ld r16,x> ld r17,y> swap r16> add r16,r17> ret
aber damit bist du bereits auf 11 Takten und der Vorteil ist
dahin :-)
> Eventuell bekommst du es in C auch hin, wenn du vereinfachende> Festlegungen triffst, oder geht das nicht?
Nein, das geht nicht mehr.
In einer Hochsprache muss man gewisse Dinge aufgeben. Einer
davon ist: Der Compiler hat die Kontrolle über die Register
und entscheidet welches Register er wofür nimmt. Dies unter
anderem auch deshalb, weil es vernünftig ist ein Register-
benutzungsschema zu verwenden. Der Nachteil dabei ist, dass
dieses Schema für alle Programme immer gleich ist. Hier
hast du in Assembler den Vorteil, dass du das Registerschema
individuell an jedes Programm anpassen kannst. Du kannst daher
ein Register für nur einen Zweck reservieren, in C geht das
dann so nicht mehr.
> Noch was, ich kann C nur ansatzweise, es war mir immer suspekt weil ich> nicht genau wußte was da passiert. Ich find Assembler einfach besser,> bilde mir ein, dadurch die volle Kontrolle zu haben. Allerdings muß ich> zugeben bekommt man dabei leicht Kopfschmerzen und graue Haare. Aber was> solls
:-)
Etwas Kontrolle muss man in jeder Hochsprache abtreten. Dafür
befreit einen der Compiler allerdings aber auch von vielen
Detail- und Routineaufgaben.
Das Augenmerk bei der Programmierung in einer Hochsprache liegt
daher auch weniger in den Details wie Registerbelegung oder wo
genau im Speicher eine Variable liegt. In einer Hochsprache
musst du dich um solche Dinge nicht mehr kümmern und kannst dich
mehr auf den Problemaspekt und Algorithmen konzentrieren.
Bei einem µC, wie einem Mega8 oder Mega16 mag das noch nicht so
sehr die Rolle spielen, aber bei Programmen die in die 100-erte
Kilobytes oder Megabytes gehen spielt das dann die überragende
Rolle. Entwicklungszeit ist teuer!
Ein guter Assemblerprogrammierer kann einen Compiler schlagen,
allerdings meist nicht um sehr viel.
In einer Hochsprache muss man gewisse Dinge aufgeben. Einer
davon ist: Der Compiler hat die Kontrolle über die Register
und entscheidet welches Register er wofür nimmt. Dies unter
anderem auch deshalb, weil es vernünftig ist ein Register-
benutzungsschema zu verwenden. Der Nachteil dabei ist, dass
dieses Schema für alle Programme immer gleich ist.
Das ist dann also der Grund für das ständige gepoppe bei C.
Ich dachte schon, ein sexist der gerne poppt hätte C erfunden.
Ich hab kein Schema, denk mir aus wie man es am besten machen könnte und
los gehts.
Am liebsten sind mir interruptgesteuerte Programme, weil, ich hab mal
früher Maschinensteuerungen gebastelt. Da kam es darauf an, das die
Maschine sofort reagiert wenn eine Position erreicht oder ein Notaus
betätigt wurde.
Besonders gefallen hat mir dabei, das der Interruptvektor nicht fest
vorgegeben war, sondern im highteil in der cpu der lowteil in dem
interruptfähigem peripheren Baustein hinterlegt wurde.Es mußte also
nicht von einer vorgegebenen Interrupttabelle erst irgendwo
hingesprungen werden, man konnte sofort an der Interruptvektoradresse
mit der Bearbeitung beginnen
Damals war das Zeug auch etwas langsamer, der U880 (Z80) lief in meiner
Jugendzeit mit 2,5 MHz maximalem Takt.
@ Ralph
>Warum dieser Aufwand ??????>Schreib die Datei doch direkt im Binärformat auf die SD Karte.>Dein Pc macht die Wandlung gerne.
Mensch Ralph, schreib doch nicht so was.
Das könnte das Tempo ja glatt verdoppeln.
Solch einfache Lösungen sind hier nicht gefragt.
Gleich gibts Mecker vom Simon ;)
Duck, und wech
holger wrote:
> Mensch Ralph, schreib doch nicht so was.> Das könnte das Tempo ja glatt verdoppeln.
HEX ist sogar fast 3-mal größer.
Aber die 10ms Schreibzeit pro Page (256 Byte) dürften den Löwenanteil
ausmachen, d.h. alle Optimierungen hier wirken sich bestenfalls mit
wenigen Promille aus.
Peter
>Aber die 10ms Schreibzeit pro Page (256 Byte) dürften den Löwenanteil>ausmachen, d.h. alle Optimierungen hier wirken sich bestenfalls mit>wenigen Promille aus.
Genau. Wahrscheinlich dauert die ASCII zu BIN Konvertierung
nur deshalb so lange weil die Daten extrem langsam
von der SD-Karte gelesen werden. Eine andere Erklärung
gibt es sonst eigentlich nicht.
ach so;
Lieber kompliziert als einfach.
Sagt das doch direkt !!!
:-)
@ holger
Ich stimme dir mit der SD Karte zu.
Der Flaschenhals ist eher die Übertragung von der SD Karte als die
Wandlung von ASCII in HEX.
Ralph wrote:
> Ich stimme dir mit der SD Karte zu.> Der Flaschenhals ist eher die Übertragung von der SD Karte als die> Wandlung von ASCII in HEX.
Dann würde in der Tat, die binäre Speicherung die Lesegeschwindigkeit
fast verdreifachen.
Aus dem gleichen Grund überträgt mein UART-Bootloader die Daten auch
binär.
Peter
@ W. Bl (wb1)
>Am liebsten sind mir interruptgesteuerte Programme, weil, ich hab mal>früher Maschinensteuerungen gebastelt. Da kam es darauf an, das die>Maschine sofort reagiert wenn eine Position erreicht oder ein Notaus>betätigt wurde.
Notaus und anderes sicherheitskritische Dinge macht man prinzipiell
nicht in Software sondern Hardwar.
>hingesprungen werden, man konnte sofort an der Interruptvektoradresse>mit der Bearbeitung beginnen
Die zwei Takte mehr oder weniger sind selten wirklich entscheidend.
MFg
Falk
Die Schreibzeit für 256Bytes beträgt "nur" 2ms. Die Pages sind übrigens
64k groß.
An dem Format auf der SD-Karte kann ich nichts ändern, das ist so
vorgegeben.
@ Regatti (Gast)
>Die Schreibzeit für 256Bytes beträgt "nur" 2ms.
Macht immerhin noch 7,8 us/Byte, was ~125 Takten @16 MHz entspricht.
Keinerlei Bedarf für eine Überschall Umwandlungsroutine.
> Die Pages sind übrigens 64k groß.
Und die kann man auf einmal schreiben? In 2ms?
MFG
Falk
>An dem Format auf der SD-Karte kann ich nichts ändern, das ist so>vorgegeben.
Vieleicht kannst du an der SPI Geschwindigkeit ja noch ein
bißchen drehen.
@falk
Ich wollte es mit dem Notaus nur verdeutlichen.
Damals waren es Scheibenläufermotoren mit incrementellen Gebern.
Die Geber brachten 1024 Impulse/Umdrehung, die Motoren hatten eine
Enddrehzahl von 3000U/min, das sind also rund 52000 Impulse/sec.
Die wurden von TTL-Gattern aufgefangen, die dann wiederum über die
peripheren Bausteine Interrupts auslösten. Wenn das nicht schnell genug
ging, zeigte der Roboterarm an die anderen des Werkstückes (ein bisschen
übertrieben).
holger wrote:
> @ Ralph>>>Warum dieser Aufwand ??????>>Schreib die Datei doch direkt im Binärformat auf die SD Karte.>>Dein Pc macht die Wandlung gerne.>> Mensch Ralph, schreib doch nicht so was.> Das könnte das Tempo ja glatt verdoppeln.> Solch einfache Lösungen sind hier nicht gefragt.> Gleich gibts Mecker vom Simon ;)>
OT: Von mir?
Hallo,
hier noch ein Vorschlag der die Anfangs beschriebene
Assemblerroutine nochmals um 12,5% beschleunigt.
Die ASCII-nach-BIN Wandlung braucht dann nur noch 7 ASM-Befehle.
1
; zu wandelnder Wert '4F'
2
ldi r16,'4' ;r16 enthält 0x34
3
ldi r17,'F' ;r17 enthält 0x46
4
5
ascii2bin:
6
sbrs r16,5
7
subi r16,7
8
sbrs r17,5
9
subi r17,7
10
swap r16
11
add r16,r17
12
subi r16,0x33
13
14
; Ergebnis steht in r16
OK, ist trivial, aber der Thread heisst ja: extrem schnell wandeln...
Gruß Jan