aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias <[email protected]>2022-08-19 14:15:43 +0200
committerDario Nieuwenhuis <[email protected]>2022-09-27 22:08:49 +0200
commitbcd3ab4ba1541a098a74b5abffdb30a293c97f64 (patch)
tree853f01e6f4de12183fccd05c3fda43ddfa0783b5
parent820e6462b6a48a6a59f082bccd5d7a3035937b2f (diff)
Add blocking read & write for I2C
-rw-r--r--embassy-rp/src/i2c.rs306
1 files changed, 286 insertions, 20 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 4a27ee8df..f7e6a6f6b 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -39,12 +39,15 @@ impl Default for Config {
39 } 39 }
40} 40}
41 41
42const TX_FIFO_SIZE: u8 = 16;
43const RX_FIFO_SIZE: u8 = 16;
44
42pub struct I2c<'d, T: Instance, M: Mode> { 45pub struct I2c<'d, T: Instance, M: Mode> {
43 phantom: PhantomData<(&'d mut T, M)>, 46 phantom: PhantomData<(&'d mut T, M)>,
44} 47}
45 48
46impl<'d, T: Instance> I2c<'d, T, Master> { 49impl<'d, T: Instance> I2c<'d, T, Blocking> {
47 pub fn new_master( 50 pub fn new_blocking(
48 _peri: impl Peripheral<P = T> + 'd, 51 _peri: impl Peripheral<P = T> + 'd,
49 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 52 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
50 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 53 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
@@ -60,9 +63,10 @@ impl<'d, T: Instance> I2c<'d, T, Master> {
60 unsafe { 63 unsafe {
61 p.ic_enable().write(|w| w.set_enable(false)); 64 p.ic_enable().write(|w| w.set_enable(false));
62 65
63 // select controller mode & speed 66 // Select controller mode & speed
64 p.ic_con().write(|w| { 67 p.ic_con().write(|w| {
65 // Always use "fast" mode (<= 400 kHz, works fine for standard mode too) 68 // Always use "fast" mode (<= 400 kHz, works fine for standard
69 // mode too)
66 w.set_speed(i2c::vals::Speed::FAST); 70 w.set_speed(i2c::vals::Speed::FAST);
67 w.set_master_mode(true); 71 w.set_master_mode(true);
68 w.set_ic_slave_disable(true); 72 w.set_ic_slave_disable(true);
@@ -70,7 +74,8 @@ impl<'d, T: Instance> I2c<'d, T, Master> {
70 w.set_tx_empty_ctrl(true); 74 w.set_tx_empty_ctrl(true);
71 }); 75 });
72 76
73 // Clear FIFO threshold 77 // Set FIFO watermarks to 1 to make things simpler. This is encoded
78 // by a register value of 0.
74 p.ic_tx_tl().write(|w| w.set_tx_tl(0)); 79 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
75 p.ic_rx_tl().write(|w| w.set_rx_tl(0)); 80 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
76 81
@@ -89,8 +94,9 @@ impl<'d, T: Instance> I2c<'d, T, Master> {
89 94
90 // Configure baudrate 95 // Configure baudrate
91 96
92 // There are some subtleties to I2C timing which we are completely ignoring here 97 // There are some subtleties to I2C timing which we are completely
93 // See: https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 98 // ignoring here See:
99 // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69
94 let clk_base = crate::clocks::clk_sys_freq(); 100 let clk_base = crate::clocks::clk_sys_freq();
95 101
96 let period = (clk_base + config.frequency / 2) / config.frequency; 102 let period = (clk_base + config.frequency / 2) / config.frequency;
@@ -104,21 +110,21 @@ impl<'d, T: Instance> I2c<'d, T, Master> {
104 assert!(lcnt >= 8); 110 assert!(lcnt >= 8);
105 111
106 // Per I2C-bus specification a device in standard or fast mode must 112 // Per I2C-bus specification a device in standard or fast mode must
107 // internally provide a hold time of at least 300ns for the SDA signal to 113 // internally provide a hold time of at least 300ns for the SDA
108 // bridge the undefined region of the falling edge of SCL. A smaller hold 114 // signal to bridge the undefined region of the falling edge of SCL.
109 // time of 120ns is used for fast mode plus. 115 // A smaller hold time of 120ns is used for fast mode plus.
110 let sda_tx_hold_count = if config.frequency < 1_000_000 { 116 let sda_tx_hold_count = if config.frequency < 1_000_000 {
111 // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / 1e9ns) 117 // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
112 // Reduce 300/1e9 to 3/1e7 to avoid numbers that don't fit in uint. 118 // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
113 // Add 1 to avoid division truncation. 119 // fit in uint. Add 1 to avoid division truncation.
114 ((clk_base * 3) / 10_000_000) + 1 120 ((clk_base * 3) / 10_000_000) + 1
115 } else { 121 } else {
116 // fast mode plus requires a clk_base > 32MHz 122 // fast mode plus requires a clk_base > 32MHz
117 assert!(clk_base >= 32_000_000); 123 assert!(clk_base >= 32_000_000);
118 124
119 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / 1e9ns) 125 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
120 // Reduce 120/1e9 to 3/25e6 to avoid numbers that don't fit in uint. 126 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
121 // Add 1 to avoid division truncation. 127 // fit in uint. Add 1 to avoid division truncation.
122 ((clk_base * 3) / 25_000_000) + 1 128 ((clk_base * 3) / 25_000_000) + 1
123 }; 129 };
124 assert!(sda_tx_hold_count <= lcnt - 2); 130 assert!(sda_tx_hold_count <= lcnt - 2);
@@ -138,6 +144,266 @@ impl<'d, T: Instance> I2c<'d, T, Master> {
138 } 144 }
139} 145}
140 146
147impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
148 /// Number of bytes currently in the RX FIFO
149 #[inline]
150 pub fn rx_fifo_used(&self) -> u8 {
151 unsafe { T::regs().ic_rxflr().read().rxflr() }
152 }
153
154 /// Remaining capacity in the RX FIFO
155 #[inline]
156 pub fn rx_fifo_free(&self) -> u8 {
157 RX_FIFO_SIZE - self.rx_fifo_used()
158 }
159
160 /// RX FIFO is empty
161 #[inline]
162 pub fn rx_fifo_empty(&self) -> bool {
163 self.rx_fifo_used() == 0
164 }
165
166 /// Number of bytes currently in the TX FIFO
167 #[inline]
168 pub fn tx_fifo_used(&self) -> u8 {
169 unsafe { T::regs().ic_txflr().read().txflr() }
170 }
171
172 /// Remaining capacity in the TX FIFO
173 #[inline]
174 pub fn tx_fifo_free(&self) -> u8 {
175 TX_FIFO_SIZE - self.tx_fifo_used()
176 }
177
178 /// TX FIFO is at capacity
179 #[inline]
180 pub fn tx_fifo_full(&self) -> bool {
181 self.tx_fifo_free() == 0
182 }
183
184 fn setup(addr: u16) -> Result<(), Error> {
185 if addr >= 0x80 {
186 return Err(Error::AddressOutOfRange(addr));
187 }
188
189 if i2c_reserved_addr(addr) {
190 return Err(Error::AddressReserved(addr));
191 }
192
193 let p = T::regs();
194 unsafe {
195 p.ic_enable().write(|w| w.set_enable(false));
196 p.ic_tar().write(|w| w.set_ic_tar(addr));
197 p.ic_enable().write(|w| w.set_enable(true));
198 }
199 Ok(())
200 }
201
202 fn read_and_clear_abort_reason(&mut self) -> Option<u32> {
203 let p = T::regs();
204 unsafe {
205 let abort_reason = p.ic_tx_abrt_source().read().0;
206 if abort_reason != 0 {
207 // Note clearing the abort flag also clears the reason, and this
208 // instance of flag is clear-on-read! Note also the
209 // IC_CLR_TX_ABRT register always reads as 0.
210 p.ic_clr_tx_abrt().read();
211 Some(abort_reason)
212 } else {
213 None
214 }
215 }
216 }
217
218 fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
219 if buffer.is_empty() {
220 return Err(Error::InvalidReadBufferLength);
221 }
222
223 let p = T::regs();
224 let lastindex = buffer.len() - 1;
225 for (i, byte) in buffer.iter_mut().enumerate() {
226 let first = i == 0;
227 let last = i == lastindex;
228
229 // NOTE(unsafe) We have &mut self
230 unsafe {
231 // wait until there is space in the FIFO to write the next byte
232 while self.tx_fifo_full() {}
233
234 p.ic_data_cmd().write(|w| {
235 if restart && first {
236 w.set_restart(true);
237 } else {
238 w.set_restart(false);
239 }
240
241 if send_stop && last {
242 w.set_stop(true);
243 } else {
244 w.set_stop(false);
245 }
246
247 w.cmd()
248 });
249
250 while p.ic_rxflr().read().rxflr() == 0 {
251 if let Some(abort_reason) = self.read_and_clear_abort_reason() {
252 return Err(Error::Abort(abort_reason));
253 }
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 if send_stop && last {
277 w.set_stop(true);
278 } else {
279 w.set_stop(false);
280 }
281 w.set_dat(*byte);
282 });
283
284 // Wait until the transmission of the address/data from the
285 // internal shift register has completed. For this to function
286 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
287 // TX_EMPTY_CTRL flag was set in i2c_init.
288 while !p.ic_raw_intr_stat().read().tx_empty() {}
289
290 let abort_reason = self.read_and_clear_abort_reason();
291
292 if abort_reason.is_some() || (send_stop && last) {
293 // If the transaction was aborted or if it completed
294 // successfully wait until the STOP condition has occured.
295
296 while !p.ic_raw_intr_stat().read().stop_det() {}
297
298 p.ic_clr_stop_det().read().clr_stop_det();
299 }
300
301 // Note the hardware issues a STOP automatically on an abort
302 // condition. Note also the hardware clears RX FIFO as well as
303 // TX on abort, ecause we set hwparam
304 // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
305 if let Some(abort_reason) = abort_reason {
306 return Err(Error::Abort(abort_reason));
307 }
308 }
309 }
310 Ok(())
311 }
312
313 // ========================= Blocking public API
314 // =========================
315
316 pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
317 Self::setup(address.into())?;
318 self.read_blocking_internal(buffer, false, true)
319 // Automatic Stop
320 }
321
322 pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
323 Self::setup(address.into())?;
324 self.write_blocking_internal(bytes, true)
325 }
326
327 pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
328 Self::setup(address.into())?;
329 self.write_blocking_internal(bytes, false)?;
330 self.read_blocking_internal(buffer, true, true)
331 // Automatic Stop
332 }
333}
334
335// impl<'d, T: Instance> I2c<'d, T, Async> { // ========================= //
336// Async public API // =========================
337
338// pub async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(),
339// Error> { if bytes.is_empty() { self.write_blocking_internal(address,
340// bytes, true) } else { self.write_dma_internal(address, bytes,
341// true, true).await } }
342
343// pub async fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) ->
344// Result<(), Error> { if bytes.is_empty() { return
345// Err(Error::ZeroLengthTransfer); } let mut iter = bytes.iter();
346
347// let mut first = true; let mut current = iter.next(); while let
348// Some(c) = current { let next = iter.next(); let is_last =
349// next.is_none();
350
351// self.write_dma_internal(address, c, first, is_last).await?;
352// first = false;
353// current = next;
354// } Ok(())
355// }
356
357// pub async fn read(&mut self, address: u8, buffer: &mut [u8]) ->
358// Result<(), Error> { if buffer.is_empty() {
359// self.read_blocking_internal(address, buffer, false) } else {
360// self.read_dma_internal(address, buffer, false).await } }
361
362// pub async fn write_read(&mut self, address: u8, bytes: &[u8], buffer:
363// &mut [u8]) -> Result<(), Error> { if bytes.is_empty() {
364// self.write_blocking_internal(address, bytes, false)?; } else {
365// self.write_dma_internal(address, bytes, true, true).await?; }
366
367// if buffer.is_empty() { self.read_blocking_internal(address, buffer,
368// true)?; } else { self.read_dma_internal(address, buffer,
369// true).await?; }
370
371// Ok(())
372// }
373// }
374
375mod eh02 {
376 use super::*;
377
378 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> {
379 type Error = Error;
380
381 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
382 self.blocking_read(address, buffer)
383 }
384 }
385
386 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> {
387 type Error = Error;
388
389 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
390 self.blocking_write(address, bytes)
391 }
392 }
393
394 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> {
395 type Error = Error;
396
397 fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
398 self.blocking_write_read(address, bytes, buffer)
399 }
400 }
401}
402
403fn i2c_reserved_addr(addr: u16) -> bool {
404 (addr & 0x78) == 0 || (addr & 0x78) == 0x78
405}
406
141mod sealed { 407mod sealed {
142 pub trait Instance {} 408 pub trait Instance {}
143 pub trait Mode {} 409 pub trait Mode {}
@@ -155,11 +421,11 @@ macro_rules! impl_mode {
155 }; 421 };
156} 422}
157 423
158pub struct Master; 424pub struct Blocking;
159pub struct Slave; 425pub struct Async;
160 426
161impl_mode!(Master); 427impl_mode!(Blocking);
162impl_mode!(Slave); 428impl_mode!(Async);
163 429
164pub trait Instance: sealed::Instance { 430pub trait Instance: sealed::Instance {
165 fn regs() -> pac::i2c::I2c; 431 fn regs() -> pac::i2c::I2c;