Kurs STM32 LL cz. 17. Wstęp do magistrali I2C

Z magistralą I2C spotykamy się najczęściej przy obsłudze czujników. Znajdziemy ją także jako interfejs do sterowania panelami dotykowymi czy pamięciami EEPROM. Dzisiaj postaram się przybliżyć działanie magistrali i budowę interfejsu I2C w STM32.

Protokół I2C

Interfejs I2C (Inter-Integrated Circuit) to dwukierunkowa magistrala szeregowa przeznaczona do przesyłania danych. Wykorzystuje do komunikacji dwie linie: linię zegarową (SCL) oraz linię danych (SDA). Umożliwia komunikację dwustronną. Ze względu na to, że wykorzystuje tylko jedną linię danych, nie jest możliwe przesyłanie informacji w obu kierunkach jednocześnie.

I2C to nazwa zastrzeżona przez firmę Philips. Dlatego można spotkać inne określenia dla tej samej magistrali m.in. IIC, TWI lub SCCB.

W komunikacji I2C wyróżnia się dwa typy urządzeń: master oraz slave. Te określenia są spotykane najczęściej, chociaż wg najnowszego standardu urządzenia te określane są jako controller oraz target. Zmiana spowodowana jest tym, że twórcy chcieli ujednolicić nazewnictwo  w związku z nowym standardem I3C. 

Urządzenie master (controller) odpowiada za generowanie sygnału zegarowego. Nadzoruje całą komunikację, rozpoczyna i kończy transmisję oraz steruje kierunkiem (zapis, odczyt). Ponieważ w I2C jest dodany mechanizm wykrywania zajętości linii, możliwe jest podłączenie kilku urządzeń master do jednej magistrali.

Urządzenie slave (target) jest podrzędne w procesie komunikacji. Ma nadany własny adres, dzięki czemu można podłączyć do jednej linii kilka urządzeń. Slave odpowiada na żądania wysyłane przez mastera.

Żeby możliwa była komunikacja w obie strony, piny w urządzeniach master i slave muszą być typu otwarty dren (układy na bazie MOSFET-ów) lub otwarty kolektor (układy na bazie tranzystorów bipolarnych). Taka konfiguracja pozwala zarówno na wysyłanie, jak i odczytywanie danych na pinie. Aby magistrala działała poprawnie, konieczne jest zastosowanie na obu liniach rezystorów podciągających do linii VCC. Wartość ich rezystancji zależy od pojemności linii, częstotliwości komunikacji czy napięcia zasilającego. Jednak w większości przypadków nie musimy aż tak precyzyjnie dobierać ich wartości – często stosowane rezystory 4,7 kΩ będą wystarczające.

Poziomy napięć w standardach CMOS i TTL dla stanu niskiego i wysokiego pozwalają na komunikację między urządzeniami o 3,3 V oraz 5 V bez potrzeby stosowania dodatkowych konwerterów.

I2C wykorzystuje logikę dodatnią, co oznacza, że stan wysoki to logiczna “1”, a stan niski “0”. W trakcie bezczynności na liniach SDA i SCL jest stan wysoki.

W momencie rozpoczęcia transmisji danych urządzenie master wysyła sygnał START. Następnie generuje sygnał zegarowy i przesyła dane w formie bajtów, czyli 8 bitów. Najpierw wysyła adres urządzenia slave, z którym chce się skomunikować. Adres jest 7-bitowy. 8 bit określa kierunek komunikacji – “0” oznacza operację zapisu (write), a “1” odczytu (read). W standardzie uwzględniono tzw. adres rozgłoszeniowy (generall call), który przyjmuje wartość 0x00. Na instrukcje wysłane za tym adresem zareagują wszystkie urządzenia podłączone do magistrali.

Następnie wysyłane są dane. Każdy przesłany bajt powinien być zakończony potwierdzeniem odebrania danych przez drugie urządzenie, czyli sygnałem ACK (Acknowledge). Jeżeli dane nie zostaną odebrane, przesyłany jest sygnał NACK. W momencie zakończenia transmisji master przestaje generować sygnał zegarowy i wysyła STOP, czyli przejście w stan wysoki na linii SDA.

Warto zauważyć, że w trakcie przesyłania danych stan na linii SDA zmienia się tylko w momencie, gdy na linii SCL jest stan niski. Jedynie w przypadku sygnałów START i STOP zmiana stanu następuje przy stanie wysokim na SCL. To pozwala odróżnić rozpoczęcie i zakończenie transmisji od przesyłania danych.

W standardzie I2C przewidziane zostały trzy tryby pracy: Standard -mode, Fast-mode, Fast-mode Plus. Tryb Standard-mode pozwala na komunikację z sygnałem zegarowym o częstotliwości 100 kHz. Tryb Fast-mode zakłada transmisję z sygnałem zegarowym o częstotliwości 400 kHz, a tryb Fast-mode Plus o częstotliwości 1 MHz.

Budowa interfejsu I2C w STM32

