I2C
I2C (Inter-Integrated Circuit) — синхронная последовательная шина для связи микроконтроллера с датчиками, памятью и другими микросхемами. Она использует две линии с открытым стоком: данные SDA и тактовый сигнал SCL. Обе линии должны быть подтянуты резисторами к напряжению питания интерфейса.
Для каждой доступной шины модуль определяет числовую константу, например
i2c.I2C0. Набор шин зависит от устройства; обращение к несуществующей
константе возвращает nil.
Модуль предоставляет константы i2c.MASTER и i2c.SLAVE, но описанные ниже
транзакции поддерживаются только в режиме i2c.MASTER. API передаёт 7-битные
адреса от 0x00 до 0x7f; 10-битная адресация не поддерживается.
Распространённые частоты шины — 100 и 400 кГц. Допустимая частота, номиналы подтягивающих резисторов и длина соединений зависят от всех устройств и общей ёмкости шины.
i2c.pins([as_table])
Показать текущие назначения SDA и SCL для доступных шин.
Если as_table равен true, функция возвращает массив записей с полями id,
sda и scl. В остальных случаях она выводит назначения в консоль и ничего
не возвращает.
local buses = i2c.pins(true)
for _, bus in ipairs(buses) do
print(bus.id, bus.sda, bus.scl)
end
i2c.setpins(id, sda, scl)
Изменить назначение выводов шины до её первого подключения.
Аргументы:
id: идентификатор шины, напримерi2c.I2C0;sda: GPIO с поддержкой ввода и вывода;scl: GPIO с поддержкой вывода.
Значение -1 сохраняет текущее назначение соответствующего сигнала. SDA и SCL
должны использовать разные GPIO. Функция ничего не возвращает или вызывает
исключение.
i2c.setpins(i2c.I2C0, pio.GPIO25, pio.GPIO21)
bus = i2c.attach(id, mode [, speed])
Подключить шину I2C.
Аргументы:
id: идентификатор шины, напримерi2c.I2C0;mode:i2c.MASTER; константаi2c.SLAVEзарезервирована для ведомого режима, для которого модуль не предоставляет операции обмена;speed(необязательно): частота шины в герцах, по умолчанию400000.
Возвращает экземпляр шины или вызывает исключение.
local bus = i2c.attach(i2c.I2C0, i2c.MASTER, 400000)
bus:detach()
Отключить экземпляр и освободить занятые ресурсы. После этого остальные методы
экземпляра вызывают исключение. Повторный вызов detach() безопасен.
bus:setspeed(speed)
Изменить частоту этого экземпляра шины. Новое значение применяется сразу и
сохраняется для следующих транзакций. Если к одной аппаратной шине подключены
экземпляры с разными частотами, bus:start() применяет частоту выбранного
экземпляра.
bus:start()
Добавить условие START в текущую транзакцию. Повторный вызов до stop()
добавляет repeated START.
bus:address(address, read)
Добавить в транзакцию 7-битный адрес устройства и направление обмена.
Аргументы:
address: целое число от0x00до0x7f;read:trueдля чтения,falseдля записи.
Перед вызовом нужно добавить START функцией bus:start().
byte1, ... = bus:read([length [, as_string]])
Прочитать от 1 до 128 байтов. Перед чтением нужно отправить адрес с аргументом
read = true.
Аргументы:
length(необязательно): число байтов, по умолчанию 1. Значения меньше 1 заменяются на 1, значения больше 128 — на 128;as_string(необязательно): еслиtrue, функция возвращает одну бинарную строку. Иначе каждый байт возвращается отдельным числом.
Чтение выполняет накопленную часть транзакции немедленно. Завершите обмен
вызовом bus:stop().
-- Выберите нужную форму результата:
local high, low = bus:read(2)
-- local block = bus:read(16, true)
bus:write(data1 [, data2, ...])
Добавить в транзакцию один или несколько целых байтов и бинарных строк. У
целого аргумента передаётся младший байт. Перед записью нужно отправить адрес с
аргументом read = false.
bus:write(0x10, 0x20, "data")
bus:stop()
Добавить условие STOP и выполнить накопленную транзакцию. Функция ничего не возвращает или вызывает исключение, в том числе если устройство не подтвердило адрес или истёк тайм-аут.
Пример работы с EEPROM 24LC256
Пример записывает байты в EEPROM, считывает их обратно и проверяет результат.
Выводы A2–A0 микросхемы в этом примере задают адрес 0x51.
local eeprom = i2c.attach(i2c.I2C0, i2c.MASTER, 400000)
local device_address = 0x51
local function write_address(address)
eeprom:write((address >> 8) & 0xff, address & 0xff)
end
local function wait_until_ready()
for _ = 1, 100 do
local ready = pcall(function()
eeprom:start()
eeprom:address(device_address, false)
eeprom:stop()
end)
if ready then
return
end
thread.sleepms(1)
end
error("EEPROM write timeout")
end
local function write_byte(address, value)
eeprom:start()
eeprom:address(device_address, false)
write_address(address)
eeprom:write(value)
eeprom:stop()
wait_until_ready()
end
local function read_byte(address)
eeprom:start()
eeprom:address(device_address, false)
write_address(address)
eeprom:start() -- repeated START
eeprom:address(device_address, true)
local value = eeprom:read()
eeprom:stop()
return value
end
for address = 0, 100 do
write_byte(address, address)
end
for address = 0, 100 do
local value = read_byte(address)
assert(value == address, string.format(
"address %d: read %d, expected %d",
address,
value,
address
))
end