eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronika › AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
Ilość wypowiedzi w tym wątku: 35

  • 21. Data: 2011-02-10 16:00:43
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: Michoo <m...@v...pl>

    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" ::)
    # 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ę.

    > 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


  • 22. Data: 2011-02-10 18:15:18
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: "Robbo" <y...@m...com>

    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 :(

    R.


  • 23. Data: 2011-02-10 18:35:49
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: Zbych <a...@o...pl>

    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" ::)
    > # 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.

    > 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.


  • 24. Data: 2011-02-10 18:56:42
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: Zbych <a...@o...pl>

    W dniu 2011-02-10 19:15, Robbo pisze:
    > 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 :(


    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ć.


  • 25. Data: 2011-02-10 20:56:55
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: "Robbo" <y...@m...com>

    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.


  • 26. Data: 2011-02-10 21:31:01
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: Michoo <m...@v...pl>

    W dniu 10.02.2011 19:35, Zbych pisze:
    > 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" ::)
    >> # 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 ;) - 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.

    >
    > 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źć.

    >
    >> 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


  • 27. Data: 2011-02-11 07:36:54
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: Zbych <a...@o...pl>

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

    > Tylko jeżeli [coś] jest kiepskim kodem ;) - 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.

    >> 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().

    >>> 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.

    > 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 :-)


  • 28. Data: 2011-02-11 11:05:15
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: "Robbo" <y...@m...com>

    > 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.


  • 29. Data: 2011-02-11 11:43:23
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: Michoo <m...@v...pl>

    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 ;) - 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


    > 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.

    > 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 ;)


    > 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.


    >>>> 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))

    >
    >> 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 :-)
    Po coś te grupy dyskusyjne powstały ;)

    --
    Pozdrawiam
    Michoo


  • 30. Data: 2011-02-11 12:15:56
    Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
    Od: Zbych <a...@o...pl>

    W dniu 2011-02-11 12:43, Michoo pisze:
    > 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 ;) - 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.

    > 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 :-)

strony : 1 . 2 . [ 3 ] . 4


Szukaj w grupach

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: