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

[atmega8][c] proste SPI do sterowania przyciskami (tryb "free run")

cadavre 24 Cze 2011 17:37 2869 22
REKLAMA
  • #1 9646108
    cadavre
    Poziom 10  
    Witam!
    Jakimi zasadami kieruje się SPI w prostej komunikacji między dwoma uC Atmega8?

    Utworzyłem kod dla Mastera i Slave'a - Master wyłapuje wciśnięcia przycisków i zapisuje ten status do tablicy, z której później po kolei bajty są wysyłane poprzez SPI. Slave odbiera dane i zapisuje je do bufora tymczasowego. Jeśli wartość bufora dla danego przycisku równa jest 0x01 to zapala się dioda.

    Układ jednak napisany w poniższy sposób nie chce działać. :/

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


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


    Połączenie oczywiście mosi-mosi, miso-miso, sck-sck, ss'y bez wyprowadzeń.

    Jakieś wskazówki?
  • REKLAMA
  • #2 9646829
    Fredy
    Poziom 27  
    Czemu w Slave nie użyłeś SPI_init?
  • #3 9646891
    Ch.M.
    Poziom 27  
    Witaj, na 2 stronie rozdziału traktującego o SPI znajdziesz zapis:

    The interconnection between Master and Slave CPUs with SPI is shown in Figure 18-2. The system
    consists of two shift Registers, and a Master clock generator. The SPI Master initiates the
    communication cycle when pulling low the Slave Select SS pin of the desired Slave. Master and
    Slave prepare the data to be sent in their respective shift Registers, and the Master generates
    the required clock pulses on the SCK line to interchange data. Data is always shifted from Master
    to Slave on the Master Out – Slave In, MOSI, line, and from Slave to Master on the Master In
    – Slave Out, MISO, line. After each data packet, the Master will synchronize the Slave by pulling
    high the Slave Select, SS, line.
    When configured as a Master, the SPI interface has no automatic control of the SS line. This
    must be handled by user software before communication can start. When this is done, writing a
    byte to the SPI Data Register starts the SPI clock generator, and the hardware shifts the eight
    bits into the Slave. After shifting one byte, the SPI clock generator stops, setting the end of
    Transmission Flag (SPIF). If the SPI Interrupt Enable bit (SPIE) in the SPCR Register is set, an
    interrupt is requested. The Master may continue to shift the next byte by writing it into SPDR, or
    signal the end of packet by pulling high the Slave Select, SS line. 

    Mam nadzieję, że nie użyłeś linii SS w Masterze, w przeciwnym przypadku będziesz musiał ją zwolnić :)
    Pozdrawiam
  • REKLAMA
  • #4 9646973
    cadavre
    Poziom 10  
    SPI_init wyleciał gdy czyściłem kod przed wrzuceniem na forum.

    Linia SS jest oczywiście wolna.

    Co zauważyłem przed momentem - o.O - moja atmega8 jest czuła na dotyk. Gdy przyłożę palec w okolice portów SPI port zaczyna reagować. Z góry mówię że nie ma tutaj nic do rzeczy lut ani docisk do płytki. o.O

    EDIT:
    Zaczynam czuć się troszkę jak szaman. :/ Zmieniłem pętlę by wysyłany był cały czas ten sam bajt - tzn. sygnał z tylko jednego przycisku. Teraz wszystko działa pięknie - w momencie gdy trzymam palec na atmedze lub 0,5mm nad nią. Gdy dotykam szczypcami - nic. Palcem - działa.
  • REKLAMA
  • #5 9647019
    Ch.M.
    Poziom 27  
    Powyżej wyjaśniłem czemu Ci nie działa oraz opisaną przez Ciebie sytuację z dotykiem... rozumiem, że z angielskim masz problemy: zdefiniuj SS jako wyjście i ustaw stan niski.
  • #6 9647154
    cadavre
    Poziom 10  
    Czyli w masterze mam ustawić jeden z pinów (rozumiem, że mogę SS) jako wyjście, którym będę dawał stan niski przed wysyłaniem danych, a wysoki po wysłaniu danych?

    W slave'ie natomiast SS ma być wejściem i mają te dwa piny być połączone?

    I czy wtedy będzie działać komunikacja dwustronna?
  • Pomocny post
    #7 9647636
    Konto nie istnieje
    Poziom 1  
  • #8 9649178
    cadavre
    Poziom 10  
    Dzięki, teraz już rozumiem.

    W błąd wprowadziła mnie lektura "uC AVR Język C" M. Kardasia, który stwierdził, że do transmisji między dwoma uC wystarczą tylko trzy linie.

    Przy okazji poprawiłem metody wysyłania i odbierania ciągu bajtów w trybie non-stop. W masterze wysyłanie jest inicjalizowane przez timer, a slave obsługuje transmisję przerwaniem od SPI. Jedynym niuansem w takim wypadku jest fakt, że na początku kodu programu już musimy zdefiniować pierwszą wartość do wysłania, która będzie czekać na mastera.

    Jeszcze raz dzięki i mam nadzieję, że za niedługo wrzucę tutaj na forum efekt mojego pierwszego projektu. ; )
  • REKLAMA
  • #9 9649252
    Ch.M.
    Poziom 27  
    cadavre napisał:
    Dzięki, teraz już rozumiem.

    W błąd wprowadziła mnie lektura "uC AVR Język C" M. Kardasia, który stwierdził, że do transmisji między dwoma uC wystarczą tylko trzy linie.


    Nie do końca zrozumiałeś kolegę... nie jest wymagana linia SLAVE SELECT jeśli masz układ taki jak opisałeś. Co innego gdy masz kilka procesorów i układ multimaster.

    Po prostu na samym początku ustawiasz w masterze odpowiedni stan, a w slave nie musisz nic zmieniać.
  • #10 9649424
    Andrzej__S
    Poziom 28  
    cadavre napisał:

    W błąd wprowadziła mnie lektura "uC AVR Język C" M. Kardasia, który stwierdził, że do transmisji między dwoma uC wystarczą tylko trzy linie.

    To wcale nie jest błąd, tylko w takim przypadku linię SS w układzie slave musisz mieć podpiętą na stałe do masy. Co do pinu SS w układzie master:
    - jeśli jest ustawiony jako wejście, musi być cały czas w stanie wysokim, aby SPI działało,
    - jeśli jest ustawiony jako wyjście, można z niego korzystać jak z normalnego pinu wyjściowego bez wpływu na transmisję SPI.

    Jeśli dobrze rozumiem Twoją wypowiedź z pierwszego postu:
    cadavre napisał:

    Połączenie oczywiście mosi-mosi, miso-miso, sck-sck, ss'y bez wyprowadzeń.

    linie SS zostawiłeś niepodłączone.

    Oczywiście w układzie bez użycia Slave Select, pinów od SPI nie można używać do innych celów niż komunikacja układu master z jednym układem slave.
  • #11 9649497
    cadavre
    Poziom 10  
    Cytat:
    To wcale nie jest błąd, tylko w takim przypadku linię SS w układzie slave musisz mieć podpiętą na stałe do masy.
    O czym nie wspomniano.

    Cytat:
    - jeśli jest ustawiony jako wyjście, można z niego korzystać jak z normalnego pinu wyjściowego bez wpływu na transmisję SPI.
    Więc gdy jednak zdecydowałem już, że będę masterem sterował SS slave'a i wybrałem pin SS, który w masterze miałby być wyjściem sterującym to uzyskałem odpowiedź:
    Cytat:
    cadavre napisał:
    Czyli w masterze mam ustawić jeden z pinów (rozumiem, że mogę SS) jako wyjście, którym będę dawał stan niski przed wysyłaniem danych, a wysoki po wysłaniu danych?

    Nie. Chodzi o to żebyś pin SS (konkretnie SS) ustawił w stan wysoki i już go nie ruszał.
    Z kolei jakiś dowolny inny (ale w żadnym wypadku SS) wysterowujesz tak jak napisałeś.


    Więc jak to w końcu jest? Mogę użyś SS mastera jako wyjście do sterowania SS slave'a (czyli docelowo jako zwyczajne wyjście)?
  • #12 9649602
    Ch.M.
    Poziom 27  
    TAK możesz, ale wcale nie musisz. Pisanie "docelowo jako zwyczajne wyjście" jest sprzeczne z założeniem "do sterowania slave", ponieważ w tym przypadku jest to specyficzny sposób komunikacji SPI tzn. MULTIMASTER.
  • #13 9649762
    Fredy
    Poziom 27  
    Podepnę się pod ten ciekawy temat z małym pytankiem.
    Jak zrobić przerwanie od przychodzącego znaku po SPI? Może jakiś przykład?

    Pozdrawiam
  • #14 9649798
    cadavre
    Poziom 10  
    Właśnie z takowego korzystam, zatem:

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


    Flaga zakończonej transmisji SPIF zostaje automatycznie wyczyszczona po zakończeniu procedury przerwania, więc nie musimy się tym zajmować ręcznie.
    To kod oczywiście dla układu podrzędnego.

    Dodano po 4 [minuty]:

    Ch.M. napisał:
    TAK możesz, ale wcale nie musisz. Pisanie "docelowo jako zwyczajne wyjście" jest sprzeczne z założeniem "do sterowania slave", ponieważ w tym przypadku jest to specyficzny sposób komunikacji SPI tzn. MULTIMASTER.
    Mogę, nie muszę - tyle wiem. ; )

    Czy na pewno multimaster? A gdy mamy na SPI podpięte wiele urządzeń slave to do stosownego przed rozpoczęciem transmisji sami musimy dostarczyć sygnał niski na SS. Zatem w takim wypadku i tutaj MOŻNA użyć SS mastera jako wyprowadzenia sterującego SS jednego z układów slave.
  • #15 9649810
    Fredy
    Poziom 27  
    A jeśłi nie mamy nic do wysłania to można pominąć w przerwaniu to załadowanie rejestru SPDR, czy trzeba wpisać cokolwiek?
  • #16 9649820
    cadavre
    Poziom 10  
    Można pominąć. Dla czytelności na przyszłość polecam jednak po prostu wpisanie zera. : ) Gdy jednak będzie trzeba w przyszłości coś wysłać z powrotem - wystarczy wrócić do odpowiedniego miejsca w kodzie i już.
  • #17 9649964
    Fredy
    Poziom 27  
    Zastanawia mnie jedno - jeśłi jest już przerwanie od SPI, czyli inaczej mamy już odebrany znak, a w przerwaniu ładujemy rejestr SPDR to natychmiast sprzętowy SPI rozpocznie od tego momentu wysyłkę? Czyli także sprzętowy SPI ustawi wyjścia typu SS ? Programista nie musi tym sobie zawracać głowy?
  • #18 9650069
    cadavre
    Poziom 10  
    Nie, jeśli załadujesz rejestr SPDR do wysyłki w przerwaniu, to te dane zostaną dopiero wysłane podczas inicjalizacji kolejnego transferu przez Mastera.
  • #19 9650190
    Fredy
    Poziom 27  
    Wielkie dzieki - pozdrawiam
  • #20 9677890
    cadavre
    Poziom 10  
    Witam ponownie!

    Mam kolejny problem z tym nieszczęsnym SPI. :/ Czy istnieje możliwość zawieszenie modułu transmisji SPI?

    Może nakreślę moją ideę jako tok postępowania:
    1. Odczyt wartości ADC i zapis do buforu. f = 250kHz = 0,004ms
    2. Timer2 generuje match compare interrupt. f = 8MHz / 256 / 36(OCR) = 868Hz = 1,15ms
    3. Przerwanie timera powoduje rozpoczęcie transmisji SPI i wysłanie+odebranie 1 bajta. Czas transmisji to 8MHz / 64(prescaler) / 8(bitów) = 15kHz = 0,064ms
    4. Slave odbiera dane podczas wygenerowanego przerwania przez SPI (czyli zakończono już transfer i dane czekają na odczyt w SPDR) i szykuje kolejną paczkę do wysłania podczas kolejnego transferu.
    5. Wszystko to trwa w kółko.

    Czy to poprawny tok myślenia i planowania czasu? Rozpisałem specjalnie timingi, ADC robi odczyt co 0,004ms, co 1,15ms generowane jest tyknięcie timera, który rozpoczyna wysłanie jednego bajta co zajmuje mu tylko 0,064ms (więc do 1,15ms jeszcze daleko).

    W teorii wszystko pięknie wygląda ale slave wykonuje przerwanie od SPI wyłącznie (dokładnie, za każdym razem tyle samo) 51 razy. Po tych 51 wykonaniach slave nie wiesza się, ale komunikacja SPI przestaje działać. Nie wiem czy to wina tych czasów czy czegoś innego?

    Czego więc może to być wina?

    SPI w slave wygląda dokładnie tak:
    https://www.elektroda.pl/rtvforum/topic2026692.html#9649798

    EDIT: Co jeszcze...
    Gdy w ciągu tych 51 przerwań chcę wysłać jakiś bajt - 1 wysyła bez problemu, 2 wysyła z dużymi problemami.
  • #21 9678431
    gaskoin
    Poziom 38  
    Pokaż cały program :)
  • #22 9678943
    cadavre
    Poziom 10  
    Aktualna wersja dostępna na Google Code:
    https://code.google.com/p/robotcontrol/source/browse/
    : )

    Rozważam możliwość przepełnienia stosu spowodowanego nakładaniem się przerwań od Timera2. Jutro spróbuję po prostu przerzucić lcd_refresh do ciała głównego programu. : /
  • #23 9680338
    cadavre
    Poziom 10  
    https://code.google.com/p/robotcontrol/source...unk/robot_control/atmega_slave/atmega_slave.c

    Diagnoza jest taka: w slave'ie w ogóle nie wykonują się polecenia pętli ciała głównego programu. W ogóle nie jest wykonywane
    drive_state[0] = 16;
    gdyż na ekranie LCD wciąż widzę wartość '49'. Transfer SPI działa gdyż po odpięciu jednego z kabli SPI wskakują losowe liczby, więc rejestr SPDR jest aktualizowany.

    Gdzie slave stoi?
REKLAMA