1#![allow(unused)] use crate::pac::{lp_i2c0::COMD, LP_I2C0};
6
7const LP_I2C_TRANS_COMPLETE_INT_ST_S: u32 = 7;
8const LP_I2C_END_DETECT_INT_ST_S: u32 = 3;
9const LP_I2C_NACK_INT_ST_S: u32 = 10;
10
11const I2C_LL_INTR_MASK: u32 = (1 << LP_I2C_TRANS_COMPLETE_INT_ST_S)
12 | (1 << LP_I2C_END_DETECT_INT_ST_S)
13 | (1 << LP_I2C_NACK_INT_ST_S);
14
15const LP_I2C_FIFO_LEN: u32 = 16;
16
17#[doc(hidden)]
18pub unsafe fn conjure() -> LpI2c {
19 LpI2c {
20 i2c: LP_I2C0::steal(),
21 }
22}
23
24#[allow(missing_docs)]
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum Error {
29 ExceedingFifo,
30 AckCheckFailed,
31 TimeOut,
32 ArbitrationLost,
33 ExecIncomplete,
34 CommandNrExceeded,
35 InvalidResponse,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39enum OperationType {
40 Write = 0,
41 Read = 1,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45enum Ack {
46 Ack,
47 Nack,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51enum Opcode {
52 RStart = 6,
53 Write = 1,
54 Read = 3,
55 Stop = 2,
56 End = 4,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60enum Command {
61 Start,
62 Stop,
63 End,
64 Write {
65 ack_exp: Ack,
67 ack_check_en: bool,
69 length: u8,
72 },
73 Read {
74 ack_value: Ack,
77 length: u8,
80 },
81}
82
83impl From<Command> for u16 {
84 fn from(c: Command) -> u16 {
85 let opcode = match c {
86 Command::Start => Opcode::RStart,
87 Command::Stop => Opcode::Stop,
88 Command::End => Opcode::End,
89 Command::Write { .. } => Opcode::Write,
90 Command::Read { .. } => Opcode::Read,
91 };
92
93 let length = match c {
94 Command::Start | Command::Stop | Command::End => 0,
95 Command::Write { length: l, .. } | Command::Read { length: l, .. } => l,
96 };
97
98 let ack_exp = match c {
99 Command::Start | Command::Stop | Command::End | Command::Read { .. } => Ack::Nack,
100 Command::Write { ack_exp: exp, .. } => exp,
101 };
102
103 let ack_check_en = match c {
104 Command::Start | Command::Stop | Command::End | Command::Read { .. } => false,
105 Command::Write {
106 ack_check_en: en, ..
107 } => en,
108 };
109
110 let ack_value = match c {
111 Command::Start | Command::Stop | Command::End | Command::Write { .. } => Ack::Nack,
112 Command::Read { ack_value: ack, .. } => ack,
113 };
114
115 let mut cmd: u16 = length.into();
116
117 if ack_check_en {
118 cmd |= 1 << 8;
119 } else {
120 cmd &= !(1 << 8);
121 }
122
123 if ack_exp == Ack::Nack {
124 cmd |= 1 << 9;
125 } else {
126 cmd &= !(1 << 9);
127 }
128
129 if ack_value == Ack::Nack {
130 cmd |= 1 << 10;
131 } else {
132 cmd &= !(1 << 10);
133 }
134
135 cmd |= (opcode as u16) << 11;
136
137 cmd
138 }
139}
140
141impl From<Command> for u32 {
142 fn from(c: Command) -> u32 {
143 u16::from(c) as u32
144 }
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148enum CommandRegister {
149 COMD0,
150 COMD1,
151 COMD2,
152 COMD3,
153 COMD4,
154 COMD5,
155 COMD6,
156 COMD7,
157}
158
159impl CommandRegister {
160 fn advance(&mut self) {
161 *self = match *self {
162 CommandRegister::COMD0 => CommandRegister::COMD1,
163 CommandRegister::COMD1 => CommandRegister::COMD2,
164 CommandRegister::COMD2 => CommandRegister::COMD3,
165 CommandRegister::COMD3 => CommandRegister::COMD4,
166 CommandRegister::COMD4 => CommandRegister::COMD5,
167 CommandRegister::COMD5 => CommandRegister::COMD6,
168 CommandRegister::COMD6 => CommandRegister::COMD7,
169 CommandRegister::COMD7 => panic!("Cannot advance beyond COMD7"),
170 }
171 }
172}
173
174pub struct LpI2c {
186 i2c: LP_I2C0,
187}
188
189impl LpI2c {
190 pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
192 let mut cmd_iterator = CommandRegister::COMD0;
193
194 if self.i2c.sr().read().bus_busy().bit_is_set() {
196 self.i2c.ctr().modify(|_, w| w.fsm_rst().set_bit());
197 }
198
199 if bytes.len() > 255 {
200 return Err(Error::ExceedingFifo);
201 }
202
203 self.reset_fifo();
205
206 self.add_cmd_lp(&mut cmd_iterator, Command::Start)?;
207
208 self.write_fifo((addr << 1) | OperationType::Write as u8);
210
211 self.add_cmd_lp(
212 &mut cmd_iterator,
213 Command::Write {
214 ack_exp: Ack::Ack,
215 ack_check_en: true,
216 length: 1_u8,
217 },
218 )?;
219
220 self.enable_interrupts(I2C_LL_INTR_MASK);
221
222 let mut data_idx = 0;
223 let mut remaining_bytes = bytes.len() as u32;
224
225 let mut fifo_available = LP_I2C_FIFO_LEN - 1;
226
227 while remaining_bytes > 0 {
228 let fifo_size = if remaining_bytes < fifo_available {
229 remaining_bytes
230 } else {
231 fifo_available
232 };
233 remaining_bytes -= fifo_size;
234
235 for &byte in &bytes[data_idx as usize..(data_idx as usize) + fifo_size as usize] {
237 self.write_fifo(byte);
238 }
239
240 self.add_cmd_lp(
242 &mut cmd_iterator,
243 Command::Write {
244 ack_exp: Ack::Ack,
245 ack_check_en: true,
246 length: fifo_size as u8,
247 },
248 )?;
249
250 let cmd = if remaining_bytes == 0 {
252 Command::Stop
253 } else {
254 Command::End
255 };
256
257 self.add_cmd_lp(&mut cmd_iterator, cmd)?;
259
260 self.lp_i2c_update();
262 self.i2c.ctr().modify(|_, w| w.trans_start().set_bit());
263
264 self.wait_for_completion()?;
266
267 data_idx += fifo_size;
269
270 fifo_available = LP_I2C_FIFO_LEN;
271 }
272
273 Ok(())
274 }
275
276 pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
278 if buffer.len() > 254 {
280 return Err(Error::ExceedingFifo);
281 }
282
283 let mut cmd_iterator = CommandRegister::COMD0;
284
285 self.add_cmd_lp(&mut cmd_iterator, Command::Start)?;
286
287 self.write_fifo((addr << 1) | OperationType::Read as u8);
289
290 self.add_cmd_lp(
291 &mut cmd_iterator,
292 Command::Write {
293 ack_exp: Ack::Ack,
294 ack_check_en: true,
295 length: 1_u8,
296 },
297 )?;
298
299 self.enable_interrupts(
300 (1 << LP_I2C_TRANS_COMPLETE_INT_ST_S) | (1 << LP_I2C_END_DETECT_INT_ST_S),
301 );
302
303 let mut remaining_bytes = buffer.len();
304
305 while remaining_bytes > 0 {
306 let fifo_size = if remaining_bytes < LP_I2C_FIFO_LEN as usize {
307 remaining_bytes
308 } else {
309 LP_I2C_FIFO_LEN as usize
310 };
311 remaining_bytes -= fifo_size;
312
313 if fifo_size == 1 {
314 self.add_cmd_lp(
316 &mut cmd_iterator,
317 Command::Read {
318 ack_value: Ack::Nack,
319 length: 1, },
321 )?;
322 self.add_cmd_lp(&mut cmd_iterator, Command::Stop)?;
324 } else if fifo_size > 1 && remaining_bytes == 0 {
325 self.add_cmd_lp(
328 &mut cmd_iterator,
329 Command::Read {
330 ack_value: Ack::Ack,
331 length: (fifo_size - 1) as u8,
332 },
333 )?;
334 self.add_cmd_lp(
336 &mut cmd_iterator,
337 Command::Read {
338 ack_value: Ack::Nack,
339 length: 1,
340 },
341 )?;
342 self.add_cmd_lp(&mut cmd_iterator, Command::Stop)?;
344 } else {
345 self.add_cmd_lp(
348 &mut cmd_iterator,
349 Command::Read {
350 ack_value: Ack::Ack,
351 length: fifo_size as u8,
352 },
353 )?;
354 self.add_cmd_lp(&mut cmd_iterator, Command::End)?;
356 }
357
358 self.lp_i2c_update();
359
360 self.i2c.ctr().modify(|_, w| w.trans_start().set_bit());
362
363 self.wait_for_completion()?;
366
367 for byte in buffer.iter_mut() {
369 *byte = self.read_fifo();
370 }
371 }
372 Ok(())
373 }
374
375 pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
378 self.write(addr, bytes)?;
382 self.read(addr, buffer)?;
383
384 Ok(())
385 }
386
387 fn lp_i2c_update(&self) {
388 self.i2c.ctr().modify(|_, w| w.conf_upgate().set_bit());
389 }
390
391 fn reset_fifo(&self) {
392 self.i2c
393 .fifo_conf()
394 .modify(|_, w| w.tx_fifo_rst().set_bit());
395
396 self.i2c
397 .fifo_conf()
398 .modify(|_, w| w.tx_fifo_rst().clear_bit());
399
400 self.i2c
401 .fifo_conf()
402 .modify(|_, w| w.rx_fifo_rst().set_bit());
403
404 self.i2c
405 .fifo_conf()
406 .modify(|_, w| w.rx_fifo_rst().clear_bit());
407 }
408
409 fn wait_for_completion(&self) -> Result<(), Error> {
410 loop {
411 let interrupts = self.i2c.int_st().read();
412
413 if interrupts.nack().bit_is_set() {
416 self.i2c
417 .int_clr()
418 .write(|w| unsafe { w.bits(I2C_LL_INTR_MASK) });
419 return Err(Error::InvalidResponse);
420 } else if interrupts.trans_complete().bit_is_set() {
421 self.disable_interrupts();
422
423 self.i2c
424 .int_clr()
425 .write(|w| unsafe { w.bits(I2C_LL_INTR_MASK) });
426 break;
427 } else if interrupts.end_detect().bit_is_set() {
428 self.i2c
429 .int_clr()
430 .write(|w| unsafe { w.bits(I2C_LL_INTR_MASK) });
431 break;
432 }
433 }
434
435 Ok(())
436 }
437
438 fn enable_interrupts(&self, mask: u32) {
439 self.i2c.int_ena().write(|w| unsafe { w.bits(mask) });
440 }
441
442 fn disable_interrupts(&self) {
443 self.i2c.int_ena().write(|w| unsafe { w.bits(0) });
444 }
445
446 fn write_fifo(&self, data: u8) {
447 self.i2c
448 .data()
449 .write(|w| unsafe { w.fifo_rdata().bits(data) });
450 }
451
452 fn read_fifo(&self) -> u8 {
453 self.i2c.data().read().fifo_rdata().bits()
454 }
455
456 fn add_cmd_lp(
457 &self,
458 command_register: &mut CommandRegister,
459 command: Command,
460 ) -> Result<(), Error> {
461 self.i2c
462 .comd(*command_register as usize)
463 .write(|w| unsafe { w.command().bits(command.into()) });
464
465 command_register.advance();
466
467 Ok(())
468 }
469}