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.

STM32F103RB - Brak komunikacji I2C

27 Paź 2016 16:12 1206 27
  • Poziom 9  
    Witam, problemem jest brak komunikacji z czujnikiem poprzez interfejs I2C, podczas próby wysłania danych do urządzenia zostaje podany błąd transmisji "HAL_BUSY". Wcześniej bywały problemy że mikrokontroler nie komunikował się aczkolwiek reset lub odłączenie zasilania zazwyczaj pomagało w takich sytuacjach, zdarzyło się iż przez 2 godziny nie było komunikacji i wtedy podczas usilnych prób znalezienia źródła usterki komunikacja zaczęła działać, jednakże po chwili znów przestała i już od dłuższego czasu nie działa. W celach weryfikacyjnych dodam, iż zaopatrzyłem się w drugi czujnik aby wykluczyć możliwość uszkodzenia pierwszego, także próbowałem używać drugiego interfejsu I2C będącego dostępnym w uC. Mogę dodać, iż wydaje mi się, że straciłem komunukację po przypadkowym zwarciu zasilania. Urządzeniem z którym się próbuję komunikować jest sensor TCS3414CS
  • Poziom 35  
    bernardmaster napisał:
    zostaje podany błąd transmisji "HAL_BUSY".


    A jak masz zrobiony pull-up na I2C?
  • Poziom 9  
    Tak rezystory 10k
    Dodam jeszcze, iż do generowania szkieletu kodu używam STMCubeMx
  • Poziom 35  
    bernardmaster napisał:
    Tak rezystory 10k


    Jeśli masz tam na I2C dłuższy kabel to 10k może być za dużo. Zwyczajowo przy 3,3V daje się koło 2k. A jeśli używasz Fast Mode to 10k już zdecydowanie odpada niezależnie od innych warunków.

    Ale niezależnie od pierwotnych przyczyn, dobrze by było sprawdzić linię SDA w sytuacji kiedy program wywala błąd, nawet po ponownym resecie. Jeśli na SDA jest permanentny LOW, to miałbyś do czynienia z klasycznym zablokowaniem na magistrali I2C, z którego używając tylko funkcjonalności samego I2C trudno (niemożliwe?) jest wyjść.
  • Użytkownik usunął konto  
  • Poziom 9  
    Z tego co zauważyłem to na linii nie pojawia się stałe LOW dodam także iż komunikacja wcześniej była i nagle zaniknęła.
    W dokumentacji uC zalecaną wartością rezystorów jest 4,7k i próbowałem także z tymi wartościami bez sukcesu, kable są krótkie raczej do płytki stykowej i do czujnika. Nie używam fast mode, standardowo 100kHz.
    Piotrus_999 napisał:
    Trzeba zegarem ręcznie pomachać 9-10 razy.

    Czy zadziała opcja kiedy podłączę sobie odpowiednie linie pod wyjścia cyfrowe i napiszę program, który będzie odpowiednio symulował zegar oraz linię danych i w momencie bitu ACK po prostu spróbkuję wartość jaka pojawia się na linii?
    Bo próbowałem robić ręczną transmisję zwierając odpowiednio linie i nie zauważyłem bitu ACK, aczkolwiek myślę że drganie ręki i styku mogło wyzwalać dodatkowe zbocza.
  • Pomocny post
    Poziom 35  
    bernardmaster napisał:
    Czy zadziała opcja kiedy podłączę sobie odpowiednie linie pod wyjścia cyfrowe i napiszę program


    To machanie robi się tylko w przypadku kiedy slave nadaje LOW na SDA (np. z jakiś powodów urwie się transmisja na odczycie ze slave bajtu z zerami itp.). Wtedy master nie jest w stanie wygenerować stanu START albo STOP i interpretuje tą sytuację jako zajęcie magistrali przez innego mastera.

    Ale jeśli twierdzisz że nie ma na SDA stałego LOW przed wyskoczeniem błędu to znaczy że coś innego się dzieje.

    Może jeszcze dla pewności sprawdź co jest na linii SCL przed błędem. Bo skądś ten stan BUSY musi się brać. Jeśli by nie było wcale komunikacji ze slave to jest inny rezultat.


    Zajrzałem do źródeł HAL i widzę że rezultat HAL_BUSY w funkcji zapisu może wystąpić w dwóch przypadkach.

    1. jeśli przed rozpoczęciem jakichkolwiek działań bit BUSY (w I2C_SR2) jest 1 i nie gaśnie w określonym czasie. A bit BUSY to:
    Cytat:
    BUSY: Bus busy
    0: No communication on the bus
    1: Communication ongoing on the bus
    – Set by hardware on detection of SDA or SCL low
    – cleared by hardware on detection of a Stop condition.


    2. W wypadku użycia nieblokującej funkcji zapisu kiedy wywołamy następną funkcję bez odczekania na ukończenie poprzedniej.


    Jeśli (nie wiem tego) używasz wyłącznie funkcji blokujących np. HAL_I2C_Master_Transmit, to pozostaje tylko pierwsza możliwość, że na liniach I2C po inicjalizacji a przed rozpoczęciem funkcji zapisu przeleciały jakieś duże śmieci, które ustawiły bit Busy (a nie było stanu STOP) albo któraś linia ma stały stan LOW lub tak interpretowany (twierdzisz że nie SDA to zostaje SCL).


    bernardmaster napisał:

    kable są krótkie raczej do płytki stykowej i do czujnika.


    Sprawdź te kabelki. Mieliśmy tu niedawno spory i trudny temat z STMem a okazało się że to była tylko wina serii badziewnych kabelków do stykówki.
  • Poziom 9  
    Bo dziwnie w ogóle ten błąd się pojawia: na uC mam wgrane jedynie program próbujący wpisać dane do czujnika po włączeniu nic się nie dzieje przez kilka sekund następnie funkcja która odpowiada za wysyłanie danych zwraca kod błędu.
  • Poziom 35  
    bernardmaster napisał:
    nic się nie dzieje przez kilka sekund następnie funkcja która odpowiada za wysyłanie danych zwraca kod błędu.


    To by dokładnie pasowało do moich przypuszczeń (patrz post wyżej). Rzeczywiście, przy czekaniu na zgaszenie bitu BUSY jest tam timeout 10s.
  • Poziom 9  
    rb401
    Serdecznie dziękuję za zainteresowanie oraz pomoc, przypomniało mi się dzisiaj, iż gdzieś na zagranicznym forum doczytałem o próbie dodania dodatkowego delaya pomiędzy inicjalizacją zegara, a I2C, po dodaniu takowego wszystko działa jak należy. Jedyne co bardzo mnie dziwi to fakt, że wcześniej płytka działała aczkolwiek czasami faktycznie pojawiał się błąd i nie była nawiązywana komunikacja, jednakże wtedy winą niesłusznie obciążałem płytkę stykową oraz kableki. Najwidoczniej zbyt wcześnie było włączane peryferium i jeszcze jakieś śmieci były na liniach.

    Niestety przestało działać po tym jak zamieniłem rezystory 3.3k na 10k które wcześniej miałem wstawione po powrocie do tych o niższej wartości nic się nie poprawia.

    Niestety to jest jakaś loteria raz zadziała drugim razem już nie :cry:
  • Użytkownik usunął konto  
  • Poziom 9  
    Bardzo chciałbym go resetować aczkolwiek pakiet bibliotek HAL z tego co widzę nie dostarcza takiej funkcji, a jak zrobić to ręcznie to raczej nie wiem.
  • Użytkownik usunął konto  
  • Poziom 35  
    bernardmaster napisał:
    Najwidoczniej zbyt wcześnie było włączane peryferium i jeszcze jakieś śmieci były na liniach.


    Tyle że akurat w takiej konfiguracji nie widzę takiej możliwości. Skoro jest podciągnięcie SDA i SCL opornikami do 3,3V to stan HIGH jest praktycznie natychmiastowy po włączeniu zasilania i nie jest dla mnie jasne skąd mogły by się pojawić jakieś stany przejściowe będące przyczyną ustawienia bitu BUSY.

    Z Twoich wypowiedzi odnoszę wrażenie że cały Twój problem to niewiadomej przyczyny ustawienie bitu Busy w CR2 przy nieaktywnej magistrali a to co dzieje się później to tylko tego konsekwencje.

    Może by skupić się na tym szczególe, bez wchodzenia w funkcje transmisji. Np. po inicjalizacji I2C wyświetlać ten bit w kółko na LED i jeśli będzie się zapalał pozornie bez przyczyny, próbować odłączenia po kolei kabelków, by dociec skąd śmieć przychodzi.
  • Poziom 9  
    Problem dla mnie jest chyba dostęp do rejestrów z poziomu bibliotek HAL, jeżeli chodzi działanie układu to jak zadziała to działa i zazwyczaj przestaje działać np po resecie.
  • Poziom 35  
    bernardmaster napisał:
    Problem dla mnie jest chyba dostęp do rejestrów z poziomu bibliotek HAL


    Akurat z tym nie ma problemu bo w HAL od I2C do czytania flag są wygodne makro (opisane w stm32f1xx_hal_i2c.h). Tak że nie trzeba nawet wiedzieć gdzie w którym rejestrze jaki to bit jest.

    Przykład użycia by sprawdzić bit BUSY:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    ewentualnie modyfikując pierwszy parametr do tego co masz w programie (zadeklarowany w main.c na samym początku)


    bernardmaster napisał:
    jeżeli chodzi działanie układu to jak zadziała to działa i zazwyczaj przestaje działać np po resecie.


    To co opisujesz, ten efekt, dla mnie jest szczególnie bliski, bo akurat tu koło mnie na biurku leży temat gdzie mam STMa z podłączonym czujnikiem przez I2C.

    I miałem taki denerwujący efekt że chodzi sobie ładnie, robię reset STMa lub wgrywam program, i raz na około pięć razy, I2C wiesza się na sztywno i wtedy po wszystkich kolejnych resetach mam trwały brak komunikacji. Dopiero pomaga wyłączenie i włączenie zasilania całości.

    Ale u mnie to zjawisko ma wytłumaczalną, ogólnie znaną przyczynę związaną z tym że slave trzyma SDA na LOW.
    To o czym pisał Piotrus_999 i ja wcześniej.

    Tak że nie było się czym przejmować, tylko ciągła manipulacja zasilaniem po przeprogramowaniach była trochę uciążliwa to sobie dopisałem funkcję odblokowania. Czyli przeprogramowuję piny I2C na normalne GPIO migam SCL do skutku czyli do puszczenia SDA przez slave i przeprogramowuję piny z powrotem na I2C. I mam problem z głowy. Działa niezawodnie.


    Tyle że jak twierdzisz, w momencie kiedy u Ciebie nie działa, nie masz SDA stanu LOW, co akurat zupełnie nie pasuje do tej sytuacji wyżej.

    Co prawda, nie jest też wykluczone że natknąłeś lub natkniesz się na sytuację z zablokowaniem magistrali przez slave (np. w przypadku resetu STM podczas transmisji), bo to nie jest jakiś problem związany konkretnie z STM czy typem czujnika ale sprawa wynikająca wyłącznie ze standardu I2C.
    I możliwe też że masz do czynienia z kilkoma przyczynami błedów.
  • Użytkownik usunął konto  
  • Poziom 9  
    Uruchomiłem preogram w trybie debugowania i okazało się że bit BUSY zostaje ustawiony podczas inicjalizacji peryferium i potem nie zostaje czyszczony
  • Specjalista - Mikrokontrolery
    I już tysiąc razy było pisane, że prostym rozwiązaniem jest programowy reset I2C, zajmujący dokładnie 2 linijki straszliwie skomplikowanego kodu na rejestrach...
  • Użytkownik usunął konto  
  • Specjalista - Mikrokontrolery
    Piotrus_999 napisał:
    CR1 ustawiasz bit SWRST i czekasz aż się wyzeruje.

    Tym sposobem można się akurat tego niedoczekać <:
  • Użytkownik usunął konto  
  • Specjalista - Mikrokontrolery
    Raczej będzie dalej problem, ponieważ ten bit nie kasuje się samoczynnie. A przynajmniej dokumentacja na ten temat milczy.
  • Użytkownik usunął konto  
  • Poziom 35  
    Freddie Chopin napisał:
    Raczej będzie dalej problem, ponieważ ten bit nie kasuje się samoczynnie. A przynajmniej dokumentacja na ten temat milczy.


    W RM F103 przy bicie SWRST jest uwaga:

    Cytat:
    Note: This bit can be used to reinitialize the peripheral after an error or a locked state. As an example, if the BUSY bit is set and remains locked due to a glitch on the bus, the SWRST bit can be used to exit from this state.


    Czyli BUSY da się zgasić inaczej niż tylko stanem STOP.


    Ale nurtuje mnie tu inna sprawa. Co innego jakiś glitch a co innego zablokowanie magistrali w stanie w którym slave trzyma SDA na LOW bo akurat w czasie jakieś operacji odczytu transmisja się nagle urwie bo resetujemy STM.
    A kolega bernardmaster twierdzi, że w patologicznej sytuacji nie ma LOW na SDA.
    I to mi się nie zgadza w tej całej sprawie.

    Akurat mam tu przed sobą zestaw gdzie potrafię sobie "na zawołanie" zrobić blokadę I2C. Po prostu program jaki tu puszczam, w większości czasu czyta w kółko status ze slave i wystarczy kilka razy poresetować STM by na twardo zablokować magistralę.
    Ale wtedy mam permanentny LOW na SDA z którego to funkcje obsługi I2C nie są w stanie ruszyć. No ale oczywiście "zamiganie" linią SCL przestawioną w tryb GPIO niezawodnie daje radę odetkać magistralę z tego zablokowania.

    Jeszcze taka ciekawostka. Ponieważ używam akurat mieszaniny mbed ze wstawkami HAL :wink: , to podejrzałem jak mbed (używający STMowego HALa) obsługuje I2C.
    Otóż w inicjalizacji I2C obligatoryjnie sprawdza bit BUSY i jeśli jest ustawiony to resetuje, ale nie bitem SWRST z CR1 jak można by przypuszczać. Robi mignięcie bitem resetującym w APB1RSTR.
  • Specjalista - Mikrokontrolery
    Piotrus_999 napisał:
    No nie wiem raczej logiczne że ten bit inicjalizuje reset a zarazem jest indykatorem czy i2c jest w trakcie resetu. Tak że musi być zmieniany przez hardware

    Logiczne jest, że układ zachowuje się tak jak to jest opisane w dokumentacji.

    Cytat:
    When set, the I2C is under reset state. Before resetting this bit, make sure the I2C lines are
    released and the bus is free.


    Przy każdym bicie który się sam przestawia "w drugą stronę" zawsze jest stosowna informacja. Przy tym nie ma.
  • Poziom 9  
    Dobrze, już zgaszam bit BUSSY, aczkolwiek teraz podczas próby komunikacji dostaje z nieznanej przyczyny błąd AF, czyli że nie ma potwierdzenia że strony czujnika, wątpliwa sprawą byłaby sytuacja w której uszkodzilem oba czujniki więc nie za bardzo wiem skąd pojawia się ten błąd.
  • Użytkownik usunął konto