Skip to content
This repository was archived by the owner on Aug 9, 2022. It is now read-only.

Commit 6c42f8b

Browse files
committed
initial write_then_read implementation
1 parent f1ba851 commit 6c42f8b

File tree

1 file changed

+174
-12
lines changed

1 file changed

+174
-12
lines changed

src/i2c.rs

Lines changed: 174 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use {
44
gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
55
target::{i2c, DPORT, I2C0, I2C1},
66
},
7-
core::ops::Deref,
7+
core::{ops::Deref, ptr},
88
};
99

1010
const DPORT_BASE_ADDR: u32 = 0x3FF4_0000;
@@ -231,6 +231,7 @@ where
231231
base_addr + FIFO_OFFSET
232232
}
233233

234+
// TODO: Enable ACK checks and return error if ACK check fails
234235
pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
235236
// Reset FIFO
236237
self.reset_fifo();
@@ -241,16 +242,16 @@ where
241242
.bits(Command::new(Opcode::RSTART, false, false, false, None).into())
242243
});
243244

244-
// Load bytes into FIFO
245+
// Load into FIFO
245246
unsafe {
246247
let fifo_addr = self.fifo_addr(OperationType::WRITE) as *mut u8;
247248

248249
// Address
249-
core::ptr::write_volatile(fifo_addr, addr << 1 | OperationType::WRITE as u8);
250+
ptr::write_volatile(fifo_addr, addr << 1 | OperationType::WRITE as u8);
250251

251252
// Data
252253
for byte in bytes {
253-
core::ptr::write_volatile(fifo_addr, *byte);
254+
ptr::write_volatile(fifo_addr, *byte);
254255
}
255256
}
256257

@@ -285,6 +286,7 @@ where
285286
Ok(())
286287
}
287288

289+
// TODO: Enable ACK checks and return error if ACK check fails
288290
pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
289291
dprintln!("starting I2C read");
290292
assert!(buffer.len() > 1); //TODO: temporary, just simplifying the logic during implementation
@@ -300,7 +302,7 @@ where
300302

301303
// Load address into FIFO
302304
let fifo_addr = self.fifo_addr(OperationType::READ) as *mut u8;
303-
unsafe { core::ptr::write_volatile(fifo_addr, addr << 1 | OperationType::READ as u8) };
305+
unsafe { ptr::write_volatile(fifo_addr, addr << 1 | OperationType::READ as u8) };
304306

