diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-09-27 20:09:53 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-09-27 20:09:53 +0000 |
| commit | 9bb43ffe9adddb3497bb08d0730635fbd66cff94 (patch) | |
| tree | 89aa3e8c30251b666d4c932c7af7b44506d1e7ad | |
| parent | 5c882cf4faffe68dd376b90b6ce7504fd5d259c5 (diff) | |
| parent | bf1da0497ce1a591865f2bd8d0a29489079e710b (diff) | |
Merge #914
914: (embassy-rp): Add I2C master implementation r=Dirbaio a=MathiasKoch
This PR adds both blocking and DMA based async implementations of I2C master.
Both E-H 0.2 & E-H 1.0 abstractions are implemented as well.
### Questions & concerns:
- Do we need an I2C interrupt handler (for transfer done, abort & error handling?) (async only)
- Do we need to add some automatic attempt at unblocking an I2C bus in case of failures (see ref: https://github.com/fivdi/pico-i2c-dma/blob/7ebfd553f3ce5b5b210d53102b0ecca158172633/src/i2c_dma.c#L116-L142)
- Should I add `vectored_{read, write}` implementations?
Co-authored-by: Mathias <[email protected]>
Co-authored-by: Mathias Koch <[email protected]>
| -rw-r--r-- | embassy-rp/src/i2c.rs | 556 | ||||
| -rw-r--r-- | embassy-rp/src/lib.rs | 4 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 5 |
3 files changed, 565 insertions, 0 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs new file mode 100644 index 000000000..9596d661d --- /dev/null +++ b/embassy-rp/src/i2c.rs | |||
| @@ -0,0 +1,556 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 4 | use pac::i2c; | ||
| 5 | |||
| 6 | use crate::dma::AnyChannel; | ||
| 7 | use crate::gpio::sealed::Pin; | ||
| 8 | use crate::gpio::AnyPin; | ||
| 9 | use crate::{pac, peripherals, Peripheral}; | ||
| 10 | |||
| 11 | /// I2C error abort reason | ||
| 12 | #[derive(Debug)] | ||
| 13 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 14 | pub enum AbortReason { | ||
| 15 | /// A bus operation was not acknowledged, e.g. due to the addressed device | ||
| 16 | /// not being available on the bus or the device not being ready to process | ||
| 17 | /// requests at the moment | ||
| 18 | NoAcknowledge, | ||
| 19 | /// The arbitration was lost, e.g. electrical problems with the clock signal | ||
| 20 | ArbitrationLoss, | ||
| 21 | Other(u32), | ||
| 22 | } | ||
| 23 | |||
| 24 | /// I2C error | ||
| 25 | #[derive(Debug)] | ||
| 26 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 27 | pub enum Error { | ||
| 28 | /// I2C abort with error | ||
| 29 | Abort(AbortReason), | ||
| 30 | /// User passed in a read buffer that was 0 length | ||
| 31 | InvalidReadBufferLength, | ||
| 32 | /// User passed in a write buffer that was 0 length | ||
| 33 | InvalidWriteBufferLength, | ||
| 34 | /// Target i2c address is out of range | ||
| 35 | AddressOutOfRange(u16), | ||
| 36 | /// Target i2c address is reserved | ||
| 37 | AddressReserved(u16), | ||
| 38 | } | ||
| 39 | |||
| 40 | #[non_exhaustive] | ||
| 41 | #[derive(Copy, Clone)] | ||
| 42 | pub struct Config { | ||
| 43 | pub frequency: u32, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl Default for Config { | ||
| 47 | fn default() -> Self { | ||
| 48 | Self { frequency: 100_000 } | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | const FIFO_SIZE: u8 = 16; | ||
| 53 | |||
| 54 | pub struct I2c<'d, T: Instance, M: Mode> { | ||
| 55 | _tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 56 | _rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 57 | _dma_buf: [u16; 256], | ||
| 58 | phantom: PhantomData<(&'d mut T, M)>, | ||
| 59 | } | ||
| 60 | |||
| 61 | impl<'d, T: Instance> I2c<'d, T, Blocking> { | ||
| 62 | pub fn new_blocking( | ||
| 63 | _peri: impl Peripheral<P = T> + 'd, | ||
| 64 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||
| 65 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||
| 66 | config: Config, | ||
| 67 | ) -> Self { | ||
| 68 | into_ref!(scl, sda); | ||
| 69 | Self::new_inner(_peri, scl.map_into(), sda.map_into(), None, None, config) | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | ||
| 74 | fn new_inner( | ||
| 75 | _peri: impl Peripheral<P = T> + 'd, | ||
| 76 | scl: PeripheralRef<'d, AnyPin>, | ||
| 77 | sda: PeripheralRef<'d, AnyPin>, | ||
| 78 | _tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 79 | _rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 80 | config: Config, | ||
| 81 | ) -> Self { | ||
| 82 | into_ref!(_peri); | ||
| 83 | |||
| 84 | assert!(config.frequency <= 1_000_000); | ||
| 85 | assert!(config.frequency > 0); | ||
| 86 | |||
| 87 | let p = T::regs(); | ||
| 88 | |||
| 89 | unsafe { | ||
| 90 | p.ic_enable().write(|w| w.set_enable(false)); | ||
| 91 | |||
| 92 | // Select controller mode & speed | ||
| 93 | p.ic_con().modify(|w| { | ||
| 94 | // Always use "fast" mode (<= 400 kHz, works fine for standard | ||
| 95 | // mode too) | ||
| 96 | w.set_speed(i2c::vals::Speed::FAST); | ||
| 97 | w.set_master_mode(true); | ||
| 98 | w.set_ic_slave_disable(true); | ||
| 99 | w.set_ic_restart_en(true); | ||
| 100 | w.set_tx_empty_ctrl(true); | ||
| 101 | }); | ||
| 102 | |||
| 103 | // Set FIFO watermarks to 1 to make things simpler. This is encoded | ||
| 104 | // by a register value of 0. | ||
| 105 | p.ic_tx_tl().write(|w| w.set_tx_tl(0)); | ||
| 106 | p.ic_rx_tl().write(|w| w.set_rx_tl(0)); | ||
| 107 | |||
| 108 | // Configure SCL & SDA pins | ||
| 109 | scl.io().ctrl().write(|w| w.set_funcsel(3)); | ||
| 110 | sda.io().ctrl().write(|w| w.set_funcsel(3)); | ||
| 111 | |||
| 112 | scl.pad_ctrl().write(|w| { | ||
| 113 | w.set_schmitt(true); | ||
| 114 | w.set_ie(true); | ||
| 115 | w.set_od(false); | ||
| 116 | w.set_pue(true); | ||
| 117 | w.set_pde(false); | ||
| 118 | }); | ||
| 119 | sda.pad_ctrl().write(|w| { | ||
| 120 | w.set_schmitt(true); | ||
| 121 | w.set_ie(true); | ||
| 122 | w.set_od(false); | ||
| 123 | w.set_pue(true); | ||
| 124 | w.set_pde(false); | ||
| 125 | }); | ||
| 126 | |||
| 127 | // Configure baudrate | ||
| 128 | |||
| 129 | // There are some subtleties to I2C timing which we are completely | ||
| 130 | // ignoring here See: | ||
| 131 | // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 | ||
| 132 | let clk_base = crate::clocks::clk_peri_freq(); | ||
| 133 | |||
| 134 | let period = (clk_base + config.frequency / 2) / config.frequency; | ||
| 135 | let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low | ||
| 136 | let hcnt = period - lcnt; // and 2/5 (40%) of the period high | ||
| 137 | |||
| 138 | // Check for out-of-range divisors: | ||
| 139 | assert!(hcnt <= 0xffff); | ||
| 140 | assert!(lcnt <= 0xffff); | ||
| 141 | assert!(hcnt >= 8); | ||
| 142 | assert!(lcnt >= 8); | ||
| 143 | |||
| 144 | // Per I2C-bus specification a device in standard or fast mode must | ||
| 145 | // internally provide a hold time of at least 300ns for the SDA | ||
| 146 | // signal to bridge the undefined region of the falling edge of SCL. | ||
| 147 | // A smaller hold time of 120ns is used for fast mode plus. | ||
| 148 | let sda_tx_hold_count = if config.frequency < 1_000_000 { | ||
| 149 | // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / | ||
| 150 | // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't | ||
| 151 | // fit in uint. Add 1 to avoid division truncation. | ||
| 152 | ((clk_base * 3) / 10_000_000) + 1 | ||
| 153 | } else { | ||
| 154 | // fast mode plus requires a clk_base > 32MHz | ||
| 155 | assert!(clk_base >= 32_000_000); | ||
| 156 | |||
| 157 | // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / | ||
| 158 | // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't | ||
| 159 | // fit in uint. Add 1 to avoid division truncation. | ||
| 160 | ((clk_base * 3) / 25_000_000) + 1 | ||
| 161 | }; | ||
| 162 | assert!(sda_tx_hold_count <= lcnt - 2); | ||
| 163 | |||
| 164 | p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); | ||
| 165 | p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); | ||
| 166 | p.ic_fs_spklen() | ||
| 167 | .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); | ||
| 168 | p.ic_sda_hold() | ||
| 169 | .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); | ||
| 170 | |||
| 171 | // Enable I2C block | ||
| 172 | p.ic_enable().write(|w| w.set_enable(true)); | ||
| 173 | } | ||
| 174 | |||
| 175 | Self { | ||
| 176 | _tx_dma, | ||
| 177 | _rx_dma, | ||
| 178 | _dma_buf: [0; 256], | ||
| 179 | phantom: PhantomData, | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | fn setup(addr: u16) -> Result<(), Error> { | ||
| 184 | if addr >= 0x80 { | ||
| 185 | return Err(Error::AddressOutOfRange(addr)); | ||
| 186 | } | ||
| 187 | |||
| 188 | if i2c_reserved_addr(addr) { | ||
| 189 | return Err(Error::AddressReserved(addr)); | ||
| 190 | } | ||
| 191 | |||
| 192 | let p = T::regs(); | ||
| 193 | unsafe { | ||
| 194 | p.ic_enable().write(|w| w.set_enable(false)); | ||
| 195 | p.ic_tar().write(|w| w.set_ic_tar(addr)); | ||
| 196 | p.ic_enable().write(|w| w.set_enable(true)); | ||
| 197 | } | ||
| 198 | Ok(()) | ||
| 199 | } | ||
| 200 | |||
| 201 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { | ||
| 202 | let p = T::regs(); | ||
| 203 | unsafe { | ||
| 204 | let abort_reason = p.ic_tx_abrt_source().read(); | ||
| 205 | if abort_reason.0 != 0 { | ||
| 206 | // Note clearing the abort flag also clears the reason, and this | ||
| 207 | // instance of flag is clear-on-read! Note also the | ||
| 208 | // IC_CLR_TX_ABRT register always reads as 0. | ||
| 209 | p.ic_clr_tx_abrt().read(); | ||
| 210 | |||
| 211 | let reason = if abort_reason.abrt_7b_addr_noack() | ||
| 212 | | abort_reason.abrt_10addr1_noack() | ||
| 213 | | abort_reason.abrt_10addr2_noack() | ||
| 214 | { | ||
| 215 | AbortReason::NoAcknowledge | ||
| 216 | } else if abort_reason.arb_lost() { | ||
| 217 | AbortReason::ArbitrationLoss | ||
| 218 | } else { | ||
| 219 | AbortReason::Other(abort_reason.0) | ||
| 220 | }; | ||
| 221 | |||
| 222 | Err(Error::Abort(reason)) | ||
| 223 | } else { | ||
| 224 | Ok(()) | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { | ||
| 230 | if buffer.is_empty() { | ||
| 231 | return Err(Error::InvalidReadBufferLength); | ||
| 232 | } | ||
| 233 | |||
| 234 | let p = T::regs(); | ||
| 235 | let lastindex = buffer.len() - 1; | ||
| 236 | for (i, byte) in buffer.iter_mut().enumerate() { | ||
| 237 | let first = i == 0; | ||
| 238 | let last = i == lastindex; | ||
| 239 | |||
| 240 | // NOTE(unsafe) We have &mut self | ||
| 241 | unsafe { | ||
| 242 | // wait until there is space in the FIFO to write the next byte | ||
| 243 | while p.ic_txflr().read().txflr() == FIFO_SIZE {} | ||
| 244 | |||
| 245 | p.ic_data_cmd().write(|w| { | ||
| 246 | w.set_restart(restart && first); | ||
| 247 | w.set_stop(send_stop && last); | ||
| 248 | |||
| 249 | w.set_cmd(true); | ||
| 250 | }); | ||
| 251 | |||
| 252 | while p.ic_rxflr().read().rxflr() == 0 { | ||
| 253 | self.read_and_clear_abort_reason()?; | ||
| 254 | } | ||
| 255 | |||
| 256 | *byte = p.ic_data_cmd().read().dat(); | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | Ok(()) | ||
| 261 | } | ||
| 262 | |||
| 263 | fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> { | ||
| 264 | if bytes.is_empty() { | ||
| 265 | return Err(Error::InvalidWriteBufferLength); | ||
| 266 | } | ||
| 267 | |||
| 268 | let p = T::regs(); | ||
| 269 | |||
| 270 | for (i, byte) in bytes.iter().enumerate() { | ||
| 271 | let last = i == bytes.len() - 1; | ||
| 272 | |||
| 273 | // NOTE(unsafe) We have &mut self | ||
| 274 | unsafe { | ||
| 275 | p.ic_data_cmd().write(|w| { | ||
| 276 | w.set_stop(send_stop && last); | ||
| 277 | w.set_dat(*byte); | ||
| 278 | }); | ||
| 279 | |||
| 280 | // Wait until the transmission of the address/data from the | ||
| 281 | // internal shift register has completed. For this to function | ||
| 282 | // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The | ||
| 283 | // TX_EMPTY_CTRL flag was set in i2c_init. | ||
| 284 | while !p.ic_raw_intr_stat().read().tx_empty() {} | ||
| 285 | |||
| 286 | let abort_reason = self.read_and_clear_abort_reason(); | ||
| 287 | |||
| 288 | if abort_reason.is_err() || (send_stop && last) { | ||
| 289 | // If the transaction was aborted or if it completed | ||
| 290 | // successfully wait until the STOP condition has occured. | ||
| 291 | |||
| 292 | while !p.ic_raw_intr_stat().read().stop_det() {} | ||
| 293 | |||
| 294 | p.ic_clr_stop_det().read().clr_stop_det(); | ||
| 295 | } | ||
| 296 | |||
| 297 | // Note the hardware issues a STOP automatically on an abort | ||
| 298 | // condition. Note also the hardware clears RX FIFO as well as | ||
| 299 | // TX on abort, ecause we set hwparam | ||
| 300 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | ||
| 301 | abort_reason?; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | Ok(()) | ||
| 305 | } | ||
| 306 | |||
| 307 | // ========================= | ||
| 308 | // Blocking public API | ||
| 309 | // ========================= | ||
| 310 | |||
| 311 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 312 | Self::setup(address.into())?; | ||
| 313 | self.read_blocking_internal(buffer, true, true) | ||
| 314 | // Automatic Stop | ||
| 315 | } | ||
| 316 | |||
| 317 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { | ||
| 318 | Self::setup(address.into())?; | ||
| 319 | self.write_blocking_internal(bytes, true) | ||
| 320 | } | ||
| 321 | |||
| 322 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | ||
| 323 | Self::setup(address.into())?; | ||
| 324 | self.write_blocking_internal(bytes, false)?; | ||
| 325 | self.read_blocking_internal(buffer, true, true) | ||
| 326 | // Automatic Stop | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | mod eh02 { | ||
| 331 | use super::*; | ||
| 332 | |||
| 333 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { | ||
| 334 | type Error = Error; | ||
| 335 | |||
| 336 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 337 | self.blocking_read(address, buffer) | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> { | ||
| 342 | type Error = Error; | ||
| 343 | |||
| 344 | fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 345 | self.blocking_write(address, bytes) | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> { | ||
| 350 | type Error = Error; | ||
| 351 | |||
| 352 | fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 353 | self.blocking_write_read(address, bytes, buffer) | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | #[cfg(feature = "unstable-traits")] | ||
| 359 | mod eh1 { | ||
| 360 | use super::*; | ||
| 361 | |||
| 362 | impl embedded_hal_1::i2c::Error for Error { | ||
| 363 | fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { | ||
| 364 | match *self { | ||
| 365 | Self::Abort(AbortReason::ArbitrationLoss) => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, | ||
| 366 | Self::Abort(AbortReason::NoAcknowledge) => { | ||
| 367 | embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) | ||
| 368 | } | ||
| 369 | Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 370 | Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 371 | Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 372 | Self::AddressOutOfRange(_) => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 373 | Self::AddressReserved(_) => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 374 | } | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> { | ||
| 379 | type Error = Error; | ||
| 380 | } | ||
| 381 | |||
| 382 | impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::blocking::I2c for I2c<'d, T, M> { | ||
| 383 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 384 | self.blocking_read(address, buffer) | ||
| 385 | } | ||
| 386 | |||
| 387 | fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 388 | self.blocking_write(address, buffer) | ||
| 389 | } | ||
| 390 | |||
| 391 | fn write_iter<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error> | ||
| 392 | where | ||
| 393 | B: IntoIterator<Item = u8>, | ||
| 394 | { | ||
| 395 | let mut peekable = bytes.into_iter().peekable(); | ||
| 396 | Self::setup(address.into())?; | ||
| 397 | |||
| 398 | while let Some(tx) = peekable.next() { | ||
| 399 | self.write_blocking_internal(&[tx], peekable.peek().is_none())?; | ||
| 400 | } | ||
| 401 | Ok(()) | ||
| 402 | } | ||
| 403 | |||
| 404 | fn write_iter_read<B>(&mut self, address: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Self::Error> | ||
| 405 | where | ||
| 406 | B: IntoIterator<Item = u8>, | ||
| 407 | { | ||
| 408 | let peekable = bytes.into_iter().peekable(); | ||
| 409 | Self::setup(address.into())?; | ||
| 410 | |||
| 411 | for tx in peekable { | ||
| 412 | self.write_blocking_internal(&[tx], false)? | ||
| 413 | } | ||
| 414 | self.read_blocking_internal(buffer, true, true) | ||
| 415 | } | ||
| 416 | |||
| 417 | fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 418 | self.blocking_write_read(address, wr_buffer, rd_buffer) | ||
| 419 | } | ||
| 420 | |||
| 421 | fn transaction<'a>( | ||
| 422 | &mut self, | ||
| 423 | address: u8, | ||
| 424 | operations: &mut [embedded_hal_1::i2c::blocking::Operation<'a>], | ||
| 425 | ) -> Result<(), Self::Error> { | ||
| 426 | Self::setup(address.into())?; | ||
| 427 | for i in 0..operations.len() { | ||
| 428 | let last = i == operations.len() - 1; | ||
| 429 | match &mut operations[i] { | ||
| 430 | embedded_hal_1::i2c::blocking::Operation::Read(buf) => { | ||
| 431 | self.read_blocking_internal(buf, false, last)? | ||
| 432 | } | ||
| 433 | embedded_hal_1::i2c::blocking::Operation::Write(buf) => self.write_blocking_internal(buf, last)?, | ||
| 434 | } | ||
| 435 | } | ||
| 436 | Ok(()) | ||
| 437 | } | ||
| 438 | |||
| 439 | fn transaction_iter<'a, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error> | ||
| 440 | where | ||
| 441 | O: IntoIterator<Item = embedded_hal_1::i2c::blocking::Operation<'a>>, | ||
| 442 | { | ||
| 443 | Self::setup(address.into())?; | ||
| 444 | let mut peekable = operations.into_iter().peekable(); | ||
| 445 | while let Some(operation) = peekable.next() { | ||
| 446 | let last = peekable.peek().is_none(); | ||
| 447 | match operation { | ||
| 448 | embedded_hal_1::i2c::blocking::Operation::Read(buf) => { | ||
| 449 | self.read_blocking_internal(buf, false, last)? | ||
| 450 | } | ||
| 451 | embedded_hal_1::i2c::blocking::Operation::Write(buf) => self.write_blocking_internal(buf, last)?, | ||
| 452 | } | ||
| 453 | } | ||
| 454 | Ok(()) | ||
| 455 | } | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | fn i2c_reserved_addr(addr: u16) -> bool { | ||
| 460 | (addr & 0x78) == 0 || (addr & 0x78) == 0x78 | ||
| 461 | } | ||
| 462 | |||
| 463 | mod sealed { | ||
| 464 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 465 | |||
| 466 | pub trait Instance { | ||
| 467 | const TX_DREQ: u8; | ||
| 468 | const RX_DREQ: u8; | ||
| 469 | |||
| 470 | type Interrupt: Interrupt; | ||
| 471 | |||
| 472 | fn regs() -> crate::pac::i2c::I2c; | ||
| 473 | } | ||
| 474 | |||
| 475 | pub trait Mode {} | ||
| 476 | |||
| 477 | pub trait SdaPin<T: Instance> {} | ||
| 478 | pub trait SclPin<T: Instance> {} | ||
| 479 | } | ||
| 480 | |||
| 481 | pub trait Mode: sealed::Mode {} | ||
| 482 | |||
| 483 | macro_rules! impl_mode { | ||
| 484 | ($name:ident) => { | ||
| 485 | impl sealed::Mode for $name {} | ||
| 486 | impl Mode for $name {} | ||
| 487 | }; | ||
| 488 | } | ||
| 489 | |||
| 490 | pub struct Blocking; | ||
| 491 | pub struct Async; | ||
| 492 | |||
| 493 | impl_mode!(Blocking); | ||
| 494 | impl_mode!(Async); | ||
| 495 | |||
| 496 | pub trait Instance: sealed::Instance {} | ||
| 497 | |||
| 498 | macro_rules! impl_instance { | ||
| 499 | ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { | ||
| 500 | impl sealed::Instance for peripherals::$type { | ||
| 501 | const TX_DREQ: u8 = $tx_dreq; | ||
| 502 | const RX_DREQ: u8 = $rx_dreq; | ||
| 503 | |||
| 504 | type Interrupt = crate::interrupt::$irq; | ||
| 505 | |||
| 506 | fn regs() -> pac::i2c::I2c { | ||
| 507 | pac::$type | ||
| 508 | } | ||
| 509 | } | ||
| 510 | impl Instance for peripherals::$type {} | ||
| 511 | }; | ||
| 512 | } | ||
| 513 | |||
| 514 | impl_instance!(I2C0, I2C0_IRQ, 32, 33); | ||
| 515 | impl_instance!(I2C1, I2C1_IRQ, 34, 35); | ||
| 516 | |||
| 517 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} | ||
| 518 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} | ||
| 519 | |||
| 520 | macro_rules! impl_pin { | ||
| 521 | ($pin:ident, $instance:ident, $function:ident) => { | ||
| 522 | impl sealed::$function<peripherals::$instance> for peripherals::$pin {} | ||
| 523 | impl $function<peripherals::$instance> for peripherals::$pin {} | ||
| 524 | }; | ||
| 525 | } | ||
| 526 | |||
| 527 | impl_pin!(PIN_0, I2C0, SdaPin); | ||
| 528 | impl_pin!(PIN_1, I2C0, SclPin); | ||
| 529 | impl_pin!(PIN_2, I2C1, SdaPin); | ||
| 530 | impl_pin!(PIN_3, I2C1, SclPin); | ||
| 531 | impl_pin!(PIN_4, I2C0, SdaPin); | ||
| 532 | impl_pin!(PIN_5, I2C0, SclPin); | ||
| 533 | impl_pin!(PIN_6, I2C1, SdaPin); | ||
| 534 | impl_pin!(PIN_7, I2C1, SclPin); | ||
| 535 | impl_pin!(PIN_8, I2C0, SdaPin); | ||
| 536 | impl_pin!(PIN_9, I2C0, SclPin); | ||
| 537 | impl_pin!(PIN_10, I2C1, SdaPin); | ||
| 538 | impl_pin!(PIN_11, I2C1, SclPin); | ||
| 539 | impl_pin!(PIN_12, I2C0, SdaPin); | ||
| 540 | impl_pin!(PIN_13, I2C0, SclPin); | ||
| 541 | impl_pin!(PIN_14, I2C1, SdaPin); | ||
| 542 | impl_pin!(PIN_15, I2C1, SclPin); | ||
| 543 | impl_pin!(PIN_16, I2C0, SdaPin); | ||
| 544 | impl_pin!(PIN_17, I2C0, SclPin); | ||
| 545 | impl_pin!(PIN_18, I2C1, SdaPin); | ||
| 546 | impl_pin!(PIN_19, I2C1, SclPin); | ||
| 547 | impl_pin!(PIN_20, I2C0, SdaPin); | ||
| 548 | impl_pin!(PIN_21, I2C0, SclPin); | ||
| 549 | impl_pin!(PIN_22, I2C1, SdaPin); | ||
| 550 | impl_pin!(PIN_23, I2C1, SclPin); | ||
| 551 | impl_pin!(PIN_24, I2C0, SdaPin); | ||
| 552 | impl_pin!(PIN_25, I2C0, SclPin); | ||
| 553 | impl_pin!(PIN_26, I2C1, SdaPin); | ||
| 554 | impl_pin!(PIN_27, I2C1, SclPin); | ||
| 555 | impl_pin!(PIN_28, I2C0, SdaPin); | ||
| 556 | impl_pin!(PIN_29, I2C0, SclPin); | ||
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 9ac98d226..e784399d4 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -8,6 +8,7 @@ mod intrinsics; | |||
| 8 | 8 | ||
| 9 | pub mod dma; | 9 | pub mod dma; |
| 10 | pub mod gpio; | 10 | pub mod gpio; |
| 11 | pub mod i2c; | ||
| 11 | pub mod interrupt; | 12 | pub mod interrupt; |
| 12 | pub mod rom_data; | 13 | pub mod rom_data; |
| 13 | pub mod rtc; | 14 | pub mod rtc; |
| @@ -75,6 +76,9 @@ embassy_hal_common::peripherals! { | |||
| 75 | SPI0, | 76 | SPI0, |
| 76 | SPI1, | 77 | SPI1, |
| 77 | 78 | ||
| 79 | I2C0, | ||
| 80 | I2C1, | ||
| 81 | |||
| 78 | DMA_CH0, | 82 | DMA_CH0, |
| 79 | DMA_CH1, | 83 | DMA_CH1, |
| 80 | DMA_CH2, | 84 | DMA_CH2, |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index d9285ee51..567c79db3 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -428,9 +428,11 @@ mod eh02 { | |||
| 428 | 428 | ||
| 429 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> { | 429 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> { |
| 430 | type Error = Error; | 430 | type Error = Error; |
| 431 | |||
| 431 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 432 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| 432 | self.blocking_write(buffer) | 433 | self.blocking_write(buffer) |
| 433 | } | 434 | } |
| 435 | |||
| 434 | fn bflush(&mut self) -> Result<(), Self::Error> { | 436 | fn bflush(&mut self) -> Result<(), Self::Error> { |
| 435 | self.blocking_flush() | 437 | self.blocking_flush() |
| 436 | } | 438 | } |
| @@ -438,6 +440,7 @@ mod eh02 { | |||
| 438 | 440 | ||
| 439 | impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> { | 441 | impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> { |
| 440 | type Error = Error; | 442 | type Error = Error; |
| 443 | |||
| 441 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | 444 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { |
| 442 | embedded_hal_02::serial::Read::read(&mut self.rx) | 445 | embedded_hal_02::serial::Read::read(&mut self.rx) |
| 443 | } | 446 | } |
| @@ -445,9 +448,11 @@ mod eh02 { | |||
| 445 | 448 | ||
| 446 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> { | 449 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> { |
| 447 | type Error = Error; | 450 | type Error = Error; |
| 451 | |||
| 448 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 452 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| 449 | self.blocking_write(buffer) | 453 | self.blocking_write(buffer) |
| 450 | } | 454 | } |
| 455 | |||
| 451 | fn bflush(&mut self) -> Result<(), Self::Error> { | 456 | fn bflush(&mut self) -> Result<(), Self::Error> { |
| 452 | self.blocking_flush() | 457 | self.blocking_flush() |
| 453 | } | 458 | } |
