Elektroda.pl
Elektroda.pl
X

Wyszukiwarki naszych partnerów

Wyszukaj w ofercie 200 tys. produktów TME
Kategoria: Kamery IP / Alarmy / Automatyka Bram
Montersi
Proszę, dodaj wyjątek elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[atmega8] [C] Raz jeszcze TWI- nie ustawiana flaga TWINT

4everYoung 09 Paź 2009 18:11 2578 6
  • #1 09 Paź 2009 18:11
    4everYoung
    Poziom 9  

    Witam! Na forum zawsze znajdowałem odpowiedzi i drążyłem każdy temat samodzielnie w myśl zasady jednego z moich wykładowców "świat dzieli się na samouków i nieuków"... lecz tym razem rozłożyłem ręce po 3-dniowej walce z TWI/i2c (w między czasie wypiłem tylko 2 bro) i postanowiłem nieśmiało założyć temat (chyba mój inauguracyjny...).

    Przeczytałem regulamin oczywiście i przewertowałem forum (z którego wziąłem wzory kodów), noty aplikacyjne (na których się opierałem odn. teorii), znalazłem mnóstwo artykułów (wszystkie zarchiwizowane już mam więc są pod ręką)...

    Jestem może nie początkującym jeśli idzie o uP, ale na pewno dosyć oporny na wiedzę z tym tematem i jej przyswajanie postępuje niestety powoli, więc sorka za niedobór jakiejś części wiedzy.

    Do rzeczy, bo może uda się szybko zamknąć temat. Potrzebuję skomunikować narazie 2 tytułowe AT8, by nauczyć się w praktyce działania i2c (docelowo mają komunikować się w niewolniczym trybie wysyłającym i odbierającym z robotami mobilnymi opartymi o Basic Atom Pro i/lub Basic Stamp przez medium bezprzewodowe- dzięki modułom rfm12, przy czym komunikacja bezp. już jest wykonana). Jedną chce mieć jako Master a 2gą jako Slave (w jakich trybach to się okaże). Chcę tak jakby zasymulować (w ramach edukacji) np. układ pcf8574, by zwierając jakiś pin na niewolniku wywołać odpowiedni stan na tym samym układzie, oczywiście sterując go masterem.

    Zasadniczy problem z TWI: czy da się w AvrStudio 4 tak zasymulować pracę przykładowego programu, by wyzerować bit (wpisać 1) TWINT w rejestrze TWCR, czy trzeba go "wymusić" np. kliknięciem myszką? Jak nazwa wskazuje jest to przerwanie, a choć robiłem jakieś zegarki dawno temu, trochę nie rozumiem go w tym miejscu. Może symulator AS4 nie ustawi go i trzeba to fizycznie wykonać przez skomunikowanie procków?

    Nie mam fizycznego debuggera, więc tylko na tym się opieram. Programowałem i sprawdzałem czy sekwencja startu przeszła przez zgaszenie diody na płytce testowej(klawisz załącza pierwszy krok startu, po nim powinna zgasnąć diodka), ale ta dalej się świeci.

    problem podobny jak w temacie

    ATMEGA32 - Problem z TWI

    ale tam kolega rozwiązał go przez ustawienie TWINT...

    Może coś w AvrStudio4 mam źle ustawione? Jakieś biblioteki nie takie?

    Więc tak, kod wygooglowany/elektrodowany wygląda następująco (najważniejsze jego części):

    Code:

    #include <inttypes.h>
    #include <avr/interrupt.h>
    //#include <avr/signal.h>
    #include <C:\WinAVR-20090313\avr\include\compat\twi.h>
    #include <avr/io.h>
    #include <util/delay.h>

    //Definicja czestotliwosci taktowania zegara

    #ifndef F_CPU
    #define F_CPU 8000000UL
    #endif

    //Czestotliwosc magistrali I2C
    #define SCL_CLOCK  100000L


    //Inicjalizacja magistrali I2C
    void i2c_init(void)
    {
      //Czestotliwosc TWI 100 KHz TWPS = 0 => preskaler = 1
     
      TWSR = 0;                         //brak preskalera
      TWBR = ((F_CPU/SCL_CLOCK)-16)/2;

    }

    /*Wysyla sygnal start na magistrale,
    adresuje urzadzenie oraz okresla kierunek transmisji
    zwraca 0 jezeli urzadzenie jest dostepne, 1 gdy wystapil blad*/
    unsigned char i2c_start(unsigned char address)
    {
        uint8_t   twst;         // typ zmiennej unsigned integer o dł. słowa 8b (=
       //START
       TWBR=32;
       TWSR &= ~0x03;
       TWCR = (1<<TWIE);
       TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
       // czekaj na zakonczenie transmisji
       while(!(TWCR & (1<<TWINT)));
       // Sprawdz rejestr statusu
       twst = TW_STATUS & 0xF8;
       //wystapil blad, zwroc 1
       if ( (twst != TW_START) && (twst != TW_REP_START))

    Oczywiście to część kodu przy której się zawiesza, a jest on wszędzie opisywany, np http://radzio.dxp.pl/twi/ albo http://ds5.agh.edu.pl/~czaro/naukowo/soft/avr_twiobsluga.pdf
    Wywołuję funkcję u2c_start w części głównej (tylko kilka linijek, by sprawdzić czy działa):
    Code:
    int main (void)
    
    {
    int j;            // zmienna j by coś było w rejestrze TWDR jako dana
    j = 0xCC;

    while (1)
    {
    i2c_init();         // ustawienie preskalera
    TWDR = j;          // dana do TWDR
    i2c_start(0x2);      // byle jaki adres
    }
    }

    Oczywiście program zapętla się przy TWINT, a powinien iść dalej, gdyby flaga się ustawiła zgodnie z linijką
    Code:
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

    Pewnie czegoś z przerwaniami nie dostrzegam/nie rozumiem... albo mam fizycznie połączyć te At8? Choć wydawałoby się to dziwne- powinien zwrócić kod błędu program gdy nie jest slave dostępny, czy mylę się?
    Proszę o wskazanie błędu lub o nakierowanie nad czym się zastanowić i co dokładniej doczytać (no i o wyrozumiałość (= )

  • #2 13 Lis 2009 01:51
    nigel0
    Poziom 9  

    Witam szanownych kolegów ja również stawiam pierwsze kroki w programowaniu, skorzystałem z gotowych procedur obsługi twi(projekt z zegarkiem RTC) i wszystko śmiga jak należy, jednak jedno nie daje mi spokoju. Procedura którą zamieściłem poniżej działa bez zarzutu, jednak nie do końca rozumiem mechanizmu działania instrukcji: while(!(TWCR & (1<<TWINT)));

    Oto opis: "Oczekiwanie na ustawienie flagi
    TWINT. Sygnalizuje to, e bit
    SLA+W został wysłany, zas bit
    ACK/NACK został odebrany"


    Po pomyslnym wysłaniu danych i odebraniu ack, mikrokontroler ustawia wartość TWINT na 0, zaś pętla while(!(TWCR & (1<<TWINT))); zakończy oczekiwanie(działanie) gdy wartość TWINT osiągnie 1 czyli zupełnie na odwrót, na tym polega rozbieżność której nie rozumiem, poniżej cały kod bc może ktoś znajdzie chwilkę na odpowiedź, pozdrwawiam

    poniżej cała procedura:
    void TWI_write(unsigned char dane)
    {
    TWDR=dane;
    TWCR=(1<<TWINT)|(1<<TWEN);
    while(!(TWCR & (1<<TWINT)));
    if(((TWSR & 0xF8)!=0x18)&&((TWSR & 0xF8)!=0x28)&&((TWSR & 0xF8)!=0x40))
    LCD_putstr_P(PSTR("ERROR WRITE"));
    }

  • #3 13 Lis 2009 14:15
    cavendish
    Poziom 17  

    nigel0 napisał:

    Po pomyslnym wysłaniu danych i odebraniu ack, mikrokontroler ustawia wartość TWINT na 0

    Skąd ta wiadomość? Według dokumentacji:
    [atmega8] [C] Raz jeszcze TWI- nie ustawiana flaga TWINT

    Flaga ta po resecie ustawiona jest na zero. Po wystąpieniu zdarzenia wymagającego programowej obsługi ustawiana jest na 1. Transmisję rozpoczyna się od wyzerowania tej flagi. Wyzerować ją można poprzez wpisanie do niej logicznej "1".

    @4everYoung - po co ustawiasz flagę TWIE skoro nie wykorzystujesz przerwań od TWI?

    4everYoung napisał:

    Pewnie czegoś z przerwaniami nie dostrzegam/nie rozumiem... albo mam fizycznie połączyć te At8? Choć wydawałoby się to dziwne- powinien zwrócić kod błędu program gdy nie jest slave dostępny, czy mylę się?


    Pierwszym zdarzeniem, po którym w atmedze pracującej jako master zostanie ustawiona flaga TWINT jest: "warunek startu został wysłany" - co powinno skutkować przejściem w stan 0x08 po czym można wysłać SLAW/SLAR. Jako, że w TWI wyjścia są typu open drain/collector, warunek startu będzie mógł zostać wysłany tylko wtedy gdy na liniach SCL, SDA będą rezystory podciągające (dałeś je?). Dopiero po wysłaniu warunku startu i SLAW/SLAR, otrzyma się status informujący o tym czy slave wystawił na linii SDA potwierdzenie o swojej obecności (ACK).

  • #4 13 Lis 2009 15:21
    nigel0
    Poziom 9  

    dzieki cav za mertoryczną odpowiedz, mam jeszcze jedno pytanko, oto co dzieje się z flagą TWINT podczas typowej operacji na magistrali I2c

    TWINT=1 -stan flagi przed programowym zerowaniem
    TWCR=(1<<TWINT)|(1<<TWEN); -zerowanie flagi poprzez przypisanie jej logicznej jedynki
    TWINT=0 -stan flagi po programowym zerowaniu (trwa przesyłanie danych z lub do TWDR)
    TWINT=1 -stan flagi gdy dane zostaną przesłane oraz zostanie odebrany ack od slave(wracamy do punktu wyjścia)

    moje pytanie brzmi w jaki celu ustawiamy (1<<TWINT) skoro przed zerowaniem flaga ta ma już ustawioną wartość równą 1 ?.

  • #5 13 Lis 2009 16:25
    cavendish
    Poziom 17  

    Tak właśnie dokonuje się zerowania tej flagi. Jest to, przyznam, sprzeczne z intuicyjnym rozumieniem "zerowania". Bardzo często, także w innych kontrolerach zerowanie jakiejś flagi wiąże się z koniecznością wpisania do niej "1". Nie wiem jaka filozofia się za tym kryje ale chodzi być może o jakieś niuansy sprzętowe, o których wiedzieć mogą ludzie, którzy projektują takie układy.

  • #6 27 Maj 2010 15:54
    Siwyyx
    Poziom 9  

    Witam,
    Przepraszam za odkopywanie tematu, ale posiadam ten sam problem.
    Chodzi o mikrokontroler atmega16 i pamięć EEPROM 24C16. Dopiero zaczynam swoją przygodę i na początek chciałbym zapisać i odczytać 1B danych. Zapoznałem się z dokumentacjami oraz z wieloma opracowaniami.
    Oto kod źródłowy:

    Code:
    void start_twi()
    
    {
       TWCR = (_BV(TWINT) | _BV(TWEN) | _BV(TWSTA) );
       while(!(TWCR & _BV(TWINT)));                  //pętla jest wykonywana dopóki w rejestrze TWCR nie zostanie
                                              //ustawiony bit TWINT, który jest ustawiany sprzętowo po
                                              //zakończeniu bierzącej operacji przez interfejs
       TWCR &= ~(_BV(TWSTA) | _BV(TWINT));    
    }

    void stop_twi()
    {
       TWCR |= (_BV(TWINT)|_BV(TWEN)|_BV(TWSTO));
       while((TWCR & _BV(TWSTO)));
    }

    unsigned char read_twi(unsigned char ack)
    {
       TWCR |= (_BV(TWINT)|(ack<<TWEA)|_BV(TWEN));
       while(!(TWCR & _BV(TWINT)))
       return TWDR;
    }

    void write_twi(unsigned char data)
    {
       TWDR = data;                              //bajt danych do wysłania
       TWCR |= (_BV(TWINT) | _BV(TWEN));
       while(!(TWCR & _BV(TWINT)));                  //z nieznanych przyczyn bit TWINT nie zostaje ustawiony
    }

    unsigned char write_to_EEPROM(unsigned char address, unsigned char data)
    {
       start_twi;
       write_twi(0xA0);                           //adres urządzenia
       write_twi(address);                             //adres komórki do zapisu
       write_twi(data);                                //dane do zapisu
       stop_twi;
       _delay_ms(15);
    }

    unsigned char read_from_EEPROM(unsigned char address)
    {
       unsigned char read_data;
       
       start_twi;
       write_twi(0xA0);
       write_twi(address);
       start_twi;
       write_twi(0xA1);
       read_data = read_twi(0);
       stop_twi;
       
       return read_data;
    }

    int main()
    {
       DDRD = 0xff;
       write_to_EEPROM(1,0xaf);
       PORTD = read_from_EEPROM(1);
       while(1)
       return 0;
    }

    Po obserwacji stwierdziłem, że program zatrzymuje się w poniższym fragmencie w pętli while.
    Code:
    void write_twi(unsigned char data)
    
    {
       TWDR = data;                                          //bajt danych do wysłania
       TWCR |= (_BV(TWINT) | _BV(TWEN));
       while(!(TWCR & _BV(TWINT)));                  //z nieznanych przyczyn bit TWINT nie zostaje ustawiony
    }


    W temacie Link zostały podane rozwiązanie tego problemu (wyzerowanie bitu TWSTA w funkcji start_twi) - to samo zrobiłem u siebie jednak bez skutku.
    Próbowałem nawet kopiować gotowe kody źródłowe do obsługi TWI znalezione w internecie jednak i one nie działały. Wszystko wskazuje na to, że problem leży w połączeniu układu jednak wygląda na to, że jest dobrze, mianowicie:
    - SDA(pin 5) i SCL(pin 6) na rezystorach podciągających 4,7K do +5V
    - A0, A1, A2 i GND (piny odpowiednio 1, 2, 3 i 4) do masy
    - WP(pin 7) niepodłączony
    - VCC(pin 8) do +5V

    Opierałem się na dokumentacji pamięci atmela ponieważ do swojej nie mogłem znaleźć (oznaczenia na obudowie: ATMLU740 NZ7F6197).

  • #7 29 Maj 2010 17:00
    cavendish
    Poziom 17  

    Cytat:
    Opierałem się na dokumentacji pamięci atmela ponieważ do swojej nie mogłem znaleźć (oznaczenia na obudowie: ATMLU740 NZ7F6197).


    Trzeba dysponować oryginalną dokumentacją, bo inaczej można pobłądzić w podstawowych kwestiach. Chyba, że gdzieś jest powiedziane, że są to zamienniki. Więcej na temat zachowania się magistrali wiedzielibyśmy znając status, w którym "grzęźnie" (TWSR, bodajże).

 
Promocja -20%
Zamknij 
Wyszukaj w ofercie 200 tys. produktów TME
tme