Schiebeoperation mit int16_t-Variable

Gast #797605
Lesenswert?

Hallo,

ich möchte eine Division durch 4 mittels Schiebeoperation durchführen, 
da der Compiler (Optimierung -Os), das wohl nicht automatisch macht, 
sondern eine rechenzeitintensivere Division durchführt.
Wenn ich das richtig verstanden habe, funktioniert das Schieben 
folgendermaßen:

1<<3 bedeutet: 0000 0001 -> 0000 1000
3<<4 bedeutet: 0000 0011 -> 0011 0000

Eigentlich sollte ich das dann ja auch einach für eine als int16_t 
deklarierte Variable so anwenden können?

also:
int16_t mean;
mean = mean>>2

Wird das so funktionieren?
#797637
Lesenswert?

Dennis wrote:
> Hallo,
>
> ich möchte eine Division durch 4 mittels Schiebeoperation durchführen,
> da der Compiler (Optimierung -Os), das wohl nicht automatisch macht,

Was, zumindest beim gcc, im Übrigen nicht stimmt.
Der Compiler achtet nur darauf, nicht den gleichen Fehler zu
machen und bei negativen Zahlen in die falsche Richtung zu gehen :-)

Wenn die Variable aber sowieso nicht negativ werden kann, erhebt
sich die Frage, warum sie dann ein int16_t ist und kein uint16_t.
Denn dann klappts beim gcc auch wieder mit dem einfachen Schieben.

Ich bleibe dabei: Solche Low-Level Optimierungen überlässt man
sinnigerweise dem Compiler. Der kann das besser.
#797663
Lesenswert?

@  Karl heinz Buchegger (kbuchegg) (Moderator)

>Ich bleibe dabei: Solche Low-Level Optimierungen überlässt man
>sinnigerweise dem Compiler. Der kann das besser.

Nur bedingt. Ich hab vor kurzen ein kleines Projekt gemacht, Soft-PWM 
mit 20 Kanälen. Dort wird im Interrupt ein uint32_t gelesen und 
byteweise auf die Ports geschrieben.

1
ISR(TIMER1_COMPA_vect) {
2

3
    static uint8_t pwm_cnt;
4
    uint32_t tmp;
5

6

7
    OCR1A   += isr_ptr->time[pwm_cnt];
8
    tmp      = isr_ptr->mask[pwm_cnt];
9
    
10
    if (pwm_cnt == 0) {
11
        PORTA = tmp;                            // set ports at begin of PWM
12
        PORTC = tmp>>8;
13
        PORTD = tmp>>16;
14
        pwm_cnt++;
15
    }
16
    else {      
17
        PORTA &= tmp;                       // clear ports
18
        PORTC &= tmp>>8;
19
        PORTD &= tmp>>16;                        
20
        if (pwm_cnt == pwm_cnt_max) {
21
            pwm_sync = 1;                           // update now possible
22
            pwm_cnt=0;
23
        }
24
        else pwm_cnt++;
25
    } 
26
}

GCC ist in allen Optimierungsstufen NICHT clever genug, einfach die 
richtigen Register in die IO-Ports zu schreiben. Er erkennt zwar, dass 
man das per Bytekopie machen kann, kopiert und löscht aber noch 
unsinnigerweise Register, die in der realen Schiebeoperation gelöscht 
werden.

Erst der (halblegale) Trick per Union erreicht das gewünschte, optimale 
Ergebnis.

1
ISR(TIMER1_COMPA_vect) {
2
    typedef union {                 // little trick, to speed up data access
3
        uint32_t d32;
4
        uint8_t ary[4];
5
        } ut_t;
6

7
    static uint8_t pwm_cnt;
8
    ut_t tmp;
9

10

11
    OCR1A   += isr_ptr->time[pwm_cnt];
12
    tmp.d32  = isr_ptr->mask[pwm_cnt];
13
    
14
    if (pwm_cnt == 0) {
15
        PORTA = tmp.ary[0];                         // set ports at begin of PWM
16
        PORTC = tmp.ary[1];
17
        PORTD = tmp.ary[2];
18
        pwm_cnt++;
19
    }
20
    else {      
21
        PORTA &= tmp.ary[0];                        // clear ports
22
        PORTC &= tmp.ary[1];
23
        PORTD &= tmp.ary[2];                        
24
        if (pwm_cnt == pwm_cnt_max) {
25
            pwm_sync = 1;                           // update now possible
26
            pwm_cnt=0;
27
        }
28
        else pwm_cnt++;
29
    } 
30
}

Mfg
Falk

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren