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

Atmega8 problem z przerwaniową obsługą TWI

02 Lut 2008 22:48 3238 20
  • Poziom 11  
    Witam!

    Problem polega na tym, że moduł TWI wydaje się nie generować przerwań. Korzystam z przerwaniowej obsługi I2C.
    Gdy wysyłam start nic się nie dzieje. TWSR nie zmienia swojej wartośći, a z tego co wiem,
    to po wysłaniu startu powinien, po zamaskowaniu bitów nastawy preskalera ,przyjąć wartość 0x08.
    Nie ma także przerwania z TWI. TWINT cały czas ma wartość 0.
    Może istnieje jakiś tajemniczy bug o którym brak żadnych informacji w dokumentacji?
    Ktoś się spotkał z podobnym problemem? Będę wdzięczny za wszelkie sugestie.
  • Poziom 39  
    No to wniosek jest prosty - coś "pokręciłeś".Niestety nie powiem co , bo ... nie wiem.

    Piotrek
  • Poziom 11  
    Więc może wkleję trochę kodu.

    Code:

    I2C_ini:

       ldi R16, (1<<TWEN)|(1<<TWIE)
       out TWCR, R16         

       ldi R16, 50   
       sbr R16, TWGCE   
       out TWAR, R16

       ldi R16, 32            ; FOSC 16+2*32*4^(TWPS10)= 100KHz
       out TWBR, R16

       ldi R16, 0b11111010
       out TWSR, R16

       ret

               (...)

       in R16, TWCR
       sbr R16, TWSTA
       sbr R16, TWINT
       out TWCR, R16

       rt:
       in R16, TWSR
       rcall Pokaz_bajt_LCD
       ldi R16, 10
       ldi R17, 100
       rcall czekaj_ms
       rjmp rt



    Na wyświetlaczu wyświetla się wartość 250. Dodam jeszcze, że korzystam z wewnętrznych rezystorów podciągających, ale to raczej znaczenia żadnego nie ma.
  • Specjalista - Mikrokontrolery
    a gdzie aktywacja przerwan globalnych?

    w asm przewaznie istotna jest calosc kodu [;

    0x41 0x56 0x45!!
  • Poziom 11  
    Wcześniej. Nie martw się o to ;)
  • Specjalista - Mikrokontrolery
    to dobrze, milosniku Candlemass <:

    co do tych pullupow - jaka to mniej wiecej wartosc? bo od ich wartosci zalezy predkosc I2C. moze przy wlaczeniu I2C te pullupy staja sie nieaktywne? ja bym na twoim miejscu sprobowal ze standardowymi pullupami 4.7k, bez tych wewnetrznych.

    0x41 0x56 0x45!!
  • Poziom 11  
    Z tego co wiem wartości rezystorów podciągających wahają się pomiędzy 20-50k. Pewna mądra książka mówi, że takie rezystory powinny starczyć, jeżeli używa się niskich częstotliwości, i małej ilości obsługiwanych urządzeń. No w moim przypadku jest to PCF8583. Hmm.. właśnie, czy przypadkiem moduł TWI nie testuje czy wartość na wyjściu równa się wartości która powinna być? Ale jeżeli tak to powiniennem dostać w TWSR 0x38 po zamaskowaniu - czyli utracono kontrolę nad magistralą. Lub 0x00 nieoczekiwany start lub stop... No cóż jutro spróbuję z tymi standardowymi pull-up'ami. Zobaczymy czy coś da.

    A co do Candlemass to nie to, żebym był ich wielkim miłośnikiem.. po prostu spodobało mi się to zdjecie.. ale to już jest temat na inne forum ;)

    Dodano po 1 [minuty]:

    A no sprawa nieaktywności pull-up'ow. Otóż można je włączyć, nawet jak TWI jest włączone. Pewnie z myśla o zastosowaniu ich w ten właśnie sposób.
  • Poziom 11  
    Dodałem pull-up'y.. To samo. Odłączyłem PCF8583.. to samo. Pomierzyłem napięcia przy włączonym TWI i wynoszą one na obu wyprowadzeniach ~5V. Jak ustawiłem te wyprowadzenia na we/wy to działają, więc ogólnie porty nie są ufajczone. Nie wiem w czym problem. Może w atmedze8..
  • Poziom 32  
    Napisz obsługę programową i po kłopocie będzie a na dodatek mozesz przyłączyc do dowolnych pinów
  • Poziom 11  
    Problem w tym, że obsługa programowa znacznie mi utrudni pracę. Poza tym byłoby to pewne pójście na łatwiznę ;) No ale cóż albo zrobię to programowo, albo spróbuję na atmedze16.
  • Poziom 32  
    wcale nie na łatwiznę ja tez próbowałem tego sprzetowego i okazało sie ze ani to szybsze ani miej pamieciożerne. A przede wszystki zaleta dowolne piny do wykorzytania w moim przypadku to super zaleta.
    Na 99.9% nie jest to problem w Atmedz8:)
  • Poziom 33  
    pl7 napisał:
    Witam!
    TWINT cały czas ma wartość 0.
    Może istnieje jakiś tajemniczy bug o którym brak żadnych informacji w dokumentacji?

    Skoro porty działają to raczej masz "bug" w programie :wink:. Ja też korzystam ze sprzętowego TWI (tylko bez przerwania) i wszystko jest w porządku. Nie ukrywam że spędziłem nad tym sporo czasu, tylko obsługę mam napisaną w C.

    Cytat:
    próbowałem tego sprzetowego i okazało sie ze ani to szybsze ani miej pamieciożerne


    Wszystko zależy kto ile potrzebuje "mocy". Bo te kilkadziesiąt taktów na czekanie przy sygnale SCL to czasami jest dużo.
  • Poziom 11  
    Raczej nie, bo bez przerwania też nie chce działać. Na innym forum spotkałem się z podobnym problemem jaki mam teraz. Pewien człowiek zasugerował, że istnieje tajemniczy bug nie objęty w żadnej erracie. Kto wie przecież są różne serie. Jedna mogła być trefna. Analizowałem to setki razy (choć nie ma za wiele do analizowania jeśli chodzi o TWI) dziesiątki razy zaglądałem do dokumentacji i nic. Tak więc śmiem twierdzić, że na 99,9% się nie walnąłem w programie.
  • Poziom 27  
    Przeczytałem wszystkie posty i nic nie rozumiem.... albo rozumiem wszystko (zależy od podejścia)
    Po 1 rozumiem, że TWI służy do komunikowania z PCF8583
    Po 2 to nie rozumiem do czego służyć ma przerwanie od TWI, przecież mamy konfigurację master-slave a w takiej konfiguracji slave tylko odpowiada na zapytania.
    Z tego co rozumiem z pdf to przerwanie jest od zgodności adresu odebranego z zapisanym, tudzież z globalnym wywołaniem jeśli nie zablokowano takiej możliwości.

    A komunikacja Ci nie działa, bo masz zły program :)
    Inaczej się czyta jeden bajt a inaczej blok (kilka) bajtów, ale zakładam, że do tego już doszedłeś.
    Co by nie byc gołosłownym to masz tu moja komunikację M128 z tym RTC. W tej chwili podciąganie to 5,1k/100kHz ale na 1k wyciągałem 500kHz:

    inicjalizacja:
    Code:
    ; INIT TWI ATMEGA 8MHz clock, TWI clock 100kHz 
    
       ldi R16, 8
       sts TWBR, R16
       ldi R16, 1
       sts TWSR, R16

    Przykład odczytu JEDNEJ komórki pamięci:
    Code:
    ; xxxxxxxxxxxxxxxxx wyswietlanie minut xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
    Wyswietl_minuty:
       rcall i2c_START
       rcall i2c_SLAVE_ADR_W      ; envoi
       ldi R16, 3               ; adres do odczytu
       rcall i2c_WORD_ADR         ; envoi
       rcall i2c_RESTART         ; envoi restart
       rcall i2c_SLAVE_ADR_R      ; envoi
       rcall i2c_RD_DATA         ; czytam dane
    ; ======================
    ; ======================
       rcall BCD_2_DEC                                       ; konwertuje BCD do DEC
    ; ======================
       rcall i2c_STOP            ; STOP
       mov R16, R8
    ret


    Przykład odczytu BLOKU danych:
    Code:
    //------------------------------------------------------------------------------
    
    Czytaj_czas:                ; czytam sekundy, minuty i godziny
       rcall i2c_START
       rcall i2c_SLAVE_ADR_W
       ldi R16, 2               ; adres do odczytu sekund
       rcall i2c_WORD_ADR
       rcall i2c_RESTART
       rcall i2c_SLAVE_ADR_R
       rcall i2c_RD_DATA_MORE      ; czekam na kolejne dane
    ; ======================
       lds R16, TWDR            ; kopiuje godziny [BCD]
       rcall BCD_2_DEC
       sts RTC_sekundy, R8
       rcall i2c_RD_DATA_MORE      ; czekam na kolejne dane
    ; ======================
       lds R16, TWDR            ; kopiuje minuty [BCD]
       rcall BCD_2_DEC
       sts RTC_minuty, R8
       rcall i2c_RD_DATA         ; czekam na ostatnia paczke danych
    ; ======================
       lds R16, TWDR            ; kopiuje godziny [BCD]
       rcall BCD_2_DEC
       sts RTC_godziny, R8
       rcall i2c_STOP            ; STOP
                    ret


    Oczywiści emożna przed odczytem zatrzasnąć wartości liczników RTC, ale myślę, że to na początek wystarczy :)

    Reszta komend potrzebnych do działania:
    Code:
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
    i2c_START:
    ldi R16, 0b10100100            //(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
    sts TWCR,R16                  ; envoi condition de start sur le bus
    ldi R16,0b10000100            // zeruje komendę start
    sts TWCR,R16
    rcall i2c_WAIT
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    i2c_RESTART:
    ldi R16,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN) ; preparation condition  start
    sts TWCR,R16                    ; envoi condition de start sur le bus
    rcall i2c_WAIT
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    i2c_SLAVE_ADR_w:
    ldi R16, 0b10100000
    sts TWDR, R16                 ; place la dans le 'TW dAtA register'
    ldi R16,(1<<TWINT)|(1<<TWEN)   ; effacement twint (a 1) et activation module twi
    sts TWCR,R16               ; envoi Attente extinction de twint (twint a 1 voir doc)                     
    rcall i2c_WAIT           
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    i2c_SLAVE_ADR_r:
    ldi R16, 0b10100001
    sts TWDR,R16                 ; place la dans le 'TW data register'
    ldi R16,(1<<TWINT)|(1<<TWEN)   ; effacement twint (a 1) et activation module twi
    sts TWCR,R16                  ; envoi                       
    rcall i2c_wait                ; Attente extinction de twint (twint a 1 voir doc)
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    i2c_WORD_ADR:
    ; tu wpisac do R16, adres rejestru do zapisu
    sts TWDR,R16                  ; charge a dans le TWDR
    ldi R16,(1<<TWINT)|(1<<TWEN)
    sts TWCR,R16                  ; envoi sur le bus
    rcall i2c_wait                ; Attente effacement twint
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    i2c_TR_DATA:               ; tu wpisac do R16, dane do wyslania
    sts TWDR,R16                  ; envoi  dans TWdata register
    ldi R16,(1<<TWINT)|(1<<TWEN) ;
    sts TWCR,R16                  ; envoi sur le bus
    rcall i2c_wait
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    i2c_RD_DATA:
    ldi R16,(1<<TWINT)|(1<<TWEN)
    sts TWCR,R16                  ; envoi sur le bus
    rcall i2c_WAIT
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    i2c_RD_DATA_MORE:            ; czekam na kolejne dane
    ldi R16,(1<<TWINT)|(1<<TWEN)|(1<<TWEA) 
    sts TWCR,R16
    rcall i2c_WAIT
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    i2c_STOP:
    ldi R16,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
    sts TWCR,R16                    ; STOP et raz
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx         
    i2c_WAIT:                        ; Attente extinction de twint (twint a 1 voir doc)
    lds R16,TWCR                    ; et si ack ou nack
    sbrs R16,TWINT           
    rjmp i2c_WAIT
    ret
    ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    ; ======================== konwersja BCD-->DEC ==================================
    BCD_2_DEC:                  // pobieramy z R16 wartosc w BCD i zamieniamy na dziesietna
    ;   lds R16, TWDR
       mov R17, R16
       mov R18, R16
       andi R17, 0x0F            //czyszcze gorny polbajt
       swap R18
       andi R18, 0x0F            //czyszcze gorny polbajt
       ldi R16, 10
       mul R16, R18
       add R17, R0
       mov R8, R17
    ret
    ; ============================== koniec ==========================================

    Oczywiście pamiętaj, że rejestry M8 i M128 mogą się nieco różnić, a na pewno piny, więc przy kompilacji poszukaj odpowiedników.
    Mi najwięcej problemu sprawiło wymyślenie (znalezienie) rozwiązania do odczytywania bloku informacji, na szczęście na elce jest dużo postów i dotarłem do sedna sprawy. Kod opisany w 3 językach więc jeśli czegoś nie chwytasz to pytaj.
    Pozdrawiam
  • Poziom 11  
    Cytat:

    Po 1 rozumiem, że TWI służy do komunikowania z PCF8583

    Aktualnie nie ma znaczenia z czyms się komunikuje. Bo TWI nie daje znaku życia. Czyli w TWSR stan się nie zmienia, TWINT się nie ustawia.
    Cytat:

    Po 2 to nie rozumiem do czego służyć ma przerwanie od TWI, przecież mamy konfigurację master-slave a w takiej konfiguracji slave tylko odpowiada na zapytania.

    Czasami nie można sobie pozwolic na takie marnotrastwo czasu by testować TWINT i trzeba korzystać z obsługi przerwaniowej.
    Cytat:

    Z tego co rozumiem z pdf to przerwanie jest od zgodności adresu odebranego z zapisanym, tudzież z globalnym wywołaniem jeśli nie zablokowano takiej możliwości.

    Mylisz się. Z tego co widzę nie wiesz jak działają przerwania od TWI. TWI daje przerwanie w m.in. takich przypadkach: przesłano start, przesłano SLA+W, Przesłano SLA+R, odebrano dane, przesłano ACK. itp. Czyli w przypadkach w których ustawia się znacznik TWINT.
    Cytat:

    A komunikacja Ci nie działa, bo masz zły program

    A widziałeś ten fragment kodu w mym drugim poście? Zauważyłeś jakąś nieprawidłowość? ( Oprócz tego, że preskaler częstotliwości jest źle ustawiony)

    Ale dzięki za pomoc i dobre intencje ;)
    Pozdrawiam
  • Poziom 27  
    moja przygoda z TWI zaczęła się od tego, że źle podłączyłem kondensator do kwarcu (masa z zasilaniem mi się pomyliła) i wogóle nie ruszał zegar, nie zmieniał się stan wyjścia INT.
    Później kombinowałem z innym układem RTC marki Epson ale także coś mi nie wychodziło, a w końcu wróciłem do PCF8583 i jakoś wszystko powoli ruszyło. Podstawa to cierpliwość
    Pozdrawiam
  • Poziom 11  
    Ja też mam problem z TWINT. w żaden sposób nie mogę tego bitu ustawić, chociaż testowałem programy ze wszystkich stron świata. Najzabawniejsze (haha #%%#@!!!) jest to, że w symulatorze też się nie ustawia. próbuję na siłę: TWCE = 0xFF. I ... blada. Wszystkie bity w tym rejestrze się ustawiają, a ten łobuz TWINT nie! Dodam, że używam avrstudio4.
  • Poziom 27  
    Wpisując wysoką wartośc do "pewnych" znaczników zerujesz je :)
    Jeśli chcesz zasymulowac sprzętowo zgłoszenie tego przerwania to zrób to po prostu myszką - działa :)
    Pozdrawiam
  • Poziom 11  
    Ostatnio spojrzałem w ten stary kod i zauważyłem rażącą pomyłkę, która poskutkowała ogólnym niedziałaniem. Mianowicie:
    Code:

       in R16, TWCR
       sbr R16, TWSTA
       sbr R16, TWINT
       out TWCR, R16


    Powinno być:

    Code:

       in R16, TWCR
       sbr R16, 1<<TWSTA
       sbr R16, 1<<TWINT
       out TWCR, R16


    I tym oto sposobem sam odpowiedziałem sobie na zadane pytanie.
    Dziwne, że nikt tego nie zauważył.. Taka pomyłka. Starzy assemblerowi wyjadacze powinni od razu to zauważyć. No cóż. Może kiedyś komus ta wiedza zawarta w tym wątku się przyda.
    Pozdrawiam
    EOT
  • Poziom 34  
    Większość wyjadaczy użyje symulatora lub debugera i zobaczy co nie gra ale nie da sie tego zrobić na strzępach kodu M8 nie ma jtaga ale jest M88 która ma DW.
  • Poziom 11  
    Uups zapomniałem zamknąć. Zaraz to zrobię.
    Hmm czyli wszyscy pro wyjadacze do zlokalizowania tak prostego błędu potrzebują debugger? :lol:
    Rozumiem, że to taki żartobliwy akcent pod koniec tematu miał być? :lol: