stm32/i2c: use one static per instance instead of an array.

This commit is contained in:
Dario Nieuwenhuis 2022-02-26 01:23:17 +01:00
parent 8d46d31824
commit e6299549a0
3 changed files with 29 additions and 45 deletions

View File

@ -21,9 +21,10 @@ pub enum Error {
}
pub(crate) mod sealed {
use super::*;
pub trait Instance: crate::rcc::RccPeripheral {
fn regs() -> crate::pac::i2c::I2c;
fn state_number() -> usize;
fn state() -> &'static State;
}
}
@ -36,24 +37,6 @@ pin_trait!(SdaPin, Instance);
dma_trait!(RxDma, Instance);
dma_trait!(TxDma, Instance);
macro_rules! i2c_state {
(I2C1) => {
0
};
(I2C2) => {
1
};
(I2C3) => {
2
};
(I2C4) => {
3
};
(I2C5) => {
4
};
}
crate::pac::interrupts!(
($inst:ident, i2c, $block:ident, EV, $irq:ident) => {
impl sealed::Instance for peripherals::$inst {
@ -61,8 +44,9 @@ crate::pac::interrupts!(
crate::pac::$inst
}
fn state_number() -> usize {
i2c_state!($inst)
fn state() -> &'static State {
static STATE: State = State::new();
&STATE
}
}

View File

@ -7,6 +7,14 @@ use crate::i2c::{Error, Instance, SclPin, SdaPin};
use crate::pac::i2c;
use crate::time::Hertz;
pub struct State {}
impl State {
pub(crate) const fn new() -> Self {
Self {}
}
}
pub struct I2c<'d, T: Instance> {
phantom: PhantomData<&'d mut T>,
}

View File

@ -13,31 +13,23 @@ use futures::future::poll_fn;
use crate::dma::NoDma;
use crate::gpio::sealed::AFType;
use crate::i2c::{Error, Instance, SclPin, SdaPin};
use crate::pac;
use crate::pac::i2c;
use crate::time::Hertz;
const I2C_COUNT: usize = pac::peripheral_count!(i2c);
pub struct State {
waker: [AtomicWaker; I2C_COUNT],
chunks_transferred: [AtomicUsize; I2C_COUNT],
waker: AtomicWaker,
chunks_transferred: AtomicUsize,
}
impl State {
const fn new() -> Self {
const AW: AtomicWaker = AtomicWaker::new();
const CT: AtomicUsize = AtomicUsize::new(0);
pub(crate) const fn new() -> Self {
Self {
waker: [AW; I2C_COUNT],
chunks_transferred: [CT; I2C_COUNT],
waker: AtomicWaker::new(),
chunks_transferred: AtomicUsize::new(0),
}
}
}
static STATE: State = State::new();
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
phantom: PhantomData<&'d mut T>,
tx_dma: TXDMA,
@ -108,9 +100,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let isr = regs.isr().read();
if isr.tcr() || isr.tc() {
let n = T::state_number();
STATE.chunks_transferred[n].fetch_add(1, Ordering::Relaxed);
STATE.waker[n].wake();
let state = T::state();
state.chunks_transferred.fetch_add(1, Ordering::Relaxed);
state.waker.wake();
}
// The flag can only be cleared by writting to nbytes, we won't do that here, so disable
// the interrupt
@ -411,8 +403,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
crate::dma::write(ch, request, bytes, dst)
};
let state_number = T::state_number();
STATE.chunks_transferred[state_number].store(0, Ordering::Relaxed);
let state = T::state();
state.chunks_transferred.store(0, Ordering::Relaxed);
let mut remaining_len = total_len;
let _on_drop = OnDrop::new(|| {
@ -445,8 +437,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
poll_fn(|cx| {
STATE.waker[state_number].register(cx.waker());
let chunks_transferred = STATE.chunks_transferred[state_number].load(Ordering::Relaxed);
state.waker.register(cx.waker());
let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
if chunks_transferred == total_chunks {
return Poll::Ready(());
@ -504,8 +496,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
crate::dma::read(ch, request, src, buffer)
};
let state_number = T::state_number();
STATE.chunks_transferred[state_number].store(0, Ordering::Relaxed);
let state = T::state();
state.chunks_transferred.store(0, Ordering::Relaxed);
let mut remaining_len = total_len;
let _on_drop = OnDrop::new(|| {
@ -530,8 +522,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
poll_fn(|cx| {
STATE.waker[state_number].register(cx.waker());
let chunks_transferred = STATE.chunks_transferred[state_number].load(Ordering::Relaxed);
state.waker.register(cx.waker());
let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
if chunks_transferred == total_chunks {
return Poll::Ready(());