Merge pull request #2854 from ericyanush/feat/add-bxcan-sleep-wakeup
Add stm32 bxCAN sleep/wakeup functionality
This commit is contained in:
commit
511bee7230
@ -67,12 +67,23 @@ pub struct SceInterruptHandler<T: Instance> {
|
|||||||
|
|
||||||
impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
// info!("sce irq");
|
info!("sce irq");
|
||||||
let msr = T::regs().msr();
|
let msr = T::regs().msr();
|
||||||
let msr_val = msr.read();
|
let msr_val = msr.read();
|
||||||
|
|
||||||
if msr_val.erri() {
|
if msr_val.slaki() {
|
||||||
msr.modify(|v| v.set_erri(true));
|
msr.modify(|m| m.set_slaki(true));
|
||||||
|
T::state().err_waker.wake();
|
||||||
|
} else if msr_val.erri() {
|
||||||
|
info!("Error interrupt");
|
||||||
|
// Disable the interrupt, but don't acknowledge the error, so that it can be
|
||||||
|
// forwarded off the the bus message consumer. If we don't provide some way for
|
||||||
|
// downstream code to determine that it has already provided this bus error instance
|
||||||
|
// to the bus message consumer, we are doomed to re-provide a single error instance for
|
||||||
|
// an indefinite amount of time.
|
||||||
|
let ier = T::regs().ier();
|
||||||
|
ier.modify(|i| i.set_errie(false));
|
||||||
|
|
||||||
T::state().err_waker.wake();
|
T::state().err_waker.wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,6 +191,10 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
w.set_fmpie(0, true);
|
w.set_fmpie(0, true);
|
||||||
w.set_fmpie(1, true);
|
w.set_fmpie(1, true);
|
||||||
w.set_tmeie(true);
|
w.set_tmeie(true);
|
||||||
|
w.set_bofie(true);
|
||||||
|
w.set_epvie(true);
|
||||||
|
w.set_ewgie(true);
|
||||||
|
w.set_lecie(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
T::regs().mcr().write(|w| {
|
T::regs().mcr().write(|w| {
|
||||||
@ -239,6 +254,50 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enables or disables the peripheral from automatically wakeup when a SOF is detected on the bus
|
||||||
|
/// while the peripheral is in sleep mode
|
||||||
|
pub fn set_automatic_wakeup(&mut self, enabled: bool) {
|
||||||
|
Registers(T::regs()).set_automatic_wakeup(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Manually wake the peripheral from sleep mode.
|
||||||
|
///
|
||||||
|
/// Waking the peripheral manually does not trigger a wake-up interrupt.
|
||||||
|
/// This will wait until the peripheral has acknowledged it has awoken from sleep mode
|
||||||
|
pub fn wakeup(&mut self) {
|
||||||
|
Registers(T::regs()).wakeup()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the peripheral is currently in sleep mode
|
||||||
|
pub fn is_sleeping(&self) -> bool {
|
||||||
|
T::regs().msr().read().slak()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Put the peripheral in sleep mode
|
||||||
|
///
|
||||||
|
/// When the peripherial is in sleep mode, messages can still be queued for transmission
|
||||||
|
/// and any previously received messages can be read from the receive FIFOs, however
|
||||||
|
/// no messages will be transmitted and no additional messages will be received.
|
||||||
|
///
|
||||||
|
/// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected
|
||||||
|
/// the peripheral will automatically wake and receive the incoming message.
|
||||||
|
pub async fn sleep(&mut self) {
|
||||||
|
T::regs().ier().modify(|i| i.set_slkie(true));
|
||||||
|
T::regs().mcr().modify(|m| m.set_sleep(true));
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
T::state().err_waker.register(cx.waker());
|
||||||
|
if self.is_sleeping() {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
T::regs().ier().modify(|i| i.set_slkie(false));
|
||||||
|
}
|
||||||
|
|
||||||
/// Queues the message to be sent.
|
/// Queues the message to be sent.
|
||||||
///
|
///
|
||||||
/// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
|
/// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
|
||||||
|
|||||||
@ -145,7 +145,21 @@ impl Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn curr_error(&self) -> Option<BusError> {
|
pub fn curr_error(&self) -> Option<BusError> {
|
||||||
let err = { self.0.esr().read() };
|
if !self.0.msr().read().erri() {
|
||||||
|
// This ensures that once a single error instance has
|
||||||
|
// been acknowledged and forwared to the bus message consumer
|
||||||
|
// we don't continue to re-forward the same error occurrance for an
|
||||||
|
// in-definite amount of time.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we have not already acknowledge the error, and the interrupt was
|
||||||
|
// disabled in the ISR, we will acknowledge the current error and re-enable the interrupt
|
||||||
|
// so futher errors are captured
|
||||||
|
self.0.msr().modify(|m| m.set_erri(true));
|
||||||
|
self.0.ier().modify(|i| i.set_errie(true));
|
||||||
|
|
||||||
|
let err = self.0.esr().read();
|
||||||
if err.boff() {
|
if err.boff() {
|
||||||
return Some(BusError::BusOff);
|
return Some(BusError::BusOff);
|
||||||
} else if err.epvf() {
|
} else if err.epvf() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user