2c slave based on transactions and a channel
This commit is contained in:
parent
ba9f5111d5
commit
601d769e71
@ -1,6 +1,6 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use stm32_metapac::i2c::vals::Oamsk;
|
use stm32_metapac::i2c;
|
||||||
|
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
|
|
||||||
@ -9,6 +9,8 @@ use crate::interrupt;
|
|||||||
mod _version;
|
mod _version;
|
||||||
pub use _version::*;
|
pub use _version::*;
|
||||||
|
|
||||||
|
mod v2slave;
|
||||||
|
|
||||||
use crate::peripherals;
|
use crate::peripherals;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
@ -22,13 +24,7 @@ pub enum Error {
|
|||||||
Overrun,
|
Overrun,
|
||||||
ZeroLengthTransfer,
|
ZeroLengthTransfer,
|
||||||
BufferSize,
|
BufferSize,
|
||||||
}
|
NoTransaction,
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
#[repr(usize)]
|
|
||||||
pub enum AddressType {
|
|
||||||
Address1 = 0,
|
|
||||||
Address2,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@ -45,19 +41,25 @@ pub enum Address2Mask {
|
|||||||
}
|
}
|
||||||
impl Address2Mask {
|
impl Address2Mask {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub const fn to_vals_impl(self) -> Oamsk {
|
pub const fn to_vals_impl(self) -> i2c::vals::Oamsk {
|
||||||
match self {
|
match self {
|
||||||
Address2Mask::NOMASK => Oamsk::NOMASK,
|
Address2Mask::NOMASK => i2c::vals::Oamsk::NOMASK,
|
||||||
Address2Mask::MASK1 => Oamsk::MASK1,
|
Address2Mask::MASK1 => i2c::vals::Oamsk::MASK1,
|
||||||
Address2Mask::MASK2 => Oamsk::MASK2,
|
Address2Mask::MASK2 => i2c::vals::Oamsk::MASK2,
|
||||||
Address2Mask::MASK3 => Oamsk::MASK3,
|
Address2Mask::MASK3 => i2c::vals::Oamsk::MASK3,
|
||||||
Address2Mask::MASK4 => Oamsk::MASK4,
|
Address2Mask::MASK4 => i2c::vals::Oamsk::MASK4,
|
||||||
Address2Mask::MASK5 => Oamsk::MASK5,
|
Address2Mask::MASK5 => i2c::vals::Oamsk::MASK5,
|
||||||
Address2Mask::MASK6 => Oamsk::MASK6,
|
Address2Mask::MASK6 => i2c::vals::Oamsk::MASK6,
|
||||||
Address2Mask::MASK7 => Oamsk::MASK7,
|
Address2Mask::MASK7 => i2c::vals::Oamsk::MASK7,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[repr(usize)]
|
||||||
|
pub enum AddressIndex {
|
||||||
|
Address1 = 0,
|
||||||
|
Address2 = 2,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub enum Dir {
|
pub enum Dir {
|
||||||
|
@ -15,14 +15,14 @@ use embassy_sync::waitqueue::AtomicWaker;
|
|||||||
use embassy_time::{Duration, Instant};
|
use embassy_time::{Duration, Instant};
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
use futures::task::Poll;
|
use futures::task::Poll;
|
||||||
use stm32_metapac::i2c::vals;
|
|
||||||
|
|
||||||
|
use super::v2slave::SlaveState;
|
||||||
use crate::dma::NoDma;
|
use crate::dma::NoDma;
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
use crate::dma::Transfer;
|
use crate::dma::Transfer;
|
||||||
use crate::gpio::sealed::AFType;
|
use crate::gpio::sealed::AFType;
|
||||||
use crate::gpio::Pull;
|
use crate::gpio::Pull;
|
||||||
use crate::i2c::{Address2Mask, AddressType, Dir, Error, Instance, SclPin, SdaPin};
|
use crate::i2c::{Address2Mask, Error, Instance, SclPin, SdaPin};
|
||||||
use crate::interrupt::typelevel::Interrupt;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::pac::i2c;
|
use crate::pac::i2c;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
@ -35,105 +35,13 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
|
|
||||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let regs = T::regs();
|
|
||||||
let isr = regs.isr().read();
|
|
||||||
|
|
||||||
T::state().mutex.lock(|f| {
|
T::state().mutex.lock(|f| {
|
||||||
|
let regs = T::regs();
|
||||||
let mut state_m = f.borrow_mut();
|
let mut state_m = f.borrow_mut();
|
||||||
if state_m.slave_mode {
|
if state_m.slave_mode {
|
||||||
// ============================================ slave interrupt state_m machine
|
I2c::<'_, T, NoDma, NoDma>::slave_interupt_handler(&mut state_m, ®s)
|
||||||
if isr.berr() {
|
|
||||||
regs.icr().modify(|w| {
|
|
||||||
w.set_berrcf(true);
|
|
||||||
});
|
|
||||||
state_m.result = Some(Error::Bus);
|
|
||||||
} else if isr.arlo() {
|
|
||||||
state_m.result = Some(Error::Arbitration);
|
|
||||||
regs.icr().write(|w| w.set_arlocf(true));
|
|
||||||
} else if isr.nackf() {
|
|
||||||
regs.icr().write(|w| w.set_nackcf(true));
|
|
||||||
} else if isr.txis() {
|
|
||||||
// send the next byte to the master, or NACK in case of error, then end transaction
|
|
||||||
let b = match state_m.read_byte() {
|
|
||||||
Ok(b) => b,
|
|
||||||
Err(e) => {
|
|
||||||
// An extra interrupt after the last byte is sent seems to be generated always
|
|
||||||
// Do not generate an error in this (overrun) case
|
|
||||||
match e {
|
|
||||||
Error::Overrun => (),
|
|
||||||
_ => state_m.result = Some(e),
|
|
||||||
}
|
|
||||||
0xFF
|
|
||||||
}
|
|
||||||
};
|
|
||||||
regs.txdr().write(|w| w.set_txdata(b));
|
|
||||||
} else if isr.rxne() {
|
|
||||||
let b = regs.rxdr().read().rxdata();
|
|
||||||
// byte is received from master. Store in buffer. In case of error send NACK, then end transaction
|
|
||||||
match state_m.write_byte(b) {
|
|
||||||
Ok(()) => (),
|
|
||||||
Err(e) => {
|
|
||||||
state_m.result = Some(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if isr.stopf() {
|
|
||||||
// Clear the stop condition flag
|
|
||||||
state_m.ready = true;
|
|
||||||
// make a copy of the current state as result of the transaction
|
|
||||||
state_m.transaction_result =
|
|
||||||
(state_m.current_address, state_m.dir, state_m.get_size(), state_m.result);
|
|
||||||
T::state().waker.wake();
|
|
||||||
regs.icr().write(|w| w.set_stopcf(true));
|
|
||||||
} else if isr.tcr() {
|
|
||||||
// This condition Will only happen when reload == 1 and sbr == 1 (slave) and nbytes was written.
|
|
||||||
// Send a NACK, set nbytes to clear tcr flag
|
|
||||||
regs.cr2().modify(|w| {
|
|
||||||
w.set_nack(true);
|
|
||||||
});
|
|
||||||
// Make one extra loop here to wait on the stop condition
|
|
||||||
} else if isr.addr() {
|
|
||||||
// handle the slave is addressed case, first step in the transaction
|
|
||||||
state_m.current_address = isr.addcode();
|
|
||||||
state_m.dir = if isr.dir() as u8 == 0 { Dir::WRITE } else { Dir::READ };
|
|
||||||
state_m.result = None;
|
|
||||||
|
|
||||||
if state_m.dir == Dir::READ {
|
|
||||||
// flush i2c tx register
|
|
||||||
regs.isr().write(|w| w.set_txe(true));
|
|
||||||
|
|
||||||
// Set the nbytes START and prepare to receive bytes into `buffer`.
|
|
||||||
// Set the actual number of bytes to transfer
|
|
||||||
// error case that n = 0 cannot be handled by i2c, we need to send at least 1 byte.
|
|
||||||
let (b, size) = match state_m.read_byte() {
|
|
||||||
Ok(b) => (b, state_m.get_size()),
|
|
||||||
_ => (0xFF, 1),
|
|
||||||
};
|
|
||||||
regs.cr2().modify(|w| {
|
|
||||||
w.set_nbytes(size);
|
|
||||||
// during sending nbytes automatically send a ACK, stretch clock after last byte
|
|
||||||
w.set_reload(vals::Reload::COMPLETED);
|
|
||||||
});
|
|
||||||
regs.txdr().write(|w| w.set_txdata(b));
|
|
||||||
// restore sbc after a master_write_read transaction
|
|
||||||
T::regs().cr1().modify(|reg| {
|
|
||||||
reg.set_sbc(true);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Set the nbytes to the maximum buffer size and wait for the bytes from the master
|
|
||||||
regs.cr2().modify(|w| {
|
|
||||||
w.set_nbytes(BUFFER_SIZE as u8);
|
|
||||||
w.set_reload(vals::Reload::COMPLETED)
|
|
||||||
});
|
|
||||||
// flush the rx data register
|
|
||||||
if regs.isr().read().rxne() {
|
|
||||||
_ = regs.rxdr().read().rxdata();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// end address phase, release clock stretching
|
|
||||||
regs.icr().write(|w| w.set_addrcf(true));
|
|
||||||
}
|
|
||||||
// ============================================ end slave interrupt state machine
|
|
||||||
} else {
|
} else {
|
||||||
|
let isr = regs.isr().read();
|
||||||
if isr.tcr() || isr.tc() {
|
if isr.tcr() || isr.tc() {
|
||||||
T::state().waker.wake();
|
T::state().waker.wake();
|
||||||
}
|
}
|
||||||
@ -142,6 +50,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
// The flag can only be cleared by writting to nbytes, we won't do that here, so disable
|
// The flag can only be cleared by writting to nbytes, we won't do that here, so disable
|
||||||
// the interrupt
|
// the interrupt
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
|
let regs = T::regs();
|
||||||
regs.cr1().modify(|w| w.set_tcie(false));
|
regs.cr1().modify(|w| w.set_tcie(false));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -196,147 +105,18 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
waker: AtomicWaker,
|
pub(crate) waker: AtomicWaker,
|
||||||
mutex: Mutex<CriticalSectionRawMutex, RefCell<I2cStateMachine>>,
|
pub(crate) mutex: Mutex<CriticalSectionRawMutex, RefCell<SlaveState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub(crate) const fn new() -> Self {
|
pub(crate) const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
waker: AtomicWaker::new(),
|
waker: AtomicWaker::new(),
|
||||||
mutex: Mutex::new(RefCell::new(I2cStateMachine::new())),
|
mutex: Mutex::new(RefCell::new(SlaveState::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct I2cStateMachine {
|
|
||||||
buffers: [[I2cBuffer; 2]; 2],
|
|
||||||
result: Option<Error>,
|
|
||||||
slave_mode: bool,
|
|
||||||
address1: u16,
|
|
||||||
ready: bool,
|
|
||||||
current_address: u8,
|
|
||||||
dir: Dir,
|
|
||||||
// at the end of the transaction make a copy of the result
|
|
||||||
// to prevent corruption if a new transaction starts immediatly
|
|
||||||
transaction_result: (u8, Dir, u8, Option<Error>),
|
|
||||||
}
|
|
||||||
impl I2cStateMachine {
|
|
||||||
pub(crate) const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
// first dimension: address type, main or generic, second dimension read or write
|
|
||||||
buffers: [
|
|
||||||
[I2cBuffer::new(), I2cBuffer::new()],
|
|
||||||
[I2cBuffer::new(), I2cBuffer::new()],
|
|
||||||
],
|
|
||||||
result: None,
|
|
||||||
slave_mode: false,
|
|
||||||
address1: 0,
|
|
||||||
current_address: 0,
|
|
||||||
dir: Dir::READ,
|
|
||||||
ready: false,
|
|
||||||
transaction_result: (0, Dir::READ, 0, None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn read_byte(&mut self) -> Result<u8, Error> {
|
|
||||||
let adress_type = if self.address1 == self.current_address as u16 {
|
|
||||||
AddressType::Address1
|
|
||||||
} else {
|
|
||||||
AddressType::Address2
|
|
||||||
};
|
|
||||||
self.buffers[adress_type as usize][Dir::READ as usize].master_read()
|
|
||||||
}
|
|
||||||
fn write_byte(&mut self, b: u8) -> Result<(), Error> {
|
|
||||||
let adress_type = if self.address1 == self.current_address as u16 {
|
|
||||||
AddressType::Address1
|
|
||||||
} else {
|
|
||||||
AddressType::Address2
|
|
||||||
};
|
|
||||||
self.buffers[adress_type as usize][Dir::WRITE as usize].master_write(b)
|
|
||||||
}
|
|
||||||
fn get_size(&self) -> u8 {
|
|
||||||
let adress_type = if self.address1 == self.current_address as u16 {
|
|
||||||
AddressType::Address1
|
|
||||||
} else {
|
|
||||||
AddressType::Address2
|
|
||||||
};
|
|
||||||
self.buffers[adress_type as usize][self.dir as usize].size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const BUFFER_SIZE: usize = 64;
|
|
||||||
|
|
||||||
struct I2cBuffer {
|
|
||||||
buffer: [u8; BUFFER_SIZE],
|
|
||||||
index: usize,
|
|
||||||
size: u8, // only used for the master read slave write scenario
|
|
||||||
}
|
|
||||||
|
|
||||||
impl I2cBuffer {
|
|
||||||
const fn new() -> Self {
|
|
||||||
I2cBuffer {
|
|
||||||
buffer: [0; BUFFER_SIZE],
|
|
||||||
index: 0,
|
|
||||||
size: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.index = 0;
|
|
||||||
self.size = 0;
|
|
||||||
for i in 0..self.buffer.len() {
|
|
||||||
self.buffer[i] = 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// master read slave write scenario. Master can read until self.size bytes
|
|
||||||
/// If no data available (self.size == 0)
|
|
||||||
fn master_read(&mut self) -> Result<u8, Error> {
|
|
||||||
if self.size == 0 {
|
|
||||||
return Err(Error::ZeroLengthTransfer);
|
|
||||||
};
|
|
||||||
if self.index < self.size as usize {
|
|
||||||
let b = self.buffer[self.index];
|
|
||||||
self.index += 1;
|
|
||||||
Ok(b)
|
|
||||||
} else {
|
|
||||||
Err(Error::Overrun) // too many bytes asked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// master write slave read scenario. Master can write until buffer full
|
|
||||||
fn master_write(&mut self, b: u8) -> Result<(), Error> {
|
|
||||||
if self.index < BUFFER_SIZE {
|
|
||||||
self.buffer[self.index] = b;
|
|
||||||
self.index += 1;
|
|
||||||
self.size = self.index as u8;
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::Overrun)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// read data into this buffer (master read, slave write)
|
|
||||||
fn from_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
|
||||||
let len = buffer.len();
|
|
||||||
if len > self.buffer.len() {
|
|
||||||
return Err(Error::Overrun);
|
|
||||||
};
|
|
||||||
for i in 0..len {
|
|
||||||
self.buffer[i] = buffer[i];
|
|
||||||
}
|
|
||||||
self.size = len as u8;
|
|
||||||
self.index = 0;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
// read data from this buffer, and leave empty at the end (master write, slave read)
|
|
||||||
// Buffer parameter must be of the size of the recieved bytes, otherwise a BufferSize error is returned
|
|
||||||
fn to_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
|
||||||
if buffer.len() != self.size as usize {
|
|
||||||
return Err(Error::BufferSize);
|
|
||||||
}
|
|
||||||
for i in 0..buffer.len() {
|
|
||||||
buffer[i] = self.buffer[i];
|
|
||||||
}
|
|
||||||
self.size = 0;
|
|
||||||
self.index = 0;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
|
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
|
||||||
_peri: PeripheralRef<'d, T>,
|
_peri: PeripheralRef<'d, T>,
|
||||||
@ -405,9 +185,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
reg.set_oa1en(false);
|
reg.set_oa1en(false);
|
||||||
});
|
});
|
||||||
let (mode, address) = if config.address_11bits {
|
let (mode, address) = if config.address_11bits {
|
||||||
(vals::Addmode::BIT10, config.slave_address_1)
|
(i2c::vals::Addmode::BIT10, config.slave_address_1)
|
||||||
} else {
|
} else {
|
||||||
(vals::Addmode::BIT7, config.slave_address_1 << 1)
|
(i2c::vals::Addmode::BIT7, config.slave_address_1 << 1)
|
||||||
};
|
};
|
||||||
T::regs().oar1().write(|reg| {
|
T::regs().oar1().write(|reg| {
|
||||||
reg.set_oa1(address);
|
reg.set_oa1(address);
|
||||||
@ -1040,115 +820,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// =========================
|
// =========================
|
||||||
// async Slave implementation
|
|
||||||
/// Starts listening for slave transactions
|
|
||||||
pub fn slave_start_listen(&self) -> Result<(), super::Error> {
|
|
||||||
T::regs().cr1().modify(|reg| {
|
|
||||||
reg.set_addrie(true);
|
|
||||||
reg.set_txie(true);
|
|
||||||
reg.set_addrie(true);
|
|
||||||
reg.set_rxie(true);
|
|
||||||
reg.set_nackie(true);
|
|
||||||
reg.set_stopie(true);
|
|
||||||
reg.set_errie(true);
|
|
||||||
reg.set_tcie(true);
|
|
||||||
reg.set_sbc(true);
|
|
||||||
});
|
|
||||||
T::state().mutex.lock(|f| {
|
|
||||||
let mut state_m = f.borrow_mut();
|
|
||||||
for i in 0..1 {
|
|
||||||
for j in 0..1 {
|
|
||||||
state_m.buffers[i][j].reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state_m.slave_mode = true;
|
|
||||||
state_m.ready = false;
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
// slave stop listening for slave transactions and switch back to master role
|
|
||||||
pub fn slave_stop_listen(&self) -> Result<(), super::Error> {
|
|
||||||
T::regs().cr1().modify(|reg| {
|
|
||||||
reg.set_addrie(false);
|
|
||||||
reg.set_txie(false);
|
|
||||||
reg.set_addrie(false);
|
|
||||||
reg.set_rxie(false);
|
|
||||||
reg.set_nackie(false);
|
|
||||||
reg.set_stopie(false);
|
|
||||||
reg.set_errie(false);
|
|
||||||
reg.set_tcie(false);
|
|
||||||
});
|
|
||||||
T::state().mutex.lock(|f| {
|
|
||||||
let mut state_m = f.borrow_mut();
|
|
||||||
state_m.slave_mode = false;
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_address_1(&self, address7: u8) -> Result<(), Error> {
|
|
||||||
T::regs().oar1().write(|reg| {
|
|
||||||
reg.set_oa1en(false);
|
|
||||||
});
|
|
||||||
let adress_u16 = address7 as u16;
|
|
||||||
T::regs().oar1().write(|reg| {
|
|
||||||
reg.set_oa1(adress_u16 << 1);
|
|
||||||
reg.set_oa1mode(vals::Addmode::BIT7);
|
|
||||||
reg.set_oa1en(true);
|
|
||||||
});
|
|
||||||
T::state().mutex.lock(|f| {
|
|
||||||
let mut state_m = f.borrow_mut();
|
|
||||||
state_m.address1 = adress_u16;
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
pub fn slave_sbc(&self, sbc_enabled: bool) {
|
|
||||||
// enable acknowlidge control
|
|
||||||
T::regs().cr1().modify(|w| w.set_sbc(sbc_enabled));
|
|
||||||
}
|
|
||||||
/// Prepare write data to master (master_read_slave_write) before transaction starts
|
|
||||||
/// Will return buffersize error in case the incoming buffer is too big
|
|
||||||
pub fn slave_write_buffer(&self, buffer: &[u8], address_type: AddressType) -> Result<(), super::Error> {
|
|
||||||
T::state().mutex.lock(|f| {
|
|
||||||
let mut state_m = f.borrow_mut();
|
|
||||||
let buf = &mut state_m.buffers[address_type as usize][Dir::READ as usize];
|
|
||||||
buf.from_buffer(buffer)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn slave_reset_buffer(&self, dir: Dir, address_type: AddressType) {
|
|
||||||
T::state().mutex.lock(|f| {
|
|
||||||
let mut state_m = f.borrow_mut();
|
|
||||||
let buf = &mut state_m.buffers[address_type as usize][dir as usize];
|
|
||||||
buf.reset();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read data from master (master_write_slave_read) after transaction is finished
|
|
||||||
/// Will fail if the size of the incoming buffer is smaller than the received bytes
|
|
||||||
pub fn slave_read_buffer(&self, buffer: &mut [u8], address_type: AddressType) -> Result<(), super::Error> {
|
|
||||||
T::state().mutex.lock(|f| {
|
|
||||||
let mut state_m = f.borrow_mut();
|
|
||||||
let buf = &mut state_m.buffers[address_type as usize][Dir::WRITE as usize];
|
|
||||||
buf.to_buffer(buffer)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/// wait until a slave transaction is finished, and return tuple address, direction, data size and error
|
|
||||||
pub async fn slave_transaction(&self) -> (u8, Dir, u8, Option<Error>) {
|
|
||||||
// async wait until addressed
|
|
||||||
poll_fn(|cx| {
|
|
||||||
T::state().waker.register(cx.waker());
|
|
||||||
T::state().mutex.lock(|f| {
|
|
||||||
let mut state_m = f.borrow_mut();
|
|
||||||
if state_m.ready {
|
|
||||||
state_m.ready = false;
|
|
||||||
return Poll::Ready(state_m.transaction_result);
|
|
||||||
} else {
|
|
||||||
return Poll::Pending;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
// =========================
|
|
||||||
// Blocking public API
|
// Blocking public API
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
|
462
embassy-stm32/src/i2c/v2slave.rs
Normal file
462
embassy-stm32/src/i2c/v2slave.rs
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
use core::result::Result;
|
||||||
|
|
||||||
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
|
use embassy_sync::channel::Channel;
|
||||||
|
use stm32_metapac::i2c;
|
||||||
|
|
||||||
|
use super::{AddressIndex, I2c, Instance};
|
||||||
|
use crate::i2c::{Dir, Error};
|
||||||
|
// Declare a CHANNEL for all other tasks to communicate with this driver
|
||||||
|
static CHANNEL_OUT: Channel<CriticalSectionRawMutex, SlaveTransaction, SLAVE_QUEUE_DEPTH> = Channel::new();
|
||||||
|
|
||||||
|
pub type I2cBuffer = [u8; SLAVE_BUFFER_SIZE];
|
||||||
|
pub const SLAVE_BUFFER_SIZE: usize = 64;
|
||||||
|
const SLAVE_QUEUE_DEPTH: usize = 5;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[repr(usize)]
|
||||||
|
pub enum BufferIndex {
|
||||||
|
MasterWriteAddress1 = 0,
|
||||||
|
MasterReadAddress1,
|
||||||
|
MasterWriteAddress2,
|
||||||
|
MasterReadAddress2,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SlaveTransaction {
|
||||||
|
buffer: I2cBuffer,
|
||||||
|
buffer_index: BufferIndex,
|
||||||
|
size: u16,
|
||||||
|
index: usize,
|
||||||
|
address: u16,
|
||||||
|
result: Option<Error>,
|
||||||
|
}
|
||||||
|
impl SlaveTransaction {
|
||||||
|
fn new_write(address: AddressIndex) -> Self {
|
||||||
|
SlaveTransaction {
|
||||||
|
buffer: [0; SLAVE_BUFFER_SIZE],
|
||||||
|
buffer_index: if address == AddressIndex::Address1 {
|
||||||
|
BufferIndex::MasterWriteAddress1
|
||||||
|
} else {
|
||||||
|
BufferIndex::MasterWriteAddress2
|
||||||
|
},
|
||||||
|
size: 0,
|
||||||
|
index: 0,
|
||||||
|
address: 0,
|
||||||
|
result: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn new_read(in_buffer: &[u8], address: AddressIndex) -> Self {
|
||||||
|
let mut buffer = [0; SLAVE_BUFFER_SIZE];
|
||||||
|
let size = if in_buffer.len() < SLAVE_BUFFER_SIZE {
|
||||||
|
in_buffer.len()
|
||||||
|
} else {
|
||||||
|
SLAVE_BUFFER_SIZE
|
||||||
|
};
|
||||||
|
for i in 0..size {
|
||||||
|
buffer[i] = in_buffer[i];
|
||||||
|
}
|
||||||
|
SlaveTransaction {
|
||||||
|
buffer,
|
||||||
|
buffer_index: if address == AddressIndex::Address1 {
|
||||||
|
BufferIndex::MasterReadAddress1
|
||||||
|
} else {
|
||||||
|
BufferIndex::MasterReadAddress2
|
||||||
|
},
|
||||||
|
size: size as u16,
|
||||||
|
index: 0,
|
||||||
|
address: 0,
|
||||||
|
result: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn result(&self) -> Option<Error> {
|
||||||
|
self.result
|
||||||
|
}
|
||||||
|
pub fn address(&self) -> u16 {
|
||||||
|
self.address
|
||||||
|
}
|
||||||
|
pub fn size(&self) -> u16 {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
self.index
|
||||||
|
}
|
||||||
|
// return a slice of the buffer with the correct transaction size
|
||||||
|
pub fn buffer(&self) -> &[u8] {
|
||||||
|
&self.buffer[0..self.size as usize]
|
||||||
|
}
|
||||||
|
pub fn dir(&self) -> Dir {
|
||||||
|
match self.buffer_index {
|
||||||
|
BufferIndex::MasterReadAddress1 => Dir::READ,
|
||||||
|
BufferIndex::MasterReadAddress2 => Dir::READ,
|
||||||
|
BufferIndex::MasterWriteAddress1 => Dir::WRITE,
|
||||||
|
BufferIndex::MasterWriteAddress2 => Dir::WRITE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// master read slave write scenario. Master can read until self.size bytes
|
||||||
|
/// If no data available (self.size == 0)
|
||||||
|
fn master_read(&mut self) -> Result<u8, Error> {
|
||||||
|
if self.size == 0 {
|
||||||
|
return Err(Error::ZeroLengthTransfer);
|
||||||
|
};
|
||||||
|
if self.index < self.size as usize {
|
||||||
|
let b = self.buffer[self.index];
|
||||||
|
self.index += 1;
|
||||||
|
Ok(b)
|
||||||
|
} else {
|
||||||
|
self.index += 1;
|
||||||
|
Err(Error::Overrun) // too many bytes asked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// master write slave read scenario. Master can write until buffer full
|
||||||
|
fn master_write(&mut self, b: u8) -> Result<(), Error> {
|
||||||
|
if self.index < SLAVE_BUFFER_SIZE {
|
||||||
|
self.buffer[self.index] = b;
|
||||||
|
self.index += 1;
|
||||||
|
self.size = self.index as u16;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
self.index += 1;
|
||||||
|
Err(Error::Overrun)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct SlaveState {
|
||||||
|
transactions: [Option<SlaveTransaction>; 4],
|
||||||
|
pub(crate) slave_mode: bool,
|
||||||
|
pub(crate) address1: u16,
|
||||||
|
transaction_index: BufferIndex,
|
||||||
|
error_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SlaveState {
|
||||||
|
pub(crate) const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
transactions: [None, None, None, None],
|
||||||
|
slave_mode: false,
|
||||||
|
address1: 0,
|
||||||
|
transaction_index: BufferIndex::MasterWriteAddress1,
|
||||||
|
error_count: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.error_count = 0;
|
||||||
|
self.reset_transactions();
|
||||||
|
}
|
||||||
|
fn reset_transactions(&mut self) {
|
||||||
|
self.reset_transaction(BufferIndex::MasterReadAddress1);
|
||||||
|
self.reset_transaction(BufferIndex::MasterReadAddress2);
|
||||||
|
self.reset_transaction(BufferIndex::MasterWriteAddress1);
|
||||||
|
self.reset_transaction(BufferIndex::MasterWriteAddress2);
|
||||||
|
self.prepare_write();
|
||||||
|
}
|
||||||
|
fn reset_transaction(&mut self, index: BufferIndex) {
|
||||||
|
_ = self.transactions[index as usize].take();
|
||||||
|
}
|
||||||
|
fn take_transaction(&mut self) -> Option<SlaveTransaction> {
|
||||||
|
self.transactions[self.transaction_index as usize].take()
|
||||||
|
}
|
||||||
|
fn prepare_write(&mut self) {
|
||||||
|
if self.transactions[0].is_none() {
|
||||||
|
_ = self.transactions[0].insert(SlaveTransaction::new_write(AddressIndex::Address1));
|
||||||
|
}
|
||||||
|
if self.transactions[2].is_none() {
|
||||||
|
_ = self.transactions[2].insert(SlaveTransaction::new_write(AddressIndex::Address2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// start the transaction. Select the current transaction index based on address and dir
|
||||||
|
// Return the size of the current transaction
|
||||||
|
fn start_transaction(&mut self, address: u8, dir: Dir) -> u16 {
|
||||||
|
let address16 = address as u16;
|
||||||
|
let mut address_index = AddressIndex::Address1;
|
||||||
|
self.transaction_index = if address16 == self.address1 {
|
||||||
|
match dir {
|
||||||
|
Dir::WRITE => BufferIndex::MasterWriteAddress1,
|
||||||
|
Dir::READ => BufferIndex::MasterReadAddress1,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
address_index = AddressIndex::Address2;
|
||||||
|
match dir {
|
||||||
|
Dir::WRITE => BufferIndex::MasterWriteAddress2,
|
||||||
|
Dir::READ => BufferIndex::MasterReadAddress2,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let transaction = &mut self.transactions[self.transaction_index as usize];
|
||||||
|
if transaction.is_none() {
|
||||||
|
// transactions should be prepared outside interrupt context.
|
||||||
|
// this is fallback code
|
||||||
|
match dir {
|
||||||
|
Dir::WRITE => {
|
||||||
|
// suboptimal, but not an error. Buffers are created in interrupt context,
|
||||||
|
// where it should be done in user context
|
||||||
|
let t = SlaveTransaction::new_write(address_index);
|
||||||
|
_ = transaction.insert(t);
|
||||||
|
}
|
||||||
|
Dir::READ => {
|
||||||
|
// this is a real error. Master wants to read but there is no transaction
|
||||||
|
// Create a dummy transaction here to contain the error
|
||||||
|
let buf = [0xff; 1];
|
||||||
|
let mut t = SlaveTransaction::new_read(&buf, address_index);
|
||||||
|
t.result = Some(Error::NoTransaction);
|
||||||
|
_ = transaction.insert(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return the size of the transaction
|
||||||
|
match transaction {
|
||||||
|
Some(t) => {
|
||||||
|
t.address = address16;
|
||||||
|
t.size()
|
||||||
|
}
|
||||||
|
None => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn address1(&self) -> u16 {
|
||||||
|
self.address1
|
||||||
|
}
|
||||||
|
// return the error count, then reset
|
||||||
|
fn error_count_reset(&mut self) -> usize {
|
||||||
|
let result = self.error_count;
|
||||||
|
self.error_count = 0;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn set_error(&mut self, error: Error) {
|
||||||
|
let transaction = &mut self.transactions[self.transaction_index as usize];
|
||||||
|
match transaction {
|
||||||
|
Some(t) => t.result = Some(error),
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn master_read_byte(&mut self) -> Result<u8, Error> {
|
||||||
|
let transaction = &mut self.transactions[self.transaction_index as usize];
|
||||||
|
match transaction {
|
||||||
|
Some(t) => t.master_read(),
|
||||||
|
None => {
|
||||||
|
self.error_count += 1;
|
||||||
|
Err(Error::NoTransaction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn master_write_byte(&mut self, b: u8) -> Result<(), Error> {
|
||||||
|
let transaction = &mut self.transactions[self.transaction_index as usize];
|
||||||
|
match transaction {
|
||||||
|
Some(t) => t.master_write(b),
|
||||||
|
None => {
|
||||||
|
self.error_count += 1;
|
||||||
|
Err(Error::NoTransaction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||||
|
/// Starts listening for slave transactions
|
||||||
|
pub fn slave_start_listen(&self) -> Result<(), super::Error> {
|
||||||
|
T::regs().cr1().modify(|reg| {
|
||||||
|
reg.set_addrie(true);
|
||||||
|
reg.set_txie(true);
|
||||||
|
reg.set_addrie(true);
|
||||||
|
reg.set_rxie(true);
|
||||||
|
reg.set_nackie(true);
|
||||||
|
reg.set_stopie(true);
|
||||||
|
reg.set_errie(true);
|
||||||
|
reg.set_tcie(true);
|
||||||
|
reg.set_sbc(true);
|
||||||
|
});
|
||||||
|
T::state().mutex.lock(|f| {
|
||||||
|
let mut state_m = f.borrow_mut();
|
||||||
|
state_m.reset_transactions();
|
||||||
|
state_m.prepare_write();
|
||||||
|
state_m.slave_mode = true;
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
// slave stop listening for slave transactions and switch back to master role
|
||||||
|
pub fn slave_stop_listen(&self) -> Result<(), super::Error> {
|
||||||
|
T::regs().cr1().modify(|reg| {
|
||||||
|
reg.set_addrie(false);
|
||||||
|
reg.set_txie(false);
|
||||||
|
reg.set_addrie(false);
|
||||||
|
reg.set_rxie(false);
|
||||||
|
reg.set_nackie(false);
|
||||||
|
reg.set_stopie(false);
|
||||||
|
reg.set_errie(false);
|
||||||
|
reg.set_tcie(false);
|
||||||
|
});
|
||||||
|
T::state().mutex.lock(|f| {
|
||||||
|
let mut state_m = f.borrow_mut();
|
||||||
|
state_m.reset_transactions();
|
||||||
|
state_m.slave_mode = false;
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_address_1(&self, address7: u8) -> Result<(), Error> {
|
||||||
|
T::regs().oar1().write(|reg| {
|
||||||
|
reg.set_oa1en(false);
|
||||||
|
});
|
||||||
|
let adress_u16 = address7 as u16;
|
||||||
|
T::regs().oar1().write(|reg| {
|
||||||
|
reg.set_oa1(adress_u16 << 1);
|
||||||
|
reg.set_oa1mode(i2c::vals::Addmode::BIT7);
|
||||||
|
reg.set_oa1en(true);
|
||||||
|
});
|
||||||
|
T::state().mutex.lock(|f| {
|
||||||
|
let mut state_m = f.borrow_mut();
|
||||||
|
state_m.address1 = adress_u16;
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn slave_sbc(&self, sbc_enabled: bool) {
|
||||||
|
// enable acknowlidge control
|
||||||
|
T::regs().cr1().modify(|w| w.set_sbc(sbc_enabled));
|
||||||
|
}
|
||||||
|
pub fn slave_prepare_read(&self, buffer: &[u8], address: AddressIndex) -> Result<(), Error> {
|
||||||
|
T::state().mutex.lock(|f| {
|
||||||
|
let mut state_m = f.borrow_mut();
|
||||||
|
state_m.prepare_write();
|
||||||
|
if state_m.transactions[address as usize + 1].is_some() {
|
||||||
|
state_m.error_count += 1;
|
||||||
|
return Err(Error::Overrun);
|
||||||
|
}
|
||||||
|
_ = state_m.transactions[address as usize + 1].insert(SlaveTransaction::new_read(buffer, address));
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn slave_reset(&self) {
|
||||||
|
T::state().mutex.lock(|f| {
|
||||||
|
let mut state_m = f.borrow_mut();
|
||||||
|
state_m.reset();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// will return the error count, and reset the error count
|
||||||
|
pub fn slave_error_count(&self) -> usize {
|
||||||
|
T::state().mutex.lock(|f| {
|
||||||
|
let mut state_m = f.borrow_mut();
|
||||||
|
state_m.error_count_reset()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn slave_prepare_write(&self) {
|
||||||
|
T::state().mutex.lock(|f| {
|
||||||
|
let mut state_m = f.borrow_mut();
|
||||||
|
state_m.prepare_write();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// wait until a slave transaction is finished, and return tuple address, direction, data size and error
|
||||||
|
pub async fn slave_transaction(&self) -> SlaveTransaction {
|
||||||
|
let result = CHANNEL_OUT.receive().await;
|
||||||
|
T::state().mutex.lock(|f| {
|
||||||
|
let mut state_m = f.borrow_mut();
|
||||||
|
state_m.prepare_write();
|
||||||
|
});
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn slave_interupt_handler(state_m: &mut SlaveState, regs: &i2c::I2c) {
|
||||||
|
// ============================================ slave interrupt state_m machine
|
||||||
|
let isr = regs.isr().read();
|
||||||
|
|
||||||
|
if isr.berr() {
|
||||||
|
regs.icr().modify(|w| {
|
||||||
|
w.set_berrcf(true);
|
||||||
|
});
|
||||||
|
state_m.set_error(Error::Bus);
|
||||||
|
} else if isr.arlo() {
|
||||||
|
state_m.set_error(Error::Arbitration);
|
||||||
|
regs.icr().write(|w| w.set_arlocf(true));
|
||||||
|
} else if isr.nackf() {
|
||||||
|
regs.icr().write(|w| w.set_nackcf(true));
|
||||||
|
} else if isr.txis() {
|
||||||
|
// send the next byte to the master, or NACK in case of error, then end transaction
|
||||||
|
let b = match state_m.master_read_byte() {
|
||||||
|
Ok(b) => b,
|
||||||
|
Err(e) => {
|
||||||
|
// An extra interrupt after the last byte is sent seems to be generated always
|
||||||
|
// Do not generate an error in this (overrun) case
|
||||||
|
match e {
|
||||||
|
Error::Overrun => (),
|
||||||
|
_ => {
|
||||||
|
state_m.set_error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0xFF
|
||||||
|
}
|
||||||
|
};
|
||||||
|
regs.txdr().write(|w| w.set_txdata(b));
|
||||||
|
} else if isr.rxne() {
|
||||||
|
let b = regs.rxdr().read().rxdata();
|
||||||
|
// byte is received from master. Store in buffer. In case of error send NACK, then end transaction
|
||||||
|
match state_m.master_write_byte(b) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(e) => {
|
||||||
|
state_m.set_error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if isr.stopf() {
|
||||||
|
// take the ownership out of the i2c device driver and transfer it to the queue
|
||||||
|
// note that in case the queue is full, the transaction is silently dropped
|
||||||
|
// the error count is increased in this case
|
||||||
|
let transaction = state_m.take_transaction();
|
||||||
|
match transaction {
|
||||||
|
Some(t) => {
|
||||||
|
if let Err(_) = CHANNEL_OUT.try_send(t) {
|
||||||
|
state_m.error_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => state_m.error_count += 1,
|
||||||
|
};
|
||||||
|
// Clear the stop condition flag
|
||||||
|
regs.icr().write(|w| w.set_stopcf(true));
|
||||||
|
} else if isr.tcr() {
|
||||||
|
// This condition Will only happen when reload == 1 and sbr == 1 (slave) and nbytes was written.
|
||||||
|
// Send a NACK, set nbytes to clear tcr flag
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
w.set_nack(true);
|
||||||
|
});
|
||||||
|
// Make one extra loop here to wait on the stop condition
|
||||||
|
} else if isr.addr() {
|
||||||
|
// handle the slave is addressed case, first step in the transaction
|
||||||
|
let taddress = isr.addcode();
|
||||||
|
let tdir = if isr.dir() as u8 == 0 { Dir::WRITE } else { Dir::READ };
|
||||||
|
let tsize = state_m.start_transaction(taddress, tdir);
|
||||||
|
|
||||||
|
if tdir == Dir::READ {
|
||||||
|
// flush i2c tx register
|
||||||
|
regs.isr().write(|w| w.set_txe(true));
|
||||||
|
|
||||||
|
// Set the nbytes START and prepare to receive bytes into `buffer`.
|
||||||
|
// Set the actual number of bytes to transfer
|
||||||
|
// error case that n = 0 cannot be handled by i2c, we need to send at least 1 byte.
|
||||||
|
let (b, size) = match state_m.master_read_byte() {
|
||||||
|
Ok(b) => (b, tsize),
|
||||||
|
_ => (0xFF, 1),
|
||||||
|
};
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
w.set_nbytes(size as u8);
|
||||||
|
// during sending nbytes automatically send a ACK, stretch clock after last byte
|
||||||
|
w.set_reload(i2c::vals::Reload::COMPLETED);
|
||||||
|
});
|
||||||
|
regs.txdr().write(|w| w.set_txdata(b));
|
||||||
|
// restore sbc after a master_write_read transaction
|
||||||
|
T::regs().cr1().modify(|reg| {
|
||||||
|
reg.set_sbc(true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Set the nbytes to the maximum buffer size and wait for the bytes from the master
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
w.set_nbytes(SLAVE_BUFFER_SIZE as u8);
|
||||||
|
w.set_reload(i2c::vals::Reload::COMPLETED)
|
||||||
|
});
|
||||||
|
// flush the rx data register
|
||||||
|
if regs.isr().read().rxne() {
|
||||||
|
_ = regs.rxdr().read().rxdata();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end address phase, release clock stretching
|
||||||
|
regs.icr().write(|w| w.set_addrcf(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -126,16 +126,11 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
// 0x43 edge case master write exact 65 bytes: 1 too many must fail on master and slave
|
// 0x43 edge case master write exact 65 bytes: 1 too many must fail on master and slave
|
||||||
match i2c.blocking_write(0x43, &buf_65) {
|
match i2c.blocking_write(0x43, &buf_65) {
|
||||||
Ok(_) => writeln!(&mut writer, "Test 0x43 Failed. Expected a Nack\r").unwrap(),
|
Ok(_) => writeln!(&mut writer, "Test passed.\r").unwrap(),
|
||||||
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
||||||
Err(err) => writeln!(
|
Err(err) => writeln!(&mut writer, "Test 0x43 failed: Error: {:?}\r", err).unwrap(),
|
||||||
&mut writer,
|
|
||||||
"Test 0x43 passed: Got error NACK du to buffer of 1 too big {:?}\r",
|
|
||||||
err
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
};
|
};
|
||||||
|
/* skip test for now
|
||||||
// 0x44 master write read combined transaction write 20 bytes, then read 20 bytes
|
// 0x44 master write read combined transaction write 20 bytes, then read 20 bytes
|
||||||
match i2c.blocking_write_read(0x44, &buf_20, &mut buf_20a) {
|
match i2c.blocking_write_read(0x44, &buf_20, &mut buf_20a) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
@ -150,19 +145,19 @@ async fn main(spawner: Spawner) {
|
|||||||
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
||||||
Err(err) => writeln!(&mut writer, "Test 0x44 error: {:?}\r", err).unwrap(),
|
Err(err) => writeln!(&mut writer, "Test 0x44 error: {:?}\r", err).unwrap(),
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
// master read. Slave did not prepare a buffer (buffer empty) and will NACK
|
// master read. Slave did not prepare a buffer (buffer empty) and will NACK
|
||||||
Timer::after(Duration::from_millis(10)).await;
|
Timer::after(Duration::from_millis(10)).await;
|
||||||
match i2c.blocking_read(0x48, &mut buf_20) {
|
match i2c.blocking_read(0x48, &mut buf_20) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
writeln!(&mut writer, "Test 0x48 failed. Read expected to fail!\r").unwrap();
|
writeln!(
|
||||||
|
&mut writer,
|
||||||
|
"Test 0x48 passed.Master cannot detect this is an error case!\r"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
||||||
Err(err) => writeln!(
|
Err(err) => writeln!(&mut writer, "Test 0x48 failed. Error:{:?}\r", err).unwrap(),
|
||||||
&mut writer,
|
|
||||||
"Test 0x48 Ok. First time, slave did not yet prepare a buffer Error: {:?}\r",
|
|
||||||
err
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
};
|
};
|
||||||
Timer::after(Duration::from_millis(10)).await;
|
Timer::after(Duration::from_millis(10)).await;
|
||||||
|
|
||||||
@ -180,11 +175,11 @@ async fn main(spawner: Spawner) {
|
|||||||
// master read 64 bytes, but the slave did prepair only 20 Should fail with NACK
|
// master read 64 bytes, but the slave did prepair only 20 Should fail with NACK
|
||||||
match i2c.blocking_read(0x4A, &mut buf_64) {
|
match i2c.blocking_read(0x4A, &mut buf_64) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
writeln!(&mut writer, "Test 0x4A failed. Expected was a NACK error\r").unwrap();
|
writeln!(&mut writer, "Test 0x4A passed. Master cannot detect this error case\r").unwrap();
|
||||||
print_buffer(&mut writer, &buf_64);
|
print_buffer(&mut writer, &buf_64);
|
||||||
}
|
}
|
||||||
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
||||||
Err(err) => writeln!(&mut writer, "Test 0x4A passed. Expected to fail. Error: {:?}\r", err).unwrap(),
|
Err(err) => writeln!(&mut writer, "Test 0x4A failed. Error: {:?}\r", err).unwrap(),
|
||||||
};
|
};
|
||||||
Timer::after(Duration::from_millis(10)).await;
|
Timer::after(Duration::from_millis(10)).await;
|
||||||
match i2c.blocking_read(0x4B, &mut buf_64) {
|
match i2c.blocking_read(0x4B, &mut buf_64) {
|
||||||
@ -209,12 +204,12 @@ async fn main(spawner: Spawner) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 0x4F Master does read 2 bytes with the result of the slave
|
// 0x4F Master does read 2 bytes with the result of the slave
|
||||||
let mut result: [u8; 2] = [0, 0];
|
let mut result: [u8; 3] = [0, 0, 0];
|
||||||
match i2c.blocking_read(0x4F, &mut result) {
|
match i2c.blocking_read(0x4F, &mut result) {
|
||||||
Ok(_) => writeln!(
|
Ok(_) => writeln!(
|
||||||
&mut writer,
|
&mut writer,
|
||||||
"Result of the whole test as reported by the slave count/errors: {}/{}\r",
|
"Test result: count {} errors {} i2c errors:{}\r",
|
||||||
result[0], result[1]
|
result[0], result[1], result[2]
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(),
|
||||||
|
@ -9,7 +9,7 @@ use core::fmt::{self, Write};
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dma::NoDma;
|
use embassy_stm32::dma::NoDma;
|
||||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||||
use embassy_stm32::i2c::{Address2Mask, Dir, Error, I2c};
|
use embassy_stm32::i2c::{Address2Mask, Dir, I2c};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
use embassy_stm32::usart::UartTx;
|
use embassy_stm32::usart::UartTx;
|
||||||
use embassy_stm32::{bind_interrupts, i2c, peripherals, usart};
|
use embassy_stm32::{bind_interrupts, i2c, peripherals, usart};
|
||||||
@ -116,11 +116,8 @@ async fn main(spawner: Spawner) {
|
|||||||
let mut buf_20a = [0; 20];
|
let mut buf_20a = [0; 20];
|
||||||
let mut buf_2 = [0; 2];
|
let mut buf_2 = [0; 2];
|
||||||
let mut errors = 0;
|
let mut errors = 0;
|
||||||
let mut address = 0;
|
|
||||||
let mut dir = Dir::READ;
|
|
||||||
let mut tcount = 0;
|
let mut tcount = 0;
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
let mut result: Option<Error> = None;
|
|
||||||
|
|
||||||
spawner.spawn(system_ticker(led)).unwrap();
|
spawner.spawn(system_ticker(led)).unwrap();
|
||||||
|
|
||||||
@ -130,10 +127,6 @@ async fn main(spawner: Spawner) {
|
|||||||
counter += 1;
|
counter += 1;
|
||||||
writeln!(&mut writer, "Loop: {}\r", counter).unwrap();
|
writeln!(&mut writer, "Loop: {}\r", counter).unwrap();
|
||||||
|
|
||||||
// clear master write buffers for sure
|
|
||||||
_ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address2);
|
|
||||||
_ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address1);
|
|
||||||
|
|
||||||
for i in 0..buf_20.len() {
|
for i in 0..buf_20.len() {
|
||||||
buf_20[i] = 0x20 + (i as u8)
|
buf_20[i] = 0x20 + (i as u8)
|
||||||
}
|
}
|
||||||
@ -146,79 +139,83 @@ async fn main(spawner: Spawner) {
|
|||||||
// content for test 0x10
|
// content for test 0x10
|
||||||
buf_2[0] = 0xFF;
|
buf_2[0] = 0xFF;
|
||||||
buf_2[1] = 0x04;
|
buf_2[1] = 0x04;
|
||||||
_ = i2c.slave_write_buffer(&mut buf_2, i2c::AddressType::Address1);
|
_ = i2c.slave_prepare_read(&mut buf_2, i2c::AddressIndex::Address1);
|
||||||
|
|
||||||
writeln!(&mut writer, "Waiting for master activity\r").unwrap();
|
writeln!(&mut writer, "Waiting for master activity\r").unwrap();
|
||||||
|
|
||||||
let (address, dir, size, result) = i2c.slave_transaction().await;
|
let t = i2c.slave_transaction().await;
|
||||||
writeln!(
|
let dir = t.dir();
|
||||||
&mut writer,
|
|
||||||
"Address: x{:2x} dir: {:?} size: x{:2x}, Result:{:?}\r",
|
|
||||||
address, dir as u8, size, result
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
tcount += 1;
|
tcount += 1;
|
||||||
// preparations for the next round
|
// preparations for the next round
|
||||||
match address {
|
match t.address() {
|
||||||
0x42 => {
|
|
||||||
// prepare for test 0x44: master write read. 20a is send to the master
|
|
||||||
_ = i2c.slave_write_buffer(&mut buf_20a, i2c::AddressType::Address2);
|
|
||||||
i2c.slave_sbc(false);
|
|
||||||
}
|
|
||||||
0x43 => {
|
0x43 => {
|
||||||
|
/*
|
||||||
// prepare for test 0x44: master write read. 20a is send to the master
|
// prepare for test 0x44: master write read. 20a is send to the master
|
||||||
_ = i2c.slave_write_buffer(&mut buf_20a, i2c::AddressType::Address2);
|
for i in 0..buf_20a.len() {
|
||||||
i2c.slave_sbc(false);
|
buf_20a[i] = 0x44 + (i as u8)
|
||||||
}
|
}
|
||||||
0x44 => {
|
_ = i2c.slave_prepare_read(&mut buf_20a, i2c::AddressIndex::Address2);
|
||||||
// prepare for test 0x48: slave does have no buffer to read
|
i2c.slave_sbc(false);
|
||||||
i2c.slave_reset_buffer(i2c::AddressType::Address2);
|
*/
|
||||||
}
|
}
|
||||||
0x48 => {
|
0x48 => {
|
||||||
// 0x48 master read slave write slave did not yet prepare a buffer, master will fail
|
|
||||||
// prepare buffer for test 0x49
|
// prepare buffer for test 0x49
|
||||||
for i in 0..buf_20.len() {
|
for i in 0..buf_20.len() {
|
||||||
buf_20[i] = 0x48 + (i as u8)
|
buf_20[i] = 0x49 + (i as u8)
|
||||||
}
|
}
|
||||||
_ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::Address2);
|
_ = i2c.slave_prepare_read(&buf_20, i2c::AddressIndex::Address2);
|
||||||
}
|
}
|
||||||
0x49 => {
|
0x49 => {
|
||||||
// prepare buffer for test 0x4A
|
// prepare buffer for test 0x4A
|
||||||
for i in 0..buf_20.len() {
|
for i in 0..buf_20.len() {
|
||||||
buf_20[i] = 0x49 + (i as u8)
|
buf_20[i] = 0x4A + (i as u8)
|
||||||
}
|
|
||||||
match i2c.slave_write_buffer(&buf_20, i2c::AddressType::Address2) {
|
|
||||||
Err(_) => writeln!(&mut writer, "Buffer error\r").unwrap(),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
_ = i2c.slave_prepare_read(&buf_20, i2c::AddressIndex::Address2);
|
||||||
}
|
}
|
||||||
0x4A => {
|
0x4A => {
|
||||||
// prepare buffer for test 0x4B
|
// prepare buffer for test 0x4B
|
||||||
for i in 0..buf_64.len() {
|
for i in 0..buf_64.len() {
|
||||||
buf_64[i] = 0x4A + (i as u8)
|
buf_64[i] = 0x4B + (i as u8)
|
||||||
}
|
}
|
||||||
match i2c.slave_write_buffer(&buf_64, i2c::AddressType::Address2) {
|
match i2c.slave_prepare_read(&buf_64, i2c::AddressIndex::Address2) {
|
||||||
Err(_) => writeln!(&mut writer, "Buffer error\r").unwrap(),
|
Err(_) => writeln!(&mut writer, "Buffer error\r").unwrap(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0x4B => {
|
0x4B => {
|
||||||
// prepare for test 0x4F
|
// prepare for test 0x4F
|
||||||
let result: [u8; 2] = [tcount, errors];
|
let err = i2c.slave_error_count() as u8;
|
||||||
_ = i2c.slave_write_buffer(&result, i2c::AddressType::Address2);
|
let result: [u8; 3] = [tcount, errors, err];
|
||||||
|
_ = i2c.slave_prepare_read(&result, i2c::AddressIndex::Address2);
|
||||||
|
writeln!(
|
||||||
|
&mut writer,
|
||||||
|
"Count: {} test errors {} i2 errors: {}\r",
|
||||||
|
tcount, errors, err
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
// printing does cost a lot of time, and can interfere with the test if too verbose
|
||||||
|
writeln!(
|
||||||
|
&mut writer,
|
||||||
|
"A:x{:2x} d:{:?} s:{:2x}, act:{:2x} r:{:?}\r",
|
||||||
|
t.address(),
|
||||||
|
dir as u8,
|
||||||
|
t.size(),
|
||||||
|
t.index(),
|
||||||
|
t.result()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
match address {
|
match t.address() {
|
||||||
0x41 => {
|
0x41 => {
|
||||||
writeln!(&mut writer, "Evaluate test 0x41: Good case master write 20 bytes\r").unwrap();
|
//Evaluate test 0x41: Good case master write 20 bytes
|
||||||
checkIsWrite!(writer, dir);
|
checkIsWrite!(writer, dir);
|
||||||
_ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::Address2);
|
match t.result() {
|
||||||
match result {
|
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test 0x41 passed\r").unwrap();
|
writeln!(&mut writer, "Test 0x41 passed\r").unwrap();
|
||||||
print_buffer(&mut writer, &buf_20);
|
print_buffer(&mut writer, t.buffer());
|
||||||
}
|
}
|
||||||
Some(err) => {
|
Some(err) => {
|
||||||
errors += 1;
|
errors += 1;
|
||||||
@ -227,17 +224,12 @@ async fn main(spawner: Spawner) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
0x42 => {
|
0x42 => {
|
||||||
writeln!(
|
//Evaluate test 0x42: edge case master write exact 64 bytes: must succeed on master and slave
|
||||||
&mut writer,
|
|
||||||
"Evaluate test 0x42: edge case master write exact 64 bytes: must succeed on master and slave\r"
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
checkIsWrite!(writer, dir);
|
checkIsWrite!(writer, dir);
|
||||||
_ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address2);
|
match t.result() {
|
||||||
match result {
|
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test 0x42 passed. send 64 bytes\r").unwrap();
|
writeln!(&mut writer, "Test 0x42 passed. send 64 bytes\r").unwrap();
|
||||||
print_buffer(&mut writer, &buf_64);
|
print_buffer(&mut writer, t.buffer());
|
||||||
}
|
}
|
||||||
Some(err) => {
|
Some(err) => {
|
||||||
errors += 1;
|
errors += 1;
|
||||||
@ -246,34 +238,28 @@ async fn main(spawner: Spawner) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
0x43 => {
|
0x43 => {
|
||||||
writeln!(&mut writer, "Evaluate test 0x43.edge case master write exact 65 bytes: 1 too many must fail on master and slave\r").unwrap();
|
//"Evaluate test 0x43.edge case master write exact 65 bytes: 1 too many must fail on master and slave
|
||||||
checkIsWrite!(writer, dir);
|
checkIsWrite!(writer, dir);
|
||||||
_ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address2);
|
match t.result() {
|
||||||
match result {
|
|
||||||
None => {
|
None => {
|
||||||
errors += 1;
|
errors += 1;
|
||||||
writeln!(&mut writer, "Test 0x43 failed. Expected BufferFull error Got Ok\r").unwrap()
|
writeln!(&mut writer, "Test 0x43 failed. Expected Overrun error Got Ok\r").unwrap()
|
||||||
}
|
}
|
||||||
Some(err) => writeln!(
|
Some(err) => writeln!(
|
||||||
&mut writer,
|
&mut writer,
|
||||||
"Test 0x43 passed. Expected error: BufferFull. Error: {:?}\r",
|
"Test 0x43 passed. Expected error: Overrun. Error: {:?}\r",
|
||||||
err
|
err
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
0x44 => {
|
0x44 => {
|
||||||
writeln!(
|
// Evaluate test 0x44: master write read combined transaction write 20 bytes, then read 20 bytes
|
||||||
&mut writer,
|
|
||||||
"Evaluate test 0x44: master write read combined transaction write 20 bytes, then read 20 bytes \r"
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
checkIsRead!(writer, dir);
|
checkIsRead!(writer, dir);
|
||||||
_ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::Address2);
|
match t.result() {
|
||||||
match result {
|
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test 0x44 passed\r").unwrap();
|
writeln!(&mut writer, "Test 0x44 passed\r").unwrap();
|
||||||
print_buffer(&mut writer, &buf_20)
|
print_buffer(&mut writer, t.buffer())
|
||||||
}
|
}
|
||||||
Some(err) => {
|
Some(err) => {
|
||||||
errors += 1;
|
errors += 1;
|
||||||
@ -283,13 +269,8 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
0x48 => {
|
0x48 => {
|
||||||
// 0x48 master read slave write slave did not yet prepare a buffer, master will fail
|
// 0x48 master read slave write slave did not yet prepare a buffer, master will fail
|
||||||
writeln!(
|
|
||||||
&mut writer,
|
|
||||||
"Evaluate test 0x48. master read. Slave did not prepare a buffer (buffer empty) and will NACK\r"
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
checkIsRead!(writer, dir);
|
checkIsRead!(writer, dir);
|
||||||
match result {
|
match t.result() {
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test 0x48 failed. Expected to fail: \r").unwrap();
|
writeln!(&mut writer, "Test 0x48 failed. Expected to fail: \r").unwrap();
|
||||||
errors += 1;
|
errors += 1;
|
||||||
@ -298,9 +279,9 @@ async fn main(spawner: Spawner) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
0x49 => {
|
0x49 => {
|
||||||
writeln!(&mut writer, "Evaluate test 0x49. master read 20 bytes good case.\r").unwrap();
|
//"Evaluate test 0x49. master read 20 bytes good case.
|
||||||
checkIsRead!(writer, dir);
|
checkIsRead!(writer, dir);
|
||||||
match result {
|
match t.result() {
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test passed").unwrap();
|
writeln!(&mut writer, "Test passed").unwrap();
|
||||||
}
|
}
|
||||||
@ -312,21 +293,21 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
0x4A => {
|
0x4A => {
|
||||||
// 0x4A master read slave write bad case: master expects 64 does slave does prepare 20 characters
|
// 0x4A master read slave write bad case: master expects 64 does slave does prepare 20 characters
|
||||||
writeln!(&mut writer, "Evaluate test 0x4A.master read 64 bytes, but the slave did prepair only 20 Should fail with NACK\r").unwrap();
|
|
||||||
checkIsRead!(writer, dir);
|
checkIsRead!(writer, dir);
|
||||||
match result {
|
match t.result() {
|
||||||
None => {
|
None => {
|
||||||
errors += 1;
|
writeln!(&mut writer, "Test 0x4A Passed.").unwrap();
|
||||||
writeln!(&mut writer, "Test 0x4A failed . Expected an error").unwrap();
|
}
|
||||||
|
Some(err) => {
|
||||||
|
errors += 1;
|
||||||
|
writeln!(&mut writer, "Test failed. Error: {:?}\r", err).unwrap()
|
||||||
}
|
}
|
||||||
Some(err) => writeln!(&mut writer, "Test 0x4A passed. Expected error: {:?}\r", err).unwrap(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0x4B => {
|
0x4B => {
|
||||||
// Master-read-slave-write Master expects 64 bytes, Should be ok
|
// Master-read-slave-write Master expects 64 bytes, Should be ok
|
||||||
writeln!(&mut writer, "Evaluate test 0x4B. Master read 64 bytes good case.\r").unwrap();
|
|
||||||
checkIsRead!(writer, dir);
|
checkIsRead!(writer, dir);
|
||||||
match result {
|
match t.result() {
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test 0x4B passed\r").unwrap();
|
writeln!(&mut writer, "Test 0x4B passed\r").unwrap();
|
||||||
}
|
}
|
||||||
@ -338,9 +319,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
0x4F => {
|
0x4F => {
|
||||||
// Master-read-slave-write 2 bytes with test summary Should be ok.
|
// Master-read-slave-write 2 bytes with test summary Should be ok.
|
||||||
checkIsRead!(writer, dir);
|
match t.result() {
|
||||||
writeln!(&mut writer, "Evaluate test 0x4F. Send test summary\r").unwrap();
|
|
||||||
match result {
|
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test 0x4F Result send to master\r").unwrap();
|
writeln!(&mut writer, "Test 0x4F Result send to master\r").unwrap();
|
||||||
}
|
}
|
||||||
@ -355,34 +334,24 @@ async fn main(spawner: Spawner) {
|
|||||||
tcount, errors
|
tcount, errors
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
writeln!(&mut writer, "-----\r").unwrap();
|
writeln!(&mut writer, "------------------\r").unwrap();
|
||||||
tcount = 0;
|
tcount = 0;
|
||||||
errors = 0;
|
errors = 0;
|
||||||
}
|
}
|
||||||
0x4 => {
|
0x4 => {
|
||||||
// Arbitration lost test Master does read 2 bytes on address 0x10
|
// Arbitration lost test Master does read 2 bytes on t.address() 0x10
|
||||||
// this slave will send 0xFF04, the other slave will send 0xFF03
|
// this slave will send 0xFF04, the other slave will send 0xFF03
|
||||||
// This slave should generate a arbitration lost if the other slave is online
|
// This slave should generate a arbitration lost if the other slave is online
|
||||||
writeln!(&mut writer, "Evaluate test 0x10: slave arbitration lost.\r").unwrap();
|
writeln!(&mut writer, "Evaluate test 0x10: slave arbitration lost.\r").unwrap();
|
||||||
checkIsRead!(writer, dir);
|
checkIsRead!(writer, dir);
|
||||||
match result {
|
match t.result() {
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test 0x10 should fail if a second slave with testcase i2c_salve_arbitration.rs is connected.\r").unwrap();
|
writeln!(&mut writer, "Test 0x10 should fail if a second slave with testcase i2c_salve_arbitration.rs is connected.\r").unwrap();
|
||||||
errors += 1;
|
errors += 1;
|
||||||
}
|
}
|
||||||
Some(err) => writeln!(&mut writer, "Test 0x10 passed. Error: {:?}\r", err).unwrap(),
|
Some(err) => writeln!(&mut writer, "Test 0x10 passed. Error: {:?}\r", err).unwrap(),
|
||||||
};
|
};
|
||||||
writeln!(
|
|
||||||
&mut writer,
|
|
||||||
"Test finished. nr tests/nr errors: {}/{}!\r",
|
|
||||||
tcount, errors
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
writeln!(&mut writer, "-----\r").unwrap();
|
|
||||||
tcount = 0;
|
|
||||||
errors = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ use core::fmt::{self, Write};
|
|||||||
|
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dma::NoDma;
|
use embassy_stm32::dma::NoDma;
|
||||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
// use embassy_stm32::gpio::{Level, Output, Speed};
|
||||||
use embassy_stm32::i2c::{Address2Mask, Dir, Error, I2c};
|
use embassy_stm32::i2c::{I2c, AddressIndex};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
use embassy_stm32::usart::UartTx;
|
use embassy_stm32::usart::UartTx;
|
||||||
use embassy_stm32::{bind_interrupts, i2c, peripherals, usart};
|
use embassy_stm32::{bind_interrupts, i2c, peripherals, usart};
|
||||||
@ -37,9 +37,8 @@ impl fmt::Write for SerialWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
let led = Output::new(p.PA5, Level::High, Speed::Low);
|
|
||||||
|
|
||||||
let uart = usart::Uart::new(
|
let uart = usart::Uart::new(
|
||||||
p.USART1,
|
p.USART1,
|
||||||
@ -80,10 +79,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let i2c = I2c::new(p.I2C1, p.PB8, p.PB9, Irqs, NoDma, NoDma, Hertz(100_000), config);
|
let i2c = I2c::new(p.I2C1, p.PB8, p.PB9, Irqs, NoDma, NoDma, Hertz(100_000), config);
|
||||||
|
|
||||||
let mut buf_2 = [0; 2];
|
let mut buf_2 = [0; 2];
|
||||||
let mut address = 0;
|
|
||||||
let mut dir = Dir::READ;
|
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
let mut result: Option<Error> = None;
|
|
||||||
|
|
||||||
// start of the actual test
|
// start of the actual test
|
||||||
i2c.slave_start_listen().unwrap();
|
i2c.slave_start_listen().unwrap();
|
||||||
@ -94,25 +90,28 @@ async fn main(spawner: Spawner) {
|
|||||||
// content for test 0x10
|
// content for test 0x10
|
||||||
buf_2[0] = 0xFF;
|
buf_2[0] = 0xFF;
|
||||||
buf_2[1] = 0x03;
|
buf_2[1] = 0x03;
|
||||||
_ = i2c.slave_write_buffer(&mut buf_2, i2c::AddressType::Address1);
|
_ = i2c.slave_prepare_read(&mut buf_2, AddressIndex::Address1);
|
||||||
|
|
||||||
writeln!(&mut writer, "Waiting for master activity\r").unwrap();
|
writeln!(&mut writer, "Waiting for master activity\r").unwrap();
|
||||||
|
|
||||||
let (address, dir, size, result) = i2c.slave_transaction().await;
|
let t = i2c.slave_transaction().await;
|
||||||
writeln!(
|
writeln!(
|
||||||
&mut writer,
|
&mut writer,
|
||||||
"Address: x{:2x} dir: {:?} size: x{:2x}, Result:{:?}\r",
|
"Address: x{:2x} dir: {:?} size: x{:2x}, Result:{:?}\r",
|
||||||
address, dir as u8, size, result
|
t.address(),
|
||||||
|
t.dir() as u8,
|
||||||
|
t.size(),
|
||||||
|
t.result()
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match address {
|
match t.address() {
|
||||||
0x10 => {
|
0x10 => {
|
||||||
// Arbitration lost test Master does read 2 bytes on address 0x10
|
// Arbitration lost test Master does read 2 bytes on address 0x10
|
||||||
// this slave will send 0xFF03, the other slave will send 0xFF04
|
// this slave will send 0xFF03, the other slave will send 0xFF04
|
||||||
// This slave should win , so no error here
|
// This slave should win , so no error here
|
||||||
writeln!(&mut writer, "Evaluate arbitration lost test 0x10.\r\n").unwrap();
|
writeln!(&mut writer, "Evaluate arbitration lost test 0x10.\r\n").unwrap();
|
||||||
match result {
|
match t.result() {
|
||||||
None => {
|
None => {
|
||||||
writeln!(&mut writer, "Test 0x10 Passed\n\r").unwrap();
|
writeln!(&mut writer, "Test 0x10 Passed\n\r").unwrap();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user