logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Atmega16 [C] - SPI - Jak przesłać dane z slave do master w komunikacji SPI?

Jeżyk-1 13 Cze 2013 16:06 4017 21
REKLAMA
  • #1 12413356
    Jeżyk-1
    Poziom 25  
    Witam. Próbuję rozwiązać problem komunikacji dwóch a później trzech mikroprocesorów.
    Zacząłem od wysłania zmieniających się danych z master do slave i takie rozwiązanie mi działa:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Teraz chciałem żeby to slave wysyłem informacje do master i trochę przerobiłem kod:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I efekt taki że zupełnie nic nie działa :(
    Próbuję już trochę ten problem rozwikłać ale bez efektu. Ktoś może podpowie gdzie robię błąd?
  • REKLAMA
  • #2 12413770
    szelus
    Poziom 34  
    Chyba nie złapałeś tego, że w SPI transmisja jest zawsze dwukierunkowa i zawsze inicjowana przez mastera. Aby odebrać dane od slave-a master musi też coś wysłać.
    Jeżeli slave wpisze coś do rejestru wyjściowego, to i tak dotrze to do mastera dopiero po tym, jak master zainicjuje kolejną transmisję i wyśle coś do slave-a.
  • #3 12413816
    Jeżyk-1
    Poziom 25  
    Doczytałem tą informację i w między czasie przerobiłem swój kod. I dla jednego master i jednego slave działało mi ładnie. Teraz chciałem by był jeden master a dwa slave i zrobiłem taki kod:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I teraz wygląda jak by master wysyłał i swoje wysłane dane odbierał :(
  • REKLAMA
  • #4 12415631
    szelus
    Poziom 34  
    Może by tak kod slave?
    Dodatkowo (nie zwróciłem wcześniej uwagi) - w AVR-ach funkcje specjalne mają priorytet na porcie. Oznacza to, że włączając taką funkcję (np. SPI) nie ma potrzeby definiowania odpowiednich pinów jako wyjścia - chyba, że planujesz wylączać tą funkcję i sterować takim pinem "ręcznie".
  • #5 12415648
    Jeżyk-1
    Poziom 25  
    szelus napisał:
    Może by tak kod slave?


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod





    szelus napisał:

    Dodatkowo (nie zwróciłem wcześniej uwagi) - w AVR-ach funkcje specjalne mają priorytet na porcie. Oznacza to, że włączając taką funkcję (np. SPI) nie ma potrzeby definiowania odpowiednich pinów jako wyjścia - chyba, że planujesz wylączać tą funkcję i sterować takim pinem "ręcznie".


    Chodzi o tą definicje:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    We wszystkich poradnikach co przeglądałem zawsze ustawia się kierunek na MOSI i SCK A cs1 i cs2 ustawiłem z tego względu że następnym krokiem będzie wysłanie i odebranie informacji z slave nr2
  • REKLAMA
  • #6 12415768
    piotrva
    VIP Zasłużony dla elektroda
    szelus napisał:
    w AVR-ach funkcje specjalne mają priorytet na porcie. Oznacza to, że włączając taką funkcję (np. SPI) nie ma potrzeby definiowania odpowiednich pinów jako wyjścia - chyba, że planujesz wylączać tą funkcję i sterować takim pinem "ręcznie".

    BZDURY.
    Jeśli w jakikolwiek sposób używamy SPI to pin SS w Masterze musi być ustawiony jako wyjście, a w Slave jako wejście. Nawet jeśli używamy innych pinów jako linie CS taka konfiguracja być musi.
    To samo tyczy się innych np. sprzętowego PWM - też trzeba ręcznie skonfigurować pin jako wyjście, czy UART itp.
  • REKLAMA
  • #7 12415968
    szelus
    Poziom 34  
    No dobrze, nie byłem zbyt precyzyjny, mea culpa.
    SS tak, bo w masterze SS nie jest de facto obsługiwane przez sprzęt. Tak, mogłem o tym napisać.
    Jeżeli chodzi o USART, to jednak nie masz racji:
    ATmega 32 DS napisał:

    • TXD – Port D, Bit 1
    TXD, Transmit Data (Data output pin for the USART). When the USART Transmitter is
    enabled, this pin is configured as an output regardless of the value of DDD1.
    • RXD – Port D, Bit 0
    RXD, Receive Data (Data input pin for the USART). When the USART Receiver is
    enabled this pin is configured as an input regardless of the value of DDD0. When the
    USART forces this pin to be an input, the pull-up can still be controlled by the PORTD0
    bit.

    Podobnie pozostałe bity SPI.

    Natomiast jeżeli chodzi o sprzętowe PWM i piny OCx, faktycznie przeoczyłem taką uwagę w DS, która jednak jest raczej wyjątkiem od ogólnej zasady (dla wyjść) - wygląda na babola.
  • #8 12416069
    Jeżyk-1
    Poziom 25  
    piotrva napisał:

    Jeśli w jakikolwiek sposób używamy SPI to pin SS w Masterze musi być ustawiony jako wyjście, a w Slave jako wejście. Nawet jeśli używamy innych pinów jako linie CS taka konfiguracja być musi.


    To w slave dodałem linie obsługi portu gdzie jest CS:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Lecz to nadal nic nie dało.
  • #9 12416079
    piotrva
    VIP Zasłużony dla elektroda
    No moim zdaniem po pierwsze nie jest to "babol", ale zamierzone działania (czasem może się przydać możliwość machania pull-upem).

    A co do U(S)ART to np. w ATXmega już jest zupełnie inaczej (aktualnie właśnie te procesory wałkuję) i trzeba poustawiać kierunki ręcznie (zgodnie z Manualem rodziny), ale to mój brak precyzji w określeniu.
  • #10 12416152
    Jeżyk-1
    Poziom 25  
    Teraz mam kod tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I slave odbiera dane od master ale master nic nie odbiera od slave. :(
    Echh ciężko to zgrać jedno z drugim. :(
  • #11 12416255
    szelus
    Poziom 34  
    Zdefiniuj nie odbiera -> dostaje same zera, czy same jedynki?
    Czy włączasz najpierw S, M, czy wszystko razem?
    Problem jest tego rodzaju, że powinieneś jakoś synchronizować transmisję, bo M nadaje niezależnie od tego, czy S słucha. Jeżeli S np. nie zdąży odebrać bajtu, to wszystko Ci się rozjedzie. Rejestr SDR jest wspólny, dla nadawania i odbioru. Jeżeli S nie zdąży wpisać nowego bajtu do nadania zanim M rozpocznie następną transmisję, to M odbierze właśnie to, co sam przed chwilą nadał.
    SPI nadaje się dość dobrze do implementacji protokołów typu komenda-odpowiedź, z dobrze określoną ilością bajtów dla każdej itp. Przy czym M musi pracować na tyle wolno aby S nadążał.
    Jeżeli S zajmuje się jeszcze czymś, poza transmisją, to implementacja protokołu komunikacji bez wykorzystania przerwań może być bardzo problematyczna.
  • #12 12416409
    Jeżyk-1
    Poziom 25  
    Po małej poprawce, powyższy koda zadziałał. Odbiera i wysyła w obie strony.
    Teraz chciałem go przerobić dla dwóch slave i znów problem.
    Kod:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wygląda jak by master odbierał to co sam wyślę.
    Ja wszystkie trzy układy włączam jednym przyciskiem. Więc powinny się zsynchronizować odpowiednio. W tej chwili to jest cały kod, co jest wgrany, nic więcej mikroprocesory nie mają do roboty.
  • #13 12416703
    szelus
    Poziom 34  
    Jeżyk-1 napisał:

    Ja wszystkie trzy układy włączam jednym przyciskiem. Więc powinny się zsynchronizować odpowiednio.

    Na to nie licz, tu liczą się pojedyncze takty zegara, a tam jest różna inicjalizacja, wyświetlanie na LCD itd. Nie można nawet liczyć na to, że reset (startup) zakończy się jednocześnie. Kod musi być tak napisany, aby poprawnie działał kompletnie niezależnie od kolejności włączania.

    Jak pisałem, M będzie odbierał własną transmisję jeżeli S nie wpisze w odpowiednim momencie swoich danych. Masz problem tego rodzaju, że natychmiast po wysłaniu danych z M zaczynasz odbierać (wysyłając kolejny bajt). Powinieneś dać opóźnienie, aby S zdążył wpisać odpowiedź.
    W praktyce, S nie może też nic wpisywać do SDR zanim nie odbierze i nie zidentyfikuje pierwszej komendy odebranej z M (bo może nadpisać to, co się aktualnie odbiera). Ten protokół z zasady nie jest symetryczny. Master powinien działać na zasadzie:
    - wysyłam komendę
    - czekam
    - odbieram odpowiedź
    - zajmuję się czymś innym

    Natomiast slave:
    - czekam na komendę
    - przygotowuję odpowiedź
    - wysyłam odpowiedź (zapis do SDR)
    - powrót do czekania

    Jeżeli przygotowanie odpowiedzi miałoby zająć trochę czasu, to protokół komunikacji powienien to uwzględniać, np przez wysyłnie odpowiedzi "NIEGOTOWY" i odpytywanie przez M aż dostanie kompletną odpowiedź.
  • #14 12416860
    Jeżyk-1
    Poziom 25  
    No i tak się właśnie dzieje master odczytuje to co sam wysłał.
    Ale myślałem że opóźnienie które czeka aż wyśle daje ta linia:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Więc do mojego kodu wystarczy dać opóźnienie między funkcją TransferSpi1() a TransferSpi2() i będzie to działać czy cały kod należy przerobić ?
    Bo jak tak zrobię i dodam np funkcję _delay_us(10) to nic nie pomogło.

    Pomyślałem sobie że może prościej będzie układ slave wyposażyć w przerwanie SPI_STC_vect. Lecz to co ja napisałem to nie działa za bardzo. Zmienia się co jakiś czas cyferkę, a tak po za tym odbieranie prawie stoi.
    Kod:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #15 12418127
    szelus
    Poziom 34  
    Jeżyk-1 napisał:
    Ale myślałem że opóźnienie które czeka aż wyśle daje ta linia:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Więc do mojego kodu wystarczy dać opóźnienie między funkcją TransferSpi1() a TransferSpi2() i będzie to działać czy cały kod należy przerobić ?

    Powyższy kod (w masterze) czeka na zakończenie pierwszej transmisji (wysyłanie). Ale przed rozpoczęciem drugiej transmisji (odbiór) trzeba dać slave-owi szansę na włożenie swoich danych do rejestru. Przeczytaj jeszcze raz, to co napisałem poprzednio.
    Opóźnienie trzeba by u Ciebie dodać pomiędzy pierwszym a drugim TransferSpi1() (i analogicznie dla TransferSpi2()).
    Poza tym w S procedura powinna być w odwrotnej kolejności - najpierw czekanie na SPIF, potem odczytanie odebranych danych z SDR i na końcu wpisanie odpowiedzi do SDR.
    Ale ogólnie to cały program opiera się na złych założeniach.
  • #16 12418332
    Jeżyk-1
    Poziom 25  
    szelus napisał:

    Opóźnienie trzeba by u Ciebie dodać pomiędzy pierwszym a drugim TransferSpi1() (i analogicznie dla TransferSpi2()).


    Jak długo powinno być te opóźnienie?

    szelus napisał:

    Poza tym w S procedura powinna być w odwrotnej kolejności - najpierw czekanie na SPIF, potem odczytanie odebranych danych z SDR i na końcu wpisanie odpowiedzi do SDR.


    To tutaj nie bardzo wiem jak powinna ta funkcja wyglądać. Coś takiego raczej jest nie poprawne?
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    szelus napisał:

    Ale ogólnie to cały program opiera się na złych założeniach.

    Czy miałbyś może gotowy przykład by pokazać mi jak prawidłowo napisany program powinien wyglądać?
    To co ja znalazłem w internecie na różnych stronach to zazwyczaj jest coś podobnego do tego co ja napisałem.
  • #17 12418451
    piotrva
    VIP Zasłużony dla elektroda
    Możesz do sygnalizacji zajętości wykorzystać linię miso - jeśli po podaniu sygnału CS na tej linii np. Będziesz mial stan wysoki to znaczy że slave jest zajęty.
  • #18 12418695
    Jeżyk-1
    Poziom 25  
    piotrva napisał:
    Możesz do sygnalizacji zajętości wykorzystać linię miso - jeśli po podaniu sygnału CS na tej linii np. Będziesz mial stan wysoki to znaczy że slave jest zajęty.


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    O coś takiego chodzi ?

    Nie bardzo pomogło :(

    W tej chwili cały kod wygląda tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #19 12420346
    szelus
    Poziom 34  
    piotrva napisał:
    Możesz do sygnalizacji zajętości wykorzystać linię miso - jeśli po podaniu sygnału CS na tej linii np. Będziesz mial stan wysoki to znaczy że slave jest zajęty.

    Ta wędka była chyba po drugiej stronie jeziora. ;)

    Jeżyk-1 napisał:
    Czy miałbyś może gotowy przykład by pokazać mi jak prawidłowo napisany program powinien wyglądać?

    Nie mam nic gotowego, ale, ponieważ możliwości jest trochę, to znacznie łatwiej byłoby Ci podpowiedzieć coś konkretnego, gdybyś napisał jaki jest ostateczny cel tego eksperymentu (czyli co budujesz, jakie dane chcesz przesyłać itp.).

    Miałem na myśli, że odbiór/nadawanie w slave powinien wyglądać np. tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Opóżnienie, o którym pisałem nie musi być duże. Może być np te 10us.
  • #20 12420364
    piotrva
    VIP Zasłużony dla elektroda
    szelus napisał:
    piotrva napisał:
    Możesz do sygnalizacji zajętości wykorzystać linię miso - jeśli po podaniu sygnału CS na tej linii np. Będziesz mial stan wysoki to znaczy że slave jest zajęty.

    Ta wędka była chyba po drugiej stronie jeziora. :wink:

    Nie do końca rozumiem co masz na myśli, bo taka metoda stosowana jest na przykład w popularnych układach RFM12B (akurat pamiętam ich przykład bo niedawno wykonywałem projekt z transmisją bezprzewodową).
  • #21 12420421
    szelus
    Poziom 34  
    Metoda jest jak najbardziej OK (kwestia dobrania odpowiedniego formatu danych), ale chodziło mi o to, że musiałbyś to szczegółowo opisać, aby Jeżyk wiedział, co miałeś na myśli i jak to wykorzystać.
  • #22 12421708
    Jeżyk-1
    Poziom 25  
    Ok problem został rozgryziony. Zrobiłem to w taki sposób i działa:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Trochę inaczej niż była mowa ale tak wydaje mi się będzie lepiej z wykorzystaniem kody w jakimś większym projekcie.
    Dziękuję za cenne wskazówki
REKLAMA