aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <[email protected]>2022-09-27 23:44:14 -0700
committerJeremy Fitzhardinge <[email protected]>2022-10-01 13:26:13 -0700
commit72b645b0c96c7b8312d0a64f851e807faacd78af (patch)
tree4b8fa606ca28270c6a16ae43ddf2ea5204da8fe6
parent8d38eacae426ef1b1e1f7255eed50a9588793fb4 (diff)
rp i2c: make blocking only for Mode=Blocking
-rw-r--r--embassy-rp/src/i2c.rs212
1 files changed, 107 insertions, 105 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index a6f278827..c609b02ea 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -56,15 +56,116 @@ pub struct I2c<'d, T: Instance, M: Mode> {
56 56
57impl<'d, T: Instance> I2c<'d, T, Blocking> { 57impl<'d, T: Instance> I2c<'d, T, Blocking> {
58 pub fn new_blocking( 58 pub fn new_blocking(
59 _peri: impl Peripheral<P = T> + 'd, 59 peri: impl Peripheral<P = T> + 'd,
60 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 60 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
61 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 61 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
62 config: Config, 62 config: Config,
63 ) -> Self { 63 ) -> Self {
64 into_ref!(scl, sda); 64 into_ref!(scl, sda);
65 Self::new_inner(_peri, scl.map_into(), sda.map_into(), config) 65 Self::new_inner(peri, scl.map_into(), sda.map_into(), config)
66 }
67
68 fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
69 if buffer.is_empty() {
70 return Err(Error::InvalidReadBufferLength);
71 }
72
73 let p = T::regs();
74 let lastindex = buffer.len() - 1;
75 for (i, byte) in buffer.iter_mut().enumerate() {
76 let first = i == 0;
77 let last = i == lastindex;
78
79 // NOTE(unsafe) We have &mut self
80 unsafe {
81 // wait until there is space in the FIFO to write the next byte
82 while p.ic_txflr().read().txflr() == FIFO_SIZE {}
83
84 p.ic_data_cmd().write(|w| {
85 w.set_restart(restart && first);
86 w.set_stop(send_stop && last);
87
88 w.set_cmd(true);
89 });
90
91 while p.ic_rxflr().read().rxflr() == 0 {
92 self.read_and_clear_abort_reason()?;
93 }
94
95 *byte = p.ic_data_cmd().read().dat();
96 }
97 }
98
99 Ok(())
100 }
101
102 fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> {
103 if bytes.is_empty() {
104 return Err(Error::InvalidWriteBufferLength);
105 }
106
107 let p = T::regs();
108
109 for (i, byte) in bytes.iter().enumerate() {
110 let last = i == bytes.len() - 1;
111
112 // NOTE(unsafe) We have &mut self
113 unsafe {
114 p.ic_data_cmd().write(|w| {
115 w.set_stop(send_stop && last);
116 w.set_dat(*byte);
117 });
118
119 // Wait until the transmission of the address/data from the
120 // internal shift register has completed. For this to function
121 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
122 // TX_EMPTY_CTRL flag was set in i2c_init.
123 while !p.ic_raw_intr_stat().read().tx_empty() {}
124
125 let abort_reason = self.read_and_clear_abort_reason();
126
127 if abort_reason.is_err() || (send_stop && last) {
128 // If the transaction was aborted or if it completed
129 // successfully wait until the STOP condition has occured.
130
131 while !p.ic_raw_intr_stat().read().stop_det() {}
132
133 p.ic_clr_stop_det().read().clr_stop_det();
134 }
135
136 // Note the hardware issues a STOP automatically on an abort
137 // condition. Note also the hardware clears RX FIFO as well as
138 // TX on abort, ecause we set hwparam
139 // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
140 abort_reason?;
141 }
142 }
143 Ok(())
144 }
145
146 // =========================
147 // Blocking public API
148 // =========================
149
150 pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
151 Self::setup(address.into())?;
152 self.read_blocking_internal(buffer, true, true)
153 // Automatic Stop
154 }
155
156 pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
157 Self::setup(address.into())?;
158 self.write_blocking_internal(bytes, true)
159 }
160
161 pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
162 Self::setup(address.into())?;
163 self.write_blocking_internal(bytes, false)?;
164 self.read_blocking_internal(buffer, true, true)
165 // Automatic Stop
66 } 166 }
67} 167}
168}
68 169
69impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { 170impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
70 fn new_inner( 171 fn new_inner(
@@ -217,111 +318,12 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
217 } 318 }
218 } 319 }
219 320
220 fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
221 if buffer.is_empty() {
222 return Err(Error::InvalidReadBufferLength);
223 }
224
225 let p = T::regs();
226 let lastindex = buffer.len() - 1;
227 for (i, byte) in buffer.iter_mut().enumerate() {
228 let first = i == 0;
229 let last = i == lastindex;
230
231 // NOTE(unsafe) We have &mut self
232 unsafe {
233 // wait until there is space in the FIFO to write the next byte
234 while p.ic_txflr().read().txflr() == FIFO_SIZE {}
235
236 p.ic_data_cmd().write(|w| {
237 w.set_restart(restart && first);
238 w.set_stop(send_stop && last);
239
240 w.set_cmd(true);
241 });
242
243 while p.ic_rxflr().read().rxflr() == 0 {
244 self.read_and_clear_abort_reason()?;
245 }
246
247 *byte = p.ic_data_cmd().read().dat();
248 }
249 }
250
251 Ok(())
252 }
253
254 fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> {
255 if bytes.is_empty() {
256 return Err(Error::InvalidWriteBufferLength);
257 }
258
259 let p = T::regs();
260
261 for (i, byte) in bytes.iter().enumerate() {
262 let last = i == bytes.len() - 1;
263
264 // NOTE(unsafe) We have &mut self
265 unsafe {
266 p.ic_data_cmd().write(|w| {
267 w.set_stop(send_stop && last);
268 w.set_dat(*byte);
269 });
270
271 // Wait until the transmission of the address/data from the
272 // internal shift register has completed. For this to function
273 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
274 // TX_EMPTY_CTRL flag was set in i2c_init.
275 while !p.ic_raw_intr_stat().read().tx_empty() {}
276
277 let abort_reason = self.read_and_clear_abort_reason();
278
279 if abort_reason.is_err() || (send_stop && last) {
280 // If the transaction was aborted or if it completed
281 // successfully wait until the STOP condition has occured.
282
283 while !p.ic_raw_intr_stat().read().stop_det() {}
284
285 p.ic_clr_stop_det().read().clr_stop_det();
286 }
287
288 // Note the hardware issues a STOP automatically on an abort
289 // condition. Note also the hardware clears RX FIFO as well as
290 // TX on abort, ecause we set hwparam
291 // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
292 abort_reason?;
293 }
294 }
295 Ok(())
296 }
297
298 // =========================
299 // Blocking public API
300 // =========================
301
302 pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
303 Self::setup(address.into())?;
304 self.read_blocking_internal(buffer, true, true)
305 // Automatic Stop
306 }
307
308 pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
309 Self::setup(address.into())?;
310 self.write_blocking_internal(bytes, true)
311 }
312
313 pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
314 Self::setup(address.into())?;
315 self.write_blocking_internal(bytes, false)?;
316 self.read_blocking_internal(buffer, true, true)
317 // Automatic Stop
318 }
319} 321}
320 322
321mod eh02 { 323mod eh02 {
322 use super::*; 324 use super::*;
323 325
324 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { 326 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, Blocking> {
325 type Error = Error; 327 type Error = Error;
326 328
327 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 329 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
@@ -329,7 +331,7 @@ mod eh02 {
329 } 331 }
330 } 332 }
331 333
332 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> { 334 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, Blocking> {
333 type Error = Error; 335 type Error = Error;
334 336
335 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { 337 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
@@ -337,7 +339,7 @@ mod eh02 {
337 } 339 }
338 } 340 }
339 341
340 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> { 342 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, Blocking> {
341 type Error = Error; 343 type Error = Error;
342 344
343 fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { 345 fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
@@ -370,7 +372,7 @@ mod eh1 {
370 type Error = Error; 372 type Error = Error;
371 } 373 }
372 374
373 impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> { 375 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, Blocking> {
374 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 376 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
375 self.blocking_read(address, buffer) 377 self.blocking_read(address, buffer)
376 } 378 }