I2C runtime ISR binding (#1376)

* I2C runtime ISR binding

* CHANGELOG.md
This commit is contained in:
Björn Quentin 2024-04-02 20:03:36 +02:00 committed by GitHub
parent 21d833d2a3
commit 4aca01a7b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 125 additions and 40 deletions

View File

@ -46,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- DMA channels can/have to be explicitly created for async or blocking drivers, added `set_interrupt_handler` to DMA channels, SPI, I2S, PARL_IO, don't enable interrupts on startup for DMA, I2S, PARL_IO, GPIO (#1300) - DMA channels can/have to be explicitly created for async or blocking drivers, added `set_interrupt_handler` to DMA channels, SPI, I2S, PARL_IO, don't enable interrupts on startup for DMA, I2S, PARL_IO, GPIO (#1300)
- UART: Rework `change_baud` so it is possible to set baud rate even after instantiation (#1350) - UART: Rework `change_baud` so it is possible to set baud rate even after instantiation (#1350)
- Runtime ISR binding for SHA,ECC and RSA (#1354) - Runtime ISR binding for SHA,ECC and RSA (#1354)
- Runtime ISR binding for I2C (#1376)
### Removed ### Removed

View File

@ -111,17 +111,12 @@ pub fn init(clocks: &Clocks, td: time_driver::TimerType) {
// only enable interrupts if the async feature is present // only enable interrupts if the async feature is present
#[cfg(feature = "async")] #[cfg(feature = "async")]
{ {
#[cfg(rmt)]
crate::interrupt::enable(Interrupt::RMT, Priority::min()).unwrap();
#[cfg(usb_device)] #[cfg(usb_device)]
crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap(); crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap();
crate::interrupt::enable(Interrupt::I2C_EXT0, Priority::min()).unwrap();
crate::interrupt::enable(Interrupt::GPIO, Priority::min()).unwrap();
#[cfg(twai0)] #[cfg(twai0)]
crate::interrupt::enable(Interrupt::TWAI0, Priority::min()).unwrap(); crate::interrupt::enable(Interrupt::TWAI0, Priority::min()).unwrap();
#[cfg(twai1)] #[cfg(twai1)]
crate::interrupt::enable(Interrupt::TWAI1, Priority::min()).unwrap(); crate::interrupt::enable(Interrupt::TWAI1, Priority::min()).unwrap();
} }

View File

@ -32,11 +32,14 @@
//! } //! }
//! ``` //! ```
use core::marker::PhantomData;
use fugit::HertzU32; use fugit::HertzU32;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::i2c0::{RegisterBlock, COMD}, peripherals::i2c0::{RegisterBlock, COMD},
system::PeripheralClockControl, system::PeripheralClockControl,
@ -183,12 +186,13 @@ enum Opcode {
} }
/// I2C peripheral container (I2C) /// I2C peripheral container (I2C)
pub struct I2C<'d, T> { pub struct I2C<'d, T, DM: crate::Mode> {
peripheral: PeripheralRef<'d, T>, peripheral: PeripheralRef<'d, T>,
phantom: PhantomData<DM>,
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<T> embedded_hal_02::blocking::i2c::Read for I2C<'_, T> impl<T, DM: crate::Mode> embedded_hal_02::blocking::i2c::Read for I2C<'_, T, DM>
where where
T: Instance, T: Instance,
{ {
@ -200,7 +204,7 @@ where
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<T> embedded_hal_02::blocking::i2c::Write for I2C<'_, T> impl<T, DM: crate::Mode> embedded_hal_02::blocking::i2c::Write for I2C<'_, T, DM>
where where
T: Instance, T: Instance,
{ {
@ -212,7 +216,7 @@ where
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<T> embedded_hal_02::blocking::i2c::WriteRead for I2C<'_, T> impl<T, DM: crate::Mode> embedded_hal_02::blocking::i2c::WriteRead for I2C<'_, T, DM>
where where
T: Instance, T: Instance,
{ {
@ -229,12 +233,12 @@ where
} }
#[cfg(feature = "embedded-hal")] #[cfg(feature = "embedded-hal")]
impl<T> embedded_hal::i2c::ErrorType for I2C<'_, T> { impl<T, DM: crate::Mode> embedded_hal::i2c::ErrorType for I2C<'_, T, DM> {
type Error = Error; type Error = Error;
} }
#[cfg(feature = "embedded-hal")] #[cfg(feature = "embedded-hal")]
impl<T> embedded_hal::i2c::I2c for I2C<'_, T> impl<T, DM: crate::Mode> embedded_hal::i2c::I2c for I2C<'_, T, DM>
where where
T: Instance, T: Instance,
{ {
@ -264,33 +268,18 @@ where
} }
} }
impl<'d, T> I2C<'d, T> impl<'d, T, DM: crate::Mode> I2C<'d, T, DM>
where where
T: Instance, T: Instance,
{ {
/// Create a new I2C instance fn new_internal<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin>(
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
clocks: &Clocks,
) -> Self {
Self::new_with_timeout(i2c, sda, scl, frequency, clocks, None)
}
/// Create a new I2C instance with a custom timeout value.
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_with_timeout<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin>(
i2c: impl Peripheral<P = T> + 'd, i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd, sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd, scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32, frequency: HertzU32,
clocks: &Clocks, clocks: &Clocks,
timeout: Option<u32>, timeout: Option<u32>,
isr: Option<InterruptHandler>,
) -> Self { ) -> Self {
crate::into_ref!(i2c, sda, scl); crate::into_ref!(i2c, sda, scl);
@ -301,7 +290,10 @@ where
_ => unreachable!(), // will never happen _ => unreachable!(), // will never happen
}); });
let mut i2c = I2C { peripheral: i2c }; let mut i2c = I2C {
peripheral: i2c,
phantom: PhantomData,
};
// avoid SCL/SDA going low during configuration // avoid SCL/SDA going low during configuration
scl.set_output_high(true); scl.set_output_high(true);
@ -321,10 +313,89 @@ where
i2c.peripheral.setup(frequency, clocks, timeout); i2c.peripheral.setup(frequency, clocks, timeout);
i2c if let Some(interrupt) = isr {
unsafe {
crate::interrupt::bind_interrupt(T::interrupt(), interrupt.handler());
crate::interrupt::enable(T::interrupt(), interrupt.priority()).unwrap();
}
}
i2c
}
}
impl<'d, T> I2C<'d, T, crate::Blocking>
where
T: Instance,
{
/// Create a new I2C instance
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
clocks: &Clocks,
isr: Option<InterruptHandler>,
) -> Self {
Self::new_with_timeout(i2c, sda, scl, frequency, clocks, None, isr)
}
/// Create a new I2C instance with a custom timeout value.
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_with_timeout<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
clocks: &Clocks,
timeout: Option<u32>,
isr: Option<InterruptHandler>,
) -> Self {
Self::new_internal(i2c, sda, scl, frequency, clocks, timeout, isr)
}
}
#[cfg(feature = "async")]
impl<'d, T> I2C<'d, T, crate::Async>
where
T: Instance,
{
/// Create a new I2C instance
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_async<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
clocks: &Clocks,
) -> Self {
Self::new_with_timeout_async(i2c, sda, scl, frequency, clocks, None)
}
/// Create a new I2C instance with a custom timeout value.
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_with_timeout_async<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
clocks: &Clocks,
timeout: Option<u32>,
) -> Self {
let handler = Some(match T::I2C_NUMBER {
0 => asynch::i2c0_handler,
#[cfg(i2c1)]
1 => asynch::i2c1_handler,
_ => panic!("Unexpected I2C peripheral"),
});
Self::new_internal(i2c, sda, scl, frequency, clocks, timeout, handler)
} }
#[cfg(feature = "async")]
pub(crate) fn inner(&self) -> &T { pub(crate) fn inner(&self) -> &T {
&self.peripheral &self.peripheral
} }
@ -341,7 +412,7 @@ mod asynch {
use embassy_futures::select::select; use embassy_futures::select::select;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal::i2c::Operation; use embedded_hal::i2c::Operation;
use procmacros::interrupt; use procmacros::handler;
use super::*; use super::*;
@ -418,7 +489,7 @@ mod asynch {
} }
} }
impl<T> I2C<'_, T> impl<T> I2C<'_, T, crate::Async>
where where
T: Instance, T: Instance,
{ {
@ -571,7 +642,7 @@ mod asynch {
} }
} }
impl<'d, T> embedded_hal_async::i2c::I2c for I2C<'d, T> impl<'d, T> embedded_hal_async::i2c::I2c for I2C<'d, T, crate::Async>
where where
T: Instance, T: Instance,
{ {
@ -604,8 +675,8 @@ mod asynch {
} }
} }
#[interrupt] #[handler]
fn I2C_EXT0() { pub(super) fn i2c0_handler() {
unsafe { &*crate::peripherals::I2C0::PTR } unsafe { &*crate::peripherals::I2C0::PTR }
.int_ena() .int_ena()
.modify(|_, w| w.end_detect().clear_bit().trans_complete().clear_bit()); .modify(|_, w| w.end_detect().clear_bit().trans_complete().clear_bit());
@ -619,8 +690,8 @@ mod asynch {
} }
#[cfg(i2c1)] #[cfg(i2c1)]
#[interrupt] #[handler]
fn I2C_EXT1() { pub(super) fn i2c1_handler() {
unsafe { &*crate::peripherals::I2C1::PTR } unsafe { &*crate::peripherals::I2C1::PTR }
.int_ena() .int_ena()
.modify(|_, w| w.end_detect().clear_bit().trans_complete().clear_bit()); .modify(|_, w| w.end_detect().clear_bit().trans_complete().clear_bit());
@ -636,6 +707,10 @@ mod asynch {
/// I2C Peripheral Instance /// I2C Peripheral Instance
pub trait Instance: crate::private::Sealed { pub trait Instance: crate::private::Sealed {
const I2C_NUMBER: usize;
fn interrupt() -> crate::peripherals::Interrupt;
fn scl_output_signal(&self) -> OutputSignal; fn scl_output_signal(&self) -> OutputSignal;
fn scl_input_signal(&self) -> InputSignal; fn scl_input_signal(&self) -> InputSignal;
fn sda_output_signal(&self) -> OutputSignal; fn sda_output_signal(&self) -> OutputSignal;
@ -1581,6 +1656,8 @@ fn write_fifo(register_block: &RegisterBlock, data: u8) {
} }
impl Instance for crate::peripherals::I2C0 { impl Instance for crate::peripherals::I2C0 {
const I2C_NUMBER: usize = 0;
#[inline(always)] #[inline(always)]
fn scl_output_signal(&self) -> OutputSignal { fn scl_output_signal(&self) -> OutputSignal {
OutputSignal::I2CEXT0_SCL OutputSignal::I2CEXT0_SCL
@ -1609,10 +1686,16 @@ impl Instance for crate::peripherals::I2C0 {
fn i2c_number(&self) -> usize { fn i2c_number(&self) -> usize {
0 0
} }
fn interrupt() -> crate::peripherals::Interrupt {
crate::peripherals::Interrupt::I2C_EXT0
}
} }
#[cfg(i2c1)] #[cfg(i2c1)]
impl Instance for crate::peripherals::I2C1 { impl Instance for crate::peripherals::I2C1 {
const I2C_NUMBER: usize = 1;
#[inline(always)] #[inline(always)]
fn scl_output_signal(&self) -> OutputSignal { fn scl_output_signal(&self) -> OutputSignal {
OutputSignal::I2CEXT1_SCL OutputSignal::I2CEXT1_SCL
@ -1641,6 +1724,10 @@ impl Instance for crate::peripherals::I2C1 {
fn i2c_number(&self) -> usize { fn i2c_number(&self) -> usize {
1 1
} }
fn interrupt() -> crate::peripherals::Interrupt {
crate::peripherals::Interrupt::I2C_EXT1
}
} }
#[cfg(lp_i2c0)] #[cfg(lp_i2c0)]

View File

@ -42,7 +42,7 @@ async fn main(_spawner: Spawner) {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let i2c0 = I2C::new( let i2c0 = I2C::new_async(
peripherals.I2C0, peripherals.I2C0,
io.pins.gpio4, io.pins.gpio4,
io.pins.gpio5, io.pins.gpio5,

View File

@ -33,6 +33,7 @@ fn main() -> ! {
io.pins.gpio5, io.pins.gpio5,
100.kHz(), 100.kHz(),
&clocks, &clocks,
None,
); );
loop { loop {

View File

@ -50,6 +50,7 @@ fn main() -> ! {
io.pins.gpio5, io.pins.gpio5,
100.kHz(), 100.kHz(),
&clocks, &clocks,
None,
); );
// Initialize display // Initialize display