RTV forum PL | NewsGroups PL

Sprawdzanie działania kodu do pomiaru częstotliwości sinusoidy 2-150Hz na ATmega128

AVR ATmega, pomiar częstotliwości przebiegu, prośba o spraw

NOWY TEMAT

elektroda NewsGroups Forum Index - Elektronika Polska - Sprawdzanie działania kodu do pomiaru częstotliwości sinusoidy 2-150Hz na ATmega128

Goto page Previous  1, 2, 3  Next

Marcin Wasilewski
Guest

Thu Feb 10, 2011 7:26 am   



Użytkownik "Robbo" <yyy@mmm.com> napisał w wiadomości
news:4d531cb8$0$2457$65785112@news.neostrada.pl...

Quote:
Dziękuję.
A chciałem jeszcze prosić o odpowiedź na pytanie dotyczące użycia
sei i cli w pętli głównej.

W wielkim skrócie - cli/sei używasz wtedy gdy dokonujesz zapisu/odczytu
zmiennych, które: wykorzystujesz też w przerwaniach i cała operacja zajmuje
więcej niż 1 operację procesora (zmienne dłuższe niż 1 bajt i operacje
bitowe). No i oczywiście wtedy gdy z pewnych przyczyn (głównie czasowych)
dana operacja nie powinna zostać przerwana obsługą przerwania.

Robbo
Guest

Thu Feb 10, 2011 4:09 pm   



Oto kod:

volatile unsigned short icr, prevIcr;

SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;
acutalDuration = icr - prevIcr;
prevIcr = icr;
}


int main(void)
{
char buf[16];
unsigned short actualDurationLatch;

TCCR3A = 0;
TCCR3B |= _BV(ICES3) | _BV(ICNC3) |
_BV(CS32) | _BV(30); // prescaler 64
ETIMSK |= _BV(TICIE3);

sei();

while (1) {
cli();
actualDurationLatch = actualDuration;
sei();

sprintf(s, "%u ", actualDurationLatch);
LCDwriteString(s);
}
}

Na kwarcu 16MHz i prescalerze 64, ICR3 zwiększa się z częstotliwością
1/250000. Dla 50Hz na wyświetlaczu mam liczbę 5000. Mogę zejść do ok. 2Hz --
poniżej już się nie da, bo licznik 16-bitowy ICR3 się przepełnia. Jednak 2Hz
jest dla mnie akceptowalnym wynikiem i nie potrzebuję już zwiększać
prescalera, kosztem obniżenia dokładności pomiaru.

Chciałem zapytać
1. Czy kod jest poprawny, a jeśli nie, to co poprawić?
2. Jak poradzić sobie teraz z "odcinaniem" dla częstotliwości mniejszej niż
2Hz?
Poniżej 2Hz licznik się przekręci i wskazany czas nie będzie poprawny;
może być też sytuacja, gdy sygnał zaniknie (częstotliwość 0Hz). Muszę mieć o
tym informację.
W moim programie z timerem nie było problemu (pokazywały się "---" na
wyświetlaczu dla zbyt niskich częstotliwości) -- tu nie wiem, jak to dobrze
rozwiązać.

R.

Zbych
Guest

Thu Feb 10, 2011 4:16 pm   



W dniu 2011-02-10 16:09, Robbo pisze:

Quote:
cli();
actualDurationLatch = actualDuration;
sei();

Chciałem zapytać
1. Czy kod jest poprawny, a jeśli nie, to co poprawić?

Nie używaj cli i sei do robienia sekcji atomowych, te makra nie są
zabezpieczone przed optymalizacją i kompilator może zmienić kolejność
instrukcji (choć oczywiście nie musi). Zamiast tego posłuż się
ATOMIC_BLOCK
http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html

Quote:
2. Jak poradzić sobie teraz z "odcinaniem" dla częstotliwości mniejszej
niż 2Hz?
Poniżej 2Hz licznik się przekręci i wskazany czas nie będzie poprawny;
może być też sytuacja, gdy sygnał zaniknie (częstotliwość 0Hz). Muszę
mieć o tym informację.

