Плутанина з i2c адресами у документації деяких пристроїв та виробників

Відповідно до стандарту, адреса на шині i2c задається сімома бітами (7-біт). Також існує менш поширена 10-бітна адресація, про які у даній публікації не йдеться. 

Отже, всього може бути закодовано 2^7 = 127 адрес. З них 112 під пристрої, решту адрес зарезервовано під службові задачі та на розвиток.

Під час програмування у середовищі NodeMCU, на мові Lua, для роботи з шиною i2c використовується C-модуль з однойменною назвою “i2c.” (дивись документацію I²C Module ). Серед методів даного модуля є такий, де у складі параметрів виклику потрібно задавати адресу підпорядкованого пристрою на шині i2c. Тобто адресу саме того пристрою, до якого ми виконуємо запит. Це метод i2c.address(id, device_addr, direction). Нас цікавить параметр device_addr.

Плутанина з адресацією виникає тоді, коли виробник пише документацію на свій пристрій притримуючись одних поглядів на адресацію, а розробник читає документацію з точки зору інших вимог і правил, притаманних певному середовищу розробки. 

Більшість виробників вказують i2c адресу у документації як семибітне значення, як того і вимагає специфікація i2c. 

Саме так і потрібно вказувати в Lua в межах прошивки NodeMCU цю адресу. Наприклад, якщо дисплей має адресу 011 1100, про що вказує виробник у документації, то для нас це означає, що у шістнадцятковому форматі це буде 0x3C, а у десятковому форматі це ж число можемо виразити як 60. Тобто i2c.address(id, 0x3C, direction).

Але деякі виробники, як ви зможете побачити, працюючи з дедалі більшою кількістю пристроїв, вказують чомусь не одну єдину адресу, а цілих дві. Ця особливість заводить початківців у глухий кут і навіть на мінне поле з багатокроковим ланцюжком помилок.

За іронією долі, і ті і ті виробники пишуть свої документи вірно. Правда криється у специфікації шини i2c. Оскільки більшість пристроїв передає свої дані по шині i2c порціями щонайменше по 8 біт, то архітектори шини колись вирішили, що з наявних восьми біт під адресу буде виділено сім, а ще один біт буде використано як індикатор напрямку передачі даних – “режим отримувача з шини”, або ж “режим передавача у шину”. Для отримання даних, цей біт потрібно поставити у двійкову “1”, а для передачі даних, цей біт потрібно встановити у двійковий “0”. 

Таким чином, виробник i2c-пристрою, який вказує дві восьмибітні адреси, насправді вказує одну семибітну адресу, але з двома різними бітами режиму напрямку роботи.

Наприклад, адреса того самого дисплея 011 1100 == 0x3C буде у такій нотації виглядати як:

  • 011 1100 1 == 0x79 – адреса для читання з віддаленого пристрою 0x3C;
  • 011 1100 0 == 0x78 – адреса для запису у віддалений пристрій 0x3C.

У вже згаданого нами раніше Lua-метода i2c.address(id, device_addr, direction) є окремий параметр, який відповідає за напрямок передачі даних: direction. Цей параметр задається як i2c.TRANSMITTER або 0 у випадку початку роботи у режимі передачі даних в шину, або ж як i2c.RECEIVER чи просто 1.

Ми можемо замінити константи на числа у параметрах, адже:

Тож, можемо навести два рівнозначні записи:

Примітка: id –це ідентифікатор шини, зазвичай він приймається за 0. Але починаючи з версії NodeMCU 3.0-master_20190907 з’явилася підтримка декількох шин i2c одночасно.

Оскільки у нас є окремий параметр direction, щоб вказати напрямок передачі даних по шині, думаю, що тепер стає зрозуміло, чому у параметрі device_addr, нам необхідно вказувати саме 7-бітну, а не 8-бітну адресу пристрою на шині. Якщо ж спробувати вказати значення, що перевищує 7-бітний діапазон у 127 адрес, то отримаємо помилку:

Висновок

Якщо виробник вказує семибітну адресу – її і використовуємо без змін; якщо виробник вказує восьмибітну адресу – читаємо уважно, чи не вказано часом 7-біт адреси + 1 біт режиму. А далі орієнтуємося виходячи зі своєї задачі.

Ще багато чого можна обговорювати і наводити інші приклади, але в цій публікації ми розповіли можливо прості, але далеко не очевидні речі про адресацію на шині i2c для новачків.

Дякуємо за увагу і бажаємо успіху!

Рекомендовані матеріали

https://www.nxp.com/docs/en/user-guide/UM10204.pdf

https://www.nxp.com/docs/en/application-note/AN10216.pdf

http://www.ti.com/lit/an/slva704/slva704.pdf

https://github.com/nodemcu/nodemcu-firmware/releases