aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBarnaby Walters <[email protected]>2023-11-20 01:29:02 +0100
committerDario Nieuwenhuis <[email protected]>2023-11-24 23:55:46 +0100
commit3efc3eee5700d2a39e397f1b1b821885301c0862 (patch)
tree074c3a461d39e5295553ef30ec5c272f995a72f3 /examples
parentbc65b8f7ec1df181c793846b7c0657f689963d3a (diff)
stm32/i2c: implement async i2c v1.
Diffstat (limited to 'examples')
-rw-r--r--examples/stm32f4/src/bin/i2c_async.rs62
-rw-r--r--examples/stm32f4/src/bin/i2c_comparison.rs135
2 files changed, 197 insertions, 0 deletions
diff --git a/examples/stm32f4/src/bin/i2c_async.rs b/examples/stm32f4/src/bin/i2c_async.rs
new file mode 100644
index 000000000..9f59e4d41
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_async.rs
@@ -0,0 +1,62 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5// Example originally designed for stm32f411ceu6 reading an A1454 hall effect sensor on I2C1
6// DMA peripherals changed to compile for stm32f429zi, for the CI.
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_stm32::i2c::I2c;
11use embassy_stm32::time::Hertz;
12use embassy_stm32::{bind_interrupts, i2c, peripherals};
13use {defmt_rtt as _, panic_probe as _};
14
15const ADDRESS: u8 = 96;
16
17bind_interrupts!(struct Irqs {
18 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
19 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 info!("Hello world!");
25 let p = embassy_stm32::init(Default::default());
26
27 let mut i2c = I2c::new(
28 p.I2C1,
29 p.PB8,
30 p.PB7,
31 Irqs,
32 p.DMA1_CH6,
33 p.DMA1_CH0,
34 Hertz(100_000),
35 Default::default(),
36 );
37
38 loop {
39 let a1454_read_sensor_command = [0x1F];
40 let mut sensor_data_buffer: [u8; 4] = [0, 0, 0, 0];
41
42 match i2c
43 .write_read(ADDRESS, &a1454_read_sensor_command, &mut sensor_data_buffer)
44 .await
45 {
46 Ok(()) => {
47 // Convert 12-bit signed integer into 16-bit signed integer.
48 // Is the 12 bit number negative?
49 if (sensor_data_buffer[2] & 0b00001000) == 0b0001000 {
50 sensor_data_buffer[2] = sensor_data_buffer[2] | 0b11110000;
51 }
52
53 let mut sensor_value_raw: u16 = sensor_data_buffer[3].into();
54 sensor_value_raw |= (sensor_data_buffer[2] as u16) << 8;
55 let sensor_value: u16 = sensor_value_raw.into();
56 let sensor_value = sensor_value as i16;
57 info!("Data: {}", sensor_value);
58 }
59 Err(e) => error!("I2C Error during read: {:?}", e),
60 }
61 }
62}
diff --git a/examples/stm32f4/src/bin/i2c_comparison.rs b/examples/stm32f4/src/bin/i2c_comparison.rs
new file mode 100644
index 000000000..6d23c0ed8
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_comparison.rs
@@ -0,0 +1,135 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5// Example originally designed for stm32f411ceu6 with three A1454 hall effect sensors, connected to I2C1, 2 and 3
6// on the pins referenced in the peripheral definitions.
7// Pins and DMA peripherals changed to compile for stm32f429zi, to work with the CI.
8// MUST be compiled in release mode to see actual performance, otherwise the async transactions take 2x
9// as long to complete as the blocking ones!
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_stm32::i2c::I2c;
14use embassy_stm32::time::Hertz;
15use embassy_stm32::{bind_interrupts, i2c, peripherals};
16use embassy_time::Instant;
17use futures::future::try_join3;
18use {defmt_rtt as _, panic_probe as _};
19
20const ADDRESS: u8 = 96;
21
22bind_interrupts!(struct Irqs {
23 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
24 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
25 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
26 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
27 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
28 I2C3_ER => i2c::ErrorInterruptHandler<peripherals::I2C3>;
29});
30
31/// Convert 12-bit signed integer within a 4 byte long buffer into 16-bit signed integer.
32fn a1454_buf_to_i16(buffer: &[u8; 4]) -> i16 {
33 let lower = buffer[3];
34 let mut upper = buffer[2];
35 // Fill in additional 1s if the 12 bit number is negative.
36 if (upper & 0b00001000) == 0b0001000 {
37 upper = upper | 0b11110000;
38 }
39
40 let mut sensor_value_raw: u16 = lower.into();
41 sensor_value_raw |= (upper as u16) << 8;
42 let sensor_value: u16 = sensor_value_raw.into();
43 let sensor_value = sensor_value as i16;
44 sensor_value
45}
46
47#[embassy_executor::main]
48async fn main(_spawner: Spawner) {
49 info!("Setting up peripherals.");
50 let p = embassy_stm32::init(Default::default());
51
52 let mut i2c1 = I2c::new(
53 p.I2C1,
54 p.PB8,
55 p.PB7,
56 Irqs,
57 p.DMA1_CH6,
58 p.DMA1_CH0,
59 Hertz(100_000),
60 Default::default(),
61 );
62
63 let mut i2c2 = I2c::new(
64 p.I2C2,
65 p.PB10,
66 p.PB11,
67 Irqs,
68 p.DMA1_CH7,
69 p.DMA1_CH3,
70 Hertz(100_000),
71 Default::default(),
72 );
73
74 let mut i2c3 = I2c::new(
75 p.I2C3,
76 p.PA8,
77 p.PC9,
78 Irqs,
79 p.DMA1_CH4,
80 p.DMA1_CH2,
81 Hertz(100_000),
82 Default::default(),
83 );
84
85 let a1454_read_sensor_command = [0x1F];
86 let mut i2c1_buffer: [u8; 4] = [0, 0, 0, 0];
87 let mut i2c2_buffer: [u8; 4] = [0, 0, 0, 0];
88 let mut i2c3_buffer: [u8; 4] = [0, 0, 0, 0];
89 loop {
90 // Blocking reads one after the other. Completes in about 2000us.
91 let blocking_read_start_us = Instant::now().as_micros();
92 match i2c1.blocking_write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c1_buffer) {
93 Ok(()) => {}
94 Err(e) => error!("I2C Error: {:?}", e),
95 }
96 match i2c2.blocking_write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c2_buffer) {
97 Ok(()) => {}
98 Err(e) => error!("I2C Error: {:?}", e),
99 }
100 match i2c3.blocking_write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c3_buffer) {
101 Ok(()) => {}
102 Err(e) => error!("I2C Error: {:?}", e),
103 }
104 let blocking_read_total_us = Instant::now().as_micros() - blocking_read_start_us;
105 info!(
106 "Blocking reads completed in {}us: i2c1: {} i2c2: {} i2c3: {}",
107 blocking_read_total_us,
108 a1454_buf_to_i16(&i2c1_buffer),
109 a1454_buf_to_i16(&i2c2_buffer),
110 a1454_buf_to_i16(&i2c3_buffer)
111 );
112
113 // Async reads overlapping. Completes in about 1000us.
114 let async_read_start_us = Instant::now().as_micros();
115
116 let i2c1_result = i2c1.write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c1_buffer);
117 let i2c2_result = i2c2.write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c2_buffer);
118 let i2c3_result = i2c3.write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c3_buffer);
119
120 // Wait for all three transactions to finish, or any one of them to fail.
121 match try_join3(i2c1_result, i2c2_result, i2c3_result).await {
122 Ok(_) => {
123 let async_read_total_us = Instant::now().as_micros() - async_read_start_us;
124 info!(
125 "Async reads completed in {}us: i2c1: {} i2c2: {} i2c3: {}",
126 async_read_total_us,
127 a1454_buf_to_i16(&i2c1_buffer),
128 a1454_buf_to_i16(&i2c2_buffer),
129 a1454_buf_to_i16(&i2c3_buffer)
130 );
131 }
132 Err(e) => error!("I2C Error during async write-read: {}", e),
133 };
134 }
135}