diff options
| author | Jeremy Fitzhardinge <[email protected]> | 2022-09-27 23:44:14 -0700 |
|---|---|---|
| committer | Jeremy Fitzhardinge <[email protected]> | 2022-10-01 13:26:13 -0700 |
| commit | 72b645b0c96c7b8312d0a64f851e807faacd78af (patch) | |
| tree | 4b8fa606ca28270c6a16ae43ddf2ea5204da8fe6 | |
| parent | 8d38eacae426ef1b1e1f7255eed50a9588793fb4 (diff) | |
rp i2c: make blocking only for Mode=Blocking
| -rw-r--r-- | embassy-rp/src/i2c.rs | 212 |
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 | ||
| 57 | impl<'d, T: Instance> I2c<'d, T, Blocking> { | 57 | impl<'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 | ||
| 69 | impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | 170 | impl<'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 | ||
| 321 | mod eh02 { | 323 | mod 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 | } |
