Skip to content

Commit

Permalink
Allow interrupt-driven MACRAW operation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pdh11 committed Apr 15, 2024
1 parent a45c33e commit d34ef05
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/raw_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,48 @@ impl<SpiBus: Bus> RawDevice<SpiBus> {
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.
///
/// # Args
Expand Down
3 changes: 3 additions & 0 deletions src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ pub mod common {
/// Register: INTLEVEL (Interrupt Low Level Timer Register) [R/W] [0x0013 – 0x0014] [0x0000]
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]
pub const RETRY_TIME: u16 = 0x19;

Expand Down

0 comments on commit d34ef05

Please sign in to comment.