Jak skutecznie zastosować inline w WinAVR, by przyspieszyć obsługę przerwań?
inline w WinAVR
From: "Bogdan Gutknecht" <b_gutknecht_at_nospam_interia.pl>
Subject: inline w WinAVR
Date: Mon, 14 Nov 2005 08:22:15 +0100
Chciałbym przyspieszyć krytyczne operacje w przerwaniu. Chodzi o programową
obsługę transmisji szeregowej. Przerwanie jest co 34us, a linie są cztery.
Jeśli obsługę umieszczę w procedurze to mam ładny program, ale wolny - tracę
na każdorazowym wywołaniu prawie 5 us, co daje razem 20. I tu mam problem.
Próbowałem zastosować specyfikator inline, niestety kompilator jakby go nie
widział. Ma do tego zresztą prawo według specyfikacji. Czy mogę w jakiś
sposób zmusić go do przepisywania kodu zamiast wywoływania procedury?
BG
From: Jurek Szczesiul <jerzy.szczesiul_at_nospam_wycin.ep.com.pl>
Subject: Re: inline w WinAVR
Date: Mon, 14 Nov 2005 08:38:44 +0100
Mon, 14 Nov 2005 08:22:15 +0100, na pl.misc.elektronika, Bogdan Gutknecht
napisał(a):
Chciałbym przyspieszyć krytyczne operacje w przerwaniu. Chodzi o programową
obsługę transmisji szeregowej. Przerwanie jest co 34us, a linie są cztery.
Jeśli obsługę umieszczę w procedurze to mam ładny program, ale wolny - tracę
na każdorazowym wywołaniu prawie 5 us, co daje razem 20. I tu mam problem.
Próbowałem zastosować specyfikator inline, niestety kompilator jakby go nie
widział. Ma do tego zresztą prawo według specyfikacji. Czy mogę w jakiś
sposób zmusić go do przepisywania kodu zamiast wywoływania procedury?
BG
Dla kodu w C użyj dla handlera atrybutu naked - będzie bez prologu i
epilogu, ale całą ochronę rejestrów i reti trzeba wpisać samemu.
A jak ma byc rzeczywiście max szybkość to chyba najpewniej będzie
wyrzucić obsługę do modułu .S i popisać w czystym asm np. jakoś tak:
[..]
// s interrupt
//#define __SFR_OFFSET 0
#include <avr/io.h>
.global SIG_INTERRUPT1
.section .text,"ax",_at_nospam_progbits
SIG_INTERRUPT1:
push r24
ldi r24,0x40
out _SFR_IO_ADDR(PORTB),r24
pop r24
reti
--
Pozdrowienia
Jurek Szczesiul
From: "Bogdan Gutknecht" <b_gutknecht_at_nospam_interia.pl>
Subject: Re: inline w WinAVR
Date: Mon, 14 Nov 2005 09:15:36 +0100
Użytkownik "Jurek Szczesiul" <jerzy.szczesiul_at_nospam_wycin.ep.com.pl> napisał w
wiadomości news:1il1pzelkigyr$.1ptjq40x7kfxx.dlg_at_nospam_40tude.net...
Mon, 14 Nov 2005 08:22:15 +0100, na pl.misc.elektronika, Bogdan Gutknecht
napisał(a):
Chciałbym przyspieszyć krytyczne operacje w przerwaniu. Chodzi o
programową
obsługę transmisji szeregowej. Przerwanie jest co 34us, a linie są
cztery.
Jeśli obsługę umieszczę w procedurze to mam ładny program, ale wolny -
tracę
na każdorazowym wywołaniu prawie 5 us, co daje razem 20. I tu mam
problem.
Próbowałem zastosować specyfikator inline, niestety kompilator jakby go
nie
widział. Ma do tego zresztą prawo według specyfikacji. Czy mogę w jakiś
sposób zmusić go do przepisywania kodu zamiast wywoływania procedury?
BG
Dla kodu w C użyj dla handlera atrybutu naked - będzie bez prologu i
epilogu, ale całą ochronę rejestrów i reti trzeba wpisać samemu.
A jak ma byc rzeczywiście max szybkość to chyba najpewniej będzie
wyrzucić obsługę do modułu .S i popisać w czystym asm np. jakoś tak:
[..]
// s interrupt
//#define __SFR_OFFSET 0
#include <avr/io.h>
.global SIG_INTERRUPT1
.section .text,"ax",_at_nospam_progbits
SIG_INTERRUPT1:
push r24
ldi r24,0x40
out _SFR_IO_ADDR(PORTB),r24
pop r24
reti
--
> Pozdrowienia
> Jurek Szczesiul
Jedną ze szczęśliwszych chwil w moim życiu zawodowym było odkrycie gcc-avr.
Nie muszę się martwić o alokację zmiennych, zabezpieczanie na stosie,
arytmetykę i wiele innych, koniecznych, aczkolwiek nużących rzeczy, które
dodatkowo mogą być przyczyną kretyńskich błędów. Będę więc próbował nie
schodzić na "niższy" poziom tak długo jak się da. Tym bardziej, że w tym
przerwaniu ma być nie tylko odczytywanie i zapis linii, ale cały automat
odczytu i zapisu oraz obsługa bufora.
Chyba jednak wolę zmniejszyć szybkość transmisji do 4800, niż pisać w
asemblerze (starzeję się - zostały mi tylko ciepłe kapcie i C).
From: Jurek Szczesiul <jerzy.szczesiul_at_nospam_wycin.ep.com.pl>
Subject: Re: inline w WinAVR
Date: Mon, 14 Nov 2005 21:20:17 +0100
Mon, 14 Nov 2005 09:15:36 +0100, na pl.misc.elektronika, Bogdan Gutknecht
napisał(a):
Chyba jednak wolę zmniejszyć szybkość transmisji do 4800, niż pisać w
asemblerze (starzeję się - zostały mi tylko ciepłe kapcie i C).
Ja w sumie tak samo :-)
Podsunąłem typowe opisywane rozwiązania - sam ich też nie miałem potrzeby
używać.
Fakt, że avr-gcc nie analizuje użycia rejestrów w funkcjach wywoływanych z
handlera przerwania i na wszelki wypadek pcha na stos wszystko ( chyba
głownie o to tu chodzi ? ) co niepotrzebnie wydłuża.
Więc albo pisać wszystko bezpośrednio w handlerze, albo dopomóc sobie
makrami, albo jednak dalej próbować z inline - w przypadku prostych funkcji
to działa, na przykład :
extern void Little(char x);
void Little(char x)
{
PORTB=x;
}
SIGNAL (SIG_INTERRUPT0)
{
//PORTB=0x20;
Little(0x20);
}
generuje dość przeraźliwie nadmiarowy kod :
SIGNAL (SIG_INTERRUPT0)
{
96: 1f 92 push r1
98: 0f 92 push r0
9a: 0f b6 in r0, 0x3f ; 63
9c: 0f 92 push r0
9e: 11 24 eor r1, r1
a0: 2f 93 push r18
a2: 3f 93 push r19
a4: 4f 93 push r20
a6: 5f 93 push r21
a8: 6f 93 push r22
aa: 7f 93 push r23
ac: 8f 93 push r24
ae: 9f 93 push r25
b0: af 93 push r26
b2: bf 93 push r27
b4: ef 93 push r30
b6: ff 93 push r31
//PORTB=0x20;
Little(0x20);
b8: 80 e2 ldi r24, 0x20 ; 32
ba: eb df rcall .-42 ; 0x92
bc: ff 91 pop r31
be: ef 91 pop r30
c0: bf 91 pop r27
c2: af 91 pop r26
c4: 9f 91 pop r25
c6: 8f 91 pop r24
c8: 7f 91 pop r23
ca: 6f 91 pop r22
cc: 5f 91 pop r21
ce: 4f 91 pop r20
d0: 3f 91 pop r19
d2: 2f 91 pop r18
d4: 0f 90 pop r0
d6: 0f be out 0x3f, r0 ; 63
d8: 0f 90 pop r0
da: 1f 90 pop r1
dc: 18 95 reti
Natomiast deklaracja inline :
extern inline void Little(char x);
natychmiast robi to co chcemy ( wynik dla -Os )
SIGNAL (SIG_INTERRUPT0)
{
96: 1f 92 push r1
98: 0f 92 push r0
9a: 0f b6 in r0, 0x3f ; 63
9c: 0f 92 push r0
9e: 11 24 eor r1, r1
a0: 8f 93 push r24
a2: 80 e2 ldi r24, 0x20 ; 32
a4: 88 bb out 0x18, r24 ; 24
a6: 8f 91 pop r24
a8: 0f 90 pop r0
aa: 0f be out 0x3f, r0 ; 63
ac: 0f 90 pop r0
ae: 1f 90 pop r1
b0: 18 95 reti
Więc może po paru różnych podejściach uzyska się wystarczający rezultat.
--
Pozdrowienia
Jurek Szczesiul
From: Zbych <abuse_at_nospam_onet.pl>
Subject: Re: inline w WinAVR
Date: Mon, 14 Nov 2005 21:39:14 +0100
Jurek Szczesiul przemówił ludzkim głosem:
Fakt, że avr-gcc nie analizuje użycia rejestrów w funkcjach wywoływanych z
handlera przerwania i na wszelki wypadek pcha na stos wszystko ( chyba
głownie o to tu chodzi ? ) co niepotrzebnie wydłuża.
Ale tendencyjny przykład dobrałeś :-). Gcc nie odkłada wszystkich
rejestrów na stos jak jest w stanie śledzić ich zużycie. A że nie śledzi
co się dzieje wewnątrz wywoływanych funkcji to profilaktycznie kładzie
na stos wszystko. Wystarczy nie wywoływać funkcji z wnętrza przerwania.
From: Jurek Szczesiul <jerzy.szczesiul_at_nospam_wycin.ep.com.pl>
Subject: Re: inline w WinAVR
Date: Mon, 14 Nov 2005 22:31:10 +0100
Mon, 14 Nov 2005 21:39:14 +0100, na pl.misc.elektronika, Zbych napisał(a):
Jurek Szczesiul przemówił ludzkim głosem:
Fakt, że avr-gcc nie analizuje użycia rejestrów w funkcjach wywoływanych z
handlera przerwania i na wszelki wypadek pcha na stos wszystko ( chyba
głownie o to tu chodzi ? ) co niepotrzebnie wydłuża.
Ale tendencyjny przykład dobrałeś :-). Gcc nie odkłada wszystkich
rejestrów na stos jak jest w stanie śledzić ich zużycie. A że nie śledzi
co się dzieje wewnątrz wywoływanych funkcji to profilaktycznie kładzie
na stos wszystko. Wystarczy nie wywoływać funkcji z wnętrza przerwania.
No, ja właśnie o tym samym , hau, miau :-)
--
Pozdrowienia
Jurek Szczesiul