diff options
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 26 | ||||
| -rw-r--r-- | examples/stm32g4/src/bin/i2c_slave.rs | 149 |
3 files changed, 167 insertions, 18 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 94507eb34..2ff21702b 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -70,19 +70,19 @@ pub mod mode { | |||
| 70 | #[derive(Debug, Clone, PartialEq, Eq)] | 70 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 71 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 71 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 72 | /// The command kind to the slave from the master | 72 | /// The command kind to the slave from the master |
| 73 | pub enum CommandKind { | 73 | pub enum SlaveCommandKind { |
| 74 | /// Write to the slave | 74 | /// Write to the slave |
| 75 | SlaveReceive, | 75 | Write, |
| 76 | /// Read from the slave | 76 | /// Read from the slave |
| 77 | SlaveSend, | 77 | Read, |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | #[derive(Debug, Clone, PartialEq, Eq)] | 80 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 81 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 81 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 82 | /// The command kind to the slave from the master and the address that the slave matched | 82 | /// The command kind to the slave from the master and the address that the slave matched |
| 83 | pub struct Command { | 83 | pub struct SlaveCommand { |
| 84 | /// The kind of command | 84 | /// The kind of command |
| 85 | pub kind: CommandKind, | 85 | pub kind: SlaveCommandKind, |
| 86 | /// The address that the slave matched | 86 | /// The address that the slave matched |
| 87 | pub address: Address, | 87 | pub address: Address, |
| 88 | } | 88 | } |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 1cc41fb5f..64ccd24c7 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -887,7 +887,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 887 | /// Listen for incoming I2C messages. | 887 | /// Listen for incoming I2C messages. |
| 888 | /// | 888 | /// |
| 889 | /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. | 889 | /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. |
| 890 | pub async fn listen(&mut self) -> Result<Command, Error> { | 890 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { |
| 891 | let state = self.state; | 891 | let state = self.state; |
| 892 | self.info.regs.cr1().modify(|reg| { | 892 | self.info.regs.cr1().modify(|reg| { |
| 893 | reg.set_addrie(true); | 893 | reg.set_addrie(true); |
| @@ -902,12 +902,12 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 902 | // we do not clear the address flag here as it will be cleared by the dma read/write | 902 | // we do not clear the address flag here as it will be cleared by the dma read/write |
| 903 | // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it | 903 | // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it |
| 904 | match isr.dir() { | 904 | match isr.dir() { |
| 905 | i2c::vals::Dir::WRITE => Poll::Ready(Ok(Command { | 905 | i2c::vals::Dir::WRITE => Poll::Ready(Ok(SlaveCommand { |
| 906 | kind: CommandKind::SlaveReceive, | 906 | kind: SlaveCommandKind::Write, |
| 907 | address: self.determine_matched_address()?, | 907 | address: self.determine_matched_address()?, |
| 908 | })), | 908 | })), |
| 909 | i2c::vals::Dir::READ => Poll::Ready(Ok(Command { | 909 | i2c::vals::Dir::READ => Poll::Ready(Ok(SlaveCommand { |
| 910 | kind: CommandKind::SlaveSend, | 910 | kind: SlaveCommandKind::Read, |
| 911 | address: self.determine_matched_address()?, | 911 | address: self.determine_matched_address()?, |
| 912 | })), | 912 | })), |
| 913 | } | 913 | } |
| @@ -916,30 +916,30 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 916 | .await | 916 | .await |
| 917 | } | 917 | } |
| 918 | 918 | ||
| 919 | /// Respond to a receive command. | 919 | /// Respond to a write command. |
| 920 | pub fn blocking_respond_to_receive(&self, read: &mut [u8]) -> Result<(), Error> { | 920 | pub fn blocking_respond_to_write(&self, read: &mut [u8]) -> Result<(), Error> { |
| 921 | let timeout = self.timeout(); | 921 | let timeout = self.timeout(); |
| 922 | self.slave_read_internal(read, timeout) | 922 | self.slave_read_internal(read, timeout) |
| 923 | } | 923 | } |
| 924 | 924 | ||
| 925 | /// Respond to a send command. | 925 | /// Respond to a read command. |
| 926 | pub fn blocking_respond_to_send(&mut self, write: &[u8]) -> Result<(), Error> { | 926 | pub fn blocking_respond_to_read(&mut self, write: &[u8]) -> Result<(), Error> { |
| 927 | let timeout = self.timeout(); | 927 | let timeout = self.timeout(); |
| 928 | self.slave_write_internal(write, timeout) | 928 | self.slave_write_internal(write, timeout) |
| 929 | } | 929 | } |
| 930 | } | 930 | } |
| 931 | 931 | ||
| 932 | impl<'d> I2c<'d, Async, MultiMaster> { | 932 | impl<'d> I2c<'d, Async, MultiMaster> { |
| 933 | /// Respond to a receive command. | 933 | /// Respond to a write command. |
| 934 | /// | 934 | /// |
| 935 | /// Returns the total number of bytes received. | 935 | /// Returns the total number of bytes received. |
| 936 | pub async fn respond_to_receive(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 936 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 937 | let timeout = self.timeout(); | 937 | let timeout = self.timeout(); |
| 938 | timeout.with(self.read_dma_internal_slave(buffer, timeout)).await | 938 | timeout.with(self.read_dma_internal_slave(buffer, timeout)).await |
| 939 | } | 939 | } |
| 940 | 940 | ||
| 941 | /// Respond to a send request from an I2C master. | 941 | /// Respond to a read request from an I2C master. |
| 942 | pub async fn respond_to_send(&mut self, write: &[u8]) -> Result<SendStatus, Error> { | 942 | pub async fn respond_to_read(&mut self, write: &[u8]) -> Result<SendStatus, Error> { |
| 943 | let timeout = self.timeout(); | 943 | let timeout = self.timeout(); |
| 944 | timeout.with(self.write_dma_internal_slave(write, timeout)).await | 944 | timeout.with(self.write_dma_internal_slave(write, timeout)).await |
| 945 | } | 945 | } |
diff --git a/examples/stm32g4/src/bin/i2c_slave.rs b/examples/stm32g4/src/bin/i2c_slave.rs new file mode 100644 index 000000000..a723a0e18 --- /dev/null +++ b/examples/stm32g4/src/bin/i2c_slave.rs | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | //! This example shows how to use an stm32 as both a master and a slave. | ||
| 2 | #![no_std] | ||
| 3 | #![no_main] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::i2c::{Address, OwnAddresses, SlaveCommandKind}; | ||
| 8 | use embassy_stm32::mode::Async; | ||
| 9 | use embassy_stm32::time::Hertz; | ||
| 10 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 11 | use embassy_time::Timer; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>; | ||
| 16 | I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>; | ||
| 17 | I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||
| 18 | I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||
| 19 | }); | ||
| 20 | |||
| 21 | const DEV_ADDR: u8 = 0x42; | ||
| 22 | |||
| 23 | #[embassy_executor::task] | ||
| 24 | async fn device_task(mut dev: i2c::I2c<'static, Async, i2c::MultiMaster>) -> ! { | ||
| 25 | info!("Device start"); | ||
| 26 | |||
| 27 | let mut state = 0; | ||
| 28 | |||
| 29 | loop { | ||
| 30 | let mut buf = [0u8; 128]; | ||
| 31 | match dev.listen().await { | ||
| 32 | Ok(i2c::SlaveCommand { | ||
| 33 | kind: SlaveCommandKind::Read, | ||
| 34 | address: Address::SevenBit(DEV_ADDR), | ||
| 35 | }) => match dev.respond_to_read(&[state]).await { | ||
| 36 | Ok(i2c::SendStatus::LeftoverBytes(x)) => info!("tried to write {} extra bytes", x), | ||
| 37 | Ok(i2c::SendStatus::Done) => {} | ||
| 38 | Err(e) => error!("error while responding {}", e), | ||
| 39 | }, | ||
| 40 | Ok(i2c::SlaveCommand { | ||
| 41 | kind: SlaveCommandKind::Write, | ||
| 42 | address: Address::SevenBit(DEV_ADDR), | ||
| 43 | }) => match dev.respond_to_write(&mut buf).await { | ||
| 44 | Ok(len) => { | ||
| 45 | info!("Device received write: {}", buf[..len]); | ||
| 46 | |||
| 47 | if match buf[0] { | ||
| 48 | // Set the state | ||
| 49 | 0xC2 => { | ||
| 50 | state = buf[1]; | ||
| 51 | true | ||
| 52 | } | ||
| 53 | // Reset State | ||
| 54 | 0xC8 => { | ||
| 55 | state = 0; | ||
| 56 | true | ||
| 57 | } | ||
| 58 | x => { | ||
| 59 | error!("Invalid Write Read {:x}", x); | ||
| 60 | false | ||
| 61 | } | ||
| 62 | } { | ||
| 63 | match dev.respond_to_read(&[state]).await { | ||
| 64 | Ok(read_status) => info!( | ||
| 65 | "This read is part of a write/read transaction. The response read status {}", | ||
| 66 | read_status | ||
| 67 | ), | ||
| 68 | Err(i2c::Error::Timeout) => { | ||
| 69 | info!("The device only performed a write and it not also do a read") | ||
| 70 | } | ||
| 71 | Err(e) => error!("error while responding {}", e), | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | Err(e) => error!("error while receiving {}", e), | ||
| 76 | }, | ||
| 77 | Ok(i2c::SlaveCommand { address, .. }) => { | ||
| 78 | defmt::unreachable!( | ||
| 79 | "The slave matched address: {}, which it was not configured for", | ||
| 80 | address | ||
| 81 | ); | ||
| 82 | } | ||
| 83 | Err(e) => error!("{}", e), | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | #[embassy_executor::task] | ||
| 89 | async fn controller_task(mut con: i2c::I2c<'static, Async, i2c::Master>) { | ||
| 90 | info!("Controller start"); | ||
| 91 | |||
| 92 | loop { | ||
| 93 | let mut resp_buff = [0u8; 1]; | ||
| 94 | for i in 0..10 { | ||
| 95 | match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await { | ||
| 96 | Ok(_) => { | ||
| 97 | info!("write_read response: {}", resp_buff); | ||
| 98 | defmt::assert_eq!(resp_buff[0], i); | ||
| 99 | } | ||
| 100 | Err(e) => error!("Error writing {}", e), | ||
| 101 | } | ||
| 102 | |||
| 103 | Timer::after_millis(100).await; | ||
| 104 | } | ||
| 105 | match con.read(DEV_ADDR, &mut resp_buff).await { | ||
| 106 | Ok(_) => { | ||
| 107 | info!("read response: {}", resp_buff); | ||
| 108 | // assert that the state is the last index that was written | ||
| 109 | defmt::assert_eq!(resp_buff[0], 9); | ||
| 110 | } | ||
| 111 | Err(e) => error!("Error writing {}", e), | ||
| 112 | } | ||
| 113 | match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await { | ||
| 114 | Ok(_) => { | ||
| 115 | info!("write_read response: {}", resp_buff); | ||
| 116 | // assert that the state has been reset | ||
| 117 | defmt::assert_eq!(resp_buff[0], 0); | ||
| 118 | } | ||
| 119 | Err(e) => error!("Error writing {}", e), | ||
| 120 | } | ||
| 121 | Timer::after_millis(100).await; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | #[embassy_executor::main] | ||
| 126 | async fn main(spawner: Spawner) { | ||
| 127 | let p = embassy_stm32::init(Default::default()); | ||
| 128 | info!("Hello World!"); | ||
| 129 | |||
| 130 | let speed = Hertz::khz(400); | ||
| 131 | let config = i2c::Config::default(); | ||
| 132 | |||
| 133 | let d_addr_config = i2c::SlaveAddrConfig { | ||
| 134 | addr: OwnAddresses::OA1(Address::SevenBit(DEV_ADDR)), | ||
| 135 | general_call: false, | ||
| 136 | }; | ||
| 137 | let d_sda = p.PA8; | ||
| 138 | let d_scl = p.PA9; | ||
| 139 | let device = i2c::I2c::new(p.I2C2, d_scl, d_sda, Irqs, p.DMA1_CH1, p.DMA1_CH2, speed, config) | ||
| 140 | .into_slave_multimaster(d_addr_config); | ||
| 141 | |||
| 142 | unwrap!(spawner.spawn(device_task(device))); | ||
| 143 | |||
| 144 | let c_sda = p.PB8; | ||
| 145 | let c_scl = p.PB7; | ||
| 146 | let controller = i2c::I2c::new(p.I2C1, c_sda, c_scl, Irqs, p.DMA1_CH3, p.DMA1_CH4, speed, config); | ||
| 147 | |||
| 148 | unwrap!(spawner.spawn(controller_task(controller))); | ||
| 149 | } | ||