Albo zmniejsz taktowanie timera, albo wykorzystaj przerwanie od
przepełnienia do "dorobienia" trzeciego bajtu do licznika.

Robbo
Guest

Thu Feb 10, 2011 4:27 pm   



Quote:
... wykorzystaj przerwanie od przepełnienia do "dorobienia" trzeciego
bajtu do licznika.

Czy chodzi o coś takiego (pisane z pamięci)?

volatile unsigned long icr, prevIcr;
volatile char overflow;

SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;
acutalDuration = icr - prevIcr + overflow * 0xffffUL;
overflow = 0;
prevIcr = icr;
}

SIGNAL (SIG_INPUT_OVERFLOW3)
{
overflow++;
}

int main(void)
{
char buf[16];
unsigned long actualDurationLatch;

TCCR3A = 0;
TCCR3B |= _BV(ICES3) | _BV(ICNC3) |
_BV(CS32) | _BV(30); // prescaler 64
ETIMSK |= _BV(TICIE3) | _BV(TOIE3);

sei();

while (1) {
cli();
actualDurationLatch = actualDuration;
sei();

sprintf(s, "%ld ", actualDurationLatch);
LCDwriteString(s);
}
}

Jeśli chodzi o coś takiego, to mi nie działa. "overflow" impulsuje czasem na
wartość "1", bo ICR3 nieustannie się przepełnia.
Czy ktoś może wskazać, jak poprawnie zastosować rozwiązanie z
przepełnieniem?
To mogłoby być dobre rozwiązanie "odcięcia" niskich częstotliwości, tylko
nie wiem, jak poprawnie to zrealizować.

R.

Zbych
Guest

Thu Feb 10, 2011 4:46 pm   



W dniu 2011-02-10 16:27, Robbo pisze:
Quote:
... wykorzystaj przerwanie od przepełnienia do "dorobienia" trzeciego
bajtu do licznika.

Czy chodzi o coś takiego (pisane z pamięci)?

Po pierwsze jak obydwa przerwania (przechwytywanie i przepełnienie)
zostaną zgłoszone jednocześnie, to będziesz miał nieprawidłowy wynik.
Trzeba w przerwaniu od przechwytywania sprawdzać obecność nieobsłużonego
przepełnienia. Zmienna prev powinno pamiętać nie tylko stan licznika
sprzętowego, ale i software'owego. Zamiast mnożyć 65535 powinieneś
mnożyć przez 65536, a zdecydowanie lepiej przesunąć liczbę o 16-bitów
(albo jeszcze lepiej użyć unii liczby 32-bitowej z tablicą 4 bajtów, bo
gcc ma słabą optymalizację przy obsłudze długich liczb na avr). Do tego
trzeba pamiętać o ręcznym rzutowaniu na 32-bity przed przesunięciem, bo
kompilator tego za ciebie nie zrobi (co najwyżej zrobi promocję do
16-bitów, bo tyle ma int).

Michoo
Guest

Thu Feb 10, 2011 5:00 pm   



W dniu 10.02.2011 16:16, Zbych pisze:
Quote:
Nie używaj cli i sei do robienia sekcji atomowych, te makra nie są
zabezpieczone przed optymalizacją i kompilator może zmienić kolejność
instrukcji (choć oczywiście nie musi).
Chyba nie - definicja wyglądają tak:

# define sei() __asm__ __volatile__ ("sei" :Smile
# define cli() __asm__ __volatile__ ("cli" ::)

Co zabrania kompilatorowi zamiany kolejności ewaluacji wyrażeń.

Dziwne swoją drogą, że nie jest to zapisane na wszelki wypadek jako
# define sei() __asm__ __volatile__ ("sei" :::"memory")
ale może to wynika z tego, że ATOMIC_BLOCK robi barierę.

Quote:
Zamiast tego posłuż się
ATOMIC_BLOCK
Zwłaszcza, że przy ATOMIC_BLOCK trudniej o pomyłkę i od razu widać gdzie

