Hallo, ich stolpere über ein Laufzeitproblem bei der Verteilung der 3 unteren Bytes eines 24-bit Wertes auf 3 Ports. inline void machmal(uint32_t wert) { PORTA = (wert & 0xff); // ok, OUT PORTA,Rn PORTB = ((wert >> 8) & 0xff); // 4 Register werden sinnlos umkopiert PORTC = ((wert >> 16) & 0xff); // ok, OUT PORTC, Rn+2 } machmal(0x00112233UL); Der gcc läuft mit -o3 Wie gehts besser ? Union etc. geht nicht, weil ich alles in Registern behalten will. Gruß, Michael
Michael Appelt schrieb: > Union etc. geht nicht, weil ich alles in Registern behalten will. ??? Solange du in C programmierst, hast du eh keinen Einfluß darauf. Aber: Schau dir das ABI an. Dein uint32-Wert steht ja beim Funktionsaufruf in 4 Registern. Mit ein paar Zeilen inline-Assembler oder einer eigenen Assembler-Routine kannst du die Werte direkt aus den Registern in die Ports schreiben. Schneller gehst es nicht. Oliver
>Solange du in C programmierst, hast du eh keinen Einfluß darauf.
Nicht komplett aber man kann mit dem Schlüsselwort register eine
variable in den Registern halten.
Gruß Jonas
Hallo, @Oliver S: Union geht über den Spicher und die genannte Sequenz und ein wenig mehr sollen unter 1us laufen. Das ganze muss 6mal aufgerufen werden, und mir gefallen die hart kodierten Register nicht. Muss vermutlich tiefer in den inline-Assembler reinschauen. @Jonas: welche Casts ? PORTB = (uint8_t) ((uint16_t) wert) >> 8); Wäre das optimal ? Stimmt, hab ich noch nicht probiert. Gruß, Michael
Michael Appelt schrieb: > Der gcc läuft mit -o3 Default sollte man -Os nehmen. Besser gehts nicht:
1 | inline void machmal(uint32_t wert) |
2 | {
|
3 | PORTA = (wert & 0xff); // ok, OUT PORTA,Rn |
4 | d0: 83 e3 ldi r24, 0x33 ; 51 |
5 | d2: 82 b9 out 0x02, r24 ; 2 |
6 | PORTB = ((wert >> 8) & 0xff); // 4 Register werden sinnlos umkopiert |
7 | d4: 82 e2 ldi r24, 0x22 ; 34 |
8 | d6: 85 b9 out 0x05, r24 ; 5 |
9 | PORTC = ((wert >> 16) & 0xff); // ok, OUT PORTC, Rn+2 |
10 | d8: 81 e1 ldi r24, 0x11 ; 17 |
11 | da: 88 b9 out 0x08, r24 ; 8 |
12 | }
|
Jonas Biensack schrieb: > Nicht komplett aber man kann mit dem Schlüsselwort register eine > variable in den Registern halten. Register allocation ist Sache des Compilers. Daher wird das Schlüsselwort register seit vielen Compiler-Generationen vom gcc schlicht ignoriert. Peter Dannegger schrieb: > Besser gehts nicht: In reinem Assembler wären es nur die 3 out-Befehle und return. Oliver
Oliver S. schrieb: > In reinem Assembler wären es nur die 3 out-Befehle und return. aber nur wenn die werte schon in einem Register stehen.
Hallo, naja, bei einem Call stehen diese Parameter bei meinem Programm immer in Registern. Am Anfang steht allerdings eine Variable. Der Code von Peter ist da ein wenig zu optimistisch, aber ich probiers heute abend mit -Os Gruß, Michael
Michael Appelt schrieb: > naja, bei einem Call stehen diese Parameter bei meinem Programm immer in > Registern. es gibt aber bei inline keinen call mehr.
Michael Appelt schrieb: > Der Code von Peter ist da ein wenig zu optimistisch Ja, durch das "inline" hat er zu gut optimiert. Versuch mal erst zu maskieren und dann schieben.
Peter II schrieb: > aber nur wenn die werte schon in einem Register stehen. Die Werte stehen in Registern, weil der gcc sie darin in die Funktion übergibt. Oliver
Oliver S. schrieb: > Die Werte stehen in Registern, weil der gcc sie darin in die Funktion > übergibt. aber nur wenn eine eine Funktion gibt, und bei inline gibt es keine Funktion mehr.
>naja, bei einem Call stehen diese Parameter bei meinem Programm immer in >Registern. nö, die können auch auf dem stack liegen. Schon mal dran gedacht das es funktionensaufrufe mit mehr parametern als verfügbaren registern gibt? Gruß Jonas
:
Bearbeitet durch User
Peter II schrieb: > Michael Appelt schrieb: >> naja, bei einem Call stehen diese Parameter bei meinem Programm immer in >> Registern. > > es gibt aber bei inline keinen call mehr. Aber auf die drüberliegenden Functions, die sind nicht inline. Es sind 6 Functions f1....f6. Jede hat leicht unterschiedliche Parameter, d.h. es werden möglicherweise unterschiedliche Register benutzt. Jede ruft am Anfang die genannte inline function auf. Wegen der Registerzuweisung bin ich mit inline asm nicht glücklich. Wenn es so jetzt funktioniert, dann löst das mein Problem. Gruß, Michael
Michael Appelt schrieb: > Aber auf die drüberliegenden Functions, die sind nicht inline. die hast du uns aber nicht gezeigt, damit können wir das ja schlecht wissen.
Hallo, also man sollte schon in der Lage sein, abstrakt über ein Problem zu reden ohne immer gleich ein 8k-Programm im Source anzuhängen. Ich habe ja nicht gesagt, daß der gcc was falsch macht und die Hinweise waren durchaus zutreffend genug, um damit mein Brett vorm Kopp zu entfernen. Gruß, Michael
Michael Appelt schrieb: > Union etc. geht nicht, weil ich alles in Registern behalten will. Michael Appelt schrieb: > Union geht über den Spicher und die genannte Sequenz und ein wenig mehr > sollen unter 1us laufen. Wie kommst du darauf? Hast du's ausprobiert? Wenn nicht, dann wage einen Versuch und sei überrascht ;-)
Hallo, nein, habe ich nicht probiert. Es würde auf Union als Parametertyp hinauslaufen, und da müsste ich mich ebenfalls erstmal einlesen. Ich weiß garnicht: Wo steht, dass man hier nur Fragen stellen darf, wenn man vorher bereits alles ausprobiert hat ? Wo steht, dass man alles ausprobieren muss ? Gruß, Michael
Mit union:
1 | void out24(uint32_t val) |
2 | {
|
3 | union{ |
4 | uint32_t u32; |
5 | uint8_t u8[4]; |
6 | } in; |
7 | in.u32 = val; |
8 | PORTA = in.u8[0]; |
9 | PORTB = in.u8[1]; |
10 | PORTC = in.u8[2]; |
11 | }
|
Das Listing:
1 | 000000c0 <out24>: |
2 | union{ |
3 | uint32_t u32; |
4 | uint8_t u8[4]; |
5 | } in; |
6 | in.u32 = val; |
7 | PORTA = in.u8[0]; |
8 | c0: 62 b9 out 0x02, r22 ; 2 |
9 | PORTB = in.u8[1]; |
10 | c2: 75 b9 out 0x05, r23 ; 5 |
11 | PORTC = in.u8[2]; |
12 | c4: 88 b9 out 0x08, r24 ; 8 |
13 | }
|
14 | c6: 08 95 ret |
Wenn der Abstand zwischen den OUT Befehlen zwingend minimiert sein muss:
1 | void __attribute__ ((noinline)) |
2 | out24(uint8_t h, uint8_t m, uint8_t l) |
3 | {
|
4 | cli(); |
5 | PORTA = l; |
6 | PORTB = m; |
7 | PORTC = h; |
8 | sei(); |
9 | }
|
10 | |
11 | void f(uint32_t x) |
12 | {
|
13 | out24(x >> 16, x >> 8, x); |
14 | }
|
So spart man ein wenig an unkritischer Stelle, hat aber mehr Arbeit:
1 | out24(x >> 16, (uint16_t)x >> 8, x); |
:
Bearbeitet durch User
Jonas Biensack schrieb: > nö, die können auch auf dem stack liegen. Bei irgendwelchen Compilern für irgendwelche Zielplattformen ja. Beim avr-gcc mit einem uint32-Funktionsparameter wie im oben gezeigten Code liegt der immer in den Registern. Oliver
Hallo, ok, ich muss zugeben, dass hat was :-)) Die Details des Union bleiben in der function verborgen. Danke für die Mühe, die Ihr Euch gemacht habt. Vermutlich bleibt es aber dabei: ohne -Os klappt es auch mit union nicht. BTW die genaue Zeit der out-Befehle ist mir relativ egal, aber mal eben zusätzlich 4 register kopieren ging mir irgendwie quer - technisch wäre es aber relativ egal. Gruß, Michael
Michael Appelt schrieb: > nein, habe ich nicht probiert. Es würde auf Union als Parametertyp > hinauslaufen, und da müsste ich mich ebenfalls erstmal einlesen. > > Ich weiß garnicht: > > Wo steht, dass man hier nur Fragen stellen darf, wenn man vorher bereits > alles ausprobiert hat ? Nirgends, das ist ganz dir überlassen. > Wo steht, dass man alles ausprobieren muss ? Ebenfalls nirgends. Nur tust du dir dann mit Aussagen wie der folgenden selber keinen Gefallen: Michael Appelt schrieb: > Union geht über den Spicher Denn das erweckt den Eindruck, dass du dir diesbezüglich sicher bist und deswegen auch für die Helfenden keinerlei Bedarf siehst, die Unions doch einmal auszuprobieren. Ohne die obige Aussage wäre der Vorschlag mit der Union sicher schon in der ersten oder zweiten Antwort gekommen, so waren aber alle Hirne erst einmal blockiert. Ich selber war mir erst auch nicht sicher, ob hier eine Union etwas bringen würde. Nach einer kurzen Goole-Suche nach gcc struct argument register kam ich zum aber Schluss, dass das zumindest einen Versuch wert ist. Und siehe da ...
Hallo, jawoll, Du bist ein ganz schlauer, deshalb darfst Du ja auch Moderator sein. Also ich habe ein Berufsleben, und privat geht mein Ehrgeiz zu einer angemessene Lösung in angemessener Zeit. Aktuell erhalte ich bei -Os DATA_OUT = (uint8_t) ((uint16_t) adr >> 8); 250: 27 2f mov r18, r23 252: 33 27 eor r19, r19 254: 28 b9 out 0x08, r18 ; 8 Gruß, Michael
Michael Appelt schrieb: > Aktuell erhalte ich bei -Os > > DATA_OUT = (uint8_t) ((uint16_t) adr >> 8); > 250: 27 2f mov r18, r23 > 252: 33 27 eor r19, r19 > 254: 28 b9 out 0x08, r18 ; 8 was macht das eor r19, r19 für einen sinn?
Peter II schrieb: > was macht das für einen sinn? >> 250: 27 2f mov r18, r23 >> 252: 33 27 eor r19, r19 Das ist die optimale Sequenz für einen 16-Bit Shift um 8 mit src=r22/23, dst=r18/19. Danach kommt die Zuweisung, die nur die untere Hälfte verwendet.
:
Bearbeitet durch User
Sorry, meine Frage war rein rhetorisch. Ich wunder mich nur, was vom gcc alles optimiert wird und was andererseits manchmal auch nicht. Aber die Bewunderung der Entwickler überwiegt. Nachtrag: DATA_OUT = (uint8_t) (adr >> 16); 25a: aa 27 eor r26, r26 25c: bb 27 eor r27, r27 25e: 88 b9 out 0x08, r24 ; 8 Auch nicht schlecht....ich probiers wohl besser mit union. Gruß, Michael
:
Bearbeitet durch User
Peter II schrieb: > was macht das > eor r19, r19 > für einen sinn? Bei non-volatile lhs entfallen mov und eor.
Aus der Praxis. .h
1 | // little trick, to speed up data access
|
2 | |
3 | typedef union { |
4 | uint32_t d32; |
5 | uint8_t ary[4]; |
6 | } ut_t; |
.c
1 | ISR(TIMER1_COMPA_vect) { |
2 | |
3 | static uint8_t pwm_cnt, slow_cnt; |
4 | ut_t tmp; |
5 | int8_t enc_new, enc_diff; // encoder stuff |
6 | |
7 | OCR1A += isr_ptr->time[pwm_cnt]; |
8 | tmp.d32 = isr_ptr->mask[pwm_cnt]; |
9 | |
10 | if (pwm_cnt == 0) { // set ports at begin of PWM |
11 | PORTD = tmp.ary[0] | 0x0F; // PD0-3 no change |
12 | PORTC = tmp.ary[1]; |
13 | PORTB = tmp.ary[2] | 0xF0; // PB4-7 no change |
14 | PORTA = tmp.ary[3]; |
15 | pwm_cnt++; |
16 | slow_cnt++; |
17 | if (slow_cnt == 10) { // 100ms timer |
18 | slow_cnt=0; |
19 | flag_100ms=1; // trigger lcd refresh |
20 | }
|
21 | }
|
22 | else { // clear ports |
23 | PORTD &= (tmp.ary[0] | 0x0F); |
24 | PORTC &= tmp.ary[1]; |
25 | PORTB &= tmp.ary[2] | 0xF0; |
26 | PORTA &= tmp.ary[3]; |
27 | |
28 | if (pwm_cnt == pwm_cnt_max) { |
29 | pwm_sync = 1; // update now possible |
30 | pwm_cnt=0; |
31 | }
|
32 | else pwm_cnt++; |
33 | }
|
34 | |
35 | // decode rotary encoder, setup for DMX address
|
36 | // only active, when jogdail is pressed
|
37 | // DMX address stored in eeprom on release in main loop
|
38 | if (KEY_PRESSED) { |
39 | enc_new = 0; |
40 | if( PHASE_A ) enc_new = 3; |
41 | if( PHASE_B ) enc_new ^= 1; // convert gray to binary |
42 | enc_diff = enc_last - enc_new; // difference last - new |
43 | if( enc_diff & 1 ){ // bit 0 = value (1) |
44 | enc_last = enc_new; // store new as next last |
45 | enc_delta += (enc_diff & 2) - 1; // bit 1 = direction (+/-) |
46 | if (enc_delta < 0) enc_delta = 0; |
47 | if (enc_delta > 84) enc_delta = 84; |
48 | }
|
49 | }
|
50 | }
|
1 | // Timer 1 Output COMPARE A Interrupt |
2 | |
3 | ISR(TIMER1_COMPA_vect) { |
4 | 77a: 1f 92 push r1 |
5 | 77c: 0f 92 push r0 |
6 | 77e: 0f b6 in r0, 0x3f ; 63 |
7 | 780: 0f 92 push r0 |
8 | 782: 11 24 eor r1, r1 |
9 | 784: 2f 93 push r18 |
10 | 786: 3f 93 push r19 |
11 | 788: 4f 93 push r20 |
12 | 78a: 5f 93 push r21 |
13 | 78c: 6f 93 push r22 |
14 | 78e: 8f 93 push r24 |
15 | 790: 9f 93 push r25 |
16 | 792: af 93 push r26 |
17 | 794: bf 93 push r27 |
18 | 796: ef 93 push r30 |
19 | 798: ff 93 push r31 |
20 | |
21 | static uint8_t pwm_cnt, slow_cnt; |
22 | ut_t tmp; |
23 | int8_t enc_new, enc_diff; // encoder stuff |
24 | |
25 | OCR1A += isr_ptr->time[pwm_cnt]; |
26 | 79a: 40 91 88 00 lds r20, 0x0088 |
27 | 79e: 50 91 89 00 lds r21, 0x0089 |
28 | 7a2: e0 91 01 01 lds r30, 0x0101 |
29 | 7a6: f0 91 02 01 lds r31, 0x0102 |
30 | 7aa: 60 91 09 01 lds r22, 0x0109 |
31 | 7ae: 26 2f mov r18, r22 |
32 | 7b0: 30 e0 ldi r19, 0x00 ; 0 |
33 | 7b2: 22 0f add r18, r18 |
34 | 7b4: 33 1f adc r19, r19 |
35 | 7b6: e2 0f add r30, r18 |
36 | 7b8: f3 1f adc r31, r19 |
37 | 7ba: 80 81 ld r24, Z |
38 | 7bc: 91 81 ldd r25, Z+1 ; 0x01 |
39 | 7be: 48 0f add r20, r24 |
40 | 7c0: 59 1f adc r21, r25 |
41 | 7c2: 50 93 89 00 sts 0x0089, r21 |
42 | 7c6: 40 93 88 00 sts 0x0088, r20 |
43 | tmp.d32 = isr_ptr->mask[pwm_cnt]; |
44 | 7ca: e0 91 01 01 lds r30, 0x0101 |
45 | 7ce: f0 91 02 01 lds r31, 0x0102 |
46 | 7d2: 22 0f add r18, r18 |
47 | 7d4: 33 1f adc r19, r19 |
48 | 7d6: e2 0f add r30, r18 |
49 | 7d8: f3 1f adc r31, r19 |
50 | 7da: df 01 movw r26, r30 |
51 | 7dc: da 96 adiw r26, 0x3a ; 58 |
52 | 7de: 92 ad ldd r25, Z+58 ; 0x3a |
53 | 7e0: 11 96 adiw r26, 0x01 ; 1 |
54 | 7e2: 3c 91 ld r19, X |
55 | 7e4: 11 97 sbiw r26, 0x01 ; 1 |
56 | 7e6: 12 96 adiw r26, 0x02 ; 2 |
57 | 7e8: 2c 91 ld r18, X |
58 | 7ea: 12 97 sbiw r26, 0x02 ; 2 |
59 | 7ec: 13 96 adiw r26, 0x03 ; 3 |
60 | 7ee: 4c 91 ld r20, X |
61 | 7f0: 9f 60 ori r25, 0x0F ; 15 |
62 | 7f2: 20 6f ori r18, 0xF0 ; 240 |
63 | |
64 | if (pwm_cnt == 0) { // set ports at begin of PWM |
65 | 7f4: 66 23 and r22, r22 |
66 | 7f6: 99 f4 brne .+38 ; 0x81e <__vector_13+0xa4> |
67 | PORTD = tmp.ary[0] | 0x0F; // PD0-3 no change |
68 | 7f8: 9b b9 out 0x0b, r25 ; 11 |
69 | PORTC = tmp.ary[1]; |
70 | 7fa: 38 b9 out 0x08, r19 ; 8 |
71 | PORTB = tmp.ary[2] | 0xF0; // PB4-7 no change |
72 | 7fc: 25 b9 out 0x05, r18 ; 5 |
73 | PORTA = tmp.ary[3]; |
74 | 7fe: 42 b9 out 0x02, r20 ; 2 |
75 | pwm_cnt++; |
76 | 800: 91 e0 ldi r25, 0x01 ; 1 |
77 | 802: 90 93 09 01 sts 0x0109, r25 |
78 | slow_cnt++; |
79 | 806: 80 91 08 01 lds r24, 0x0108 |
80 | 80a: 8f 5f subi r24, 0xFF ; 255 |
81 | 80c: 80 93 08 01 sts 0x0108, r24 |
82 | if (slow_cnt == 10) { // 100ms timer |
83 | 810: 8a 30 cpi r24, 0x0A ; 10 |
84 | 812: f1 f4 brne .+60 ; 0x850 <__vector_13+0xd6> |
85 | slow_cnt=0; |
86 | 814: 10 92 08 01 sts 0x0108, r1 |
87 | flag_100ms=1; // trigger lcd refresh |
88 | 818: 90 93 bb 01 sts 0x01BB, r25 |
89 | 81c: 19 c0 rjmp .+50 ; 0x850 <__vector_13+0xd6> |
90 | } |
91 | } |
92 | else { // clear ports |
93 | PORTD &= (tmp.ary[0] | 0x0F); |
94 | 81e: 8b b1 in r24, 0x0b ; 11 |
95 | 820: 98 23 and r25, r24 |
96 | 822: 9b b9 out 0x0b, r25 ; 11 |
97 | PORTC &= tmp.ary[1]; |
98 | 824: 88 b1 in r24, 0x08 ; 8 |
99 | 826: 83 23 and r24, r19 |
100 | 828: 88 b9 out 0x08, r24 ; 8 |
101 | PORTB &= tmp.ary[2] | 0xF0; |
102 | 82a: 85 b1 in r24, 0x05 ; 5 |
103 | 82c: 28 23 and r18, r24 |
104 | 82e: 25 b9 out 0x05, r18 ; 5 |
105 | PORTA &= tmp.ary[3]; |
106 | 830: 82 b1 in r24, 0x02 ; 2 |
107 | 832: 84 23 and r24, r20 |
108 | 834: 82 b9 out 0x02, r24 ; 2 |
109 | |
110 | if (pwm_cnt == pwm_cnt_max) { |
111 | 836: 80 91 00 01 lds r24, 0x0100 |
112 | 83a: 68 17 cp r22, r24 |
113 | 83c: 31 f4 brne .+12 ; 0x84a <__vector_13+0xd0> |
114 | pwm_sync = 1; // update now possible |
115 | 83e: 81 e0 ldi r24, 0x01 ; 1 |
116 | 840: 80 93 ba 01 sts 0x01BA, r24 |
117 | pwm_cnt=0; |
118 | 844: 10 92 09 01 sts 0x0109, r1 |
119 | 848: 03 c0 rjmp .+6 ; 0x850 <__vector_13+0xd6> |
120 | } |
121 | else pwm_cnt++; |
122 | 84a: 6f 5f subi r22, 0xFF ; 255 |
123 | 84c: 60 93 09 01 sts 0x0109, r22 |
124 | } |
125 | |
126 | // decode rotary encoder, setup for DMX address |
127 | // only active, when jogdail is pressed |
128 | // DMX address stored in eeprom on release in main loop |
129 | if (KEY_PRESSED) { |
130 | 850: 49 99 sbic 0x09, 1 ; 9 |
131 | 852: 24 c0 rjmp .+72 ; 0x89c <__vector_13+0x122> |
132 | enc_new = 0; |
133 | if( PHASE_A ) enc_new = 3; |
134 | 854: 4b 9b sbis 0x09, 3 ; 9 |
135 | 856: 02 c0 rjmp .+4 ; 0x85c <__vector_13+0xe2> |
136 | 858: 23 e0 ldi r18, 0x03 ; 3 |
137 | 85a: 01 c0 rjmp .+2 ; 0x85e <__vector_13+0xe4> |
138 | 85c: 20 e0 ldi r18, 0x00 ; 0 |
139 | if( PHASE_B ) enc_new ^= 1; // convert gray to binary |
140 | 85e: 4a 9b sbis 0x09, 2 ; 9 |
141 | 860: 02 c0 rjmp .+4 ; 0x866 <__vector_13+0xec> |
142 | 862: 81 e0 ldi r24, 0x01 ; 1 |
143 | 864: 28 27 eor r18, r24 |
144 | enc_diff = enc_last - enc_new; // difference last - new |
145 | 866: 90 91 0a 01 lds r25, 0x010A |
146 | 86a: 92 1b sub r25, r18 |
147 | if( enc_diff & 1 ){ // bit 0 = value (1) |
148 | 86c: 90 ff sbrs r25, 0 |
149 | 86e: 16 c0 rjmp .+44 ; 0x89c <__vector_13+0x122> |
150 | enc_last = enc_new; // store new as next last |
151 | 870: 20 93 0a 01 sts 0x010A, r18 |
152 | enc_delta += (enc_diff & 2) - 1; // bit 1 = direction (+/-) |
153 | 874: 80 91 be 01 lds r24, 0x01BE |
154 | 878: 81 50 subi r24, 0x01 ; 1 |
155 | 87a: 92 70 andi r25, 0x02 ; 2 |
156 | 87c: 89 0f add r24, r25 |
157 | 87e: 80 93 be 01 sts 0x01BE, r24 |
158 | if (enc_delta < 0) enc_delta = 0; |
159 | 882: 80 91 be 01 lds r24, 0x01BE |
160 | 886: 87 ff sbrs r24, 7 |
161 | 888: 02 c0 rjmp .+4 ; 0x88e <__vector_13+0x114> |
162 | 88a: 10 92 be 01 sts 0x01BE, r1 |
163 | if (enc_delta > 84) enc_delta = 84; |
164 | 88e: 80 91 be 01 lds r24, 0x01BE |
165 | 892: 85 35 cpi r24, 0x55 ; 85 |
166 | 894: 1c f0 brlt .+6 ; 0x89c <__vector_13+0x122> |
167 | 896: 84 e5 ldi r24, 0x54 ; 84 |
168 | 898: 80 93 be 01 sts 0x01BE, r24 |
169 | } |
170 | } |
171 | } |
172 | 89c: ff 91 pop r31 |
173 | 89e: ef 91 pop r30 |
174 | 8a0: bf 91 pop r27 |
175 | 8a2: af 91 pop r26 |
176 | 8a4: 9f 91 pop r25 |
177 | 8a6: 8f 91 pop r24 |
178 | 8a8: 6f 91 pop r22 |
179 | 8aa: 5f 91 pop r21 |
180 | 8ac: 4f 91 pop r20 |
181 | 8ae: 3f 91 pop r19 |
182 | 8b0: 2f 91 pop r18 |
183 | 8b2: 0f 90 pop r0 |
184 | 8b4: 0f be out 0x3f, r0 ; 63 |
185 | 8b6: 0f 90 pop r0 |
186 | 8b8: 1f 90 pop r1 |
187 | 8ba: 18 95 reti |
Der wesentliche Ausschnitt ist der hier
1 | if (pwm_cnt == 0) { // set ports at begin of PWM |
2 | 7f4: 66 23 and r22, r22 |
3 | 7f6: 99 f4 brne .+38 ; 0x81e <__vector_13+0xa4> |
4 | PORTD = tmp.ary[0] | 0x0F; // PD0-3 no change |
5 | 7f8: 9b b9 out 0x0b, r25 ; 11 |
6 | PORTC = tmp.ary[1]; |
7 | 7fa: 38 b9 out 0x08, r19 ; 8 |
8 | PORTB = tmp.ary[2] | 0xF0; // PB4-7 no change |
9 | 7fc: 25 b9 out 0x05, r18 ; 5 |
10 | PORTA = tmp.ary[3]; |
11 | 7fe: 42 b9 out 0x02, r20 ; 2 |
12 | pwm_cnt++; |
13 | 800: 91 e0 ldi r25, 0x01 ; 1 |
14 | 802: 90 93 09 01 sts 0x0109, r25 |
Sieht recht optimal aus.
:
Bearbeitet durch User
A. K. schrieb: > Peter II schrieb: >> was macht das >> eor r19, r19 >> für einen sinn? > > Bei non-volatile lhs entfallen mov und eor. Das versteh ich nicht. @Falk: mir fehlt in Deinem Posting noch das Hexfile ;-) Ok, ich habs verstanden und ausprobiert, das Union hat gewonnen. Allerdings war -Os nix, weil dann meine inline functions per call aufgerufen werden. s=size und nicht s=superefficient. Zur Zeit nehme ich -Os und #defines - Blöcke statt functions, damit läufts wie gewünscht. Gruß, Michael
Michael Appelt schrieb: > Allerdings war -Os nix, weil dann meine inline functions per call > aufgerufen werden. s=size und nicht s=superefficient. dann verwende always_inline
Michael Appelt schrieb: >> Bei non-volatile lhs entfallen mov und eor. > > Das versteh ich nicht. "lhs" = left hand side, und zwar hier von der Zuweisung. Der Code mit dem EOR entsteht bei *(volatile uint8_t *)ptr = adr >> 8; aber nicht bei *(uint8_t *)ptr = adr >> 8;
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.