-
Notifications
You must be signed in to change notification settings - Fork 284
Expand file tree
/
Copy pathi2c_async_cancelled.rs
More file actions
150 lines (126 loc) · 4.1 KB
/
i2c_async_cancelled.rs
File metadata and controls
150 lines (126 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! # I²C Example
//!
//! This application demonstrates how to talk to I²C devices with an RP2040.
//! in an Async environment.
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]
use core::task::Poll;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
//use panic_halt as _;
use embedded_hal_async::i2c::I2c;
use futures::FutureExt;
// Alias for our HAL crate
use rp2040_hal as hal;
// Some traits we need
use hal::{
fugit::RateExtU32,
gpio::bank0::{Gpio20, Gpio21},
i2c::Controller,
pac::interrupt,
I2C,
};
// Import required types & traits.
use hal::{
gpio::{FunctionI2C, Pin, PullUp},
pac, Clock,
};
use defmt_rtt as _;
use panic_probe as _;
/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
/// Note: This boot block is not necessary when using a rp-hal based BSP
/// as the BSPs already perform this step.
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;
/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
/// if your board has a different frequency
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
#[interrupt]
unsafe fn I2C0_IRQ() {
use hal::async_utils::AsyncPeripheral;
I2C::<pac::I2C0, (Gpio20, Gpio21), Controller>::on_interrupt();
}
/// The function configures the RP2040 peripherals, then performs a single I²C
/// write to a fixed address.
async fn demo() {
let mut pac = pac::Peripherals::take().unwrap();
// Set up the watchdog driver - needed by the clock setup code
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
// Configure the clocks
let clocks = hal::clocks::init_clocks_and_plls(
XTAL_FREQ_HZ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
// The single-cycle I/O block controls our GPIO pins
let sio = hal::Sio::new(pac.SIO);
// Set the pins to their default state
let pins = hal::gpio::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
// Configure two pins as being I²C, not GPIO
let sda_pin: Pin<_, FunctionI2C, PullUp> = pins.gpio20.reconfigure();
let scl_pin: Pin<_, FunctionI2C, PullUp> = pins.gpio21.reconfigure();
// Create the I²C drive, using the two pre-configured pins. This will fail
// at compile time if the pins are in the wrong mode, or if this I²C
// peripheral isn't available on these pins!
let mut i2c = hal::I2C::new_controller(
pac.I2C0,
sda_pin,
scl_pin,
400.kHz(),
&mut pac.RESETS,
clocks.system_clock.freq(),
);
// Unmask the interrupt in the NVIC to let the core wake up & enter the interrupt handler.
unsafe {
pac::NVIC::unpend(hal::pac::Interrupt::I2C0_IRQ);
pac::NVIC::unmask(hal::pac::Interrupt::I2C0_IRQ);
}
let mut cnt = 0;
let timeout = core::future::poll_fn(|cx| {
cx.waker().wake_by_ref();
if cnt == 1 {
Poll::Ready(())
} else {
cnt += 1;
Poll::Pending
}
});
let mut v = [0; 32];
v.iter_mut().enumerate().for_each(|(i, v)| *v = i as u8);
// Asynchronously write three bytes to the I²C device with 7-bit address 0x2C
futures::select_biased! {
r = I2c::write(&mut i2c, 0x76u8, &v).fuse() => r.unwrap(),
_ = timeout.fuse() => {
defmt::info!("Timed out.");
}
}
I2c::write(&mut i2c, 0x76u8, &v).await.unwrap();
// Demo finish - just loop until reset
core::future::pending().await
}
/// Entry point to our bare-metal application.
#[rp2040_hal::entry]
fn main() -> ! {
let runtime = nostd_async::Runtime::new();
let mut task = nostd_async::Task::new(demo());
let handle = task.spawn(&runtime);
handle.join();
unreachable!()
}