Mikroprocesory i mikrokontrolery – interfejs I2C
Obecnie mikrokontrolery stały się praktycznie niezbędnym elementem każdego urządzenia, gdyż realizują przeróżne operacje. Nowoczesne układy integrują w swojej strukturze wiele przydatnych „zabawek”, jednak niektóre muszą być zewnętrznymi elementami do nich przyłączanymi. Jak to zrobić?
Technice mikroprocesorowej zawsze towarzyszyły specjalizowane układy do realizacji określonych funkcji. Tu można wskazać przykładowo przetworniki analogowo-cyfrowe lub cyfrowo-analogowe. Wiele z nich obecnie znajduje się w strukturze mikrokontrolera, jednak początki techniki mikroprocesorowej były trochę trudniejsze. Wykształciło się pojęcie portu mikroprocesora, który umożliwiał mikroprocesorowi interakcję z otoczeniem. Dzisiaj odpowiednik takich portów jest wbudowany w sam mikrokontroler. Przykładem może być choćby przetwornik ADC występujący w mikrokontrolerach AVR. W programie wystarczy wczytać dane z odpowiedniego rejestru mikrokontrolera, by uzyskać cyfrowy wynik odzwierciedlający wielkość analogową. Na początku burzliwego rozwoju mikroprocesorów również istniała taka potrzeba, tylko wtedy odbywało się to trochę inaczej. Sam mikroprocesor „posiadał” pamięć na program czy pamięć operacyjną, również jako elementy zewnętrzne. Nie ma powodu by inne układy (porty) działały na odmiennych zasadach. Miały (najczęściej) 8-bitową szynę danych, za pomocą której następowała wymiana danych między mikroprocesorem a dołączonym podzespołem. To oczywiście wymaga 8-bitowego interfejsu pozwalającego na te operacje (tego typu połączenie można określić jako 8-bitowe równoległe: następuje jednoczesne przesłanie wszystkich danych). Te zintegrowane w jedną strukturę mikrokontrolera nadal działają w ten sposób. Różnorodność zastosowań jednak nie pozwala na integrację w jednym układzie wszystkiego, co kiedykolwiek może być potrzebne projektantowi.
Weźmy przykładowo pod uwagę mikrokontroler ATMEGA32 – ma on do dyspozycji cztery porty po osiem bitów (więcej nie ma). Chcąc cokolwiek przyłączyć można wykorzystać do przesyłania danych cały port, ale to zużywa jego wręcz bezcenne zasoby, piny do interakcji ze środowiskiem. Powstała więc koncepcja zamiany równoległego przesyłania danych na rozwiązanie szeregowe. To pozwala jednocześnie minimalizować liczbę niezbędnych pinów przeznaczonych do komunikacji. Tu można dostrzec jeszcze jedną istotną cechę, jaką jest niezależność od długości przesyłanego słowa przy tej samej liczbie wykorzystanych pinów. Niestety zawsze jest „coś za coś”. Zamiana interfejsu równoległego na szeregowy znacząco komplikuje operację i zwiększa jej czas.
Geneza interfejsu I2C
Koncepcja rozwiązania tego interfejsu powstała w firmie Philips Semiconductor i w materiałach tej firmy (a właściwie następników Philips, jak NXP Semiconductors) najlepiej szukać materiałów opisujących ten interfejs (fotografia tytułowa pokazuje okładkę dosyć obszernego katalogu poświęconego układom z interfejsem I2C). Akronim I2C (właściwie IIC, bo pochodzi od ang. Inter-Integrated Circuit) jako dwuprzewodowa, szeregowa synchroniczna magistrala komunikacyjna stworzona do przesyłania danych między układami scalonymi na krótkich dystansach używająca tylko dwóch linii: SDA (dane) i SCL (sygnał taktujący). Krótki dystans należy rozumieć jako taki, który nie wychodzi poza urządzenie, gdyż jego zadaniem jest powiązanie układów w obrębie na przykład telewizora. Dysponując dwoma liniami (SDA, SCL) telewizyjny procesor może przeprogramować głowicę (zmienić program), wnieść korektę do procesora dźwięku (zmienić głośność) i wykonać podobnej klasy działania, wykorzystując do tego celu jedynie dwie linie swoich portów. W każdym przypadku zachodzi potrzeba przesłania kilku/kilkunastu bajtów z procesora do docelowego podzespołu. Ogólną koncepcję pokazuje rysunek 1.
Oczywiście różnych układów przyłączonych do mikrokontrolera może być więcej. Powstaje podział na dwie klasy elementów pracujących z interfejsem I2C: strona nadrzędna (master, w tej roli występuje mikrokontroler) oraz podrzędna (slave, jako układ MCP4726 – 12-bitowy przetwornik cyfrowo-analogowy oraz PCF8583 jako RTC – zegar czasu rzeczywistego). Występujące dwa rezystory są niezbędne, gdyż linia danych (SDA) raz jest sterowana przez stronę master (mikrokontroler), a w kilku innych sytuacjach przez stronę slave (przykładowo przetwornika DAC). Podobnie linia zegarowa (SCL) może być kontrolowana przez więcej niż jedno źródło – przewidziana jest możliwość pracy z kilkoma masterami oraz pracy z powolnymi układami slave. Aby nie powstawały konflikty logiczne, linie muszą pracować w trybie otwartego drenu. Żeby dane na liniach były stabilne, niezbędny jest rezystor wymuszający w stanach pasywnych wartość logicznej jedynki.
Aby ominąć kwestie patentów (I2C jest opatentowany), niektórzy producenci układów scalonych używają określenia TWI (ang. Two-Wire Interface) dla interfejsu dwuprzewodowego, który jest kompatybilny z I2C.
Adresacja w I2C
Wyobraźmy sobie, że do pary linii I2C jest przyłączonych kilka układów typu slave. Te linie jednocześnie dochodzą do każdego układu. Tu powinno zrodzić się słuszne pytanie: skąd te układy będą „wiedziały”, że dane są przesyłane do nich, skoro wszystkie jednocześnie dostają ten sam sygnał. Specyfiką protokołu I2C jest to, że w pierwszym wysłanym szeregowo bajcie znajduje się adres układu slave. To oczywiście prowadzi do wniosku, że każdy układ „wiszący” na liniach SDA i SCL musi mieć indywidualny i unikalny adres, każdy „słyszy”, ale tylko jeden się „odzywa”. Ten adres jest stały dla danego typu układu i nie może być zmieniany. Przykładowo MCP4726 ma stały niezmienny adres, choć jest produkowany w kilku wersjach adresowych, a faktyczny adres jest zakodowany w symbolu układu (MCP4726A0T ma adres [C0 hex] a MCP4726A3T [C6 hex], te dane są dostępne w dokumentacji układu). W niektórych przypadkach układ ma dodatkowy zewnętrzny pin (lub nawet kilka), którego stan może korygować adres slave. To występuje w układzie PCF8583, gdzie podstawowy jego adres sprzętowy dla I2C wynosi A0 hex i może być poprzez pin A0 zmodyfikowany do wartości A1 hex. Pomimo że przesłany do układu slave pierwszy bajt adresowy jest 8-bitowy, w rzeczywistości adresacja w I2C jest 7-bitowa. Wynika to z tego, że najmłodszy bit adresu pełni odmienną funkcję: informuje układ slave, czy aktualna operacja związana z układem dotyczy zapisu (najmłodszy bit adresu jest wyzerowany) czy odczytu (bit jest ustawiony). Pierwszy wysyłany bajt jest informacją adresową i znaczenie bitu określającego zapis lub odczyt dotyczy kolejnych danych. Jeżeli adres jest zgodny z wbudowanym, układ potwierdza odebranie i oczekuje na „dalsze instrukcje”. Te są już zależne od układu i realizowanej funkcji. W przypadku przetwornika DAC generalnie występują operacje zapisu (zapisz liczbę do konwersji na wartość analogową), ale również występują odczyty. Podobnie zachowuje się układ RTC – oprócz operacji zapisu danych do układu, występuje odczyt danych.
(…)
——– ciach! ——–
To jest tylko fragment artykułu, którego pełna wersja ukazała się w marcowym numerze czasopisma Zrozumieć Elektronikę (ZE 3/2026). Pełną wersję czasopisma znajdziesz pod tym linkiem. Natomiast niepełna, okrojona wersja, pozwalająca zapoznać się z zawartością numeru ZE 3/2026 znajduje się tutaj.
Andrzej Pawluczuk
apawluczuk@vp.pl
Uwaga! Wskazówki, jak nabyć pełne wersje dowolnych numerów ZE znajdują się na stronie:
https://piotr-gorecki.pl/n11.
