use core::ops::Deref;
use crate::pac::{bsc0, BSC0, BSC1, GPIO};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
NoAcknowledge,
ZeroLengthUnsupported,
}
impl embedded_hal::i2c::Error for Error {
fn kind(&self) -> embedded_hal::i2c::ErrorKind {
match self {
Self::NoAcknowledge => embedded_hal::i2c::ErrorKind::NoAcknowledge(
embedded_hal::i2c::NoAcknowledgeSource::Unknown,
),
Self::ZeroLengthUnsupported => embedded_hal::i2c::ErrorKind::Other,
}
}
}
pub struct I2c<I = BSC1> {
bsc: I,
}
impl I2c<BSC1> {
pub fn init(gpio: &GPIO, bsc1: BSC1, clock_divider: u16) -> Self {
gpio.gpfsel0()
.modify(|_, w| w.fsel2().sda1().fsel3().scl1());
Self::configure(bsc1, clock_divider)
}
}
impl I2c<BSC0> {
pub fn init(gpio: &GPIO, bsc0: BSC0, clock_divider: u16) -> Self {
gpio.gpfsel4()
.modify(|_, w| w.fsel44().sda0().fsel45().scl0());
Self::configure(bsc0, clock_divider)
}
}
impl<I: Deref<Target = bsc0::RegisterBlock>> I2c<I> {
fn configure(bsc: I, clock_divider: u16) -> Self {
unsafe {
bsc.div().write(|w| w.cdiv().bits(clock_divider));
}
bsc.c().write(|w| w.i2cen().bit(true));
Self { bsc }
}
fn clear_status(&self) {
self.bsc.s().write(|w| w.done().bit(true).err().bit(true));
}
fn one_shot(&mut self, address: u8, is_read: bool, len: usize) {
self.bsc.a().write(|w| unsafe { w.addr().bits(address) });
self.clear_status();
unsafe {
self.bsc.dlen().write(|w| w.dlen().bits(len as u16));
}
self.bsc.c().write(|w| {
unsafe { w.clear().bits(0b11) };
w.i2cen().bit(true).read().bit(is_read).st().set_bit()
});
}
fn write_one(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
if bytes.is_empty() {
return Err(Error::ZeroLengthUnsupported);
}
self.one_shot(address, false, bytes.len());
let mut sent = 0;
loop {
let status = self.bsc.s().read();
if status.err().bit_is_set() {
self.clear_status();
return Err(Error::NoAcknowledge);
}
if sent < bytes.len() && status.txd().bit_is_set() {
unsafe {
self.bsc.fifo().write(|w| w.data().bits(bytes[sent]));
}
sent += 1;
}
if status.done().bit_is_set() {
break;
}
}
self.clear_status();
Ok(())
}
fn read_one(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
if buffer.is_empty() {
return Err(Error::ZeroLengthUnsupported);
}
self.one_shot(address, true, buffer.len());
let mut received = 0;
loop {
let status = self.bsc.s().read();
if status.err().bit_is_set() {
self.clear_status();
return Err(Error::NoAcknowledge);
}
if received < buffer.len() && status.rxd().bit_is_set() {
buffer[received] = self.bsc.fifo().read().data().bits();
received += 1;
}
if status.done().bit_is_set() && received >= buffer.len() {
break;
}
}
self.clear_status();
Ok(())
}
}
impl<I: Deref<Target = bsc0::RegisterBlock>> embedded_hal::i2c::ErrorType for I2c<I> {
type Error = Error;
}
impl<I: Deref<Target = bsc0::RegisterBlock>> embedded_hal::i2c::I2c for I2c<I> {
fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
for operation in operations {
match operation {
embedded_hal::i2c::Operation::Read(buffer) => self.read_one(address, buffer)?,
embedded_hal::i2c::Operation::Write(bytes) => self.write_one(address, bytes)?,
}
}
Ok(())
}
}