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

[ATMEGA32][TWI] - Losowe resety podczas komunikacji TWI

dzidav8 06 Gru 2015 16:07 1770 16
REKLAMA
  • #1 15215966
    dzidav8
    Poziom 9  
    Witam, mam problem z komunikacją po TWI z zegarem RTC DS1340. Program działa dobrze, ale co jakiś czas (kompetnie losowy, potrafi chodzić kilka dni bez błędów, a czasem resetuje się co chwilę) zawiesza się i resetuje go watchdog (ustawiony na 0,5s).

    Doszedłem do miejsca w którym program się wysypuje - na powrocie z funkcji twiread().

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


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


    Funkcja read_RTC() jest wywoływana w głównym programie co 0,25s. Prędkość TWI ustawiona na 80kHz, czyli poniżej max dla DS1340 (100kHz).

    Na szynie TWI jest jeszcze pamięć FRAM i układ QT60160.

    Nie potrafię dojść o co chodzi - rozumiem gdyby program zatrzymywał się na while(), ale na return()?
  • REKLAMA
  • Pomocny post
    #2 15216326
    Andrzej__S
    Poziom 28  
    dzidav8 napisał:
    Nie potrafię dojść o co chodzi - rozumiem gdyby program zatrzymywał się na while(), ale na return()?

    Samo przerwanie TWINT nie oznacza, że operacja zakończyła się powodzeniem.

    Nie podałeś zawartości innych funkcji obsługi magistrali, ale sądząc po funkcji twi_read() nie sprawdzasz poprawności transmisji poprzez sprawdzenie jej statusu w rejestrze TWSR. Rejestr ten zawiera istotne informacje odnośnie ostatnio wykonywanej operacji i pozwala na podjęcie odpowiednich kroków, jeśli ta operacja się nie powiedzie. Ułatwia też zdiagnozowanie, jaka jest przyczyna nieprawidłowości. Można oczywiście zakładać, że wszystko pójdzie zgodnie z planem i ignorować TWSR, ale jak sam widzisz nie zawsze się to sprawdza.

    Przykładow po tej linijce:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    nie sprawdzasz nawet, czy układ slave odpowiedział bitem potwierdzenia, a to wcale nie jest pewne. Jeśli układ jest akurat zajęty wewnętrznymi operacjami może nie odpowiedzieć bitem potwierdzenia i w takiej sytuacji program powinien zatrzymać (wysłać STOP) lub ponowić transmisję (wysłać REPEATED START i ponowić adres układu slave).
  • #3 15218247
    dzidav8
    Poziom 9  
    Dzięki, chyba rozumiem o co chodzi. Poprawiłem funkcje w taki sposób:

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


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


    Testuję i jak na razie się nie resetuje. Najlepiej byłoby przerobić obsługę TWI na używającą przerwania, ale jak na razie nie ogarnąłem jak to zrobić.

    [EDIT] Niestety nic to nie zmieniło - dalej się resetuje.
  • #4 15218308
    tmf
    VIP Zasłużony dla elektroda
    Unikaj konstrukcji goto, w twoim przypadku jest to szczególnie niebezpieczne - w sytuacji permanentnego błędu na I2C (zdarza się) program się zapętli w funkcji read_RTC - warto byłoby jednak analizować typ błędu i ew. podjąć stosowną akcję. Oraz przewidzieć możliwość zakończenia funkcji z jakimś błędem sygnalizującym co jest nie tak. Przydaje się to podczas użytkowania urządzenia - np. zwrócenie abstrakcyjnej daty od razu użytkownikowi zasygnalizuje problem z RTC. Tak jak masz obecnie zostanie odebrane jako uszkodzenie z przyczyny kompletnie nieznanej. Idę o zakład, że za jakiś czas w takiej sytuacji napiszesz post "pomocy, program mi się zawiesza w losowych momentach" :)
  • REKLAMA
  • #5 15218330
    dzidav8
    Poziom 9  
    OK, to urządzenie MUSI być niezawodne, wiec myślę ze najlepiej będzie jeśli jednak zrobię tą komunikację od nowa na przerwaniach.

    Rozgryzam powoli implementację Atmela ( http://www.atmel.com/images/doc2564.pdf ). Przykład przeanalizowałem i rozumiem jak działa. Problem pojawia się kiedy chcę odczytać od konkretnego adresu w slave, chyba trzeba by dorobić obsługę kilku stanów w komunikacji żeby to obsłużyć?

    Podobnie z odczytem danych z klawiatury, teraz miałem całą komunikację TWI w przerwaniu ( klawiatura aktywuje INT0 przy zmianie stanu klawiszy):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Teraz musiałbym tylko inicjować komunikację w przerwaniu a potem w głównej pętli ją kończyć. Dobrze kombinuję?
  • Pomocny post
    #6 15219795
    tmf
    VIP Zasłużony dla elektroda
    To co zrobiłeś do niczego się nie nadaje. Ciągle masz problemy, o których jużpisaliśmy - brak sprawdzania flag interfejsu TWI, brak reakcji na przerwanie. Ze względu na czas realizacji poleceń I2C nie ma sensu umieszczać ich w ISR. Jeśli już to można wykorzystać ISR od TWI i tam to zaimplementować. TWI oparte jest o maszynę stanu, implementacja też powinna zawierać maszynę stanu, która odpowiednio zareaguje na wszelkie możliwe zdarzenia. Albo przynajmniej musisz zaimplementować wykrywanie, że coś poszło nie tak i zaczynać wtedy komunikację od nowa. Po kiluśtam nieudanych próbach po prostu wywalić komunikać, że TWI nie działa.
  • Pomocny post
    #7 15219882
    Andrzej__S
    Poziom 28  
    Jeśli masz zamiar wykorzystać driver Atmela opisany w nocie aplikacyjnej AVR315, to w załączniku masz przykład użycia do komunikacji z zegarem PCF8563 (kod nie jest mojego autorstwa).

    IMHO, sam kod drivera jest dobrym przykładem, jak to zrobić na przerwaniach, jednak aby w pełni wykorzystać dobrodziejstwo, jakim są przerwania, należałoby kod tego drivera nieco zmodyfikować, ponieważ zawiera on nadal pętle oczekujące na zakończenie transmisji. Trudno też uzyskać dokładniejsze informacje na temat problemów z transmisją.

    EDIT:

    Przykład może jednak nie najlepszy, więc dla jasności chciałbym jeszcze zaznaczyć, że przedstawiony tutaj przeze mnie przykładowy kod obsługi PCF8563 nie zawiera maszyny stanów, o której pisał kolega tmf, w związku z czym nie wykorzystuje w pełni zastosowania przerwań.
    Przykładowo wywołanie po sobie funkcji:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    skutkuje tym, że funkcja TWI_Get_Data_From_Transceiver(buff,2); musi oczekiwać w pętli na zakończenie transmisji zainicjowanej przez funkcję TWI_Start_Transceiver_With_Data(buff,2); nie robiąc w tym czasie nic pożytecznego.
    Dlatego, aby w pełni skorzystać z zastosowania przerwań, należy oczywiście zbudować maszynę stanów.

    Drugi mankament kodu, to fakt, że też nie sprawdza poprawności transmisji. Właściwie sam driver jako taki (ściślej obsługa przerwania TWI) w przypadku błędu powinien zareagować prawidłowo, na przykład generując STOP (dzięki czemu nie zrobi na magistrali "bałaganu"), ale to jeszcze nie musi oznaczać, że transmisja przebiegła bez błędów. Prawidłowo, po zakończeniu każdej transmisji zainicjowanej funkcją TWI_Start_Transceiver_With_Data(); należałoby sprawdzić poprawność za pomocą TWI_Get_State_Info(); i w razie potrzeby podjąć odpowiednie kroki.
    W zasadzie przykład miał pokazać tylko, jak manipulować buforem i funkcjami TWI_Start_Transceiver_With_Data(); oraz TWI_Get_Data_From_Transceiver(); aby wysyłać lub odbierać dane.
  • #8 15256696
    dzidav8
    Poziom 9  
    Wracam do problemu, bo rozwiązałem już wszystkie inne jakie były w programie.

    Użyłem trochę innego drivera, bez użycia przerwań i dopisałem warunki sprawdające stan transmisji zanim odczyta TWSR:

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


    Program działa dużo lepiej, ale dalej potrafi się zresetować, z tym że dużo rzadziej niż wcześniej (raz na kilka dni).

    Co ciekawe program wysypuje się już po zakończeniu transmisji TWI. Zaraz po i2c_readReg jest kolejny VISIT i do niego już program nie dociera:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #9 15256859
    Konto nie istnieje
    Konto nie istnieje  
  • #10 15256964
    Andrzej__S
    Poziom 28  
    Piotrus_999 napisał:
    REPEATED START Nie służy do ponawiania transmisji pomimo mylacej nazwy. Ma on na celu zachowanie kontroli nad magistrala po zakonczeniu poprzedniej opeacji ( z reguly w innym trybie) np. wysyłasz komende do ukladu i chcesz odpowiedz . Jezeli uklad nie potwierdził nalezy zakonczyc transakcje sygnalem STOP zwalniając magistrale.

    Proponowałbym następnym razem najpierw sprawdzić choćby w datasheet ATmega8 tabelkę 66 "Status codes for Master Transmitter Mode" na stronie 173, jakie są możliwe akcje w przypadku braku potwierdzenia przez układ slave oraz graf "Formats and States in the Master Transmitter Mode" na następnej stronie. Chyba, że Atmel też się myli ;)

    EDIT:
    Dla pewności (THE I2C-BUS SPECIFICATION) mówi:
    Cytat:

    When a slave doesn’t acknowledge the slave address (for
    example, it’s unable to receive or transmit because it’s
    performing some real-time function), the data line must be
    left HIGH by the slave. The master can then generate
    either a STOP condition to abort the transfer, or a repeated
    START condition to start a new transfer.

    If a slave-receiver does acknowledge the slave address
    but, some time later in the transfer cannot receive any
    more data bytes, the master must again abort the transfer.
    This is indicated by the slave generating the
    not-acknowledge on the first byte to follow. The slave
    leaves the data line HIGH and the master generates a
    STOP or a repeated START condition.
  • #11 15257006
    Konto nie istnieje
    Konto nie istnieje  
  • #12 15257052
    Andrzej__S
    Poziom 28  
    Piotrus_999 napisał:
    Cytat:
    Note that arbitration is not allowed between:
    • A REPEATED START condition and a data bit
    • A STOP condition and a data bit
    • A REPEATED START and a STOP condition


    oczywiście nie ma to znaczenia jak masz 2 układy na płytce - albo więcej ale tylko jednego mastera.


    A czy ten wątek dotyczy multi-master?
  • REKLAMA
  • #13 15257082
    Konto nie istnieje
    Konto nie istnieje  
  • #14 15258101
    Andrzej__S
    Poziom 28  
    Jeżeli programowanie zgodne ze specyfikacją uważasz za "złą praktykę programistyczną", to myślę, że dalsza dyskusja na ten temat nie ma sensu.

    EDIT:
    Dodam jeszcze tylko co następuje (choć Ciebie to zapewne nie przekona, ale może przekona innych).

    Najlepszym przykładem, który mi się nasuwa jest "aknowledge polling" praktycznie dowolnej pamięci EEPROM z interfejsem I2C. Tam wyraźnie widać, że po braku potwierdzenia występuje repeated start bez żadnego stopu. Chyba, że producent pamięci też się nie zna.

    To, że program może się zapętlić w przypadku, gdy slave z jakichś powodów przestanie odpowiadać łatwo rozwiązać za pomocą iteratora zliczającego nieudane próby połączenia i po przekroczeniu pewnej ilości wystarczy wyjść z pętli generując stop i ewentualnie informację o błędzie.

    Jeśli chodzi o zakłócenia na magistrali to wygenerowanie najpierw stopu, a później wznowienie transmisji niewiele zmieni. Tutaj bardziej istotne jest to, żeby monitorować cały czas status transmisji (np. w ATmega8 rejestr TWSR, który po wykonaniu każdej operacji zawiera informacje o poprawności jej wykonania) i odpowiednio reagować na błędy. Większość dostępnych w internecie kodów do obsługi I2C nie sprawdza nawet bitu potwierdzenia od układu slave, nie mówiąc o wykrywaniu innych błędów i odpowiedniej reakcji na nie, a to bardzo ważne, by utrzymać "porządek" na magistrali.

    Swego czasu zajmowałem się serwisowaniem sprzętu RTV, miałem monitor magistrali I2C i wiem, że repeated start po braku potwierdzenia od układu slave to dosyć częsta praktyka, nawet w urządzeniach renomowanych marek. Choć niewykluczone, że oni też mieli kiepskich programistów stosujących złe praktyki.

    Z mojej strony to wszystko. Musiałem się ustosunkować do tego, co napisałeś jednak jak już wspomniałem, dalsza dyskusja nie ma dla mnie sensu.
  • #15 15258623
    Konto nie istnieje
    Konto nie istnieje  
  • #16 15260965
    Andrzej__S
    Poziom 28  
    Piotrus_999 napisał:
    To ze się tego używa do tego celu nie oznacza ze jest to poprawne

    Krótko mówiąc Twoim zdaniem wszyscy (od autorów specyfikacji magistrali poprzez producentów układów z interfejsem I2C po programistów renomowanych firm) się mylą i stosują niepoprawne rozwiązania.

    ......

    Również życzę wesołych Świąt.
  • #17 15261111
    Konto nie istnieje
    Konto nie istnieje  
REKLAMA