Allow interrupt-driven MACRAW operation

This commit adds methods to RawDevice that enable interrupt-driven
operation. The enable_interrupt() method sets up SIMR so that
socket-level (internal) interrupts on Socket 0 cause chip-level
(external) interrupts (and as a convenience also sets S0_IR as
required). The disable_interrupt() method reverses those changes.
The clear_interrupt() method acknowledges all interrupts and is
intended to be called from the interrupt handler (or from thread mode
soon afterwards).

There is no change to existing functionality or operation if
enable_interrupt() is never called.

I did see PR#34 before filing this, but that change is focused on
TCP and UDP sockets, and my use case is MACRAW mode.

Tested on a W5500-Pico-EVB board with the RP2040 successfully receiving
and acting on active-low GPIO interrupts from W5500 via the INTn signal
on W5500 pin 36.
This commit is contained in:
Peter Hartley 2024-04-15 10:47:53 +01:00
commit d34ef053fd
2 changed files with 45 additions and 0 deletions

View file

@ -39,6 +39,48 @@ impl<SpiBus: Bus> RawDevice<SpiBus> {
Ok(Self { bus, raw_socket }) Ok(Self { bus, raw_socket })
} }
/// Enable one or more interrupts
///
/// # Args
/// * `which` - The interrupts to enable; see `register::socketn::Interrupt`
/// For instance, pass `Interrupt::Receive` to get interrupts
/// on packet reception only.
///
pub fn enable_interrupt(&mut self, which: u8) -> Result<(), SpiBus::Error> {
self.raw_socket.set_interrupt_mask(&mut self.bus, which)?;
self.bus.write_frame(
register::COMMON,
register::common::SOCKET_INTERRUPT_MASK,
&[1],
)?;
Ok(())
}
/// Clear pending interrupts
///
/// If using RTIC or similar, this should be called from the
/// interrupt handler. If not (i.e., if there's concern that this
/// use of the SPI bus will clobber someone else's use), then you
/// can mask the interrupt *at microcontroller level* in the
/// interrupt handler, then call this from thread mode before
/// unmasking again.
pub fn clear_interrupt(&mut self) -> Result<(), SpiBus::Error> {
self.raw_socket
.reset_interrupt(&mut self.bus, register::socketn::Interrupt::All)
}
/// Disable all interrupts
///
pub fn disable_interrupt(&mut self) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON,
register::common::SOCKET_INTERRUPT_MASK,
&[0],
)?;
self.raw_socket.set_interrupt_mask(&mut self.bus, 0xFF)?;
Ok(())
}
/// Read an ethernet frame from the device. /// Read an ethernet frame from the device.
/// ///
/// # Args /// # Args

View file

@ -22,6 +22,9 @@ pub mod common {
/// Register: INTLEVEL (Interrupt Low Level Timer Register) [R/W] [0x0013 0x0014] [0x0000] /// Register: INTLEVEL (Interrupt Low Level Timer Register) [R/W] [0x0013 0x0014] [0x0000]
pub const INTERRUPT_TIMER: u16 = 0x13; pub const INTERRUPT_TIMER: u16 = 0x13;
/// Register: SIMR (Socket Interrupt Mask Register) [R/W] [0x0018] [0x00]
pub const SOCKET_INTERRUPT_MASK: u16 = 0x18;
/// Register: RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0] /// Register: RTR (Retry Time-value Register) [R/W] [0x0019 0x001A] [0x07D0]
pub const RETRY_TIME: u16 = 0x19; pub const RETRY_TIME: u16 = 0x19;