Budowa I2C może się różnić w zależności od stosowanego numery interfejsu (I2C1, I2C2 itd.) pod względem funkcjonalności, jak wsparcie SMBus. Jednak w przypadku podstawowych funkcji I2C, każdy z interfejsów jest zbudowany podobnie. W ćwiczeniach będziemy używali magistrali I2C1, której schemat blokowy przedstawiam poniżej.

Do podstawowej komunikacji I2C wykorzystuje dwa piny – I2C_SDA do transmisji danych oraz I2C_SCL do generowania sygnału zegarowego.

Interfejs I2C1 może być taktowany za pomocą sygnału PCLK, SYSCLK lub HSI16. Domyślnie korzystamy z sygnału PCLK. Źródło to jest konfigurowane za pomocą rejestrów RCC.

Jednym z parametrów, które musimy skonfigurować na wstępie, są filtry analogowe i cyfrowe. Do czego służą i czym się różnią?

Zarówno filtr analogowy, jak i cyfrowy ma za zadanie tłumić krótkie zmiany stanów na liniach SDA i SCL, aby uzyskać poprawne dane. Filtr analogowy ma stałą długość 50 ns i jest dostępny w trybie Stop (niski pobór energii). Jest jednak wrażliwy na zmiany temperatury czy skoki napięcia. Filtr cyfrowy ma programowaną długość (od 1 do 15 cykli zegara taktującego I2C). Jest stabilniejszy, ale nie może być używany w trybie Stop.

Jednym z trudniejszych elementów do ustawienia I2C jest rejestr TIMINGR. Zawiera on parametry czasowe pracy I2C, takie jak preskaler, czas konfiguracji danych, czas przechowywania danych oraz czas trwania stanu wysokiego i niskiego na linii SCL. Parametry te pozwalają precyzyjnie skonfigurować zależności między stanami na liniach SDA i SCL, które zagwarantują poprawne wysyłanie i odbieranie danych. Ręczne dobieranie tych czasów jest dość skomplikowane i potrzebne tylko w bardzo specyficznych projektach. W naszym przypadku nie będziemy się zagłębiali w dokładną ich analizę, a rejestr ten ustawimy na podstawie kalkulatora dostępnego w STM32CubeMX. Jeżeli chciałbyś dowiedzieć się jednak więcej, odsyłam do dokumentacji Reference Manual.

W przypadku magistrali I2C1 możliwa jest praca w jednym z dwóch rodzajów interfejsu: I2C lub SMBus. SMBus to odmiana I2C stosowana m.in. w płytach głównych komputerów do zadań związanych z systemem i zarządzaniem zasilaniem. Ma dodatkowy pin SMBus Alert. My w kursie zajmować się będziemy typowym interfejsem I2C stosowanym w przypadku czujników czy pamięci EEPROM.

Tryby pracy I2C

Jak już wspominałem, w przypadku magistrali I2C wyróżnia się dwa typy urządzeń: master oraz slave. Urządzenie master odpowiada za generowanie sygnału zegarowego i  nadzoruje całą komunikację, czyli rozpoczyna i kończy transmisję oraz steruje kierunkiem (zapis, odczyt). Urządzenie slave jest podrzędne w procesie komunikacji. Ma nadany własny adres, dzięki czemu można podłączyć do jednej linii wiele urządzeń. Slave odpowiada na żądania wysyłane przez mastera.

W STM32 interfejs I2C domyślnie pracuje w trybie slave. Automatycznie przełącza się z trybu slave na master, gdy wygeneruje bit START, i z master na slave, gdy nastąpi utrata arbitrażu lub wygenerowanie bitu STOP.

Zarówno master, jak i slave może być jednocześnie w jednym ze stanów: odbierania lub wysyłania danych. Dlatego wyróżnia się cztery tryby pracy I2C:

  • Slave transmitter
  • Slave receiver
  • Master transmitter
  • Master receiver

My w kursie zajmiemy się odbieraniem i nadawaniem danych w trybie master.

Wysyłanie i odbierania danych

Transfer danych jest zarządzany przez dwa rejestry danych – nadawczy i odbiorczy – oraz rejestr przesuwny.

Przychodzące bity wpisywane są do rejestru przesuwnego aż do momentu odebrania całego bajtu danych. Wtedy, jeżeli poprzednie dane zostały odczytane i rejestr odbiorczy jest pusty, dane z rejestru przesuwnego kopiowane są do rejestru odbiorczego. Jeżeli rejestr RX nie jest pusty, komunikacja zostaje wstrzymana i sygnał SCL nie jest generowany (SCL stretch). Pozwala to uniknąć przypadkowej utraty danych.

Wysyłanie danych odbywa się w analogiczny sposób. Wpisany bajt do rejestru TXDR jest kopiowany do rejestru przesuwnego, z którego następnie bit po bicie wysyłany jest przez linię SDA. W momencie, gdy dane są już w rejestrze przesuwnym, ustawiona jest flaga TXE, która informuje, że można do rejestru danych wpisać kolejny bajt. Generowanie sygnału na linii SCL jest wstrzymywane, gdy dane z rejestru przesuwnego zostaną już wysłane, ale w rejestrze TXDR nie pojawią się nowe.

