diff options
| -rw-r--r-- | embassy-rp/src/i2c_slave.rs | 117 |
1 files changed, 66 insertions, 51 deletions
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 979686627..caebb0257 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs | |||
| @@ -83,6 +83,7 @@ impl Default for Config { | |||
| 83 | pub struct I2cSlave<'d, T: Instance> { | 83 | pub struct I2cSlave<'d, T: Instance> { |
| 84 | phantom: PhantomData<&'d mut T>, | 84 | phantom: PhantomData<&'d mut T>, |
| 85 | pending_byte: Option<u8>, | 85 | pending_byte: Option<u8>, |
| 86 | config: Config, | ||
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | impl<'d, T: Instance> I2cSlave<'d, T> { | 89 | impl<'d, T: Instance> I2cSlave<'d, T> { |
| @@ -99,6 +100,25 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 99 | assert!(!i2c_reserved_addr(config.addr)); | 100 | assert!(!i2c_reserved_addr(config.addr)); |
| 100 | assert!(config.addr != 0); | 101 | assert!(config.addr != 0); |
| 101 | 102 | ||
| 103 | // Configure SCL & SDA pins | ||
| 104 | set_up_i2c_pin(&scl); | ||
| 105 | set_up_i2c_pin(&sda); | ||
| 106 | |||
| 107 | let mut ret = Self { | ||
| 108 | phantom: PhantomData, | ||
| 109 | pending_byte: None, | ||
| 110 | config, | ||
| 111 | }; | ||
| 112 | |||
| 113 | ret.reset(); | ||
| 114 | |||
| 115 | ret | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus. | ||
| 119 | /// You can recover the bus by calling this function, but doing so will almost certainly cause | ||
| 120 | /// an i/o error in the master. | ||
| 121 | pub fn reset(&mut self) { | ||
| 102 | let p = T::regs(); | 122 | let p = T::regs(); |
| 103 | 123 | ||
| 104 | let reset = T::reset(); | 124 | let reset = T::reset(); |
| @@ -107,7 +127,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 107 | 127 | ||
| 108 | p.ic_enable().write(|w| w.set_enable(false)); | 128 | p.ic_enable().write(|w| w.set_enable(false)); |
| 109 | 129 | ||
| 110 | p.ic_sar().write(|w| w.set_ic_sar(config.addr)); | 130 | p.ic_sar().write(|w| w.set_ic_sar(self.config.addr)); |
| 111 | p.ic_con().modify(|w| { | 131 | p.ic_con().modify(|w| { |
| 112 | w.set_master_mode(false); | 132 | w.set_master_mode(false); |
| 113 | w.set_ic_slave_disable(false); | 133 | w.set_ic_slave_disable(false); |
| @@ -121,10 +141,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 121 | // Generate stop interrupts for general calls | 141 | // Generate stop interrupts for general calls |
| 122 | // This also causes stop interrupts for other devices on the bus but those will not be | 142 | // This also causes stop interrupts for other devices on the bus but those will not be |
| 123 | // propagated up to the application. | 143 | // propagated up to the application. |
| 124 | w.set_stop_det_ifaddressed(!config.general_call); | 144 | w.set_stop_det_ifaddressed(!self.config.general_call); |
| 125 | }); | 145 | }); |
| 126 | p.ic_ack_general_call() | 146 | p.ic_ack_general_call() |
| 127 | .write(|w| w.set_ack_gen_call(config.general_call)); | 147 | .write(|w| w.set_ack_gen_call(self.config.general_call)); |
| 128 | 148 | ||
| 129 | // Set FIFO watermarks to 1 to make things simpler. This is encoded | 149 | // Set FIFO watermarks to 1 to make things simpler. This is encoded |
| 130 | // by a register value of 0. Rx watermark should never change, but Tx watermark will be | 150 | // by a register value of 0. Rx watermark should never change, but Tx watermark will be |
| @@ -132,10 +152,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 132 | p.ic_tx_tl().write(|w| w.set_tx_tl(0)); | 152 | p.ic_tx_tl().write(|w| w.set_tx_tl(0)); |
| 133 | p.ic_rx_tl().write(|w| w.set_rx_tl(0)); | 153 | p.ic_rx_tl().write(|w| w.set_rx_tl(0)); |
| 134 | 154 | ||
| 135 | // Configure SCL & SDA pins | ||
| 136 | set_up_i2c_pin(&scl); | ||
| 137 | set_up_i2c_pin(&sda); | ||
| 138 | |||
| 139 | // Clear interrupts | 155 | // Clear interrupts |
| 140 | p.ic_clr_intr().read(); | 156 | p.ic_clr_intr().read(); |
| 141 | 157 | ||
| @@ -146,11 +162,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 146 | p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); | 162 | p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); |
| 147 | T::Interrupt::unpend(); | 163 | T::Interrupt::unpend(); |
| 148 | unsafe { T::Interrupt::enable() }; | 164 | unsafe { T::Interrupt::enable() }; |
| 149 | |||
| 150 | Self { | ||
| 151 | phantom: PhantomData, | ||
| 152 | pending_byte: None, | ||
| 153 | } | ||
| 154 | } | 165 | } |
| 155 | 166 | ||
| 156 | /// Calls `f` to check if we are ready or not. | 167 | /// Calls `f` to check if we are ready or not. |
| @@ -178,15 +189,13 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 178 | fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) { | 189 | fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) { |
| 179 | let p = T::regs(); | 190 | let p = T::regs(); |
| 180 | 191 | ||
| 181 | for b in &mut buffer[*offset..] { | 192 | if let Some(pending) = self.pending_byte.take() { |
| 182 | if let Some(pending) = self.pending_byte.take() { | 193 | buffer[*offset] = pending; |
| 183 | *b = pending; | 194 | *offset += 1; |
| 184 | *offset += 1; | 195 | } |
| 185 | continue; | ||
| 186 | } | ||
| 187 | 196 | ||
| 188 | let status = p.ic_status().read(); | 197 | for b in &mut buffer[*offset..] { |
| 189 | if !status.rfne() { | 198 | if !p.ic_status().read().rfne() { |
| 190 | break; | 199 | break; |
| 191 | } | 200 | } |
| 192 | 201 | ||
| @@ -207,14 +216,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 207 | } | 216 | } |
| 208 | } | 217 | } |
| 209 | 218 | ||
| 210 | #[inline(always)] | ||
| 211 | fn write_to_fifo(&mut self, buffer: &[u8]) { | ||
| 212 | let p = T::regs(); | ||
| 213 | for byte in buffer { | ||
| 214 | p.ic_data_cmd().write(|w| w.set_dat(*byte)); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | /// Wait asynchronously for commands from an I2C master. | 219 | /// Wait asynchronously for commands from an I2C master. |
| 219 | /// `buffer` is provided in case master does a 'write', 'write read', or 'general call' and is unused for 'read'. | 220 | /// `buffer` is provided in case master does a 'write', 'write read', or 'general call' and is unused for 'read'. |
| 220 | pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> { | 221 | pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> { |
| @@ -227,8 +228,9 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 227 | self.wait_on( | 228 | self.wait_on( |
| 228 | |me| { | 229 | |me| { |
| 229 | let stat = p.ic_raw_intr_stat().read(); | 230 | let stat = p.ic_raw_intr_stat().read(); |
| 231 | trace!("ls:{:013b} len:{}", stat.0, len); | ||
| 230 | 232 | ||
| 231 | if p.ic_rxflr().read().rxflr() > 0 { | 233 | if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() { |
| 232 | me.drain_fifo(buffer, &mut len); | 234 | me.drain_fifo(buffer, &mut len); |
| 233 | // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise | 235 | // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise |
| 234 | p.ic_rx_tl().write(|w| w.set_rx_tl(11)); | 236 | p.ic_rx_tl().write(|w| w.set_rx_tl(11)); |
| @@ -241,6 +243,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 241 | return Poll::Ready(Err(Error::PartialWrite(buffer.len()))); | 243 | return Poll::Ready(Err(Error::PartialWrite(buffer.len()))); |
| 242 | } | 244 | } |
| 243 | } | 245 | } |
| 246 | trace!("len:{}, pend:{}", len, me.pending_byte); | ||
| 247 | if me.pending_byte.is_some() { | ||
| 248 | warn!("pending") | ||
| 249 | } | ||
| 244 | 250 | ||
| 245 | if stat.restart_det() && stat.rd_req() { | 251 | if stat.restart_det() && stat.rd_req() { |
| 246 | p.ic_clr_restart_det().read(); | 252 | p.ic_clr_restart_det().read(); |
| @@ -257,12 +263,17 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 257 | p.ic_clr_restart_det().read(); | 263 | p.ic_clr_restart_det().read(); |
| 258 | p.ic_clr_gen_call().read(); | 264 | p.ic_clr_gen_call().read(); |
| 259 | Poll::Ready(Ok(Command::Read)) | 265 | Poll::Ready(Ok(Command::Read)) |
| 266 | } else if stat.stop_det() { | ||
| 267 | // clear stuck stop bit | ||
| 268 | // This can happen if the SDA/SCL pullups are enabled after calling this func | ||
| 269 | p.ic_clr_stop_det().read(); | ||
| 270 | Poll::Pending | ||
| 260 | } else { | 271 | } else { |
| 261 | Poll::Pending | 272 | Poll::Pending |
| 262 | } | 273 | } |
| 263 | }, | 274 | }, |
| 264 | |_me| { | 275 | |_me| { |
| 265 | p.ic_intr_mask().modify(|w| { | 276 | p.ic_intr_mask().write(|w| { |
| 266 | w.set_m_stop_det(true); | 277 | w.set_m_stop_det(true); |
| 267 | w.set_m_restart_det(true); | 278 | w.set_m_restart_det(true); |
| 268 | w.set_m_gen_call(true); | 279 | w.set_m_gen_call(true); |
| @@ -286,27 +297,30 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 286 | 297 | ||
| 287 | self.wait_on( | 298 | self.wait_on( |
| 288 | |me| { | 299 | |me| { |
| 289 | if let Err(abort_reason) = me.read_and_clear_abort_reason() { | 300 | let stat = p.ic_raw_intr_stat().read(); |
| 290 | if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { | 301 | trace!("rs:{:013b}", stat.0); |
| 291 | p.ic_clr_intr().read(); | 302 | |
| 292 | return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); | 303 | if stat.tx_abrt() { |
| 293 | } else { | 304 | if let Err(abort_reason) = me.read_and_clear_abort_reason() { |
| 294 | return Poll::Ready(Err(abort_reason)); | 305 | if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { |
| 306 | p.ic_clr_intr().read(); | ||
| 307 | return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); | ||
| 308 | } else { | ||
| 309 | return Poll::Ready(Err(abort_reason)); | ||
| 310 | } | ||
| 295 | } | 311 | } |
| 296 | } | 312 | } |
| 297 | 313 | ||
| 298 | if let Some(chunk) = chunks.next() { | 314 | if let Some(chunk) = chunks.next() { |
| 299 | me.write_to_fifo(chunk); | 315 | for byte in chunk { |
| 300 | 316 | p.ic_clr_rd_req().read(); | |
| 301 | p.ic_clr_rd_req().read(); | 317 | p.ic_data_cmd().write(|w| w.set_dat(*byte)); |
| 318 | } | ||
| 302 | 319 | ||
| 303 | Poll::Pending | 320 | Poll::Pending |
| 304 | } else { | 321 | } else { |
| 305 | let stat = p.ic_raw_intr_stat().read(); | 322 | if stat.rx_done() { |
| 306 | |||
| 307 | if stat.rx_done() && stat.stop_det() { | ||
| 308 | p.ic_clr_rx_done().read(); | 323 | p.ic_clr_rx_done().read(); |
| 309 | p.ic_clr_stop_det().read(); | ||
| 310 | Poll::Ready(Ok(ReadStatus::Done)) | 324 | Poll::Ready(Ok(ReadStatus::Done)) |
| 311 | } else if stat.rd_req() && stat.tx_empty() { | 325 | } else if stat.rd_req() && stat.tx_empty() { |
| 312 | Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) | 326 | Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) |
| @@ -316,11 +330,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 316 | } | 330 | } |
| 317 | }, | 331 | }, |
| 318 | |_me| { | 332 | |_me| { |
| 319 | p.ic_intr_mask().modify(|w| { | 333 | p.ic_intr_mask().write(|w| { |
| 320 | w.set_m_stop_det(true); | ||
| 321 | w.set_m_rx_done(true); | ||
| 322 | w.set_m_tx_empty(true); | 334 | w.set_m_tx_empty(true); |
| 323 | w.set_m_tx_abrt(true); | 335 | w.set_m_tx_abrt(true); |
| 336 | w.set_m_rx_done(true); | ||
| 324 | }) | 337 | }) |
| 325 | }, | 338 | }, |
| 326 | ) | 339 | ) |
| @@ -329,9 +342,14 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 329 | 342 | ||
| 330 | /// Respond to reads with the fill byte until the controller stops asking | 343 | /// Respond to reads with the fill byte until the controller stops asking |
| 331 | pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { | 344 | pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { |
| 345 | // Send fill bytes a full fifo at a time, to reduce interrupt noise. | ||
| 346 | // This does mean we'll almost certainly abort the write, but since these are fill bytes, | ||
| 347 | // we don't care. | ||
| 348 | let buff = [fill; FIFO_SIZE as usize]; | ||
| 332 | loop { | 349 | loop { |
| 333 | match self.respond_to_read(&[fill]).await { | 350 | match self.respond_to_read(&buff).await { |
| 334 | Ok(ReadStatus::NeedMoreBytes) => (), | 351 | Ok(ReadStatus::NeedMoreBytes) => (), |
| 352 | Ok(ReadStatus::LeftoverBytes(_)) => break Ok(()), | ||
| 335 | Ok(_) => break Ok(()), | 353 | Ok(_) => break Ok(()), |
| 336 | Err(e) => break Err(e), | 354 | Err(e) => break Err(e), |
| 337 | } | 355 | } |
| @@ -353,10 +371,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 353 | #[inline(always)] | 371 | #[inline(always)] |
| 354 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { | 372 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { |
| 355 | let p = T::regs(); | 373 | let p = T::regs(); |
| 356 | let mut abort_reason = p.ic_tx_abrt_source().read(); | 374 | let abort_reason = p.ic_tx_abrt_source().read(); |
| 357 | |||
| 358 | // Mask off master_dis | ||
| 359 | abort_reason.set_abrt_master_dis(false); | ||
| 360 | 375 | ||
| 361 | if abort_reason.0 != 0 { | 376 | if abort_reason.0 != 0 { |
| 362 | // Note clearing the abort flag also clears the reason, and this | 377 | // Note clearing the abort flag also clears the reason, and this |
