Відповідно до стандарту, адреса на шині 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.
Ми можемо замінити константи на числа у параметрах, адже:
1 2 3 4 |
print(i2c.TRANSMITTER) 0 print(i2c.RECEIVER) 1 |
Тож, можемо навести два рівнозначні записи:
1 2 |
i2c.address(id, 0x3C, i2c.TRANSMITTER) --або рівнозначний i2c.address(id, 0x3C, 0) i2c.address(id, 0x3C, i2c.RECEIVER) --або рівнозначний i2c.address(id, 0x3C, 1) |
Примітка: id –це ідентифікатор шини, зазвичай він приймається за 0. Але починаючи з версії NodeMCU 3.0-master_20190907 з’явилася підтримка декількох шин i2c одночасно.
Оскільки у нас є окремий параметр direction, щоб вказати напрямок передачі даних по шині, думаю, що тепер стає зрозуміло, чому у параметрі device_addr, нам необхідно вказувати саме 7-бітну, а не 8-бітну адресу пристрою на шині. Якщо ж спробувати вказати значення, що перевищує 7-бітний діапазон у 127 адрес, то отримаємо помилку:
1 2 3 4 5 |
> i2c.address(0, 0xff, 0) stdin:1: wrong arg range stack traceback: [C]: in function 'address' stdin:1: in main chunk |
Висновок
Якщо виробник вказує семибітну адресу – її і використовуємо без змін; якщо виробник вказує восьмибітну адресу – читаємо уважно, чи не вказано часом 7-біт адреси + 1 біт режиму. А далі орієнтуємося виходячи зі своєї задачі.
Ще багато чого можна обговорювати і наводити інші приклади, але в цій публікації ми розповіли можливо прості, але далеко не очевидні речі про адресацію на шині i2c для новачків.
Дякуємо за увагу і бажаємо успіху!
Рекомендовані матеріали
https://www.nxp.com/docs/en/user-guide/UM10204.pdf
https://www.nxp.com/docs/en/application-note/AN10216.pdf