rp-hal-boards/boards/pico/examples/pico_i2c_controller_peripheral/main.rs

120 lines
3.4 KiB
Rust
Raw Normal View History

Implement peripheral support for i2c and an advanced example (#162) * Implement peripheral support for i2c and an advanced example for the pico board. * Simplify i2c peripheral bootstrap and add a "free" function to allow switching modes. * Set dependency to futures & nostd_async to specific version/revision. * move enum & struct to the start of the file * Add a bit of documentation to the pico_i2c_controller_peripheral demo. * Migrate to pico_i2c_controller_peripheral to embassy & simplify the peripheral support nostd_async is broken since last stable roll out. The pico_i2c_controller_peripheral is being migrated to use embassy's executor. The Controller Async API is now aligned with embassy's traits to facilitate integration. The peripheral no longer require async to run and now appears as an event iterator. Embassy's support relies on unstable features (generic_associated_types and type_alias_impl_traits) and is therefore gated behind the `embassy-traits` feature flag. * make futures & embassy optional for the pico board too * Pin embassy to a specific rev. * Impl embassy_traits::i2c::WriteIter & enable unlimited transfer size on i2c * Applies comment suggestion from @9names for the advanced i2c example. Co-authored-by: 9names <60134748+9names@users.noreply.github.com> * use `I2C block` instead of `IP`. * Fix formatting (unnecessary space at end of line) * Enhance explanation for why `rd_req()` is not cleared in `Iterator::next`'s implementation. Co-authored-by: 9names <60134748+9names@users.noreply.github.com>
2021-11-08 23:23:28 +11:00
//! I2C controller and I2C peripheral async demo.
//!
//! This example demonstrates use of both I2C peripherals (I2C0 and I2C1) at the same time on a single Pico using [Embassy](https://github.com/embassy-rs/embassy), an async executor.
//!
//! Each peripheral is passed to an async task, which allows them to operate independently of each other:
//! - The controller task (ctrl_demo) uses I2C0. It calls the demo controller code in `controller.rs`
//! - The peripheral task (prph_demo) uses I2C1. It calls the demo peripheral code in `peripheral.rs`
//!
//! ### Wiring notes:
//!
//! I2C0 uses pin `GP0` for `SDA`, and `GP1` for `SCL`.
//!
//! I2C1 uses `GP2` for `SDA`, and `GP3` for `SCL`.
//!
//! For this demo to function you must connect the `SDA` signals (`GP0` and `GP2`) to each other using wires.
//! You must also connect the `SCL` signals (`GP1` and `GP3`) to each other.
//!
//! A pull up resistor (to 3.3V, which is available on pin `36`) is required on SCL & SDA lines in order to reach the expected 1MHz. Although it
//! depends on the hardware context (wire length, impedance & capacitance), a typical value of 2KOhm
//! should generally work fine.
//!
//! If you do not connect the resistor and instead use the internal pull-ups on the I2C pins, you may need to lower the I2C frequency to avoid transmission errors.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy::{executor::Executor, util::Forever};
use embedded_time::rate::Extensions;
use hal::{
clocks::{init_clocks_and_plls, Clock},
gpio::{bank0, FunctionI2C, Pin},
i2c::{peripheral::I2CPeripheralEventIterator, I2C},
pac,
sio::Sio,
watchdog::Watchdog,
};
use pico::{hal, Pins, XOSC_CRYSTAL_FREQ};
use panic_halt as _;
mod controller;
mod peripheral;
const ADDRESS: u16 = 0x55;
#[embassy::task]
async fn ctrl_demo(
mut i2c: I2C<
pac::I2C0,
(
Pin<bank0::Gpio0, FunctionI2C>,
Pin<bank0::Gpio1, FunctionI2C>,
),
>,
) {
controller::run_demo(&mut i2c).await.expect("Demo failed")
}
#[embassy::task]
async fn prph_demo(
mut i2c: I2CPeripheralEventIterator<
pac::I2C1,
(
Pin<bank0::Gpio2, FunctionI2C>,
Pin<bank0::Gpio3, FunctionI2C>,
),
>,
) {
peripheral::run_demo(&mut i2c).await.expect("Demo failed")
}
#[cortex_m_rt::entry]
fn main() -> ! {
let mut pac = pac::Peripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks_and_plls(
XOSC_CRYSTAL_FREQ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
let pins = Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
Sio::new(pac.SIO).gpio_bank0,
&mut pac.RESETS,
);
let i2c0 = I2C::new_controller(
pac.I2C0,
pins.gpio0.into_mode(),
pins.gpio1.into_mode(),
1_000.kHz(),
&mut pac.RESETS,
clocks.system_clock.freq(),
);
let i2c1 = I2C::new_peripheral_event_iterator(
pac.I2C1,
pins.gpio2.into_mode(),
pins.gpio3.into_mode(),
&mut pac.RESETS,
ADDRESS,
);
static EXECUTOR: Forever<Executor> = Forever::new();
let executor = EXECUTOR.put(Executor::new());
executor.run(|spawner| {
spawner.spawn(ctrl_demo(i2c0)).unwrap();
spawner.spawn(prph_demo(i2c1)).unwrap();
});
}