Goto page 1, 2 Next
Lukasz
Guest
Wed Feb 07, 2007 1:36 pm
W moim programie chciałbym zmieniać wektory przerwań w zalezności od
kontekstu, w którym jest program. W tej chwili robię to na przykład tak:
uint8_t kontekst = 0;
ISR(TIMER0_OVF_vect){
switch (kontekst){
case 0:
(...)
break;
case 1:
(...)
break;
}
}
Jednak, czy można to zrobić w taki sposób, żeby zdefiniować kilka funkcji
przerwań i podmieniać ich wektory w zależności od kontekstu? W assemblerze
nie ma problemu, a jak to zrobić w GCC?
Dziękuję
Lukasz
Jakub Gocaliński
Guest
Wed Feb 07, 2007 1:46 pm
"Lukasz" <lstela@poczta.onet.WYTNIJpl> wrote in message
news:eqch41$6pj$1@news.onet.pl...
Quote:
W moim programie chciałbym zmieniać wektory przerwań w zalezności od
kontekstu, w którym jest program. W tej chwili robię to na przykład tak:
uint8_t kontekst = 0;
ISR(TIMER0_OVF_vect){
switch (kontekst){
case 0:
(...)
break;
case 1:
(...)
break;
}
}
Jednak, czy można to zrobić w taki sposób, żeby zdefiniować kilka funkcji
przerwań i podmieniać ich wektory w zależności od kontekstu? W assemblerze
nie ma problemu, a jak to zrobić w GCC?
A po co tak kombinujesz? Chyba sprawdzenie warunku nie jest jakąś bardzo
obciażającą dla procka czynnością:)
Pytam z ciekawości, bo nie widzę większego sensu nad zagłebianiem się w ten
temat. No chyba, że chodzi Ci o oszczędności miejsca:)
pozdrawiam, Kuba
T.M.F.
Guest
Wed Feb 07, 2007 4:24 pm
Quote:
W moim programie chciałbym zmieniać wektory przerwań w zalezności od
kontekstu, w którym jest program. W tej chwili robię to na przykład tak:
uint8_t kontekst = 0;
ISR(TIMER0_OVF_vect){
switch (kontekst){
case 0:
(...)
break;
case 1:
(...)
break;
}
}
Jednak, czy można to zrobić w taki sposób, żeby zdefiniować kilka funkcji
przerwań i podmieniać ich wektory w zależności od kontekstu? W assemblerze
nie ma problemu, a jak to zrobić w GCC?
Dokladnie tak samo jak w assemblerze. O ile cie dobrze zrozumialem to
chesz podmieniac adres procedury obslugi przerwania? Kiepski pomysl, bo
to wymaga za kazdym razem reprogramowania FLASHa, wiec to co masz w
postaci switch/case jest zupelnie ok. Kompilator pewnie i tak to
zoptymalizuje tak, ze wielkiego opoznienia nie bedzie, ew. zrob mala
plombe w assemblerze.
--
Inteligentny dom -
http://idom.wizzard.one.pl
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz sie do projektu.
Lukasz
Guest
Wed Feb 07, 2007 4:52 pm
Quote:
Kiepski pomysl, bo to wymaga za kazdym razem reprogramowania FLASHa, wiec
to co masz w postaci switch/case jest zupelnie ok. Kompilator pewnie i tak
to zoptymalizuje tak, ze wielkiego opoznienia nie bedzie, ew. zrob mala
plombe w assemblerze.
No tak. Zapomniałem, że wektory przerwań są we flashu...
Dzieki!
--
Lukasz
Pawel K
Guest
Thu Feb 08, 2007 12:35 pm
Lukasz napisał(a):
Jednak, czy można to zrobić w taki sposób, żeby zdefiniować kilka funkcji
Quote:
przerwań i podmieniać ich wektory w zależności od kontekstu? W assemblerze
nie ma problemu, a jak to zrobić w GCC?
chyba mozna
void rtcAttach(void (*userFunc)(void)) {
rtcIntFunc = userFunc;
}
void rtcDetach(void) {
rtcIntFunc = 0;
}
SIGNAL(SIG_INTERRUPT4) {
if ( rtcIntFunc ) rtcIntFunc();
}
rtcAttach(jeden);
rtcDetach();
rtcAttach(dwa);
void jeden (void){}
void dwa (void){}
Zbych
Guest
Thu Feb 08, 2007 6:38 pm
Pawel K przemówił ludzkim głosem:
Quote:
Lukasz napisał(a):
Jednak, czy można to zrobić w taki sposób, żeby zdefiniować kilka funkcji
przerwań i podmieniać ich wektory w zależności od kontekstu? W assemblerze
nie ma problemu, a jak to zrobić w GCC?
void rtcAttach(void (*userFunc)(void)) {
rtcIntFunc = userFunc;
}
void rtcDetach(void) {
rtcIntFunc = 0;
}
Te przypisania nie są atomowe i program będzie się sypał.
Quote:
SIGNAL(SIG_INTERRUPT4) {
if ( rtcIntFunc ) rtcIntFunc();
}
Tutaj kompilator nie będzie w stanie określić, które rejestry są
niszczone przez wywoływaną funkcję i profilaktycznie odłoży wszystkie.
Chyba pomysł, ze switchem jest jednak lepszy.
Grzegorz Kurczyk
Guest
Thu Feb 08, 2007 9:19 pm
Użytkownik Adam Wysocki napisał:
Quote:
Spinacz biurowy, Lukasz <lstela@poczta.onet.wytnijpl>!
Jednak, czy można to zrobić w taki sposób, żeby zdefiniować kilka funkcji
przerwań i podmieniać ich wektory w zależności od kontekstu?
Jak sobie to wyobrażasz?
W assemblerze nie ma problemu,
W assemblerze AVR? Niewykonalne. Przecież wektory leżą w przestrzeni programu.
W assemblerze... czemu nie ? Może nie wprost, ale pośrednio. W miejscu
wektora zamiast tradycyjnego rozkazu RJMP wstawiamy IJMP. Tylko musimy
dbać coby niepotrzebnie nie tykać rejesrtów R30:R31. A przy ustawianiu
nowego wektora posługiwać się rozkazem movw (lub blokować przerwanie na
czas modyfikacji). Wadą jest to, że mozemy tak sobie obskoczyć tylko
jeden wektor przerwania no i wspomniana dość bolesna nietykalność pary
rejestrów Z. Inna sprawa to zasadność takiego rozwiązania. W wielu
przypadkach konstrukcja typu switch(cośtam) powinna być wystarczająca,
ale ma pewną wadę. Czas reakcji procedury obsługi przerwania będzie
zależał od jej położenia w łańcuszku case co w pewnych przypadkach może
być nie do przyjęcia. Wektoryzując przerwanie przez IJMP mamy pewność,
że od chwili przyjecia przerwania do wejścia w procedurę obsługi mija
zawsze ten sam czas.
Pozdrawiam
Grzegorz
Adam Wysocki
Guest
Thu Feb 08, 2007 9:41 pm
Spinacz biurowy, Lukasz <lstela@poczta.onet.wytnijpl>!
Quote:
Jednak, czy można to zrobić w taki sposób, żeby zdefiniować kilka funkcji
przerwań i podmieniać ich wektory w zależności od kontekstu?
Jak sobie to wyobrażasz?
Quote:
W assemblerze nie ma problemu,
W assemblerze AVR? Niewykonalne. Przecież wektory leżą w przestrzeni programu.
Jak tak bardzo boli cię switch, to zrób tablicę wskaźników do funkcji
indeksowaną kontekstem i wywołuj funkcję indeksując tą tablicę.
--
Adam Wysocki * Warszawa *
http://www.chmurka.net/ * GSM: 514 710 213
Korea czy Japonia, pies czy kot dla mnie jedna świnia (C) Sosna @ CB
Adam Wysocki
Guest
Thu Feb 08, 2007 9:41 pm
Spinacz biurowy, Grzegorz Kurczyk <grzegorz.usun.to@control.slupsk.pl>!
Quote:
W miejscu wektora zamiast tradycyjnego rozkazu RJMP wstawiamy IJMP.
Tylko musimy dbać coby niepotrzebnie nie tykać rejesrtów R30:R31.
Ano właśnie...
IMO za duży koszt.
Quote:
W wielu przypadkach konstrukcja typu switch(cośtam) powinna być
wystarczająca, ale ma pewną wadę. Czas reakcji procedury obsługi
przerwania będzie zależał od jej położenia w łańcuszku case co
w pewnych przypadkach może być nie do przyjęcia.
Coś typu (oczywiście printf itd. zamienić, przykład tylko do pokazania
zasady, ale kompiluje się i działa na nie-avrowym gcc).
#include <stdio.h>
typedef void (*fn_t) (void);
static void f1(void) { printf("1\n"); }
static void f2(void) { printf("2\n"); }
static void f3(void) { printf("3\n"); }
static fn_t tab[3] = {f1, f2, f3};
static void dispatch(int n) { tab[n](); }
int main(void)
{
dispatch(0);
dispatch(1);
dispatch(2);
return 0;
}
--
Adam Wysocki * Warszawa *
http://www.chmurka.net/ * GSM: 514 710 213
Jesteś emocjonalnie wykolejony (C) Bylinek do futszaK-a na apff 2002
Adam Wysocki
Guest
Thu Feb 08, 2007 9:41 pm
Spinacz biurowy, Grzegorz Kurczyk <grzegorz.usun.to@control.slupsk.pl>!
Quote:
W miejscu wektora zamiast tradycyjnego rozkazu RJMP wstawiamy IJMP.
Tylko musimy dbać coby niepotrzebnie nie tykać rejesrtów R30:R31.
Ano właśnie...
IMO za duży koszt.
Quote:
W wielu przypadkach konstrukcja typu switch(cośtam) powinna być
wystarczająca, ale ma pewną wadę. Czas reakcji procedury obsługi
przerwania będzie zależał od jej położenia w łańcuszku case co
w pewnych przypadkach może być nie do przyjęcia.
Coś typu (oczywiście printf itd. zamienić, przykład tylko do pokazania
zasady, ale kompiluje się i działa na nie-avrowym gcc).
#include <stdio.h>
typedef void (*fn_t) (void);
static void f1(void) { printf("1\n"); }
static void f2(void) { printf("2\n"); }
static void f3(void) { printf("3\n"); }
static fn_t tab[3] = {f1, f2, f3};
static void dispatch(size_t n) { tab[n](); }
int main(void)
{
dispatch(0);
dispatch(1);
dispatch(2);
return 0;
}
--
Adam Wysocki * Warszawa *
http://www.chmurka.net/ * GSM: 514 710 213
Jesteś emocjonalnie wykolejony (C) Bylinek do futszaK-a na apff 2002
Pawel K
Guest
Fri Feb 09, 2007 11:25 am
Zbych napisał(a):
Quote:
Te przypisania nie są atomowe i program będzie się sypał.
SIGNAL(SIG_INTERRUPT4) {
if ( rtcIntFunc ) rtcIntFunc();
}
Tutaj kompilator nie będzie w stanie określić, które rejestry są
niszczone przez wywoływaną funkcję i profilaktycznie odłoży wszystkie.
Chyba pomysł, ze switchem jest jednak lepszy.
ale to nie wyssane z palca ... to procedury z ktorych
kozystam... przypatrz sie dobrze ... zmienia sie tylko
wskaznik do wywolywanej funkcji. Poza tym nie jest
tak ze wszystkie rejestry ida na stos przy przerwaniu???
T.M.F.
Guest
Fri Feb 09, 2007 1:50 pm
Quote:
Te przypisania nie są atomowe i program będzie się sypał.
SIGNAL(SIG_INTERRUPT4) {
if ( rtcIntFunc ) rtcIntFunc();
}
Tutaj kompilator nie będzie w stanie określić, które rejestry są
niszczone przez wywoływaną funkcję i profilaktycznie odłoży wszystkie.
Chyba pomysł, ze switchem jest jednak lepszy.
ale to nie wyssane z palca ... to procedury z ktorych
kozystam... przypatrz sie dobrze ... zmienia sie tylko
wskaznik do wywolywanej funkcji. Poza tym nie jest
tak ze wszystkie rejestry ida na stos przy przerwaniu???
Problem polega na tym, ze zmieniasz 16 bitowy wskaznik. Jesli kompilator
uzyje movw, lub zablokujesz przerwania na czas zmiany to jest ok, jesli
nie to przerwanie ktore nadejdzie w trakcie wymiany polowki wskaznika
spowoduje wywolanie procedury pod nieprawidlowym adresem i program
pojdzie w maliny. Szansa na to jest bardzo mala, bo przerwanie musi
nastapic dokladnie pomiedzy instrukcjami przesylajacymi 8-bitowe czesci
wskaznika, stad mogles tego nie zaobserwowac, ale w koncu ten efekt
nastapi. Zgodnie z prawami Murphiego w najmniej pozadanym momencie:)
Druga rzecz to efektywnosc. To co napisales spowoduje wygenerowanie kodu
polegajacego nie na zmianie wektora przerwan. Zawsze nastapi wywolanie:
SIGNAL(SIG_INTERRUPT4) {
if ( rtcIntFunc ) rtcIntFunc();
natomiast dopiero w procedurze obslugi przerwania nastapi skok do
procedury ktorej adres zawiera wskaznik. IMHO niczym sie to nie rozni od
jawnej instrukcji switch, mysle, ze nawet generowany kod assemblerowy
moze byc podobny. Bedzie nawet gorsze, bo jak pisal Zbych kompilator nie
bedzie wstanie zoptymalizowac odkladanych na stos rejestrow.
--
Inteligentny dom -
http://idom.wizzard.one.pl
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz sie do projektu.
Pawel K
Guest
Mon Feb 12, 2007 10:38 am
T.M.F. napisał(a):
Quote:
Problem polega na tym, ze zmieniasz 16 bitowy wskaznik. Jesli kompilator
uzyje movw, lub zablokujesz przerwania na czas zmiany to jest ok, jesli
nie to przerwanie ktore nadejdzie w trakcie wymiany polowki wskaznika
spowoduje wywolanie procedury pod nieprawidlowym adresem i program
pojdzie w maliny. Szansa na to jest bardzo mala, bo przerwanie musi
nastapic dokladnie pomiedzy instrukcjami przesylajacymi 8-bitowe czesci
wskaznika, stad mogles tego nie zaobserwowac, ale w koncu ten efekt
nastapi. Zgodnie z prawami Murphiego w najmniej pozadanym momencie:)
takie samo jest ryzyko na bledne odczytanie lub zapisanie
16bit rejestru licznika TIMEROW. Ten problem jest opisany w faq.
Adam Dybkowski
Guest
Tue Feb 13, 2007 10:54 pm
Pawel K napisał(a):
Quote:
Problem polega na tym, ze zmieniasz 16 bitowy wskaznik.
[...]
Quote:
takie samo jest ryzyko na bledne odczytanie lub zapisanie
16bit rejestru licznika TIMEROW. Ten problem jest opisany w faq.
Właśnie nie. 16-bitowe liczniki timerów w AVRach są traktowane
specjalnie i dostęp do nich jest synchronizowany pod warunkiem, że
najpierw odbywa się do górnej połówki a potem do dolnej przy zapisie a
odwrotnie przy odczycie. Cytuję z dokumentacji procesora ATmega 128
(długie ale tłumaczy wszystkie zawiłości):
"The 16-bit register must be byte accessed using two read or write
operations. Each 16-bit timer has a single 8-bit register for temporary
storing of the high byte of the 16-bit access. The same Temporary
register is shared between all 16-bit registers within each 16-bit
timer. Accessing the low byte triggers the 16-bit read or write
operation. When the low byte of a 16-bit register is written by the
CPU, the high byte stored in the Temporary Register, and the low byte
written are both copied into the 16-bit register in the same clock
cycle. When the low byte of a 16-bit register is read by the CPU, the
high byte of the 16-bit register is copied into the Temporary Register
in the same clock cycle as the low byte is read.
[...]
To do a 16-bit write, the high byte must be written before the low byte.
For a 16-bit read, the low byte must be read before the high byte."
Takiego wsparcia sprzętowego nie zapewnią własne 16-bitowe zmienne w
RAMie ogólnego przeznaczenia więc trzeba wyłączać przerwania na czas ich
zmieniania.
--
Adam Dybkowski
http://www.amwaw.edu.pl/~adybkows/
Uwaga: przed wysłaniem do mnie maila usuń cyfry z adresu.
Piotrek Sz.
Guest
Wed Feb 14, 2007 7:40 am
Lukasz <lstela@poczta.onet.WYTNIJpl> napisał(a):
Quote:
W moim programie chciałbym zmieniać wektory przerwań w zalezności od
kontekstu, w którym jest program. W tej chwili robię to na przykład tak:
uint8_t kontekst = 0;
ISR(TIMER0_OVF_vect){
switch (kontekst){
case 0:
(...)
break;
case 1:
(...)
break;
}
}
Jednak, czy można to zrobić w taki sposób, żeby zdefiniować kilka funkcji
przerwań i podmieniać ich wektory w zależności od kontekstu? W assemblerze
nie ma problemu, a jak to zrobić w GCC?
Dziękuję
Lukasz
Ja proponuję takie cuś ;-)
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t kontekst = 0;
typedef void (*vFuncPtr)(void);
void func1(void){PORTB=PINA;}
void func2(void){PORTA=PINB;}
void func3(void){PORTC=PORTA;}
void func4(void){PORTB=PINC;}
void func5(void){PORTA=PINA;}
void func6(void){PORTC=PORTB;}
//------------------------------------------------------
vFuncPtr faddr[] ={func1,func2,func3,func4,func5,func6};
ISR(TIMER0_OVF_vect){faddr[kontekst]();}
int main(void)
{
return(0);
}
Zdecydowanie lepsze(?) od "switch ... case"
Funkcje zmyślone , by uniknąć zoptymalizowania ;)
Piotrek
--
Wysłano z serwisu Usenet w portalu Gazeta.pl ->
http://www.gazeta.pl/usenet/
Goto page 1, 2 Next