rp-hal-boards/boards/pico/examples/pico_i2c_controller_peripheral/main.rs
2021-12-04 16:20:27 +11:00

124 lines
3.5 KiB
Rust

//! 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,
watchdog::Watchdog,
Sio,
};
use pico::{hal, Pins, XOSC_CRYSTAL_FREQ};
use panic_halt as _;
mod controller;
mod peripheral;
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
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();
});
}