jest synchronizacja.

--
Pozdrawiam
Michoo

Robbo
Guest

Thu Feb 10, 2011 7:15 pm   



Dziękuję za odpowiedź.

Quote:
Po pierwsze jak obydwa przerwania (przechwytywanie i przepełnienie)
zostaną zgłoszone jednocześnie, to będziesz miał nieprawidłowy wynik.

Racja.

Quote:
Zmienna prev powinno pamiętać nie tylko stan licznika sprzętowego, ale i
software'owego.

Tego trochę nie rozumiem. Czy nie masz może kodu, który
realizuje taki 24-, 32-bitowy licznik? Niestety, ale nie mogę
nic znaleźć, a szukam już kilka godzin :(

R.

Zbych
Guest

Thu Feb 10, 2011 7:35 pm   



W dniu 2011-02-10 17:00, Michoo pisze:
Quote:
W dniu 10.02.2011 16:16, Zbych pisze:
Nie używaj cli i sei do robienia sekcji atomowych, te makra nie są
zabezpieczone przed optymalizacją i kompilator może zmienić kolejność
instrukcji (choć oczywiście nie musi).
Chyba nie - definicja wyglądają tak:
# define sei() __asm__ __volatile__ ("sei" :Smile
# define cli() __asm__ __volatile__ ("cli" ::)

Co zabrania kompilatorowi zamiany kolejności ewaluacji wyrażeń.

volatile zabrania usunięcia, optymalizacji, ale nie zabroni przesunięcia
czegoś co jest pomiędzy sei i cli, czyli z kodu
cli();[coś];sei();
może wyjść:
cli();sei(); [coś];

Dodatkowo taka konstrukcja nie zmusza kompilatora do zapisania wartości
tymczasowych trzymanych w rejestrach do pamięci, więc może się okazać,
że zapis wielobajtowej zmiennej nastąpi już przy włączonych przerwaniach.

Przykłady można znaleźć na liście dyskusyjnej avr-gcc.

Quote:
Dziwne swoją drogą, że nie jest to zapisane na wszelki wypadek jako
# define sei() __asm__ __volatile__ ("sei" :::"memory")

No właśnie o tę barierę na pamięci chodzi.

Zbych
Guest

Thu Feb 10, 2011 7:56 pm   



W dniu 2011-02-10 19:15, Robbo pisze:
Quote:
Dziękuję za odpowiedź.

Po pierwsze jak obydwa przerwania (przechwytywanie i przepełnienie)
zostaną zgłoszone jednocześnie, to będziesz miał nieprawidłowy wynik.

Racja.

Zmienna prev powinno pamiętać nie tylko stan licznika sprzętowego, ale
i software'owego.

Tego trochę nie rozumiem. Czy nie masz może kodu, który
realizuje taki 24-, 32-bitowy licznik? Niestety, ale nie mogę
nic znaleźć, a szukam już kilka godzin Sad


Mniej więcej (raczej mniej niż więcej) widziałbym to tak:

uint32_t period;
uint8_t overflow;

SIGNAL (SIG_INPUT_CAPTURE3)
{
static uint32_t prev = 0;
union{
struct{
uint16_t byte01;
uint8_t byte2;
uint8_t byte3
}s;
uint32_t dword;
}now;

uint32_t now.s.byte01 = ICR3;

if (przepełnienie){
overflow++;
skasuj_przepełnienie;
}
now.s.byte2 = overflow;
now.s.byte3 = 0;
period = now.dword - prev;
prev = now.dword;
}

SIGNAL (SIG_INPUT_OVERFLOW3)
{
overflow++;
}



Nie chce mi się teraz szukać w dokumentacji jak się nazywają rejestry z
flagami od przepełnienia, więc musisz fragment ze sprawdzaniem
przepełnienia odpowiednio uzupełnić.

Robbo
Guest

Thu Feb 10, 2011 9:56 pm   



Dziękuję bardzo za ten kod. Przykład z wykorzystaniem union oraz struct
również bardzo cenny!

Twój kod, tak na szybko, bez union i struct (chodzi o samą ideę):

SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;

if (ETIFR & _BV(TOV3)) {
overflow++;
ETIFR |= _BV(TOV3);
ff++; // licznik zdarzeń tego typu
}

actualDuration = ((unsigned long)icr + overflow * 65536UL) - pp;
pp = (unsigned long)icr + overflow * 65536UL;
}

