Added public interfaces for vals::Dir and vals::Oamsk, so they can be used outside the crate

This commit is contained in:
anton smeenk 2023-10-28 08:25:41 +02:00
parent 0fe0bc60fe
commit 26e37c673d
4 changed files with 97 additions and 55 deletions

View File

@ -1,5 +1,7 @@
#![macro_use] #![macro_use]
use stm32_metapac::i2c::vals;
use crate::interrupt; use crate::interrupt;
#[cfg_attr(i2c_v1, path = "v1.rs")] #[cfg_attr(i2c_v1, path = "v1.rs")]
@ -29,6 +31,50 @@ pub enum AddressType {
Address2, Address2,
} }
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum Address2Mask {
NOMASK,
MASK1,
MASK2,
MASK3,
MASK4,
MASK5,
MASK6,
MASK7,
}
impl Address2Mask {
#[inline(always)]
pub const fn to_vals_impl(self) -> vals::Oamsk {
match self {
Address2Mask::NOMASK => vals::Oamsk::NOMASK,
Address2Mask::MASK1 => vals::Oamsk::MASK1,
Address2Mask::MASK2 => vals::Oamsk::MASK2,
Address2Mask::MASK3 => vals::Oamsk::MASK3,
Address2Mask::MASK4 => vals::Oamsk::MASK4,
Address2Mask::MASK5 => vals::Oamsk::MASK5,
Address2Mask::MASK6 => vals::Oamsk::MASK6,
Address2Mask::MASK7 => vals::Oamsk::MASK7,
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum Dir {
WRITE,
READ,
}
impl Dir {
#[inline(always)]
pub const fn to_vals_impl(self) -> vals::Dir {
match self {
Dir::READ => vals::Dir::READ,
Dir::WRITE => vals::Dir::WRITE,
}
}
}
pub(crate) mod sealed { pub(crate) mod sealed {
use super::*; use super::*;
pub trait Instance: crate::rcc::RccPeripheral { pub trait Instance: crate::rcc::RccPeripheral {

View File

@ -22,7 +22,7 @@ use crate::dma::NoDma;
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::{AddressType, Error, Instance, SclPin, SdaPin}; use crate::i2c::{Address2Mask, AddressType, Dir, 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;
@ -48,8 +48,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
}); });
state_m.result = Some(Error::Bus); state_m.result = Some(Error::Bus);
} else if isr.arlo() { } else if isr.arlo() {
regs.icr().write(|w| w.set_arlocf(true));
state_m.result = Some(Error::Arbitration); state_m.result = Some(Error::Arbitration);
regs.icr().write(|w| w.set_arlocf(true));
} else if isr.nackf() { } else if isr.nackf() {
regs.icr().write(|w| w.set_nackcf(true)); regs.icr().write(|w| w.set_nackcf(true));
} else if isr.txis() { } else if isr.txis() {
@ -78,9 +78,12 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
} }
} else if isr.stopf() { } else if isr.stopf() {
// Clear the stop condition flag // Clear the stop condition flag
regs.icr().write(|w| w.set_stopcf(true));
state_m.ready = true; 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(); T::state().waker.wake();
regs.icr().write(|w| w.set_stopcf(true));
} else if isr.tcr() { } else if isr.tcr() {
// This condition Will only happen when reload == 1 and sbr == 1 (slave) and nbytes was written. // 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 // Send a NACK, set nbytes to clear tcr flag
@ -91,10 +94,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
} else if isr.addr() { } else if isr.addr() {
// handle the slave is addressed case, first step in the transaction // handle the slave is addressed case, first step in the transaction
state_m.current_address = isr.addcode(); state_m.current_address = isr.addcode();
state_m.dir = isr.dir(); state_m.dir = if isr.dir() as u8 == 0 { Dir::WRITE } else { Dir::READ };
state_m.result = None; state_m.result = None;
if state_m.dir == vals::Dir::READ { if state_m.dir == Dir::READ {
// Set the nbytes START and prepare to receive bytes into `buffer`. // Set the nbytes START and prepare to receive bytes into `buffer`.
regs.cr2().modify(|w| { regs.cr2().modify(|w| {
// Set number of bytes to transfer: maximum as all incoming bytes will be ACK'ed // Set number of bytes to transfer: maximum as all incoming bytes will be ACK'ed
@ -153,7 +156,7 @@ pub struct Config {
pub scl_pullup: bool, pub scl_pullup: bool,
pub slave_address_1: u16, pub slave_address_1: u16,
pub slave_address_2: u8, pub slave_address_2: u8,
pub slave_address_mask: vals::Oamsk, pub slave_address_mask: Address2Mask,
pub address_11bits: bool, pub address_11bits: bool,
#[cfg(feature = "time")] #[cfg(feature = "time")]
pub transaction_timeout: Duration, pub transaction_timeout: Duration,
@ -173,7 +176,7 @@ impl Config {
} }
/// Slave address 2 as 7 bit address in range 0 .. 127. /// Slave address 2 as 7 bit address in range 0 .. 127.
/// The mask makes all slaves within the mask addressable /// The mask makes all slaves within the mask addressable
pub fn slave_address_2(&mut self, address: u8, mask: vals::Oamsk) { pub fn slave_address_2(&mut self, address: u8, mask: Address2Mask) {
// assert!(address < (2 ^ 7)); // assert!(address < (2 ^ 7));
self.slave_address_2 = address; self.slave_address_2 = address;
self.slave_address_mask = mask; self.slave_address_mask = mask;
@ -186,7 +189,7 @@ impl Default for Config {
scl_pullup: false, scl_pullup: false,
slave_address_1: 0, slave_address_1: 0,
slave_address_2: 0, slave_address_2: 0,
slave_address_mask: vals::Oamsk::NOMASK, slave_address_mask: Address2Mask::NOMASK,
address_11bits: false, address_11bits: false,
#[cfg(feature = "time")] #[cfg(feature = "time")]
transaction_timeout: Duration::from_millis(100), transaction_timeout: Duration::from_millis(100),
@ -214,7 +217,10 @@ struct I2cStateMachine {
address1: u16, address1: u16,
ready: bool, ready: bool,
current_address: u8, current_address: u8,
dir: vals::Dir, 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 { impl I2cStateMachine {
pub(crate) const fn new() -> Self { pub(crate) const fn new() -> Self {
@ -228,8 +234,9 @@ impl I2cStateMachine {
slave_mode: false, slave_mode: false,
address1: 0, address1: 0,
current_address: 0, current_address: 0,
dir: vals::Dir::READ, dir: Dir::READ,
ready: false, ready: false,
transaction_result: (0, Dir::READ, 0, None),
} }
} }
fn read_byte(&mut self) -> Result<u8, Error> { fn read_byte(&mut self) -> Result<u8, Error> {
@ -238,7 +245,7 @@ impl I2cStateMachine {
} else { } else {
AddressType::Address2 AddressType::Address2
}; };
self.buffers[adress_type as usize][vals::Dir::READ as usize].master_read() self.buffers[adress_type as usize][Dir::READ as usize].master_read()
} }
fn write_byte(&mut self, b: u8) -> Result<(), Error> { fn write_byte(&mut self, b: u8) -> Result<(), Error> {
let adress_type = if self.address1 == self.current_address as u16 { let adress_type = if self.address1 == self.current_address as u16 {
@ -246,7 +253,7 @@ impl I2cStateMachine {
} else { } else {
AddressType::Address2 AddressType::Address2
}; };
self.buffers[adress_type as usize][vals::Dir::WRITE as usize].master_write(b) self.buffers[adress_type as usize][Dir::WRITE as usize].master_write(b)
} }
fn get_size(&self) -> u8 { fn get_size(&self) -> u8 {
let adress_type = if self.address1 == self.current_address as u16 { let adress_type = if self.address1 == self.current_address as u16 {
@ -420,7 +427,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
reg.set_oa2en(false); reg.set_oa2en(false);
}); });
T::regs().oar2().write(|reg| { T::regs().oar2().write(|reg| {
reg.set_oa2msk(config.slave_address_mask); reg.set_oa2msk(config.slave_address_mask.to_vals_impl());
reg.set_oa2(config.slave_address_2); reg.set_oa2(config.slave_address_2);
reg.set_oa2en(true); reg.set_oa2en(true);
}); });
@ -1079,6 +1086,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}); });
Ok(()) Ok(())
} }
pub fn set_address_1(&self, address7: u8) -> Result<(), Error> {
T::regs().oar1().modify(|reg| {
reg.set_oa1en(false);
});
T::regs().oar1().modify(|reg| {
reg.set_oa1(address7 as u16);
reg.set_oa1en(true);
});
T::state().mutex.lock(|f| {
let mut state_m = f.borrow_mut();
state_m.address1 = address7 as u16;
});
Ok(())
}
pub fn slave_sbc(&self, sbc_enabled: bool) { pub fn slave_sbc(&self, sbc_enabled: bool) {
// enable acknowlidge control // enable acknowlidge control
T::regs().cr1().modify(|w| w.set_sbc(sbc_enabled)); T::regs().cr1().modify(|w| w.set_sbc(sbc_enabled));
@ -1088,16 +1110,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
pub fn slave_write_buffer(&self, buffer: &[u8], address_type: AddressType) -> Result<(), super::Error> { pub fn slave_write_buffer(&self, buffer: &[u8], address_type: AddressType) -> Result<(), super::Error> {
T::state().mutex.lock(|f| { T::state().mutex.lock(|f| {
let mut state_m = f.borrow_mut(); let mut state_m = f.borrow_mut();
let buf = &mut state_m.buffers[address_type as usize][vals::Dir::READ as usize]; let buf = &mut state_m.buffers[address_type as usize][Dir::READ as usize];
buf.from_buffer(buffer) buf.from_buffer(buffer)
}) })
} }
pub fn slave_reset_buffer(&self, address_type: AddressType) { pub fn slave_reset_buffer(&self, address_type: AddressType) {
T::state().mutex.lock(|f| { T::state().mutex.lock(|f| {
let mut state_m = f.borrow_mut(); let mut state_m = f.borrow_mut();
let buf_r = &mut state_m.buffers[address_type as usize][vals::Dir::READ as usize]; let buf_r = &mut state_m.buffers[address_type as usize][Dir::READ as usize];
buf_r.reset(); buf_r.reset();
let buf_w = &mut state_m.buffers[address_type as usize][vals::Dir::WRITE as usize]; let buf_w = &mut state_m.buffers[address_type as usize][Dir::WRITE as usize];
buf_w.reset(); buf_w.reset();
}) })
} }
@ -1107,12 +1129,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
pub fn slave_read_buffer(&self, buffer: &mut [u8], address_type: AddressType) -> Result<(), super::Error> { pub fn slave_read_buffer(&self, buffer: &mut [u8], address_type: AddressType) -> Result<(), super::Error> {
T::state().mutex.lock(|f| { T::state().mutex.lock(|f| {
let mut state_m = f.borrow_mut(); let mut state_m = f.borrow_mut();
let buf = &mut state_m.buffers[address_type as usize][vals::Dir::WRITE as usize]; let buf = &mut state_m.buffers[address_type as usize][Dir::WRITE as usize];
buf.to_buffer(buffer) buf.to_buffer(buffer)
}) })
} }
/// wait until a slave transaction is finished, and return tuple address, direction, data size and error /// wait until a slave transaction is finished, and return tuple address, direction, data size and error
pub async fn slave_transaction(&self) -> (u8, vals::Dir, u8, Option<Error>) { pub async fn slave_transaction(&self) -> (u8, Dir, u8, Option<Error>) {
// async wait until addressed // async wait until addressed
poll_fn(|cx| { poll_fn(|cx| {
T::state().waker.register(cx.waker()); T::state().waker.register(cx.waker());
@ -1120,7 +1142,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let mut state_m = f.borrow_mut(); let mut state_m = f.borrow_mut();
if state_m.ready { if state_m.ready {
state_m.ready = false; state_m.ready = false;
return Poll::Ready((state_m.current_address, state_m.dir, state_m.get_size(), state_m.result)); return Poll::Ready(state_m.transaction_result);
} else { } else {
return Poll::Pending; return Poll::Pending;
} }

View File

@ -9,8 +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::{Error, I2c}; use embassy_stm32::i2c::{Address2Mask, Dir, Error, I2c};
use embassy_stm32::pac::i2c::vals;
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};
@ -25,7 +24,7 @@ bind_interrupts!(struct Irqs {
macro_rules! checkIsWrite { macro_rules! checkIsWrite {
($writer:ident, $direction:ident) => { ($writer:ident, $direction:ident) => {
match $direction { match $direction {
vals::Dir::WRITE => (), Dir::WRITE => (),
_ => { _ => {
write!($writer, "Error incorrect direction {:?}\r", $direction as usize).unwrap(); write!($writer, "Error incorrect direction {:?}\r", $direction as usize).unwrap();
continue; continue;
@ -36,7 +35,7 @@ macro_rules! checkIsWrite {
macro_rules! checkIsRead { macro_rules! checkIsRead {
($writer:ident, $direction:ident) => { ($writer:ident, $direction:ident) => {
match $direction { match $direction {
vals::Dir::READ => (), Dir::READ => (),
_ => { _ => {
write!($writer, "Error incorrect direction {:?}\r", $direction as usize).unwrap(); write!($writer, "Error incorrect direction {:?}\r", $direction as usize).unwrap();
continue; continue;
@ -108,7 +107,7 @@ async fn main(spawner: Spawner) {
let mut config = i2c::Config::default(); let mut config = i2c::Config::default();
config.slave_address_7bits(0x10); // for arbitration lost test config.slave_address_7bits(0x10); // for arbitration lost test
config.slave_address_2(0x41, vals::Oamsk::MASK4); config.slave_address_2(0x41, Address2Mask::MASK4);
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);
@ -116,9 +115,10 @@ async fn main(spawner: Spawner) {
let mut buf_20 = [0; 20]; // buffer is shorter than master will send: wait for STOP condition let mut buf_20 = [0; 20]; // buffer is shorter than master will send: wait for STOP condition
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 buf_1 = [0; 1];
let mut errors = 0; let mut errors = 0;
let mut address = 0; let mut address = 0;
let mut dir = vals::Dir::READ; 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; let mut result: Option<Error> = None;
@ -360,7 +360,7 @@ async fn main(spawner: Spawner) {
tcount = 0; tcount = 0;
errors = 0; errors = 0;
} }
0x10 => { 0x4 => {
// 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 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

View File

@ -10,12 +10,10 @@ 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::{Error, I2c}; use embassy_stm32::i2c::{Dir, Error, I2c};
use embassy_stm32::pac::i2c::vals;
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};
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs { bind_interrupts!(struct Irqs {
@ -23,29 +21,6 @@ bind_interrupts!(struct Irqs {
USART1 => usart::InterruptHandler<peripherals::USART1>; USART1 => usart::InterruptHandler<peripherals::USART1>;
}); });
macro_rules! checkIsWrite {
($writer:ident, $direction:ident) => {
match $direction {
vals::Dir::WRITE => (),
_ => {
write!($writer, "Error incorrect direction {:?}\r", $direction as usize).unwrap();
continue;
}
}
};
}
macro_rules! checkIsRead {
($writer:ident, $direction:ident) => {
match $direction {
vals::Dir::READ => (),
_ => {
write!($writer, "Error incorrect direction {:?}\r", $direction as usize).unwrap();
continue;
}
}
};
}
pub struct SerialWriter { pub struct SerialWriter {
tx: UartTx<'static, peripherals::USART1, peripherals::DMA1_CH1>, tx: UartTx<'static, peripherals::USART1, peripherals::DMA1_CH1>,
} }
@ -106,7 +81,7 @@ async fn main(spawner: Spawner) {
let mut buf_2 = [0; 2]; let mut buf_2 = [0; 2];
let mut address = 0; let mut address = 0;
let mut dir = vals::Dir::READ; let mut dir = Dir::READ;
let mut counter = 0; let mut counter = 0;
let mut result: Option<Error> = None; let mut result: Option<Error> = None;
@ -119,7 +94,7 @@ 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::MainAddress); _ = i2c.slave_write_buffer(&mut buf_2, i2c::AddressType::Address1);
writeln!(&mut writer, "Waiting for master activity\r").unwrap(); writeln!(&mut writer, "Waiting for master activity\r").unwrap();
@ -137,7 +112,6 @@ async fn main(spawner: Spawner) {
// 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();
checkIsRead!(writer, dir);
match result { match result {
None => { None => {
writeln!(&mut writer, "Test 0x10 Passed\n\r").unwrap(); writeln!(&mut writer, "Test 0x10 Passed\n\r").unwrap();