diff options
| author | Jeremy Fitzhardinge <[email protected]> | 2022-09-28 01:20:04 -0700 |
|---|---|---|
| committer | Jeremy Fitzhardinge <[email protected]> | 2022-10-01 13:43:37 -0700 |
| commit | 5e2c52ee5b6fcc5b50589fd2590657e3f1083bff (patch) | |
| tree | 90dd2a95bc276bed26bb2574deaed75891178e76 | |
| parent | 72b645b0c96c7b8312d0a64f851e807faacd78af (diff) | |
embassy-rp: async i2c implementation
This is an interrupt-driven async i2c master implementation. It makes as
best use of the RP2040's i2c block's fifos as possible to minimize
interrupts.
It implements embedded_hal_async::i2c for easy interop.
WIP async impl
| -rw-r--r-- | embassy-rp/src/i2c.rs | 376 | ||||
| -rw-r--r-- | examples/rp/Cargo.toml | 3 |
2 files changed, 369 insertions, 10 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index c609b02ea..6fc64d849 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | use core::future; | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use core::task::Poll; | ||
| 2 | 4 | ||
| 5 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | 6 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 4 | use pac::i2c; | 8 | use pac::i2c; |
| 5 | 9 | ||
| 6 | use crate::gpio::sealed::Pin; | 10 | use crate::gpio::sealed::Pin; |
| @@ -79,7 +83,7 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> { | |||
| 79 | // NOTE(unsafe) We have &mut self | 83 | // NOTE(unsafe) We have &mut self |
| 80 | unsafe { | 84 | unsafe { |
| 81 | // wait until there is space in the FIFO to write the next byte | 85 | // wait until there is space in the FIFO to write the next byte |
| 82 | while p.ic_txflr().read().txflr() == FIFO_SIZE {} | 86 | while Self::tx_fifo_full() {} |
| 83 | 87 | ||
| 84 | p.ic_data_cmd().write(|w| { | 88 | p.ic_data_cmd().write(|w| { |
| 85 | w.set_restart(restart && first); | 89 | w.set_restart(restart && first); |
| @@ -88,7 +92,7 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> { | |||
| 88 | w.set_cmd(true); | 92 | w.set_cmd(true); |
| 89 | }); | 93 | }); |
| 90 | 94 | ||
| 91 | while p.ic_rxflr().read().rxflr() == 0 { | 95 | while Self::rx_fifo_len() == 0 { |
| 92 | self.read_and_clear_abort_reason()?; | 96 | self.read_and_clear_abort_reason()?; |
| 93 | } | 97 | } |
| 94 | 98 | ||
| @@ -165,9 +169,250 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> { | |||
| 165 | // Automatic Stop | 169 | // Automatic Stop |
| 166 | } | 170 | } |
| 167 | } | 171 | } |
| 172 | |||
| 173 | static I2C_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 174 | |||
| 175 | impl<'d, T: Instance> I2c<'d, T, Async> { | ||
| 176 | pub fn new_async( | ||
| 177 | peri: impl Peripheral<P = T> + 'd, | ||
| 178 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||
| 179 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||
| 180 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 181 | config: Config, | ||
| 182 | ) -> Self { | ||
| 183 | into_ref!(scl, sda, irq); | ||
| 184 | |||
| 185 | let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config); | ||
| 186 | |||
| 187 | irq.set_handler(Self::on_interrupt); | ||
| 188 | unsafe { | ||
| 189 | let i2c = T::regs(); | ||
| 190 | |||
| 191 | // mask everything initially | ||
| 192 | i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); | ||
| 193 | } | ||
| 194 | irq.unpend(); | ||
| 195 | debug_assert!(!irq.is_pending()); | ||
| 196 | irq.enable(); | ||
| 197 | |||
| 198 | i2c | ||
| 199 | } | ||
| 200 | |||
| 201 | /// Calls `f` to check if we are ready or not. | ||
| 202 | /// If not, `g` is called once the waker is set (to eg enable the required interrupts). | ||
| 203 | async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U | ||
| 204 | where | ||
| 205 | F: FnMut(&mut Self) -> Poll<U>, | ||
| 206 | G: FnMut(&mut Self), | ||
| 207 | { | ||
| 208 | future::poll_fn(|cx| { | ||
| 209 | let r = f(self); | ||
| 210 | |||
| 211 | if r.is_pending() { | ||
| 212 | I2C_WAKER.register(cx.waker()); | ||
| 213 | g(self); | ||
| 214 | } | ||
| 215 | r | ||
| 216 | }) | ||
| 217 | .await | ||
| 218 | } | ||
| 219 | |||
| 220 | // Mask interrupts and wake any task waiting for this interrupt | ||
| 221 | unsafe fn on_interrupt(_: *mut ()) { | ||
| 222 | let i2c = T::regs(); | ||
| 223 | i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default()); | ||
| 224 | |||
| 225 | I2C_WAKER.wake(); | ||
| 226 | } | ||
| 227 | |||
| 228 | async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { | ||
| 229 | if buffer.is_empty() { | ||
| 230 | return Err(Error::InvalidReadBufferLength); | ||
| 231 | } | ||
| 232 | |||
| 233 | let p = T::regs(); | ||
| 234 | |||
| 235 | let mut remaining = buffer.len(); | ||
| 236 | let mut remaining_queue = buffer.len(); | ||
| 237 | |||
| 238 | let mut abort_reason = None; | ||
| 239 | |||
| 240 | while remaining > 0 { | ||
| 241 | // Waggle SCK - basically the same as write | ||
| 242 | let tx_fifo_space = Self::tx_fifo_capacity(); | ||
| 243 | let mut batch = 0; | ||
| 244 | |||
| 245 | debug_assert!(remaining_queue > 0); | ||
| 246 | |||
| 247 | for _ in 0..remaining_queue.min(tx_fifo_space as usize) { | ||
| 248 | remaining_queue -= 1; | ||
| 249 | let last = remaining_queue == 0; | ||
| 250 | batch += 1; | ||
| 251 | |||
| 252 | unsafe { | ||
| 253 | p.ic_data_cmd().write(|w| { | ||
| 254 | w.set_restart(restart && remaining_queue == buffer.len() - 1); | ||
| 255 | w.set_stop(last && send_stop); | ||
| 256 | w.set_cmd(true); | ||
| 257 | }); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | // We've either run out of txfifo or just plain finished setting up | ||
| 262 | // the clocks for the message - either way we need to wait for rx | ||
| 263 | // data. | ||
| 264 | |||
| 265 | debug_assert!(batch > 0); | ||
| 266 | let res = self | ||
| 267 | .wait_on( | ||
| 268 | |me| { | ||
| 269 | let rxfifo = Self::rx_fifo_len(); | ||
| 270 | if let Err(abort_reason) = me.read_and_clear_abort_reason() { | ||
| 271 | Poll::Ready(Err(abort_reason)) | ||
| 272 | } else if rxfifo >= batch { | ||
| 273 | Poll::Ready(Ok(rxfifo)) | ||
| 274 | } else { | ||
| 275 | Poll::Pending | ||
| 276 | } | ||
| 277 | }, | ||
| 278 | |_me| unsafe { | ||
| 279 | // Set the read threshold to the number of bytes we're | ||
| 280 | // expecting so we don't get spurious interrupts. | ||
| 281 | p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); | ||
| 282 | |||
| 283 | p.ic_intr_mask().modify(|w| { | ||
| 284 | w.set_m_rx_full(true); | ||
| 285 | w.set_m_tx_abrt(true); | ||
| 286 | }); | ||
| 287 | }, | ||
| 288 | ) | ||
| 289 | .await; | ||
| 290 | |||
| 291 | match res { | ||
| 292 | Err(reason) => { | ||
| 293 | abort_reason = Some(reason); | ||
| 294 | // XXX keep going anyway? | ||
| 295 | break; | ||
| 296 | } | ||
| 297 | Ok(rxfifo) => { | ||
| 298 | // Fetch things from rx fifo. We're assuming we're the only | ||
| 299 | // rxfifo reader, so nothing else can take things from it. | ||
| 300 | let rxbytes = (rxfifo as usize).min(remaining); | ||
| 301 | let received = buffer.len() - remaining; | ||
| 302 | for b in &mut buffer[received..received + rxbytes] { | ||
| 303 | *b = unsafe { p.ic_data_cmd().read().dat() }; | ||
| 304 | } | ||
| 305 | remaining -= rxbytes; | ||
| 306 | } | ||
| 307 | }; | ||
| 308 | } | ||
| 309 | |||
| 310 | // wait for stop condition to be emitted. | ||
| 311 | self.wait_on( | ||
| 312 | |_me| unsafe { | ||
| 313 | if !p.ic_raw_intr_stat().read().stop_det() && send_stop { | ||
| 314 | Poll::Pending | ||
| 315 | } else { | ||
| 316 | Poll::Ready(()) | ||
| 317 | } | ||
| 318 | }, | ||
| 319 | |_me| unsafe { | ||
| 320 | p.ic_intr_mask().modify(|w| { | ||
| 321 | w.set_m_stop_det(true); | ||
| 322 | w.set_m_tx_abrt(true); | ||
| 323 | }); | ||
| 324 | }, | ||
| 325 | ) | ||
| 326 | .await; | ||
| 327 | unsafe { p.ic_clr_stop_det().read() }; | ||
| 328 | |||
| 329 | if let Some(abort_reason) = abort_reason { | ||
| 330 | return Err(abort_reason); | ||
| 331 | } | ||
| 332 | Ok(()) | ||
| 333 | } | ||
| 334 | |||
| 335 | async fn write_async_internal( | ||
| 336 | &mut self, | ||
| 337 | bytes: impl IntoIterator<Item = u8>, | ||
| 338 | send_stop: bool, | ||
| 339 | ) -> Result<(), Error> { | ||
| 340 | let p = T::regs(); | ||
| 341 | |||
| 342 | let mut bytes = bytes.into_iter().peekable(); | ||
| 343 | |||
| 344 | 'xmit: loop { | ||
| 345 | let tx_fifo_space = Self::tx_fifo_capacity(); | ||
| 346 | |||
| 347 | for _ in 0..tx_fifo_space { | ||
| 348 | if let Some(byte) = bytes.next() { | ||
| 349 | let last = bytes.peek().is_none(); | ||
| 350 | |||
| 351 | unsafe { | ||
| 352 | p.ic_data_cmd().write(|w| { | ||
| 353 | w.set_stop(last && send_stop); | ||
| 354 | w.set_cmd(false); | ||
| 355 | w.set_dat(byte); | ||
| 356 | }); | ||
| 357 | } | ||
| 358 | } else { | ||
| 359 | break 'xmit; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | self.wait_on( | ||
| 364 | |me| { | ||
| 365 | if let Err(abort_reason) = me.read_and_clear_abort_reason() { | ||
| 366 | Poll::Ready(Err(abort_reason)) | ||
| 367 | } else if !Self::tx_fifo_full() { | ||
| 368 | Poll::Ready(Ok(())) | ||
| 369 | } else { | ||
| 370 | Poll::Pending | ||
| 371 | } | ||
| 372 | }, | ||
| 373 | |_me| unsafe { | ||
| 374 | p.ic_intr_mask().modify(|w| { | ||
| 375 | w.set_m_tx_empty(true); | ||
| 376 | w.set_m_tx_abrt(true); | ||
| 377 | }) | ||
| 378 | }, | ||
| 379 | ) | ||
| 380 | .await?; | ||
| 381 | } | ||
| 382 | |||
| 383 | // wait for fifo to drain | ||
| 384 | self.wait_on( | ||
| 385 | |_me| unsafe { | ||
| 386 | if p.ic_raw_intr_stat().read().tx_empty() { | ||
| 387 | Poll::Ready(()) | ||
| 388 | } else { | ||
| 389 | Poll::Pending | ||
| 390 | } | ||
| 391 | }, | ||
| 392 | |_me| unsafe { | ||
| 393 | p.ic_intr_mask().modify(|w| { | ||
| 394 | w.set_m_tx_empty(true); | ||
| 395 | w.set_m_tx_abrt(true); | ||
| 396 | }); | ||
| 397 | }, | ||
| 398 | ) | ||
| 399 | .await; | ||
| 400 | |||
| 401 | Ok(()) | ||
| 402 | } | ||
| 403 | |||
| 404 | pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 405 | Self::setup(addr)?; | ||
| 406 | self.read_async_internal(buffer, false, true).await | ||
| 407 | } | ||
| 408 | |||
| 409 | pub async fn write_async(&mut self, addr: u16, buffer: &[u8]) -> Result<(), Error> { | ||
| 410 | Self::setup(addr)?; | ||
| 411 | self.write_async_internal(buffer.iter().copied(), true).await | ||
| 412 | } | ||
| 168 | } | 413 | } |
| 169 | 414 | ||
| 170 | impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | 415 | impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { |
| 171 | fn new_inner( | 416 | fn new_inner( |
| 172 | _peri: impl Peripheral<P = T> + 'd, | 417 | _peri: impl Peripheral<P = T> + 'd, |
| 173 | scl: PeripheralRef<'d, AnyPin>, | 418 | scl: PeripheralRef<'d, AnyPin>, |
| @@ -182,6 +427,10 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 182 | let p = T::regs(); | 427 | let p = T::regs(); |
| 183 | 428 | ||
| 184 | unsafe { | 429 | unsafe { |
| 430 | let reset = T::reset(); | ||
| 431 | crate::reset::reset(reset); | ||
| 432 | crate::reset::unreset_wait(reset); | ||
| 433 | |||
| 185 | p.ic_enable().write(|w| w.set_enable(false)); | 434 | p.ic_enable().write(|w| w.set_enable(false)); |
| 186 | 435 | ||
| 187 | // Select controller mode & speed | 436 | // Select controller mode & speed |
| @@ -267,9 +516,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 267 | p.ic_enable().write(|w| w.set_enable(true)); | 516 | p.ic_enable().write(|w| w.set_enable(true)); |
| 268 | } | 517 | } |
| 269 | 518 | ||
| 270 | Self { | 519 | Self { phantom: PhantomData } |
| 271 | phantom: PhantomData, | ||
| 272 | } | ||
| 273 | } | 520 | } |
| 274 | 521 | ||
| 275 | fn setup(addr: u16) -> Result<(), Error> { | 522 | fn setup(addr: u16) -> Result<(), Error> { |
| @@ -290,6 +537,23 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 290 | Ok(()) | 537 | Ok(()) |
| 291 | } | 538 | } |
| 292 | 539 | ||
| 540 | #[inline] | ||
| 541 | fn tx_fifo_full() -> bool { | ||
| 542 | Self::tx_fifo_capacity() == 0 | ||
| 543 | } | ||
| 544 | |||
| 545 | #[inline] | ||
| 546 | fn tx_fifo_capacity() -> u8 { | ||
| 547 | let p = T::regs(); | ||
| 548 | unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() } | ||
| 549 | } | ||
| 550 | |||
| 551 | #[inline] | ||
| 552 | fn rx_fifo_len() -> u8 { | ||
| 553 | let p = T::regs(); | ||
| 554 | unsafe { p.ic_rxflr().read().rxflr() } | ||
| 555 | } | ||
| 556 | |||
| 293 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { | 557 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { |
| 294 | let p = T::regs(); | 558 | let p = T::regs(); |
| 295 | unsafe { | 559 | unsafe { |
| @@ -317,7 +581,6 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 317 | } | 581 | } |
| 318 | } | 582 | } |
| 319 | } | 583 | } |
| 320 | |||
| 321 | } | 584 | } |
| 322 | 585 | ||
| 323 | mod eh02 { | 586 | mod eh02 { |
| @@ -444,6 +707,91 @@ mod eh1 { | |||
| 444 | } | 707 | } |
| 445 | } | 708 | } |
| 446 | } | 709 | } |
| 710 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] | ||
| 711 | mod nightly { | ||
| 712 | use core::future::Future; | ||
| 713 | |||
| 714 | use embedded_hal_1::i2c::Operation; | ||
| 715 | use embedded_hal_async::i2c::AddressMode; | ||
| 716 | |||
| 717 | use super::*; | ||
| 718 | |||
| 719 | impl<'d, A, T> embedded_hal_async::i2c::I2c<A> for I2c<'d, T, Async> | ||
| 720 | where | ||
| 721 | A: AddressMode + Into<u16> + 'static, | ||
| 722 | T: Instance + 'd, | ||
| 723 | { | ||
| 724 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a | ||
| 725 | where Self: 'a; | ||
| 726 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a | ||
| 727 | where Self: 'a; | ||
| 728 | type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a | ||
| 729 | where Self: 'a; | ||
| 730 | type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Error>> + 'a | ||
| 731 | where Self: 'a, 'b: 'a; | ||
| 732 | |||
| 733 | fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 734 | let addr: u16 = address.into(); | ||
| 735 | |||
| 736 | async move { | ||
| 737 | Self::setup(addr)?; | ||
| 738 | self.read_async_internal(buffer, false, true).await | ||
| 739 | } | ||
| 740 | } | ||
| 741 | |||
| 742 | fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 743 | let addr: u16 = address.into(); | ||
| 744 | |||
| 745 | async move { | ||
| 746 | Self::setup(addr)?; | ||
| 747 | self.write_async_internal(write.iter().copied(), true).await | ||
| 748 | } | ||
| 749 | } | ||
| 750 | |||
| 751 | fn write_read<'a>( | ||
| 752 | &'a mut self, | ||
| 753 | address: A, | ||
| 754 | bytes: &'a [u8], | ||
| 755 | buffer: &'a mut [u8], | ||
| 756 | ) -> Self::WriteReadFuture<'a> { | ||
| 757 | let addr: u16 = address.into(); | ||
| 758 | |||
| 759 | async move { | ||
| 760 | Self::setup(addr)?; | ||
| 761 | self.write_async_internal(bytes.iter().cloned(), false).await?; | ||
| 762 | self.read_async_internal(buffer, false, true).await | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | fn transaction<'a, 'b>( | ||
| 767 | &'a mut self, | ||
| 768 | address: A, | ||
| 769 | operations: &'a mut [Operation<'b>], | ||
| 770 | ) -> Self::TransactionFuture<'a, 'b> { | ||
| 771 | let addr: u16 = address.into(); | ||
| 772 | |||
| 773 | async move { | ||
| 774 | let mut iterator = operations.iter_mut(); | ||
| 775 | |||
| 776 | while let Some(op) = iterator.next() { | ||
| 777 | let last = iterator.len() == 0; | ||
| 778 | |||
| 779 | match op { | ||
| 780 | Operation::Read(buffer) => { | ||
| 781 | Self::setup(addr)?; | ||
| 782 | self.read_async_internal(buffer, false, last).await?; | ||
| 783 | } | ||
| 784 | Operation::Write(buffer) => { | ||
| 785 | Self::setup(addr)?; | ||
| 786 | self.write_async_internal(buffer.into_iter().cloned(), last).await?; | ||
| 787 | } | ||
| 788 | } | ||
| 789 | } | ||
| 790 | Ok(()) | ||
| 791 | } | ||
| 792 | } | ||
| 793 | } | ||
| 794 | } | ||
| 447 | 795 | ||
| 448 | fn i2c_reserved_addr(addr: u16) -> bool { | 796 | fn i2c_reserved_addr(addr: u16) -> bool { |
| 449 | (addr & 0x78) == 0 || (addr & 0x78) == 0x78 | 797 | (addr & 0x78) == 0 || (addr & 0x78) == 0x78 |
| @@ -459,6 +807,7 @@ mod sealed { | |||
| 459 | type Interrupt: Interrupt; | 807 | type Interrupt: Interrupt; |
| 460 | 808 | ||
| 461 | fn regs() -> crate::pac::i2c::I2c; | 809 | fn regs() -> crate::pac::i2c::I2c; |
| 810 | fn reset() -> crate::pac::resets::regs::Peripherals; | ||
| 462 | } | 811 | } |
| 463 | 812 | ||
| 464 | pub trait Mode {} | 813 | pub trait Mode {} |
| @@ -485,7 +834,7 @@ impl_mode!(Async); | |||
| 485 | pub trait Instance: sealed::Instance {} | 834 | pub trait Instance: sealed::Instance {} |
| 486 | 835 | ||
| 487 | macro_rules! impl_instance { | 836 | macro_rules! impl_instance { |
| 488 | ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { | 837 | ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { |
| 489 | impl sealed::Instance for peripherals::$type { | 838 | impl sealed::Instance for peripherals::$type { |
| 490 | const TX_DREQ: u8 = $tx_dreq; | 839 | const TX_DREQ: u8 = $tx_dreq; |
| 491 | const RX_DREQ: u8 = $rx_dreq; | 840 | const RX_DREQ: u8 = $rx_dreq; |
| @@ -496,13 +845,20 @@ macro_rules! impl_instance { | |||
| 496 | fn regs() -> pac::i2c::I2c { | 845 | fn regs() -> pac::i2c::I2c { |
| 497 | pac::$type | 846 | pac::$type |
| 498 | } | 847 | } |
| 848 | |||
| 849 | #[inline] | ||
| 850 | fn reset() -> pac::resets::regs::Peripherals { | ||
| 851 | let mut ret = pac::resets::regs::Peripherals::default(); | ||
| 852 | ret.$reset(true); | ||
| 853 | ret | ||
| 854 | } | ||
| 499 | } | 855 | } |
| 500 | impl Instance for peripherals::$type {} | 856 | impl Instance for peripherals::$type {} |
| 501 | }; | 857 | }; |
| 502 | } | 858 | } |
| 503 | 859 | ||
| 504 | impl_instance!(I2C0, I2C0_IRQ, 32, 33); | 860 | impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); |
| 505 | impl_instance!(I2C1, I2C1_IRQ, 34, 35); | 861 | impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); |
| 506 | 862 | ||
| 507 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} | 863 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} |
| 508 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} | 864 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} |
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 3c8f923e7..e689df6bd 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -30,3 +30,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } | |||
| 30 | embedded-hal-async = { version = "0.1.0-alpha.1" } | 30 | embedded-hal-async = { version = "0.1.0-alpha.1" } |
| 31 | embedded-io = { version = "0.3.0", features = ["async", "defmt"] } | 31 | embedded-io = { version = "0.3.0", features = ["async", "defmt"] } |
| 32 | static_cell = "1.0.0" | 32 | static_cell = "1.0.0" |
| 33 | |||
| 34 | [profile.release] | ||
| 35 | debug = true | ||
