@ 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