Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Написание драйвера I²C: сложная версия

Мы не будем писать драйвер целиком, только первый шаг: «hello world» написания драйверов, то есть чтение идентификатора устройства датчика. Эта версия называется сложной, потому что содержимое методов придётся придумать самим, а информацию искать в embedded-hal и даташитах. Вы можете работать в одном и том же файле с любой из версий.

i2c-driver/src/icm42670p.rs — это текст с пропусками, представляющий собой очень простой драйвер IMU-датчика I²C. Задача — дописать файл так, чтобы запуск main.rs выводил в лог идентификатор устройства драйвера.

i2c-driver/src/icm42670p_solution.rs содержит решение этого упражнения. Чтобы его запустить, нужно поменять импорты в main.rs и lib.rs. Импорты уже есть: достаточно закомментировать текущие импорты и раскомментировать решения, отмеченные комментариями в строках.

API драйвера

Экземпляр датчика

✅ Создайте структуру, которая представляет датчик. У неё два поля: одно — адрес устройства датчика, другое — сама шина I²C. Это делается с помощью трейтов, определённых в крейте embedded-hal. Структура публичная, так как к ней нужен доступ извне крейта, но её поля приватные.

✅ Реализуйте метод создания экземпляра в блоке impl. Этот метод должен быть доступен извне, поэтому помечен как pub. Метод забирает владение шиной I²C и создаёт экземпляр структуры, которую вы определили ранее.

Адрес устройства

✅ У этого устройства I²C два возможных адреса. Найдите их в даташите, раздел 9.3.

🔎 Мы указываем устройству, какой адрес использовать, подавая на вывод AP_AD0 либо 0V, либо 3.3V. При 0V устройство отвечает на адрес 0x68, при 3.3V — на 0x69. Поэтому вывод AP_AD0 можно считать однобитным входом, который задаёт младший бит адреса устройства.

✅ Создайте перечисление, которое представляет оба варианта адреса. Значения вариантов должны быть записаны в двоичном виде.

Представление регистров

✅ Создайте перечисление, которое представляет регистры датчика. Каждый вариант имеет адрес регистра в качестве значения. Пока вам нужен только регистр WhoAmI. Его адрес найдите в даташите.

✅ Реализуйте метод, который возвращает адрес варианта как u8.

read_register() и write_register()

✅ Изучите функции write и write_read в embedded-hal. Почему это write_read, а не просто read?

Ответ Причина — в особенностях протокола I²C. Сначала нужно записать по шине команду, которая указывает, из какого регистра мы хотим читать.

✅ Определите методы read_register и write_register для экземпляра датчика. Используйте методы, которые предоставляет крейт embedded-hal. Они служат вспомогательными средствами для более конкретных методов и абстракцией под датчик с 8-битными регистрами. Это значит, что записываемые и читаемые данные — беззнаковые 8-битные целые. Вспомогательные методы могут оставаться приватными, так как им не нужен доступ извне крейта.

✅ Реализуйте публичный метод, который читает регистр WhoAmI по адресу 0x75. Используйте метод read_register(), описанный выше.

✅ Необязательно: реализуйте дополнительные методы, которые добавляют драйверу возможности. Адреса и описание соответствующих регистров смотрите в документации. 💡 Несколько идей:

  • включение гироскопа или акселерометра;
  • запуск измерений;
  • чтение измерений.

🔎 Общие сведения о регистрах периферии

  • Регистры — это небольшие ячейки памяти, к которым процессор имеет прямой доступ. Регистры датчика имеют размер 8 бит.
  • К ним можно обращаться по адресу.
  • Карты регистров можно найти в разделе 14.
  • Составление значения из старшего и младшего байтов (MSB и LSB) делается сдвигом значения MSB и операцией OR со значением LSB.
#![allow(unused)]
fn main() {
let GYRO_DATA_X: i16 = ((GYRO_DATA_X1 as i16) << 8) | GYRO_DATA_X0 as i16;
}