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