Forum: Compiler & IDEs AVR: unsigned 24 bit auf 3 Ports verteilen


von Michael A. (micha54)


Lesenswert?

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

von Jonas B. (jibi)


Lesenswert?

Da fehlen die casts...

gruß Jonas

von Oliver S. (oliverso)


Lesenswert?

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

von Jonas B. (jibi)


Lesenswert?

>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

von Michael A. (micha54)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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
}

von Oliver S. (oliverso)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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.

von Michael A. (micha54)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

Michael Appelt schrieb:
> naja, bei einem Call stehen diese Parameter bei meinem Programm immer in
> Registern.

es gibt aber bei inline keinen call mehr.

von Peter D. (peda)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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.

von Jonas B. (jibi)


Lesenswert?

>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
von Michael A. (micha54)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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.

von Michael A. (micha54)


Lesenswert?

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

von Yalu X. (yalu) (Moderator)


Lesenswert?

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 ;-)

von Michael A. (micha54)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von Oliver S. (oliverso)


Lesenswert?

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

von Michael A. (micha54)


Lesenswert?

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

von Yalu X. (yalu) (Moderator)


Lesenswert?

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 ...

von Michael A. (micha54)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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?

von (prx) A. K. (prx)


Lesenswert?

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
von Michael A. (micha54)


Lesenswert?

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
von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> was macht das
> eor  r19, r19
> für einen sinn?

Bei non-volatile lhs entfallen mov und eor.

von Falk B. (falk)


Lesenswert?

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
von Michael A. (micha54)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
Noch kein Account? Hier anmelden.