Główne cechy protokołu I²C
Protokół I²C jest szeregowym, synchronicznym protokołem dwukierunkowej wymiany danych. Od strony elektrycznej magistrala składa się z dwóch linii: do przesyłania danych (oznaczanej najczęściej jako SDA) oraz zegarowych impulsów synchronizujących (oznaczanej jako SCL). Interfejsy wszystkich układów dołączonych do magistrali są typu otwarty dren, więc mogą aktywnie wymusić na magistrali jedynie stan niski. Z tego powodu linie SDA i SCL muszą być podciągane do napięcia zasilania za pomocą osobnych oporników. Układy podłączone do magistrali pełnią funkcję mastera (układu nadrzędnego) lub slave’a (układu podrzędnego). Na rysunku 1 pokazano schemat typowej magistrali I²C z podłączonymi układami.
Każdą transmisję – zarówno zapisu, jak i odczytu danych pomiędzy masterem a slave’em – zawsze inicjuje urządzenie nadrzędne. Przesył danych otwiera sekwencja START, po której wysyłany jest 7-bitowy (lub, w trybie rozszerzonym, 10-bitowy) identyfikator układu, do którego kierowana jest transmisja.
Poziom ostatniego, ósmego bitu identyfikatora określa, czy chodzi o zapis (poziom niski), czy odczyt (poziom wysoki). Urządzenie, którego identyfikator został wysłany, potwierdza swoją gotowość sygnałem ACK, czyli wymusza na linii SDA stan niski w czasie 9. taktu zegara. W następnej kolejności, w przypadku zapisu, wysyłane są przez mastera bajty danych. W przypadku odczytu to zaadresowane urządzenie podrzędne wysyła bajty danych w takt zegara SCL. Transmisję zamyka sekwencja STOP, po której magistrala powinna zostać zwolniona.
Interfejsy API sterowników I²C
ESP32 ma wbudowane dwa kontrolery sprzętowe odpowiedzialne za obsługę komunikacji za pośrednictwem magistrali I²C. Pojedynczy kontroler I²C może działać jako master lub slave. Do podłączenia do magistrali I²C służą predefiniowane porty: GPIO21 jako SDA i GPIO22 jako SCL, jednak można te funkcje zmienić programowo i wybrać inne linie wejścia/wyjścia.
ESP-IDF dostarcza bibliotekę driver/i2c.h, która steruje blokami peryferyjnymi I²C modułu ESP32. Najistotniejsze procedury biblioteki to:
i2c_param_config() – inicjalizacja sterownika I²C. Funkcja ma dwa parametry:
- i2c_port_t – numer portu: I²C_NUM_0 lub I²C_NUM_1,
- i2c_config_t – wskaźnik na strukturę zawierającą takie parametry konfiguracyjne, jak: tryb pracy, numery użytych portów GPIO do podłączania linii SDA i SCL, prędkość zegara. Przykład struktury można zobaczyć na listingu 1.
i2c_config_t conf = {
.mode = I²C_MODE_MASTER, //tryb pracy
.sda_io_num = 21, //numer GPIO połączony z SDA
.scl_io_num = 22, //numer GPIO połączony z SCL
.sda_pullup_en = GPIO_PULLUP_ENABLE, //włączenie wewnętrznego podciągania SDA
.scl_pullup_en = GPIO_PULLUP_ENABLE, //włączenie wewnętrznego podciągania SCL
.master.clk_speed = 400000, //szybkość zegara
};
Listing 1. Przykładowa definicja struktury i2c_config_t
i2c_driver_install() – instalacja sterownika. Funkcja ma 5 parametrów:
- i2c_port_t – numer portu I²C,
- i2c_mode_t – tryb pracy: master lub slave,
- kolejne 2 parametry określają rozmiar buforów: nadawczego i odbiorczego. Jeżeli urządzenie będzie pracować w trybie mastera, mogą być one ustawione na 0,
- ostatni parametr to flagi związane z przerwaniami. Jeżeli w obsłudze magistrali I²C nie korzystamy z przerwań, wartość parametru może wynosić 0.
i2c_master_write_to_device() – wysłanie danych do urządzenia podrzędnego. Funkcja może być wywoływana tylko w celu obsługi układów pracujących w trybie master i przyjmuje 5 parametrów:
- i2c_port_t – numer portu I²C,
- device_address – 7-bitowy adres urządzenia podrzędnego, do którego będą zapisywane bajty danych,
- write_buffer – wskaźnik do bufora z bajtami do wysłania,
- write_size – rozmiar bufora zapisu (wyrażony w bajtach),
- ticks_to_wait – maksymalny czas oczekiwania na zakończenie przesyłania danych.
Funkcja jest dostępna, począwszy od wersji ESP-IDF v.4.4.
Alternatywnie można używać funkcji i2c_cmd_link_create(), i2c_master_start(), i2c_master_write_byte(), i2c_master_write(), i2c_master_stop(), i2c_master_cmd_begin(), i2c_cmd_link_delete().
i2c_master_read_from_device() – odczyt danych z urządzenia podrzędnego. Funkcja może być wywoływana tylko do obsługi układów pracujących w trybie master i ma 5 parametrów:
- i2c_port_t – numer portu,
- device_address – 7-bitowy adres urządzenia podrzędnego, z którego będą odczytywane bajty danych,
- read_buffer – wskaźnik do bufora odczytywanych danych,
- read_size – rozmiar bufora odczytu (w bajtach),
- ticks_to_wait – maksymalny czas oczekiwania na zakończenie odczytu danych.
Funkcja jest dostępna od ESP-IDF v.4.4. Alternatywnie można używać funkcji i2c_master_start(), i2c_master_write(), i2c_master_read(), itd.