Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[ATmega32][C][AVR Studio 4] Slave SPI, timery i przerwania - kolizja.

Co_pat 23 Oct 2011 14:40 1865 6
  • #1
    Co_pat
    Level 15  
    Witam!

    ATmega32 16MHz jako slave odbiera dwa bajty po SPI 1MHz ( 15cm taśmy 10 żyłowej )od mastera LPC2148 . Jeżeli jest włączone tylko SPI, a inne przerwania są wyłączone jest wszystko dobrze. Jeżeli włączę przerwanie od timera2 generowane co 100us to zdarza się że atmega gubi jeden bajt i krzaczy się cała transmisja, ale po jakimś czasie jak zgubi następny to wraca wszystko do normy.
    Czy istnieje możliwość, że podczas przerwania generowanego przez SPI przerwanie zgłaszane przez timera2 psuje całość?
    Myślałem, aby wyłączać inne przerwania podczas obsługi SPI, ale problem jest w tym, że zarówno dokładne odmierzanie czasu jak i poprawna transmisja SPI jest dla mnie kluczowa ponieważ jest to układ regulacji silnikiem prądu stałego gdzie timer2 wyznacza częstotliwość pracy regulatora, a przez SPI przesyłana jest wartość referencyjna.
    Za wszelkie wskazówki będę wdzięczny.

    Poniżej obsługa przerwań:
    Code: c
    Log in, to see the code
  • #2
    tadzik85
    Level 38  
    Przerwanie od t1 nieblokowane lub w jego wnętrzu sprawdzasz flagę SPI i obsługujesz przerwanie programowo od SPI odbierając bajt
  • #3
    Co_pat
    Level 15  
    tadzik85 dziękuję za błyskawiczna odpowiedź. Próbowałem tego rozwiązania i niestety gdy w przerwaniu od SPI umieszczę flagę i bez względu gdzie realizuję odbiór czy w przerwaniu od timera czy w pętli głównej drugi bajt wraca do mastera czyli wydaje mi się, że ATmega nie nadąża z odczytem.
  • #4
    janbernat
    Level 38  
    Albo wręcz zrobić naked i wykorzystać jakiś rejestr sprzętowy.
    Co prawda jest to 16 bitów.
    Ale można to zrobić albo w dwóch 8 bitowych- żeby było atomowo albo jako Atomic Block.
  • #5
    tadzik85
    Level 38  
    a czemu transmisji SPI nie zrobisz buforowanej? widzę ze masz tam sporo obliczeń w przerwanie od T1 jest bardzo krótkie.
  • #6
    BoskiDialer
    Level 34  
    Jeśli układ nadrzędny nadaje te dwa bajty jeden po drugim, to może się okazać, że przerwa między bajtami jest zbyt mała: realizując proste wyślij-czekaj_na_koniec-wyślij-czekaj w poolingu uzyska się odstęp między bajtami rzędu pojedynczych us, co może być zbyt małe na zareagowanie układu podrzędnego. Używając na masterze DMA (jeśli jest taka możliwość) odstępy te będą jeszcze krótsze. Rozwiązania sprzętowe układów podrzędnych zawsze można ciągnąć do wysokich prędkości przy znikomych opóźnieniach, tutaj jeśli obsługa slave'a wymaga ingerencji programu, nie można sobie już na to pozwolić - należy wstawić jakieś opóźnienia.

    Warto w tym przypadku użyć jakiegoś timera na masterze, który dawał by przerwanie np co 20us, to przerwanie wyzwalało by wymianę jednego bajtu. Wymiana trwała by 8us, pozostały czas był by czasem dla układu podrzędnego na zareagowanie.
    Inne rozwiązanie, to rozwiązanie kombinowane - dodatkowy przewód sygnalizujący gotowość układu podrzędnego - po przetworzeniu bajtu, slave zmieniał by stan na tym przewodzie.
    Jeśli jest możliwość użycia kanałów DMA na tym lpc, to może warto by zamienić ze sobą role układów?
  • #7
    Co_pat
    Level 15  
    Dziś wróciłem do sprawy po krótkiej przerwie. Zastosowałem się do rady:
    BoskiDialer wrote:
    Jeśli układ nadrzędny nadaje te dwa bajty jeden po drugim, to może się okazać, że przerwa między bajtami jest zbyt mała

    i okazało się, że transmisja zaczęła śmigać znacznie lepiej. W LPC2148 pomiędzy wysyłanymi bajtami dałem minimalne opóźnienie w postaci pustej pętli for X100. Ale niestety zdarzyły się błędy mniej więcej raz na kilka sekund gdzie bajty były wysyłane z częstotliwością 50Hz.

    janbernat wrote:
    Ale można to zrobić albo w dwóch 8 bitowych- żeby było atomowo albo jako Atomic Block

    Po zrobieniu przerwania jako Atomic Block udało się uzyskać jak na razie bezbłędną transmisję. Domyślam się, że takie rozwiązanie wpływa na opóźnienie timera, ale zliczany czas przez timer jest sukcesywnie resetowany więc błąd się nie kumuluje

    Problem uważam za rozwiązany.
    Dziękuję wszystkim za pomoc!