SIGNAL (SIG_OVERFLOW3)
{
overflow++;
}

Wyświetlam sobie na LCD wartość ff. Na ogół ma wartość "1" i tak już
zostaje. Wynika z tego, że bardzo rzadko mam sytuację z jednoczesnymi
przerwaniami.

Wydaje mi się, że możliwe jest jeszcze pewne uproszczenie -- w praktyce mi
ono zdaje egzamin (a przynajmniej tak mi się wydaje na podstawie
obserwacji). Chodzi o to, że u Ciebie "overflow" inkrementowany jest
nieustannie. To nie jest błąd -- wszystko działa jak należy. Niemniej ja
chciałem mieć "overflow" zerowany, gdyż zależnie od jego wartości chciałem
zrobić odcinanie niskich częstotliwości mierzonego sygnału. Oto przeróbka:

*** KROK 1

SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;

if (ETIFR & _BV(TOV3)) {
overflow++;
ETIFR |= _BV(TOV3);
}

actualDuration = ((unsigned long)icr + overflow * 65536UL) - pp;
pp = (unsigned long)icr + overflow * 65536UL;

pp -= overflow * 65536UL;
overflow = 0;
}

powyższe można uprościć do takiej postaci:

*** KROK 2

SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;

if (ETIFR & _BV(TOV3)) {
overflow++;
ETIFR |= _BV(TOV3);
}

actualDuration = ((unsigned long)icr + overflow * 65536UL) - pp;
pp = (unsigned long)icr;

overflow = 0;
}

Zatem wydaje mi się (może się mylę, ale w praktyce działa i wygląda OK), że
w "pp" nie musimy trzymać wartości licznika software'owego, a wystarczy
trzymać ICR.
Co o tym myślisz?

A oto kompletny kod -- odcinamy poniżej ok. 2Hz (w szczególności, gdy sygnał
w ogóle jest zerowy).

SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;

if (ETIFR & _BV(TOV3)) {
overflow++;
ETIFR |= _BV(TOV3);
}

actualDuration = ((unsigned long)icr + overflow * 65536UL) - pp;
pp = (unsigned long)icr;

overflow = 0;
}

SIGNAL (SIG_OVERFLOW3)
{
overflow++;
}

int main(void)
{
char buf[16];
unsigned long actualDurationLatch;

TCCR3A = 0;
TCCR3B |= _BV(ICES3) | _BV(ICNC3) |
_BV(CS32) | _BV(30); // prescaler 64
ETIMSK |= _BV(TICIE3) | _BV(TOIE3);

sei();

while (1) {
cli();
actualDurationLatch = actualDuration;
sei();

if ((overflow >= 5) || (actualDurationLatch > 150000)) {
LCDwriteString("-------------");
} else {
sprintf(s, "%ld ", actualDurationLatch);
LCDwriteString(s);
}
}
}


