mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-22 14:53:03 +00:00
rp/i2c: add address flexibility and example
Previous i2c examples are using either blocking Embassy API or e-h traits, this example uses Embassy pub API directly. Signed-off-by: Krzysztof Królczyk <Krzysztof.Krolczyk@o2.pl>
This commit is contained in:
parent
26e660722c
commit
96cdf9c9e0
@ -313,25 +313,29 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read from address into buffer using DMA.
|
/// Read from address into buffer using DMA.
|
||||||
pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> {
|
pub async fn read_async(&mut self, addr: impl Into<u16>, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
Self::setup(addr)?;
|
Self::setup(addr.into())?;
|
||||||
self.read_async_internal(buffer, true, true).await
|
self.read_async_internal(buffer, true, true).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to address from buffer using DMA.
|
/// Write to address from buffer using DMA.
|
||||||
pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> {
|
pub async fn write_async(
|
||||||
Self::setup(addr)?;
|
&mut self,
|
||||||
|
addr: impl Into<u16>,
|
||||||
|
bytes: impl IntoIterator<Item = u8>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
Self::setup(addr.into())?;
|
||||||
self.write_async_internal(bytes, true).await
|
self.write_async_internal(bytes, true).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to address from bytes and read from address into buffer using DMA.
|
/// Write to address from bytes and read from address into buffer using DMA.
|
||||||
pub async fn write_read_async(
|
pub async fn write_read_async(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: u16,
|
addr: impl Into<u16>,
|
||||||
bytes: impl IntoIterator<Item = u8>,
|
bytes: impl IntoIterator<Item = u8>,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Self::setup(addr)?;
|
Self::setup(addr.into())?;
|
||||||
self.write_async_internal(bytes, false).await?;
|
self.write_async_internal(bytes, false).await?;
|
||||||
self.read_async_internal(buffer, true, true).await
|
self.read_async_internal(buffer, true, true).await
|
||||||
}
|
}
|
||||||
@ -595,20 +599,20 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
// =========================
|
// =========================
|
||||||
|
|
||||||
/// Read from address into buffer blocking caller until done.
|
/// Read from address into buffer blocking caller until done.
|
||||||
pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
|
pub fn blocking_read(&mut self, address: impl Into<u16>, read: &mut [u8]) -> Result<(), Error> {
|
||||||
Self::setup(address.into())?;
|
Self::setup(address.into())?;
|
||||||
self.read_blocking_internal(read, true, true)
|
self.read_blocking_internal(read, true, true)
|
||||||
// Automatic Stop
|
// Automatic Stop
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to address from buffer blocking caller until done.
|
/// Write to address from buffer blocking caller until done.
|
||||||
pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, address: impl Into<u16>, write: &[u8]) -> Result<(), Error> {
|
||||||
Self::setup(address.into())?;
|
Self::setup(address.into())?;
|
||||||
self.write_blocking_internal(write, true)
|
self.write_blocking_internal(write, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to address from bytes and read from address into buffer blocking caller until done.
|
/// Write to address from bytes and read from address into buffer blocking caller until done.
|
||||||
pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
|
pub fn blocking_write_read(&mut self, address: impl Into<u16>, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
|
||||||
Self::setup(address.into())?;
|
Self::setup(address.into())?;
|
||||||
self.write_blocking_internal(write, false)?;
|
self.write_blocking_internal(write, false)?;
|
||||||
self.read_blocking_internal(read, true, true)
|
self.read_blocking_internal(read, true, true)
|
||||||
@ -719,25 +723,15 @@ where
|
|||||||
T: Instance + 'd,
|
T: Instance + 'd,
|
||||||
{
|
{
|
||||||
async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> {
|
async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
let addr: u16 = address.into();
|
self.read_async(address, read).await
|
||||||
|
|
||||||
Self::setup(addr)?;
|
|
||||||
self.read_async_internal(read, false, true).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
|
async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
|
||||||
let addr: u16 = address.into();
|
self.write_async(address, write.iter().copied()).await
|
||||||
|
|
||||||
Self::setup(addr)?;
|
|
||||||
self.write_async_internal(write.iter().copied(), true).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
async fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
let addr: u16 = address.into();
|
self.write_read_async(address, write.iter().copied(), read).await
|
||||||
|
|
||||||
Self::setup(addr)?;
|
|
||||||
self.write_async_internal(write.iter().cloned(), false).await?;
|
|
||||||
self.read_async_internal(read, true, true).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn transaction(
|
async fn transaction(
|
||||||
|
85
examples/rp/src/bin/i2c_async_embassy.rs
Normal file
85
examples/rp/src/bin/i2c_async_embassy.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
//! This example shows how to communicate asynchronous using i2c with external chip.
|
||||||
|
//!
|
||||||
|
//! It's using embassy's functions directly instead of traits from embedded_hal_async::i2c::I2c.
|
||||||
|
//! While most of i2c devices are addressed using 7 bits, an extension allows 10 bits too.
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use defmt::*;
|
||||||
|
use embassy_rp::i2c::InterruptHandler;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
// Our anonymous hypotetical temperature sensor could be:
|
||||||
|
// a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C
|
||||||
|
// It requires no configuration or calibration, works with all i2c bus speeds,
|
||||||
|
// never stretches clock or does anything complicated. Replies with one u16.
|
||||||
|
// It requires only one write to take it out of suspend mode, and stays on.
|
||||||
|
// Often result would be just on 12 bits, but here we'll simplify it to 16.
|
||||||
|
|
||||||
|
enum UncomplicatedSensorId {
|
||||||
|
A(UncomplicatedSensorU8),
|
||||||
|
B(UncomplicatedSensorU16),
|
||||||
|
}
|
||||||
|
enum UncomplicatedSensorU8 {
|
||||||
|
First = 0x48,
|
||||||
|
}
|
||||||
|
enum UncomplicatedSensorU16 {
|
||||||
|
Other = 0x0049,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u16> for UncomplicatedSensorU16 {
|
||||||
|
fn into(self) -> u16 {
|
||||||
|
self as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<u16> for UncomplicatedSensorU8 {
|
||||||
|
fn into(self) -> u16 {
|
||||||
|
0x48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<UncomplicatedSensorId> for u16 {
|
||||||
|
fn from(t: UncomplicatedSensorId) -> Self {
|
||||||
|
match t {
|
||||||
|
UncomplicatedSensorId::A(x) => x.into(),
|
||||||
|
UncomplicatedSensorId::B(x) => x.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
embassy_rp::bind_interrupts!(struct Irqs {
|
||||||
|
I2C1_IRQ => InterruptHandler<embassy_rp::peripherals::I2C1>;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_task_spawner: embassy_executor::Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
let sda = p.PIN_14;
|
||||||
|
let scl = p.PIN_15;
|
||||||
|
let config = embassy_rp::i2c::Config::default();
|
||||||
|
let mut bus = embassy_rp::i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, config);
|
||||||
|
|
||||||
|
const WAKEYWAKEY: u16 = 0xBABE;
|
||||||
|
let mut result: [u8; 2] = [0, 0];
|
||||||
|
// wait for sensors to initialize
|
||||||
|
embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await;
|
||||||
|
|
||||||
|
let _res_1 = bus
|
||||||
|
.write_async(UncomplicatedSensorU8::First, WAKEYWAKEY.to_be_bytes())
|
||||||
|
.await;
|
||||||
|
let _res_2 = bus
|
||||||
|
.write_async(UncomplicatedSensorU16::Other, WAKEYWAKEY.to_be_bytes())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let s1 = UncomplicatedSensorId::A(UncomplicatedSensorU8::First);
|
||||||
|
let s2 = UncomplicatedSensorId::B(UncomplicatedSensorU16::Other);
|
||||||
|
let sensors = [s1, s2];
|
||||||
|
for sensor in sensors {
|
||||||
|
if bus.read_async(sensor, &mut result).await.is_ok() {
|
||||||
|
info!("Result {}", u16::from_be_bytes(result.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user