aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias <[email protected]>2022-09-27 07:55:28 +0200
committerDario Nieuwenhuis <[email protected]>2022-09-27 22:08:49 +0200
commit44c46e3c93ae0718110a8805cab4c6c8a9b5df55 (patch)
treec31ee1fecfd3dc8d1aa6dbdbbddf959543610e1c
parentb0d91e9f310f86b4eb9d75c92471831f1656ed1b (diff)
Move async i2c implementation to new PR, to merge working blocking implementation faster
-rw-r--r--embassy-rp/src/i2c.rs179
1 files changed, 1 insertions, 178 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 12fae3b7b..d1ec77d33 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -1,11 +1,9 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use atomic_polyfill::Ordering;
4use embassy_cortex_m::interrupt::InterruptExt;
5use embassy_hal_common::{into_ref, PeripheralRef}; 3use embassy_hal_common::{into_ref, PeripheralRef};
6use pac::i2c; 4use pac::i2c;
7 5
8use crate::dma::{AnyChannel, Channel}; 6use crate::dma::AnyChannel;
9use crate::gpio::sealed::Pin; 7use crate::gpio::sealed::Pin;
10use crate::gpio::AnyPin; 8use crate::gpio::AnyPin;
11use crate::{pac, peripherals, Peripheral}; 9use crate::{pac, peripherals, Peripheral};
@@ -60,159 +58,6 @@ pub struct I2c<'d, T: Instance, M: Mode> {
60 phantom: PhantomData<(&'d mut T, M)>, 58 phantom: PhantomData<(&'d mut T, M)>,
61} 59}
62 60
63impl<'d, T: Instance> I2c<'d, T, Async> {
64 pub fn new(
65 _peri: impl Peripheral<P = T> + 'd,
66 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
67 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
68 irq: impl Peripheral<P = T::Interrupt> + 'd,
69 tx_dma: impl Peripheral<P = impl Channel> + 'd,
70 rx_dma: impl Peripheral<P = impl Channel> + 'd,
71 config: Config,
72 ) -> Self {
73 into_ref!(scl, sda, irq, tx_dma, rx_dma);
74
75 // Enable interrupts
76 unsafe {
77 T::regs().ic_intr_mask().modify(|w| {
78 w.set_m_rx_done(true);
79 });
80 }
81
82 irq.set_handler(Self::on_interrupt);
83 irq.unpend();
84 irq.enable();
85
86 Self::new_inner(
87 _peri,
88 scl.map_into(),
89 sda.map_into(),
90 Some(tx_dma.map_into()),
91 Some(rx_dma.map_into()),
92 config,
93 )
94 }
95
96 unsafe fn on_interrupt(_: *mut ()) {
97 let status = T::regs().ic_intr_stat().read();
98
99 // FIXME:
100 if status.tcr() || status.tc() {
101 let state = T::state();
102 state.chunks_transferred.fetch_add(1, Ordering::Relaxed);
103 state.waker.wake();
104 }
105 // The flag can only be cleared by writting to nbytes, we won't do that here, so disable
106 // the interrupt
107 // critical_section::with(|_| {
108 // regs.cr1().modify(|w| w.set_tcie(false));
109 // });
110 }
111
112 async fn write_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> {
113 let len = bytes.len();
114 for (idx, chunk) in bytes.chunks(self.dma_buf.len()).enumerate() {
115 let first = idx == 0;
116 let last = idx * self.dma_buf.len() + chunk.len() == len;
117
118 for (i, byte) in chunk.iter().enumerate() {
119 let mut b = i2c::regs::IcDataCmd::default();
120 b.set_dat(*byte);
121 b.set_stop(send_stop && last);
122
123 self.dma_buf[i] = b.0 as u16;
124 }
125
126 // Note(safety): Unwrap should be safe, as this can only be called
127 // when `Mode == Async`, where we have dma channels.
128 let ch = self.tx_dma.as_mut().unwrap();
129 let transfer = unsafe {
130 T::regs().ic_dma_cr().modify(|w| {
131 w.set_tdmae(true);
132 });
133
134 crate::dma::write(ch, &self.dma_buf, T::regs().ic_data_cmd().ptr() as *mut _, T::TX_DREQ)
135 };
136
137 transfer.await;
138 }
139
140 Ok(())
141 }
142
143 async fn read_internal(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
144 let len = buffer.len();
145 self.read_blocking_internal(&mut buffer[..1], true, len == 1)?;
146
147 if len >= 2 {
148 // Note(safety): Unwrap should be safe, as this can only be called
149 // when `Mode == Async`, where we have dma channels.
150 let ch = self.rx_dma.as_mut().unwrap();
151 let transfer = unsafe {
152 T::regs().ic_data_cmd().modify(|w| {
153 w.set_cmd(true);
154 });
155
156 T::regs().ic_dma_cr().modify(|reg| {
157 reg.set_rdmae(true);
158 });
159 // If we don't assign future to a variable, the data register pointer
160 // is held across an await and makes the future non-Send.
161 crate::dma::read(
162 ch,
163 T::regs().ic_data_cmd().ptr() as *const _,
164 &mut buffer[1..len - 1],
165 T::RX_DREQ,
166 )
167 };
168 transfer.await;
169 }
170
171 if len >= 2 {
172 self.read_blocking_internal(&mut buffer[len - 1..], false, true)?;
173 }
174
175 Ok(())
176 }
177
178 // =========================
179 // Async public API
180 // =========================
181
182 pub async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
183 Self::setup(address.into())?;
184 if bytes.is_empty() {
185 self.write_blocking_internal(bytes, true)
186 } else {
187 self.write_internal(bytes, true).await
188 }
189 }
190
191 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
192 Self::setup(address.into())?;
193 if buffer.is_empty() {
194 self.read_blocking_internal(buffer, true, true)
195 } else {
196 self.read_internal(buffer).await
197 }
198 }
199
200 pub async fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
201 Self::setup(address.into())?;
202 if bytes.is_empty() {
203 self.write_blocking_internal(bytes, false)?;
204 } else {
205 self.write_internal(bytes, true).await?;
206 }
207
208 if buffer.is_empty() {
209 self.read_blocking_internal(buffer, true, true)
210 } else {
211 self.read_internal(buffer).await
212 }
213 }
214}
215
216impl<'d, T: Instance> I2c<'d, T, Blocking> { 61impl<'d, T: Instance> I2c<'d, T, Blocking> {
217 pub fn new_blocking( 62 pub fn new_blocking(
218 _peri: impl Peripheral<P = T> + 'd, 63 _peri: impl Peripheral<P = T> + 'd,
@@ -616,23 +461,7 @@ fn i2c_reserved_addr(addr: u16) -> bool {
616} 461}
617 462
618mod sealed { 463mod sealed {
619 use atomic_polyfill::AtomicUsize;
620 use embassy_cortex_m::interrupt::Interrupt; 464 use embassy_cortex_m::interrupt::Interrupt;
621 use embassy_sync::waitqueue::AtomicWaker;
622
623 pub(crate) struct State {
624 pub(crate) waker: AtomicWaker,
625 pub(crate) chunks_transferred: AtomicUsize,
626 }
627
628 impl State {
629 pub(crate) const fn new() -> Self {
630 Self {
631 waker: AtomicWaker::new(),
632 chunks_transferred: AtomicUsize::new(0),
633 }
634 }
635 }
636 465
637 pub trait Instance { 466 pub trait Instance {
638 const TX_DREQ: u8; 467 const TX_DREQ: u8;
@@ -641,7 +470,6 @@ mod sealed {
641 type Interrupt: Interrupt; 470 type Interrupt: Interrupt;
642 471
643 fn regs() -> crate::pac::i2c::I2c; 472 fn regs() -> crate::pac::i2c::I2c;
644 fn state() -> &'static State;
645 } 473 }
646 474
647 pub trait Mode {} 475 pub trait Mode {}
@@ -678,11 +506,6 @@ macro_rules! impl_instance {
678 fn regs() -> pac::i2c::I2c { 506 fn regs() -> pac::i2c::I2c {
679 pac::$type 507 pac::$type
680 } 508 }
681
682 fn state() -> &'static sealed::State {
683 static STATE: sealed::State = sealed::State::new();
684 &STATE
685 }
686 } 509 }
687 impl Instance for peripherals::$type {} 510 impl Instance for peripherals::$type {}
688 }; 511 };