W moim pierwotnym liście podałem kod z wykorzystaniem SIG_OUTPUT_COMPARE2
oraz SIG_INTERRUPT7. Kod tamten miał (w porównaniu do tego z wykorzystaniem
input capture) tę wadę, że zwiększanie zmiennej "timer" 100000 razy na
sekundę obciążąło procesor. Niemniej miał on też pewną zaletę -- chodzi o
to, że dla niskich częstotliwości "odcinanie" miałem zawsze w określonym
czasie (np. gdy timer osiągnął wartość 100000; timer był resetowany po
każdym zboczu narastającym -- zatem wartość 100000 mówiła, że minęło 100000
ticków zegara od ostatniego zbocza narastającego sygnału mierzonego). Tu
(chodzi o kod z input capture) niestety jest problem. Gdy sygnał zaniknie
nagle, to "overflow" musi doliczyć do 5 (taką wartość sobie przyjąłem), ale
przecież ICR może mieć różną wartość i czas, w którym "overflow" doliczy do
5 może być różny (gdy ICR było bliskie 0, to będzie to czas prawie pięciu
przepełnień ICR; gdy ICR było prawie 65000, to będzie to czas nieco ponad
czterech przepełnień ICR). Aby mieć dokładne odcinanie (po upływie dokładnie
określonego czasu), musiałbym zrobić dodatkowy timer (np. dający impuls co 1
sekundę), resetowany w SIG_INPUT_CAPTURE3. Jeśli timer da impuls (czyli nie
został zresetowany w ciągu ostatniej sekundy), to znaczy, że sygnał jest
poniżej 1Hz i robimy odcinanie.

R.

Michoo
Guest

Thu Feb 10, 2011 10:31 pm   



W dniu 10.02.2011 19:35, Zbych pisze:
Quote:
W dniu 2011-02-10 17:00, Michoo pisze:
W dniu 10.02.2011 16:16, Zbych pisze:
Nie używaj cli i sei do robienia sekcji atomowych, te makra nie są
zabezpieczone przed optymalizacją i kompilator może zmienić kolejność
instrukcji (choć oczywiście nie musi).
Chyba nie - definicja wyglądają tak:
# define sei() __asm__ __volatile__ ("sei" :Smile
# define cli() __asm__ __volatile__ ("cli" ::)

Co zabrania kompilatorowi zamiany kolejności ewaluacji wyrażeń.

volatile zabrania usunięcia, optymalizacji, ale nie zabroni przesunięcia
czegoś co jest pomiędzy sei i cli, czyli z kodu
cli();[coś];sei();
może wyjść:
cli();sei(); [coś];
Tylko jeżeli [coś] jest kiepskim kodem Wink - Używanie w sekcji krytycznej

czegoś co nie jest volatile i nie zawiera bariery na przesyłanej
zmiennej jest sprzeczne zarówno ze standardem jak i ze zdrowym rozsądkiem.
Gdy [coś] operuje na zmiennych volatile wszystko musi działać a
jednocześnie nie ma konieczności synchronizacji wszystkich rejestrów jak
przy klasycznej barierze.

Quote:

Dodatkowo taka konstrukcja nie zmusza kompilatora do zapisania wartości
tymczasowych trzymanych w rejestrach do pamięci, więc może się okazać,
że zapis wielobajtowej zmiennej nastąpi już przy włączonych przerwaniach.

Przykłady można znaleźć na liście dyskusyjnej avr-gcc.
Masz może linkę? Bo na szybko nie mogłem znaleźć.


Quote:

Dziwne swoją drogą, że nie jest to zapisane na wszelki wypadek jako
# define sei() __asm__ __volatile__ ("sei" :::"memory")

No właśnie o tę barierę na pamięci chodzi.
Tylko bariera jest wolna i nieoptymalna. W sumie jak się głębiej

zastanowić to to jest sensowne:
cli();[operacje na volatile]sei();
- działa jak należy
cli();[dowolne operacje i synchronizacja zmiennej współdzielonej]sei();
- też działa
cli();[operacje bez synchronizacji]sei();
- robi to co programista napisał a nie to co chciał, ale C jest znane z
tego że pozwala się postrzelić w stopę

--
Pozdrawiam
Michoo

Zbych
Guest

Fri Feb 11, 2011 8:36 am   



W dniu 2011-02-10 22:31, Michoo pisze:

Quote:
Tylko jeżeli [coś] jest kiepskim kodem Wink - Używanie w sekcji krytycznej
czegoś co nie jest volatile i nie zawiera bariery na przesyłanej
zmiennej jest sprzeczne zarówno ze standardem jak i ze zdrowym rozsądkiem.