305307
// WRITE command
306308
self.0.comd1.write(|w| unsafe {
@@ -352,20 +354,178 @@ where
352354
// Read bytes from FIFO
353355
dprintln!("rxfifo: {:?}", self.0.sr.read().rxfifo_cnt().bits());
354356
for byte in buffer.iter_mut() {
355-
*byte = unsafe { core::ptr::read_volatile(fifo_addr) };
357+
*byte = unsafe { ptr::read_volatile(fifo_addr) };
356358
}
357359
dprintln!("{:?}", &buffer);
358360

359361
Ok(())
360362
}
361363

364+
// TODO: Enable ACK checks and return error if ACK check fails
362365
pub fn write_then_read(
363366
&mut self,
364367
addr: u8,
365368
bytes: &[u8],
366369
buffer: &mut [u8],
367370
) -> Result<(), Error> {
368-
unimplemented!()
371+
// Reset FIFO
372+
self.reset_fifo();
373+
374+
// START
375+
self.0.comd0.write(|w| unsafe {
376+
w.command0().bits(
377+
Command::new(
378+
Opcode::RSTART,
379+
false,
380+
false,
381+
false,
382+
None,
383+
).into()
384+
)
385+
});
386+
387+
// load into FIFO
388+
let fifo_addr = self.fifo_addr(OperationType::WRITE) as *mut u8;
389+
unsafe {
390+
// load address
391+
ptr::write_volatile(fifo_addr, addr << 1 | OperationType::WRITE as u8);
392+
393+
// load data
394+
for byte in bytes {
395+
ptr::write_volatile(fifo_addr, *byte);
396+
}
397+
}
398+
399+
// WRITE
400+
self.0.comd1.write(|w| unsafe {
401+
w.command1().bits(
402+
Command::new(
403+
Opcode::WRITE,
404+
false,
405+
true,
406+
true,
407+
Some(1 + bytes.len() as u8),
408+
).into(),
409+
)
410+
});
411+
412+
// repeat START
413+
self.0.comd2.write(|w| unsafe {
414+
w.command2().bits(
415+
Command::new(
416+
Opcode::RSTART,
417+
false,
418+
false,
419+
false,
420+
None,
421+
).into(),
422+
)
423+
});
424+
425+
// WRITE slave address
426+
self.0.comd3.write(|w| unsafe {
427+
w.command3().bits(
428+
Command::new(
429+
Opcode::WRITE,
430+
false,
431+
true,
432+
true,
433+
Some(1),
434+
).into(),
435+
)
436+
});
437+
438+
// load slave address into FIFO
439+
unsafe { ptr::write_volatile(fifo_addr, addr << 1 | OperationType::READ as u8) };
440+
441+
if buffer.len() > 1 {
442+
// READ first n - 1 bytes
443+
self.0.comd4.write(|w| unsafe {
444+
w.command4().bits(
445+
Command::new(
446+
Opcode::READ,
447+
true,
448+
false,
449+
false,
450+
Some(buffer.len() as u8 - 1),
451+
).into()
452+
)
453+
});
454+
455+
// READ last byte
456+
self.0.comd5.write(|w| unsafe {
457+
w.command5().bits(
458+
Command::new(
459+
Opcode::READ,
460+
false,
461+
false,
462+
false,
463+
Some(1),
464+
).into()
465+
)
466+
});
467+
468+
// STOP
469+
self.0.comd6.write(|w| unsafe {
470+
w.command6().bits(
471+
Command::new(
472+
Opcode::STOP,
473+
false,
474+
false,
475+
false,
476+
None,
477+
).into(),
478+
)
479+
});
480+
} else {
481+
// READ byte
482+
self.0.comd4.write(|w| unsafe {
483+
w.command4().bits(
484+
Command::new(
485+
Opcode::READ,
486+
false,
487+
false,
488+
false,
489+
Some(1),
490+
).into()
491+
)
492+
});
493+
494+
// STOP
495+
self.0.comd5.write(|w| unsafe {
496+
w.command5().bits(
497+
Command::new(
498+
Opcode::STOP,
499+
false,
500+
false,
501+
false,
502+
None,
503+
).into(),
504+
)
505+
});
506+
}
507+
508+
// Start transmission
509+
self.0.ctr.modify(|_, w| w.trans_start().set_bit());
510+
511+
// Busy wait for all commands to be marked as done
512+
while self.0.comd0.read().command0_done().bit() != true {}
513+
while self.0.comd1.read().command1_done().bit() != true {}
514+
while self.0.comd2.read().command2_done().bit() != true {}
515+
while self.0.comd3.read().command3_done().bit() != true {}
516+
while self.0.comd4.read().command4_done().bit() != true {}
517+
while self.0.comd5.read().command5_done().bit() != true {}
518+
if buffer.len() > 1 {
519+
while self.0.comd6.read().command6_done().bit() != true {}
520+
}
521+
522+
// read bytes from FIFO
523+
let fifo_addr = self.fifo_addr(OperationType::READ) as *mut u8;
524+
for byte in buffer.iter_mut() {
525+
*byte = unsafe { ptr::read_volatile(fifo_addr) };
526+
}
527+
528+
Ok(())
369529
}
370530

371531
/// Return the raw interface to the underlying I2C peripheral
@@ -430,6 +590,7 @@ pub enum Error {
430590
}
431591

432592
/// I2C Command
593+
/// TODO: turn this into an enum instead
433594
struct Command {
434595
/// Opcode of the command
435596
opcode: Opcode,
@@ -438,8 +599,9 @@ struct Command {
438599
/// This bit is to set an expected ACK value for the transmitter
439600
ack_exp: bool,
440601
/// When transmitting a byte, this bit enables checking the ACK value received against the ack_exp value
441-
ack_en: bool,
442-
/// Length of data to be read or written, maximum length of 255, minimum of 1
602+
ack_check_en: bool,
603+
/// Length of data (in bytes) to be read or written. The maximum length is 255, while the
604+
/// minimum is 1. When the opcode is RSTART, STOP, or END, this value is meaningless.
443605
length: Option<u8>,
444606
}
445607

@@ -449,14 +611,14 @@ impl Command {
449611
opcode: Opcode,
450612
ack_value: bool,
451613
ack_exp: bool,
452-
ack_en: bool,
614+
ack_check_en: bool,
453615
length: Option<u8>,
454616
) -> Self {
455617
Self {
456618
opcode,
457619
ack_value,
458620
ack_exp,
459-
ack_en,
621+
ack_check_en,
460622
length,
461623
}
462624
}
@@ -469,7 +631,7 @@ impl From<Command> for u16 {
469631
None => 0,
470632
};
471633

472-
if c.ack_en {
634+
if c.ack_check_en {
473635
cmd |= 1 << 8;
474636
} else {
475637
cmd &= !(1 << 8);

0 commit comments

Comments
 (0)