Использование драйвера
Как мы уже говорили в главе 5, embedded-hal предоставляет абстракции, с помощью которых можно писать не зависящий от платформы код для работы с оборудованием. Фактически все методы, которыми мы пользовались для работы с оборудованием в главе LED-рулетка и вплоть до этой главы, были методами трейтов, определённых в embedded-hal. Теперь впервые по-настоящему воспользуемся трейтами, которые предоставляет embedded-hal.
Писать драйвер для LSM303AGR под каждую платформу, которую поддерживает встраиваемый Rust (и под новые, которые могут появиться), было бы бессмысленно. Чтобы этого избежать, драйвер можно написать так, чтобы он принимал обобщённые типы, реализующие трейты embedded-hal, — тогда получается не зависящая от платформы версия драйвера. К счастью, это уже сделано в крейте lsm303agr. Поэтому чтение реальных значений акселерометра и магнитометра теперь почти работает по принципу «подключи и пользуйся» (плюс немного чтения документации). На странице crates.io уже есть всё, что нужно, чтобы читать данные акселерометра, — но для Raspberry Pi. Нам остаётся адаптировать этот пример под наш чип:
Посмотрите пример кода для Raspberry Pi под Linux на той странице.
Поскольку мы уже знаем, как создать объект, реализующий трейты embedded_hal::blocking::i2c, из предыдущего раздела, адаптировать пример просто (examples/show-accel.rs):
#![deny(unsafe_code)]
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use microbit::{
hal::{twim, Timer},
pac::twim0::frequency::FREQUENCY_A,
};
use lsm303agr::{AccelMode, AccelOutputDataRate, Lsm303agr};
#[entry]
fn main() -> ! {
rtt_init_print!();
let board = microbit::Board::take().unwrap();
let i2c = { twim::Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100) };
let mut timer0 = Timer::new(board.TIMER0);
// Код из документации
let mut sensor = Lsm303agr::new_with_i2c(i2c);
sensor.init().unwrap();
sensor
.set_accel_mode_and_odr(
&mut timer0,
AccelMode::HighResolution,
AccelOutputDataRate::Hz50,
)
.unwrap();
loop {
if sensor.accel_status().unwrap().xyz_new_data() {
let (x, y, z) = sensor.acceleration().unwrap().xyz_mg();
// RTT вместо обычного print
rprintln!("Acceleration: x {} y {} z {}", x, y, z);
}
}
}
Как и в предыдущем фрагменте, попробовать эту программу можно так:
$ cargo embed --example show-accel
Кроме того, если немного подвигать micro:bit (физически), вы увидите, как меняются выводимые значения ускорения.