I2C runtime ISR binding (#1376)
* I2C runtime ISR binding * CHANGELOG.md
This commit is contained in:
parent
21d833d2a3
commit
4aca01a7b6
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
if let Some(interrupt) = isr {
|
||||||
|
unsafe {
|
||||||
|
crate::interrupt::bind_interrupt(T::interrupt(), interrupt.handler());
|
||||||
|
crate::interrupt::enable(T::interrupt(), interrupt.priority()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i2c
|
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)]
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -33,6 +33,7 @@ fn main() -> ! {
|
|||||||
io.pins.gpio5,
|
io.pins.gpio5,
|
||||||
100.kHz(),
|
100.kHz(),
|
||||||
&clocks,
|
&clocks,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@ -50,6 +50,7 @@ fn main() -> ! {
|
|||||||
io.pins.gpio5,
|
io.pins.gpio5,
|
||||||
100.kHz(),
|
100.kHz(),
|
||||||
&clocks,
|
&clocks,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize display
|
// Initialize display
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user