Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Atmega8 i komunikacja z laptopem SPI<->LPT

s_ice 06 Gru 2005 20:22 3970 12
  • #1 06 Gru 2005 20:22
    s_ice
    Poziom 14  

    Witam.
    Mam problem z komunikacją mikrokontrolera Atmega8 z komputerem przez port LPT. Do komunikacji wykorzystuje sprzętowy interfejs SPI mikrokontrolera.

    Atmega8 pracuje jako Slave, a laptop jako Master.

    Slave ma za zadanie wysyłać kolejno liczby od 0 do 255 (dla testów). Master steruje transmisją i odbiera te dane. Problem w tym, że nie za każdym razem Slave wchodzi do procedury obsługi przerwania SPI.

    Ciąg odbierany: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [2] [12] [13] [14] [2] [2] [15] [16] ...
    Master zawsze wysyła wartość [2] do Slave’a ,nie ma ona w tym przypadku większego znaczenia.

    Jak widać w ciągu nie gubi kolejności ,ale wstawia wartość [2] (bajt wysyłany przez mastera) między poprawny ciąg. Co może być przyczyną tego stanu rzeczy?

    Atmega8 jest bezpośrednio podłączona do portu LPT. Programuje się bezproblemowo.

    Czy ktoś z Was komunikuje się prockiem z komputerem PC przez SPI?
    Jak rozwiązaliście transmisję aby nie było takich błędów?

    Kod częściowy Slave’a – ATMega8

    void spi_slave_init(void)
    {
    DDR_SPI = (1<<DD_MISO); //ustaw pin MISO jako wyjście
    SPCR = (1<<SPE)|(1<<SPIE);//włącz SPI oraz przerwanie do jego obsługi
    asm("sei"); //włącz globalne przerwania
    }

    char licznik=0;
    SIGNAL(SIG_SPI)
    {
    char data1;
    data1=SPDR;

    SPDR=licznik;
    licznik++;
    }

    int main()
    {
    spi_slave_init();

    for( ; ; )
    {
    }
    return 0;
    }

    Kod mastera napisałem w Delphi 7.0 Personal.

    Inicjacja wygląda tak:

    procedure init_spi;
    begin
    stan_prt:=CzytajLPT(port_out);(*odczytaj stan portu wyjsciowego*)
    set_ss(1);
    set_sck(0);
    end;

    Odczyt i wysyłanie danych obsługuje poniższa funkcja:

    function TransmitSPI(dat:byte):byte;
    var i,bajt,send:byte;
    begin
    set_ss(0);(*start transmisji*)

    for i:=0 to 7 do
    begin
    czekaj(10);
    set_sck(0);(*sygnal zegarowy LO- dane mozna zmieniac*)

    send:=(dat shr (7-i))and 1;

    czekaj(10);
    set_mosi(send);(*bit wysylany do slave'a*)

    czekaj(10);
    set_sck(1);(*sygnal zegarowy - dane stabilne*)

    czekaj(10);
    bajt:=(bajt shl 1)or get_miso;(*odbiera bit ze slave'a i pakuje do bajta*)
    end;
    (*koniec transmisji SCK-LO SS-HI*)
    set_sck(0);
    set_ss(1);

    czekaj(2000);(*odczekaj chwile*)
    TransmitSPI:=bajt;
    end;


    Procedury są raczej poprawne gdyż większość transmisji przebiega bezbłędnie i odbiera to co powinien. Jedynie te opuszczone wejścia do procedury obsługi przerwania są problemem (na pewno nie wchodzi do procedury bo licznik nie jest inkrementowany).

    Proszę o pomoc w tej sprawie bo niestety w laptopie nie mam innego portu którym mógłbym się komunikować z procesorem, żadnego COM’a nie ma ,tylko LPT ewentualnie wbudowany modem [AC97 SoftV92 Data Fax Modem with SmartCP] , z tego co pisze to na porcie COM3.

    pozdrawiam

    0 12
  • #2 06 Gru 2005 20:38
    genetix
    Poziom 24  

    Wiem, że to nie rozwiązanie problemów z SPI, jednakże chyba bardziej uniwersalnie będzie jak zastosujesz kartę PCIMCIA z RS232.... Chyba nie jest to taki wielki wydatek, a napewno COM się przyda...

    0
  • #3 06 Gru 2005 21:35
    s_ice
    Poziom 14  

    Pewnie by się przydało, ale taka karta kosztuje ponad 100zł, a do tego SPI jest chyba szybsze od RS232 chociaż nie wiem dokładnie bo nie mam na ten temat dużej wiedzy.

    0
  • #4 07 Gru 2005 09:44
    genetix
    Poziom 24  

    Zobacz, czy taktowanie SPI nie jest zbyt szybkie w stosunku to zegara u-kontrolera. Daj większe opóźnienie w generowaniu SCLK, albo zmień kwarc na "szybszy".

    Aha, jeszcze jedno - obiło mi się o uszy (lub raczej oczy-bo na elektroda.pl), że w laptopach bywają problemy z poziomami napięć na LPT (tzn. niższy poziom) ATmega8 powinien chodzić przy 4.5V (lub mniej w wersji L), więc może spróbuj zmniejszyć Vcc.

    0
  • #5 07 Gru 2005 18:53
    s_ice
    Poziom 14  

    Niestety nie pomogło zwolnienie SCLK, oraz obniżenie napięcia, ciągle pojawiają się błędy. Częstotliwość zwiększyłem do 2MHz (wewnętrzny generator bo nie używam zewnętrznego kwarcu).

    0
  • #6 08 Gru 2005 19:17
    s_ice
    Poziom 14  

    Zauważyłem przy testowaniu ,że podczas wysyłania sygnałów SCK z mastera po prostu czasami nie zostają odebrane przez slave’a i dlatego transmisja nie zostaje zakończona. Warunkiem końca transmisji jest wysłanie 8 razy sygnału SCK, a slave odbiera niekiedy tylko 6 albo 7 i po podaniu na linię SS przez mastera stanu wysokiego transmisja zostaje przerwana. Niestety nie mam możliwości sprawdzenia czy wszystkie bity zostały odebrane przez slave’a tak ,aby master o tym wiedział.

    Czy mógłbym zastosować jakiś bufor z bramek schmita np. 4093 ? Bo taki mam akurat pod ręką.
    Czy właściwie to może coś pomóc?

    Negacja raczej nie przeszkadza bo programowo mogę to odwrócić w programie mastera. Może właśnie te napięcia są zakłócane, dziwi mnie tylko, że programowanie przebiega bezbłędnie ,a transmisja SPI nie.

    0
  • #7 08 Gru 2005 19:30
    genetix
    Poziom 24  

    Możesz połączyć 2 bramki z 4093, i dostaniesz sygnał prawdziwy.
    Sprawdź woltomierzem jaki jest poziom logicznej jedynki na wyjściu CLK.

    Dodano po 2 [minuty]:

    a ile to jest czekaj(10)? w mikrosekundach?

    0
  • #8 08 Gru 2005 20:20
    s_ice
    Poziom 14  

    napięcie na wyjściu CLK z portu LPT to 4.79V.

    Procedurę czekaj(i:integer); napisałem tylko po to aby zrobić opóźnienia mniejsze od 1ms jakie delphi ma w procedurze sleep(); (w celu zwiększenia prędkości transmisji). Także ciężko mi określić ile to jest czekaj(10); ale raczej mało (może kilkanaście mikrosekund).


    (*procedura opóźniająca zależna od prędkości procesora*)
    procedure czekaj(i:integer);
    var j,k,l:integer;
    begin
    k:=1;l:=1;
    for j:=0 to i do begin k:=k div l;end;
    end;

    0
  • #9 08 Gru 2005 20:44
    genetix
    Poziom 24  

    popróbowałbym z opóźnieniem rzędu 1-2ms, czyli ok 0.5-1kHz

    0
  • #10 11 Lut 2006 18:37
    s_ice
    Poziom 14  

    Witam po długiej przerwie.

    Niestety nie udało mi się znaleźć przyczyny, czemu transmisja ma błędy. Opóźnienia wpisywałem już, nawet sekundowe żeby niczego nie zgubił, ale i tak są błędy. Najlepiej jeśli by ktoś z Was zrobił próbę na swoim komputerze. Czy występuje ten sam problem, bo ja już nie wiem czemu tak się dzieje, a nie chce robić programowo transmisji skoro jest sprzętowa i w dodatku działa na przerwaniach. Możliwe że przyczyną jest port LPT w moim laptopie, chociaż nie powinien bo programowanie przebiega bezbłędnie.

    Aha ,buforowanie przez bramki schmitta też nic nie pomogło.

    Więc jeśli ktoś miałby czas i ochotę sprawdzić czy to działa i podzielił się spostrzeżeniami, to może znalazłbym wreszcie przyczynę „błędów” transmisji.

    0
  • #11 25 Lut 2006 13:41
    lukrow
    Poziom 11  

    Napisz na jakim systemie działasz, windows 98,xp, linux, (Delphi działa tez na linux)
    wiem ze windowsy oparte na technologi nt maja problem z dostepem do portu lpt i trzeba sterowniki odpowiednie instalowac.
    Sprubuj na windows 98 odpalic program. Na moim lapotpie nie moge zainstalowac 98 wiec jezeli to nie pomoze to sprubuje u siebie na xp.
    Droga rzecz jest taka ,że jezeli masz w kompie usb to mozesz kupic kabel przejsciowke z usb na 2 comy.

    0
  • #12 01 Mar 2006 15:19
    s_ice
    Poziom 14  

    Wszystko robię w systemie Windows XP, win98 też mi się na laptopie nie zainstaluje. Porty w XP sobie odblokowałem programem UserPort więc mam dostęp do LPT.

    Porty USB posiadam, w ostateczności prawdopodobnie zakupie takową przejściówkę, ale to wiąże się raczej z rozbudową układu w celu dopasowania napięć procesora i portu COM.

    Więc jak na razie staram się rozwiązać problem z komunikacją przez SPI gdyż jak dla mnie jest ona bardziej wygodna.

    pozdrawiam

    0
  • #13 21 Sie 2006 12:15
    pokost
    Poziom 11  

    Cześć !

    Pisałem swoją, całkiem niezależną procedurę i otrzymałem objaw dokładnie taki sam jak Twój. Moja procedura wysyłania znaku z komputera wygląda tak:

    Code:
    void wys_znak (char znak) {
    
      int i;
      unsigned char bit, znak_odb = 0;
      char bufor[200];

      Sleep (PAUZA);
      OutPort (0x378, 1<<D_RESET | bit | 1<<D_SS); // to troche pomog│o.
      for (i=0; i<8; i++) {
        bit = 0;
        if (0x80 & znak)
          bit = 1;
        bit <<= D_MOSI;

        //printf ("  znak = %x, bit = %d\n", znak, bit);
        Sleep (PAUZA);
        OutPort (0x378, 1<<D_RESET | bit);
        Sleep (PAUZA);
        OutPort (0x378, 1<<D_RESET | bit | 1<<D_SCK);
        Sleep (PAUZA);
        znak <<= 1;

        znak_odb <<= 1;
        if ( InPort (0x379) & 1<<D_MISO )
          znak_odb |= 0x01;
        Sleep (PAUZA);
      }
      // to jest kluczowa poprawka !!!
      OutPort (0x378, 1<<D_RESET | bit);
      Sleep (PAUZA);
      OutPort (0x378, 1<<D_RESET | bit | 1<<D_SS);
     
    sprintf (bufor, "Odebrana wartoťŠ: %d (%X) '%c'\r\n", znak_odb, znak_odb,
       (znak_odb >= 32 ? znak_odb : '?'));
    log (bufor);

    }

    Jak widać, każdy znak synchronizuję sygnałem SS, ale ustawiam go dopiero po wyzerowaniu sygnału SCK. Dopóki tego nie zrobiłem, pojawiały się błędy (odbierałem znak wysłany wcześniej - zdarzało sie czasami, nie przy każdym bajcie). Konfigurację (po stronie uC) mam taką jak Ty, tzn
    Code:
    SPCR = (1<<SPE)|(1<<SPIE);


    Nie wiem czy komuś po pół roku to się przyda, ale może... :-)
    Najlepszego, Jejek

    0
  Szukaj w 5mln produktów