Skip to content

Commit ae23196

Browse files
committed
Implement embedded-hal 1.0 I2c for Twim.
1 parent 85ff92c commit ae23196

1 file changed

Lines changed: 141 additions & 0 deletions

File tree

nrf-hal-common/src/twim.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! - nRF52840: Section 6.31
77
use core::ops::Deref;
88
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
9+
use embedded_hal::i2c::{self, ErrorKind, ErrorType, I2c, NoAcknowledgeSource, Operation};
910

1011
#[cfg(any(feature = "9160", feature = "5340-app", feature = "5340-net"))]
1112
use crate::pac::{twim0_ns as twim0, TWIM0_NS as TWIM0};
@@ -194,6 +195,10 @@ where
194195
self.0.events_stopped.reset();
195196
break;
196197
}
198+
if self.0.events_suspended.read().bits() != 0 {
199+
self.0.events_suspended.reset();
200+
break;
201+
}
197202
if self.0.events_error.read().bits() != 0 {
198203
self.0.events_error.reset();
199204
self.0.tasks_stop.write(|w| unsafe { w.bits(1) });
@@ -392,6 +397,125 @@ where
392397
},
393398
)
394399
}
400+
401+
fn write_part(
402+
&mut self,
403+
buffer: &[u8],
404+
last_operation_read: Option<bool>,
405+
final_operation: bool,
406+
) -> Result<(), Error> {
407+
unsafe { self.set_tx_buffer(buffer)? };
408+
409+
// Set appropriate lasttx shortcut.
410+
if final_operation {
411+
self.0.shorts.write(|w| w.lasttx_stop().enabled());
412+
} else {
413+
self.0.shorts.write(|w| w.lasttx_suspend().enabled());
414+
}
415+
416+
if last_operation_read != Some(false) {
417+
// Start write.
418+
self.0.tasks_starttx.write(|w| unsafe { w.bits(1) });
419+
}
420+
self.0.tasks_resume.write(|w| unsafe { w.bits(1) });
421+
422+
self.wait();
423+
self.read_errorsrc()?;
424+
if self.0.txd.amount.read().bits() != buffer.len() as u32 {
425+
return Err(Error::Transmit);
426+
}
427+
428+
Ok(())
429+
}
430+
}
431+
432+
impl<T> ErrorType for Twim<T> {
433+
type Error = Error;
434+
}
435+
436+
impl<T: Instance> I2c for Twim<T> {
437+
fn transaction(
438+
&mut self,
439+
address: u8,
440+
operations: &mut [Operation],
441+
) -> Result<(), Self::Error> {
442+
compiler_fence(SeqCst);
443+
444+
self.0
445+
.address
446+
.write(|w| unsafe { w.address().bits(address) });
447+
448+
// `Some(true)` if the last operation was a read, `Some(false)` if it was a write.
449+
let mut last_operation_read = None;
450+
let operations_count = operations.len();
451+
for (i, operation) in operations.into_iter().enumerate() {
452+
// Clear events
453+
self.0.events_stopped.reset();
454+
self.0.events_error.reset();
455+
self.0.events_lasttx.reset();
456+
self.0.events_lastrx.reset();
457+
self.clear_errorsrc();
458+
459+
match operation {
460+
Operation::Read(buffer) => {
461+
unsafe { self.set_rx_buffer(buffer)? };
462+
463+
// Set appropriate lastrx shortcut.
464+
if i == operations_count - 1 {
465+
rtt_target::rprintln!("Stopping after read.");
466+
self.0.shorts.write(|w| w.lastrx_stop().enabled());
467+
} else {
468+
#[cfg(not(any(
469+
feature = "5340-app",
470+
feature = "5340-net",
471+
feature = "52832"
472+
)))]
473+
self.0.shorts.write(|w| w.lastrx_suspend().enabled());
474+
}
475+
476+
if last_operation_read != Some(true) {
477+
// Start read.
478+
self.0.tasks_startrx.write(|w| unsafe { w.bits(1) });
479+
}
480+
self.0.tasks_resume.write(|w| unsafe { w.bits(1) });
481+
482+
self.wait();
483+
self.read_errorsrc()?;
484+
if self.0.rxd.amount.read().bits() != buffer.len() as u32 {
485+
return Err(Error::Receive);
486+
}
487+
488+
last_operation_read = Some(true);
489+
}
490+
Operation::Write(buffer) => {
491+
if crate::slice_in_ram(buffer) {
492+
self.write_part(buffer, last_operation_read, i == operations_count - 1)?;
493+
} else if buffer.len() > FORCE_COPY_BUFFER_SIZE {
494+
return Err(Error::TxBufferTooLong);
495+
} else {
496+
let mut copy = [0; FORCE_COPY_BUFFER_SIZE];
497+
let num_chunks = buffer.len().div_ceil(FORCE_COPY_BUFFER_SIZE);
498+
for (chunk_index, chunk) in buffer
499+
.chunks(FORCE_COPY_BUFFER_SIZE)
500+
.into_iter()
501+
.enumerate()
502+
{
503+
copy[..chunk.len()].copy_from_slice(chunk);
504+
self.write_part(
505+
&copy[..chunk.len()],
506+
last_operation_read,
507+
i == operations_count - 1 && chunk_index == num_chunks - 1,
508+
)?;
509+
}
510+
}
511+
512+
last_operation_read = Some(false);
513+
}
514+
}
515+
}
516+
517+
Ok(())
518+
}
395519
}
396520

397521
#[cfg(feature = "embedded-hal-02")]
@@ -473,6 +597,23 @@ pub enum Error {
473597
Overrun,
474598
}
475599

600+
impl i2c::Error for Error {
601+
fn kind(&self) -> ErrorKind {
602+
match self {
603+
Self::TxBufferTooLong
604+
| Self::RxBufferTooLong
605+
| Self::TxBufferZeroLength
606+
| Self::RxBufferZeroLength
607+
| Self::Transmit
608+
| Self::Receive
609+
| Self::DMABufferNotInDataMemory => ErrorKind::Other,
610+
Self::AddressNack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address),
611+
Self::DataNack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data),
612+
Self::Overrun => ErrorKind::Overrun,
613+
}
614+
}
615+
}
616+
476617
/// Implemented by all TWIM instances
477618
pub trait Instance: Deref<Target = twim0::RegisterBlock> + sealed::Sealed {}
478619

0 commit comments

Comments
 (0)