Pokaż mi gdzie jest to napisane w standardzie. Ja wtykanie volatile
wszędzie gdzie się da uważam co najmniej za lenistwo. Jak już muszę użyć
to często robię unię zmiennej volatile i bez volatile. Dzięki czemu nie
mam nadmiarowego kodu np. w przerwaniach.

Quote:
Dodatkowo taka konstrukcja nie zmusza kompilatora do zapisania wartości
tymczasowych trzymanych w rejestrach do pamięci, więc może się okazać,
że zapis wielobajtowej zmiennej nastąpi już przy włączonych przerwaniach.

Przykłady można znaleźć na liście dyskusyjnej avr-gcc.
Masz może linkę? Bo na szybko nie mogłem znaleźć.

Nie chce mi się szukać. Musisz przejrzeć daty w okolicach dodania makr
ATOMIC do biblioteki. Te makra powstały właśnie po tym jak ludzie
zaczęli zgłaszać błędy związane przenoszeniem operacji poza blok
cli()-sei().

Quote:
Dziwne swoją drogą, że nie jest to zapisane na wszelki wypadek jako
# define sei() __asm__ __volatile__ ("sei" :::"memory")

No właśnie o tę barierę na pamięci chodzi.
Tylko bariera jest wolna i nieoptymalna.

Ta bariera nie jest wolniejsza niż używanie volatile. Wymusza tylko
zrzut i pobranie zmiennych.

Quote:
cli();[operacje bez synchronizacji]sei();
- robi to co programista napisał a nie to co chciał, ale C jest znane z
tego że pozwala się postrzelić w stopę

Tia, temat na kolejne bicie piany Smile

Robbo
Guest

Fri Feb 11, 2011 12:05 pm   



Quote:
Jak już muszę użyć to często robię unię zmiennej volatile i bez volatile.
Dzięki czemu nie mam nadmiarowego kodu np. w przerwaniach.

Gdybyś mógł wyjaśnić, co daje taka konstrukcja...?

R.

Michoo
Guest

Fri Feb 11, 2011 12:43 pm   



W dniu 11.02.2011 08:36, Zbych pisze:
Quote:
W dniu 2011-02-10 22:31, Michoo pisze:

Tylko jeżeli [coś] jest kiepskim kodem Wink - Używanie w sekcji krytycznej
czegoś co nie jest volatile i nie zawiera bariery na przesyłanej
zmiennej jest sprzeczne zarówno ze standardem jak i ze zdrowym
rozsądkiem.

Pokaż mi gdzie jest to napisane w standardzie.
C++:

When the processing of the abstract machine is interrupted by receipt of
a signal, the values of objects with type other than volatile
sig_atomic_t are unspecified, and the value of any object not of
volatile sig_atomic_t that is modified by the handler becomes undefined.

Czyli przerzucanie program<->przerwanie czegoś innego niż "volatile
sig_atomic_t" w myśl standardu nie jest zdefiniowane. Ale jednocześnie:

Accessing an object designated by a volatile lvalue (3.10), modifying an
object, calling a library I/O function, or calling a function that does
any of those operations are all side effects, which are changes in the
state of the execution environment. Evaluation of an expression might
produce side effects. At certain specified points in the execution
sequence called sequence points, all side effects of previous
evaluations shall be complete and no side effects of subsequent
evaluations shall have taken place.)

W związku z tym gcc/g++ daje gwarancję na prawidłowe przekazanie
obiektów volatile.
http://gcc.gnu.org/onlinedocs/gcc/Volatiles.html


Quote:
Ja wtykanie volatile
wszędzie gdzie się da uważam co najmniej za lenistwo.
Ja za błąd w sztuce - nie dość, że optymalizacje psuje to jeszcze

wprowadza bardzo trudne do wykrycia błędy (przesyłanie wielobajtowych
obiektów volatile bez synchronizacji a jedynie licząc, że samo volatile
wystarczy) Niemniej *nie oznaczenie* obiektu przekazywanego jako
volatile to już lampka ostrzegawcza, bo trzeba dodatkowo pamiętać o
barierach.