Ilość danych wysyłanych lub odbieranych przez urządzenie master ustawiane jest w rejestrze CR2 w miejsce bitów NBYTES. Ponieważ to pole ma 8 bitów, możliwe jest ustawienie maksymalnie 255 bajtów do wysłania. W przypadku gdy chcemy wysłać lub odebrać w ramach jednej transmisji większą ilość danych, musimy wykorzystać bit RELOAD. W tym trybie flaga TCR jest ustawiana po przesłaniu liczby bajtów zaprogramowanej w NBYTES. Flaga jest kasowana programowo, gdy w miejsce NBYTES zostanie zapisana niezerowa wartość.

Każda transmisja rozpoczyna się, gdy urządzenie master wyśle sygnał START. Do zakończenia transmisji może wykorzystać automatyczne lub programowe generowanie sygnału stop. Służy do tego bit AUTOEND.

Inicjalizacja I2C

Omówiliśmy podstawowe parametry interfejsu I2C. Możemy je podsumować, przedstawiając proces inicjalizacji I2C. Przebieg pokazany jest na diagramie poniżej.

  • Przed rozpoczęciem konfiguracji I2C należy upewnić się, że interfejs jest wyłączony (bit PE w rejestrze CR1 musi być 0).
  • Następnie konfigurujemy filtr analogowy i cyfrowy. Filtr analogowy możemy włączyć lub wyłączyć. Dla filtru cyfrowego dodatkowo ustawiamy czas jego trwania w cyklach I2CCLK.
  • Potem przechodzimy do ustawienia czasów w rejestrze TIMINGR. Jak już wspominałem, do wyznaczenia tej wartości skorzystamy z kalkulatora w STM32CubeMX.
  • Na koniec powinniśmy jeszcze skonfigurować bit NOSTRETCH w rejestrze CR1. Odpowiada on za pracę w trybie slave, a w trybie master powinien być ustawiony na 0 (Clock stretching enabled).
  • Po ustawieniu tych parametrów możemy włączyć interfejs I2C.

Konfiguracja w trybie Master

Urządzenie Master inicjalizuje komunikację poprzez wysłanie sygnału START i adresu urządzenia oraz kończy ją sygnałem STOP. Dodatkowo steruje kierunkiem przepływu danych, czyli decyduje, czy będzie wysyłał dane do urządzenia Slave, czy oczekuje na dane.

Aby zainicjalizować poprawnie komunikację po stronie urządzenia master, należy: 

  • skonfigurować tryb adresowania (7 lub 10 bitowy) oraz adres urządzenia 
  • ustawić kierunek przepływu danych w bicie RD_WRN
  • skonfigurować ilość bajtów, które chcemy wysłać (za pomocą wartości w NBYTES)

Po wybraniu tych parametrów należy ustawić bit START, który rozpocznie transmisję. Wówczas urządzenie master automatycznie wygeneruje sygnał START i wyśle adres urządzenia.

Wysyłanie danych w trybie Master

Po rozpoczęciu transmisji czas na przesyłanie danych. Każde wysłanie bajtu powoduje ustawienie flagi TXIS, która informuje, że możemy do rejestru danych wpisać kolejną daną. 

Jeżeli korzystamy z trybu AUTOEND, automatycznie zostanie wygenerowany sygnał STOP i transmisja się zakończy. Jeżeli korzystamy z trybu SOFTEND, wystawiona zostanie flaga końca transmisji TC (Transfer Complete), a sygnał SCL będzie oczekiwał na dalsze działania.

Odbieranie danych w trybie Master

W przypadku odczytu danych flaga RXNE jest ustawiana po każdym odebraniu bajtu. Flaga jest kasowana po odczytaniu danych z rejestru RXDR.

Jeżeli korzystamy z trybu AUTOEND, automatycznie zostanie wygenerowany sygnał STOP i komunikacja się zakończy. Jeżeli korzystamy z trybu SOFTEND, wystawiona zostanie flaga końca transmisji TC (Transfer Complete), a sygnał SCL będzie oczekiwał na dalsze działania.

Podstawowe rejestry I2C

Rejestr I2C_CR1- rejestr konfiguracyjny I2C

Bity ANFOFF i DNF[3:0] – konfiguracja filtru analogowego i cyfrowego

Bit PE – włączenie magistrali

Rejestr I2C_CR2- rejestr konfiguracyjny I2C

Bit AUTOEND – automatyczne wysyłanie sygnału STOP po zakończeniu transmisji

Bity NBYTES[7:0] – liczba bajtów do wysłania lub odebrania w ramach transferu

Bit STOP – generowanie sygnału STOP

BIT START – generowanie sygnału START

Bit ADD10 – wybór rozmiaru adresu (trybu adresowania)

Bit RD_WRN – kierunek transmisji

Bity SADD[9:0] – adres urządzenia slave, z którym odbywa się komunikacja

Rejestr I2C_TIMINGR – rejestr dotyczący ustawień czasowych

Rejestr I2C_RXDR – rejestr danych odebranych

Rejestr I2C_TXDR – rejestr danych wysyłanych

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *