Hmm, ich benutze einfach nur das WinAVR-Makefile.
Bei -O (Optimierung) habe ich alles ausprobiert (0, 1, 2, 3, s), das hat
aber keinen Einfluss auf den SRAM-Zugriff, nur auf die Verzweigung oben
im switch. Was ich hier gepostet habe ist -Os, der Rest benutzt im
wesentlichen mehr Register.
Insgesamt habe ich diese Optionen gefunden, kenne aber die meisten
Bedeutungen nicht (noch nicht benutzt...):
Im Makefile:
Tuxpilot schrieb:> weil die Funkion sehr oft> ausgeführt werden soll
Die ganze Funktion wäre auch sinnvoll, um den Scope der Variablen zu
kennen.
Ich habe zwar eine grobe Ahnung, wie der Rückgabewert aussehen soll,
aber wissen ist besser als raten.
Walter T. schrieb:> Die ganze Funktion wäre auch sinnvoll, um den Scope der Variablen zu> kennen.
Nicht nur der Scope ist interessant, sondern auch die genauen
Datentypen.
Tuxpilot schrieb:> Hmm, ich benutze einfach nur das WinAVR-Makefile.
WinAvr wieviel? 2010....?
Der ist auch steinalt und danach wurde das AVR-Backend deutlich
verbessert.
Allgemein: Wenn der Typ vom Index kleiner ist als eine Adressrechnung,
tritt der beschriebene Effekt auf. Nicht nur beim AVR, auch bei 64-Bit
x86.
Wenn der Compiler die Bereichsgrenzen vom Index kennt, kann er das
besser machen. Ich hatte den Code oben aber bewusst so formuliert, dass
er das nicht kann.
Und da sollte sich schon mancher drüber gewundert haben, denn die
üblicherweise als Index verwendeten int/unsigned sind 32 Bit breit,
Adressrechnungen aber 64 Bit. Weshalb das ähnlich mies aussieht wie oben
beim AVR:
1
movq %rsi, %rdx
2
movl %edi, %eax
3
shrq $24, %rdx
4
movb %dl, a(%rax)
5
leal 1(%rdi), %eax
6
movq %rsi, %rdx
7
shrq $16, %rdx
8
movb %dl, a(%rax)
9
leal 2(%rdi), %eax
10
movq %rsi, %rdx
11
shrq $8, %rdx
12
addl $3, %edi
13
movb %dl, a(%rax)
14
movb %sil, a(%rdi)
Macht man den Index 64 Bit breit, sieht es besser aus:
Carl D. schrieb:> Tuxpilot schrieb:>> Hmm, ich benutze einfach nur das WinAVR-Makefile.>> WinAvr wieviel? 2010....?
Steht da nicht...
> Der ist auch steinalt und danach wurde das AVR-Backend deutlich> verbessert.
Wo bekomme ich denn neuere Makefiles, ohne sie neu zu erfinden? Im Wiki
scheinbar nicht:
Tuxpilot schrieb:> Ich glaube, das Makefile kam damals von hier:> https://www.mikrocontroller.net/articles/Beispiel_MakefileA. K. schrieb:> Was ändert sich, wenn du den Index zu einem 16-Bit Typ machst?
Der Index war uint8_t, ändert aber nichts.
Aber: Wenn der Index uint16_t ist, und der switch komplett fehlt, gibt
es std Z+1, r17 usw. Auch gut, wenn ich den switch nicht bräuchte.
st Z+, r17 bekomme ich nur mit einer Schleife drumrum, aber eine
Schleife brauche ich da nicht.
So, der restliche Code funktioniert jetzt, ich habe alles zum .zip
gemacht und angehängt.
Walter T. schrieb:> Ich habe zwar eine grobe Ahnung, wie der Rückgabewert aussehen soll,> aber wissen ist besser als raten.
(Rückgabetyp ist void...)
Die Funktion dient dazu, Daten mit variabler Bitzahl in ein Array zu
packen, um dieses als Base64 "geschützt" an den PC zu senden. Auf dessen
AMD64 läuft dann die Umkehrfunktion.
(Wegen diesem schlecht passenden C-'<<' und -'>>' habe ich inzwischen
Zweifel, dass dies schneller geht, als jedes Byte einzeln per UART zu
senden, oder gar CSV draus zu machen.)
Ich konnte mit switch und C allgemein nicht mehr viel rausholen, und
habe die Funktion in Assembler neu geschrieben, mit "Store Indirect and
Post-Inc." sehr sinnvoll eingesetzt.
Wird später noch wichtig, diese Funktion. Heute nicht mehr.
Hier eine gekürzte Version, bei der man noch geschätzt 5 bis 10 Takte
sparen kann:
1
push_value:
2
; Calculate and store new bits_in_buffer:
3
lds r18, bits_in_buffer
4
mov r21, r18
5
add r18, r20
6
sts bits_in_buffer, r18
7
mov r18, r21
8
9
; Calculate how many bits are free in the last buffer element:
10
neg r21
11
andi r21, 0x07
12
; Set X to first buffer element with free space
13
ldi r26, lo8(base64_buffer)
14
ldi r27, hi8(base64_buffer)
15
lsr r18
16
lsr r18
17
lsr r18
18
add r26, r18
19
adc r27, r1
20
21
; Calculate how many bits our value must be shifted left
22
ldi r19, 32
23
sub r19, r20
24
add r19, r21
25
26
; Calculate how many bits and bytes this are:
27
mov r0, r19
28
lsr r0
29
lsr r0
30
lsr r0
31
andi r19, 0x07
32
33
clr r18
34
35
; Shift value left by r0 bytes:
36
rjmp 2f
37
1:
38
mov r18, r25
39
mov r25, r24
40
mov r24, r23
41
mov r23, r22
42
clr r22
43
2:
44
dec r0
45
brpl 1b
46
47
; Shift value left by r19 bits:
48
rjmp 7f
49
6:
50
lsl r22
51
rol r23
52
rol r24
53
rol r25
54
rol r18
55
7:
56
dec r19
57
brpl 6b
58
59
; OR last buffer element with our highest bits:
60
tst r21
61
breq 9f
62
ld r19, X
63
or r19, r18
64
st X+, r19
65
9:
66
67
; Store all bytes of value in next buffer elements:
68
st X+, r25
69
st X+, r24
70
st X+, r23
71
st X+, r22
72
73
ret
Min. 49 Takte mit RCALL und RET, Max. 139 Takte.
Hier wird erstmal nichts mehr verbessert. ;)
A. K. schrieb:> Und da sollte sich schon mancher drüber gewundert haben, denn die> üblicherweise als Index verwendeten int/unsigned sind 32 Bit breit,> Adressrechnungen aber 64 Bit.
Ist das tatsächlich üblich? Ich verwende auf dem PC als Index
normalerweise immer size_t.
Aber ist interessant zu sehen, dass es auf einem 8-Bitter durchaus
effizienter sein kann, den Index nicht 8, sondern 16 Bit breit zu
machen.
Rolf M. schrieb:> Ist das tatsächlich üblich?
In legacy code schon. Ob man heute konsequent xxx_t Typen statt
Basistypen einsetzt, dafür fehlt mit der Überblick über genug aktuellen
Code.
A. K. schrieb:> Rolf M. schrieb:>> Ist das tatsächlich üblich?>> In legacy code schon. Ob man heute konsequent xxx_t Typen statt> Basistypen einsetzt, dafür fehlt mit der Überblick über genug aktuellen> Code.
Naja, size_t ist ja nicht gerade neu. Das gab's auch vor C99 schon.
Bevor man Micro-Optimization betreibt, sollte man erstmal prüfen, ob
sich das im realen Programm auch wirklich auswirkt, d.h. ein
Timingproblem oder zu hohe CPU-Last beseitigt wird.
würde mich jetzt auch interessieren..
es sollen "Joystick" Daten (also von einem Menschen eingegeben)
direkt an eine PC übergeben werden
auch wenn man das (übertrieben) 250 mal in der Sekunden macht, wäre die
Datenmenge trotzdem noch sehr überschaubar.
und in 1/250 Sekunde kann man schon verdammt viel Code ausführen ..
dass man hier base64 braucht wäre auch zu bezweifeln.. (oder schickt er
a e-mail ;-) )
wüsste nicht wo da bit 8 verloren gehen sollte..
Robert L. schrieb:> auch wenn man das (übertrieben) 250 mal in der Sekunden macht, wäre die> Datenmenge trotzdem noch sehr überschaubar.
Hähä, stimmt.
Ich möchte allerdings später 10.000 Datensätze pro Sekunde übertragen,
bestehend aus ein paar ADC-Werten (rund 10 Bit) und ein paar internen
Variablen (rund 1 Bit).
Um sich beim Programmieren daran zu tasten, welche Daten man braucht,
ist so eine Funktion push_value() sehr praktisch. Wenn es schneller
werden soll, muss man natürlich den Puffer manuell befüllen, evtl. gar
nicht linear.
Base64 ist auch nicht nötig, macht aber das überprüfen des Datenstroms
im Terminal einfacher, da die Datensätze durch \n getrennt sind. Die
Datenrate ist besser als Hexadezimal, ausserdem werde ich mein
Plotprogramm noch auf Uuencoding umstellen.
Carl D. schrieb:> Erst mal frischen Compiler besorgen:> http://blog.zakkemble.net/avr-gcc-builds/
Gemacht, der Code wird tatsächlich etwas schlanker. Nur das "Store
Indirect and Post-Inc." wird immer noch unelegant umgangen. Compiliert
habe ich hiermit:
Tuxpilot schrieb:> Die Datenrate ist besser als Hexadezimal
Kann ich mir nur schwer vorstellen. Denn durch die Codierung musst du
entweder genau so viele (Bytes/3 = 0) oder sogar mehr Bytes (Bytes/3 !=
0 -> Padding) uebertragen als bei Hex. Die Datenrate kann mit Base64
also gar nicht besser werden.
Aber vielleicht kannst du mich ja erleuchten, und erklaeren wie das
funktionieren soll.
Rentenzahler schrieb:> Ich vermute er meint HEX als ASCII übertragen.
Ja. Wie kann man es denn sonst noch übertragen? Jeweils zwei Hex-Werte
in einem Byte, das wäre ja wieder binär, so kann man kein \n senden.
Padding in Form von = oder == braucht man nicht anhängen. Enthält keine
weitere Information, denn das Format ist ja bekannt. Nur die 2 oder 4
Bits im letzten Zeichen muss man anhängen.
Synchronisierung. Eine Zeile ist ein Datensatz.
Wahrscheinlich so wie im Matrix Film, wenn es da darum geht, die
Verbindung (besonders die Baudrate) zu prüfen. Wie will man das bei
binären Daten machen? Da hilft nur ein Adapter mit Auto Baud Rate
Detection, wenn man sich nicht mehr an die Baudrate erinnert.
Wenn du eine Adresse suchst, multiplizierst du die Hausnummer mit 7,62
Meter und fährst von der Kreuzung aus genau soweit, oder schaust du auf
die Nummern die an den Häusern stehen?