Quote:
Jak już muszę użyć
to często robię unię zmiennej volatile i bez volatile. Dzięki czemu nie
mam nadmiarowego kodu np. w przerwaniach.
Ja zazwyczaj używam volatile do samego przekazania i osobne zmienne "po

obu stronach" albo nie daję volatile i pamiętam o synchronizacji ;)


Quote:
Musisz przejrzeć daty w okolicach dodania makr
ATOMIC do biblioteki. Te makra powstały właśnie po tym jak ludzie
zaczęli zgłaszać błędy związane przenoszeniem operacji poza blok
cli()-sei().
Ok, będę miał chwilę to poszukam.



Quote:
Dziwne swoją drogą, że nie jest to zapisane na wszelki wypadek jako
# define sei() __asm__ __volatile__ ("sei" :::"memory")

No właśnie o tę barierę na pamięci chodzi.
Tylko bariera jest wolna i nieoptymalna.

Ta bariera nie jest wolniejsza niż używanie volatile. Wymusza tylko
zrzut i pobranie zmiennych.
Wszystkich zmiennych. Używanie volatile jest wolne tylko w odniesieniu

do tego jednego obiektu.

Napisałem kiedyś makro, które robiło barierę na podanej zmiennej -
dziwię się, że nie ma czegoś takiego w bibliotece:
#define SYNC_VARIABLE(var) __asm__ __volatile__ ("" :"=m"(var):"m"(var))

Quote:

cli();[operacje bez synchronizacji]sei();
- robi to co programista napisał a nie to co chciał, ale C jest znane z
tego że pozwala się postrzelić w stopę

Tia, temat na kolejne bicie piany Smile
Po coś te grupy dyskusyjne powstały Wink


--
Pozdrawiam
Michoo

Zbych
Guest

Fri Feb 11, 2011 1:15 pm   



W dniu 2011-02-11 12:43, Michoo pisze:
Quote:
W dniu 11.02.2011 08:36, Zbych pisze:
W dniu 2011-02-10 22:31, Michoo pisze:

Tylko jeżeli [coś] jest kiepskim kodem Wink - Używanie w sekcji krytycznej
czegoś co nie jest volatile i nie zawiera bariery na przesyłanej
zmiennej jest sprzeczne zarówno ze standardem jak i ze zdrowym
rozsądkiem.

Pokaż mi gdzie jest to napisane w standardzie.
C++:
When the processing of the abstract machine is interrupted by receipt of
a signal, the values of objects with type other than volatile
sig_atomic_t are unspecified, and the value of any object not of
volatile sig_atomic_t that is modified by the handler becomes undefined.

Czyli przerzucanie program<->przerwanie czegoś innego niż "volatile
sig_atomic_t" w myśl standardu nie jest zdefiniowane. Ale jednocześnie:

Accessing an object designated by a volatile lvalue (3.10), modifying an
object, calling a library I/O function, or calling a function that does
any of those operations are all side effects, which are changes in the
state of the execution environment. Evaluation of an expression might
produce side effects. At certain specified points in the execution
sequence called sequence points, all side effects of previous
evaluations shall be complete and no side effects of subsequent
evaluations shall have taken place.)

Co prawda c++, a nie c, ale dzięki za podesłanie tego. Miło wiedzieć, że
jest to w ogóle ustandaryzowane.

Quote:
Napisałem kiedyś makro, które robiło barierę na podanej zmiennej -
dziwię się, że nie ma czegoś takiego w bibliotece:
#define SYNC_VARIABLE(var) __asm__ __volatile__ ("" :"=m"(var):"m"(var))

Fajne Smile

Goto page Previous  1, 2, 3  Next

elektroda NewsGroups Forum Index - Elektronika Polska - Sprawdzanie działania kodu do pomiaru częstotliwości sinusoidy 2-150Hz na ATmega128

NOWY TEMAT

Regulamin - Zasady uzytkowania Polityka prywatnosci Kontakt RTV map News map