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

Komunikacja spi między atmegami

mijadzi 28 Wrz 2011 21:01 2538 22
  • #1 9973580
    mijadzi
    Poziom 10  
    Proszę pomóżcie.
    Master zapala lampkę i wysyła polecenie do slava by też zapalił lampkę, potem czeka parę sekund i gasi ją i wysyła do slava wiadomość by on też swoją gasił.
    To chciałem zrobić ale efekt jest taki, że lampka po stronie slava mruga jak chce. Czasami posłucha mastera a czasami nie: (nie wiem gdzie jest błąd w kodzie, proszę rzućcie okiem:
    master:
    void SPI_master_init() 
    { 
       PORTB|=_BV(PB2);//wlaczenie lini ss na stan wysoki 
       DDRB|=(_BV(PB2) | _BV(PB3) | _BV(PB5));   //Piny SS, MOSI, SCK jako wyjście 
       SPCR=_BV(SPE) | _BV(MSTR); //Tryb master, CLK/4 
       SPSR; 
       SPDR; //Skasuj flagę SPIF 
    } 
    uint8_t SPI_send_byte(uint8_t byte) 
    { 
       SPDR=byte; 
       while(!(SPSR & _BV(SPIF))); 
    } 
    int main() 
    { 
       _delay_ms(100); 
       uint8_t i; 
       SPI_master_init(); 
       while(1) 
       { 
          DDRB|=_BV(DDB7); 
          PORTB&=~(_BV(PB2));//stan niski na lini ss slava 
          i=(uint8_t)1; 
          SPI_send_byte(i); 
          PORTB|=_BV(PB2);//stan wysoki na lini ss slava 
          PORTB|=_BV(PORTB7); 
          _delay_ms(1000); 
          PORTB&=~(_BV(PB2));//stan niski na lini ss slava 
          i=(uint8_t)0; 
          SPI_send_byte(i); 
          PORTB|=_BV(PB2);//stan wysoki na lini ss slava 
          PORTB&=~_BV(PORTB7); 
          _delay_ms(1000); 
       } 
    } 

    slave:
    ISR(SPI_STC_vect) 
    { 
       const uint8_t s=(uint8_t)1; 
       const uint8_t n=(uint8_t)0; 
       if(SPDR==s) 
          { 
             PORTB|=_BV(PORTB0); 
          } 
       else if(SPDR==n) 
          { 
             PORTB&=~_BV(PORTB0); 
          } 
    } 
    void SPI_slave_init() 
    { 
       DDRB|=_BV(PB6);   //Pin MISO jako wyjście 
       SPCR=_BV(SPE) | _BV(SPIE); //Tryb master, CLK/4, przerwania 
       SPSR; 
       SPDR; //Skasuj flagę SPIF 
    } 
    
    
    int main() 
    { 
       DDRB|=_BV(DDB0); 
       SPI_slave_init(); 
       sei(); 
       while(1); 
    }
  • #2 9974549
    arturt134
    Poziom 27  
    1. Jak jest długość przewodów między masterem i slavem?
    2. Jaka jest częstotliwość kwarca (kwarców)?
    3. Czy na liniach są jakieś rezystory, kondensatory, itp.?
    4. Po co są linie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Przecież taki kod nic nie robi... a już na pewno nie kasuje żadnych flag.
  • #3 9974748
    mijadzi
    Poziom 10  
    Co do kodu, to nie wiedziałem że on nic nie robi(znalazłem go gdzieś w internecie). W jaki sposób zgasić flagę SPIfinish?

    Na linii spi jest tylko kabel i nic więcej.

    W programie nic nie zmieniałem z częstotliwością kwarcu, a w datasheecie dla obydwóch atmeg jest napisane 16MHz. Używam: master-Atmega8L, slave-Atmega32L.

    Kabel jest około 75 cm.(tego samego kabla używam do programowania uC (a programowanie odbywa się za pomocą spi).
  • #4 9974846
    arturt134
    Poziom 27  
    75cm to baaaaardzo dużo jak na 4MHz SPI....
    Spróbuj zmniejszyć prędkość, np do 100kHz (albo i jeszcze bardziej, jeżeli nie zadziała).
    Co do kasowania flagi, to zrób tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Ta ostatnia linia jest po to, żeby kompilator nie generował warninga, że tmp jest nieużywany...
  • #5 9974875
    piotrva
    VIP Zasłużony dla elektroda
    mijadzi napisał:
    a w datasheecie dla obydwóch atmeg jest napisane 16MHz

    Hmm, dziwne bo wg. mnie częstotliwość pracy procesora zależy nie od tego co piszą w datasheecie (bezpośrednio), ale od konfiguracji Fusebitów CKSEL oraz ewentualnych elementów sprzętowych jak zewnętrzne kwarce, generatory sygnału zegarowego itp.
    No i też piszesz że masz kabel, ale nie piszesz jaki. 75cm jakiegoś zwykłego kabla to na 4MHz za dużo. Poza tym sprawdź czy kabel nie leży gdzieś przy innych kablach (230VAC, USB, ...) - to wprowadza straszne zakłócenia a przy takiej długości i częstotliwości zachowuje się on jak klasyczna antena jeśli nie jest odpowiednio ekranowany (stąd też porada - stosuj kable ekranowane).
  • #6 9974943
    mijadzi
    Poziom 10  
    transmisje zaprogramowałem na 125KHz, niżej się już nie da:( zmieniłem kabel na krótszy(11cm). Problem pozostał, może trochę lepiej jest ale nadal około co dwa mrugnięcia zawodzi spi.

    Przesyłam kod programu:
    Master:
    
    void SPI_master_init() 
    { 
       PORTB|=_BV(PB2);//wlaczenie lini ss na stan wysoki 
       DDRB|=(_BV(PB2) | _BV(PB3) | _BV(PB5));   //Piny SS, MOSI, SCK jako wyjście 
       SPCR=_BV(SPE) | _BV(MSTR) |  _BV(SPR1) |  _BV(SPR0); //Tryb master, CLK/128
       SPCR&=~(_BV(SPI2X));
       uint8_t tmp;
       tmp = SPSR;
       tmp = SPDR;
       (void) tmp;
    } 
    uint8_t SPI_send_byte(uint8_t byte) 
    { 
       SPDR=byte; 
       while(!(SPSR & _BV(SPIF))); 
    } 
    int main() 
    { 
       _delay_ms(100); 
       uint8_t i; 
       SPI_master_init(); 
       while(1) 
       { 
          DDRB|=_BV(DDB7); 
          PORTB&=~(_BV(PB2));//stan niski na lini ss slava 
          i=(uint8_t)1; 
          SPI_send_byte(i); 
          PORTB|=_BV(PB2);//stan wysoki na lini ss slava 
          PORTB|=_BV(PORTB7); 
          _delay_ms(1000); 
          PORTB&=~(_BV(PB2));//stan niski na lini ss slava 
          i=(uint8_t)0; 
          SPI_send_byte(i); 
          PORTB|=_BV(PB2);//stan wysoki na lini ss slava 
          PORTB&=~_BV(PORTB7); 
          _delay_ms(1000); 
       } 
    }

    slave:
    ISR(SPI_STC_vect) 
    { 
       const uint8_t s=(uint8_t)1; 
       const uint8_t n=(uint8_t)0; 
       if(SPDR==s) 
          { 
             PORTB|=_BV(PORTB0); 
          } 
       else if(SPDR==n) 
          { 
             PORTB&=~_BV(PORTB0); 
          } 
    } 
    void SPI_slave_init() 
    { 
       DDRB|=_BV(PB6);   //Pin MISO jako wyjście 
       SPCR=_BV(SPE) | _BV(SPIE) |  _BV(SPR1) |  _BV(SPR0); //Tryb master, CLK/128, przerwania
       SPCR&=~(_BV(SPI2X));
       uint8_t tmp;
       tmp = SPSR;
       tmp = SPDR;
       (void) tmp;
    } 
    
    
    int main() 
    { 
       DDRB|=_BV(DDB0); 
       SPI_slave_init(); 
       sei(); 
       while(1); 
    }

    Może może to pomogło, ale jeszcze jest widocznie jakaś skucha. Proszę o pomoc.
  • #7 9974975
    arturt134
    Poziom 27  
    Co to za procesor?
    Jaki jest jego częstotliwość zegara (kwarc + ewentualne dzielniki, a nie f_max z datasheet)

    PS. Bit SPI2X jest innym rejestrze w ATmega128.
    PS2. Kasowanie flagi SPIF w inicjalizacji mastera i slave'a możesz wywalić, nie jest potrzebne.
  • #8 9975055
    mijadzi
    Poziom 10  
    piotrva, wysłałem posta i nie zdążyłem zobaczyć twojego:) Nie mam podpiętego żadnego zewnętrznego kwarca. Szczerze mówiąc nie wiem co to są te Fusebity CKSEL i nic z nimi nie robiłem, więc wnioskuje że to jest tak jak w datasheecie. Ale jeśli to ma jakieś znaczenie to proszę o wskazówkę, co mam z nimi zrobić. Co do kabla to jest taki jak do spi(10 żyłowy), na nim jest napisane coś takiego: connfly shaec1000386523/chem awm 2651 uw-1 105oC 300V 28awg 20101224 - to jest ten dłuższy kabel. Kabel 11cm jest 8 żyłowy i na nim nic nie jest napisane, ale wygląda tak samo jak ten dłuższy. Sprawdziłem w bliskiej odległość nie ma żadnych takich urządzeń zakłócających, jedynie BTM-222(do komunikacji prze bluetooth ale go na razie nie używam chociaż możliwe że sam coś domyślnie wysyła), w pobliżu znajdują się jeszcze kable zasilające, ale to jest 3,3v prądu stałego, no i parę stabilizatorów napięcia.

    Teraz odpowiedź do arturt134:
    co do rejestru SPI2X, przesyłam obrazek z datasheeta z atmegi8, w 32 jest tak samo.
    Komunikacja spi między atmegami

    Jeśli chodzi o ten procesor to nie wiem, cały czas myślałem że częstotliwość taktowania jest 16MHz przesyłam link to datasheeta bo nie mogę się w nim połapać jeśli chodzi o tą częstotliwość.

    Flagę SPIF już wywaliłem:)
  • #9 9975075
    arturt134
    Poziom 27  
    Szanowny kolego. Ja nie proszę o datasheeta, tylko o odpowiedź na jedno proste pytanie - jaki to jest procesor. Nie będę ciągnąć 6MB tylko po to, żeby to sobie zobaczyć.
    Częstotliwość zegara procesora powinieneś znać pisząc program. Ja nie będę wertował dokumentacji, żeby do tego dojść - szkoda mi na to czasu. Sprawdź proszę jak masz ustawione bezpieczniki, zajrzyj do dokumentacji i odpowiedz na moje pytanie - jaka jest częstotliwość procesora.
    Jak otrzymam odpowiedzi na te dwa pytania, to postaram się Ci pomóc. Na pewno nie będę nic zgadywał, bo wróżką nie jestem.
  • #10 9975374
    mijadzi
    Poziom 10  
    Douczyłem się trochę o tych Fuesbitów(polecam stronkę: http://mirley.firlej.org/fuse_bity_w_mikrokontrolerach_avr ) i ustawiłem częstotliwość 2Mhz(wewnętrzny oscylator RC), zmieniłem szybkość spi-a na CLK/16, czyli wychodzi że częstotliwość sck wychodzi 125KHz, przy kablu 11cm, powinno wystarczyć. Obydwa uC są tak samo ustawione. Problem nie znikł, wręcz przeciwnie teraz wydaje mi się że co czwarte mrugnięcie slave załapuje co ma zrobić. Macie jeszcze jakieś pomysły co jest nie tak? Z góry dziękuje.
  • #11 9975457
    arturt134
    Poziom 27  
    Nadal nie napisałeś jaki to procesor. Wobec tego zabawię się we wróżkę i postaram się znaleźć błąd zakładając, że jest to ATmega8.
    1. Bit SPI2X znajduje się w rejestrze SPSR. W Twoim kodzie zerujesz go w rejestrze SPCR. Warto sprawdzić, czy się nie pomyliłeś i nie powinieneś zerować go w rejestrze SPSR.
    2. Dodaj małe opóźnienie po wystawieniu CS-a i przed jego zdjęciem (kilka milisekund; sprawdź, czy zmiana czasu opóźnienia wpływa jakoś na ilość błędów).
    3. Jeżeli powyższe nie pomoże, to dalej obniżaj prędkość transmisji; czy jest prędkość, przy której ilość błędów spadnie do zera?
    4. Jeżeli zawiodą wszystkie punkty, to pozostaje tylko wziąć oscyloskop (jak rozumiem nie masz go pod ręką, bo gdyś miał, to najprościej byłoby od tego zacząć) i pooglądać przebiegi.
  • #14 9975710
    mijadzi
    Poziom 10  
    mijadzi napisał:
    Używam: master-Atmega8L, slave-Atmega32L.
    Nie wiem czy z tym procesorem o to ci chodziło, ale już nie mam pomysłów co mam podać.

    Ogólnie jest tak jak przedtem. Zmniejszam i zwiększam częstotliwość SCK i widocznych zmian nie ma. Nadal slave nie do końca słucha. Poprawiłem też to:SPI2X. Przesyłam ostatnią wersje programu, nie działającą do końca dobrze. Niestety nie mam ani analizatora stanów logicznych ani oscyloskopu. Jak by ktoś jeszcze na coś wpadł to proszę pisać.
    master:
    void SPI_master_init() 
    { 
       PORTB|=_BV(PB2);//wlaczenie lini ss na stan wysoki 
       DDRB|=(_BV(PB2) | _BV(PB3) | _BV(PB5));   //Piny SS, MOSI, SCK jako wyjście 
       SPCR=_BV(SPE) | _BV(MSTR) |  _BV(SPR1) |  _BV(SPR0); //Tryb master, CLK/128, przerwania
       SPSR&=~(_BV(SPI2X));
    } 
    uint8_t SPI_send_byte(uint8_t byte) 
    { 
       SPDR=byte; 
       while(!(SPSR & _BV(SPIF))); 
    } 
    int main() 
    { 
       _delay_ms(100); 
       uint8_t i; 
       SPI_master_init(); 
       while(1) 
       { 
          DDRB|=_BV(DDB7); 
          PORTB&=~(_BV(PB2));//stan niski na lini ss slava
    	  _delay_ms(30); 
          i=(uint8_t)1; 
          SPI_send_byte(i);
    	  _delay_ms(30);  
          PORTB|=_BV(PB2);//stan wysoki na lini ss slava 
          PORTB|=_BV(PORTB7); 
          _delay_ms(1000); 
          PORTB&=~(_BV(PB2));//stan niski na lini ss slava 
          _delay_ms(30); 
    	  i=(uint8_t)0; 
          SPI_send_byte(i);
    	  _delay_ms(30);  
          PORTB|=_BV(PB2);//stan wysoki na lini ss slava 
          PORTB&=~_BV(PORTB7); 
          _delay_ms(1000); 
       } 
    }

    slave:
    ISR(SPI_STC_vect) 
    { 
       const uint8_t s=(uint8_t)1; 
       const uint8_t n=(uint8_t)0; 
       if(SPDR==s) 
          { 
             PORTB|=_BV(PORTB0); 
          } 
       else if(SPDR==n) 
          { 
             PORTB&=~_BV(PORTB0); 
          } 
    } 
    void SPI_slave_init() 
    { 
       DDRB|=_BV(PB6);   //Pin MISO jako wyjście 
       SPCR=_BV(SPE) | _BV(SPIE) |  _BV(SPR1) |  _BV(SPR0); //Tryb master, CLK/128, przerwania
       SPSR&=~(_BV(SPI2X));
    } 
    
    
    int main() 
    { 
       DDRB|=_BV(DDB0); 
       SPI_slave_init(); 
       sei(); 
       while(1); 
    }
  • #16 9978004
    arturt134
    Poziom 27  
    Dokładnie o to mi chodziło. Dziękuję.
    1. W przerwaniu spróbuj zmienić:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

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

    2. Na linii zegara (SCK) daj mały rezystor od strony slave'a (np. 33R..50R, taki jak masz pod ręką).
  • #17 9978377
    piotrva
    VIP Zasłużony dla elektroda
    ad. 2. do czego podpiąć ten rezystor? Do masy czy do zasilania drugą końcówką? I czy wtedy aby nie popłynie zbyt duży prąd? Bo wydaje mi się, że wtedy master traci swój pin SCK ;-)
  • #19 9978504
    piotrva
    VIP Zasłużony dla elektroda
    A to może być, ale raczej nie widzę w tym szans na poprawę sytuacji - sięgnij po analizator stanów i zobacz co "leci" na tych liniach...
  • #20 9978580
    arturt134
    Poziom 27  
    Dokładnie. Chodzi o rezystor szeregowy, żeby wytłumić ewentualne "dzwonienie" na linii zegarowej. Na pozostałych liniach też nie zaszkodzą, powinny polepszyć jakość sygnału przy przewodzie o znacznej pojemności.
    A co z punktem 1)? Coś to zmieniło?
  • #21 9990216
    mijadzi
    Poziom 10  
    Przepraszam że tak długo nie odpowiadałem, ale byłem na wyjeździe i nie miałem układu przy sobie. Dzięki artur, jak by się trochę polepszyło i w sumie twoje rozwiązanie jest bardziej logiczne, ale problemu w zupełności nie rozwiązało. Nadal raz mruga prawidłowo a raz nie:( z tym rezystorem to próbowałem z 400 Om i w ogóle nie działało. Niestety nie mam mniejszego. Później kupie mniejszy i wypróbuje. Co do analizatora stanów logicznych, to nie mam portu LPT( to jest w miarę nowy laptop i tu już nie ma tego portu, jest tylko port VGA). Proszę o dalsze wskazówki.
  • #22 9990971
    piotrva
    VIP Zasłużony dla elektroda
    A próbowałeś na krótkich drucikach do 10cm? Może kabel oprócz tego że długi to uszkodzony?
  • #23 9991185
    arturt134
    Poziom 27  
    Nie ma problemu, nie zawsze ma się czas.
    Szczerze mówiąc to już mi się pomysły skończyły. Sprawdź jeszcze te rezystory, a jak nie, to zostanie tylko oscyloskop.
REKLAMA