Skip to content

soc_esp32::crosscore

Interrupting the other core.

The ESP32 has four “from CPU” interrupt sources. Each is a single bit in a DPORT register that any core may set, and it asserts a level-triggered interrupt source in the crossbar. Which core it lands on is decided by [crate::intr_map], not by which register was written: route the source in one core’s table and leave it parked in the other’s, and the signal is aimed.

Level-triggered, so the handler must clear the bit. Returning without calling [clear] re-enters it forever.

From soc/dport_reg.h and soc/soc.h at v4.4, read rather than recalled:

DPORT_CPU_INTR_FROM_CPU_0_REG DPORT + 0x0DC bit 0 source 24
DPORT_CPU_INTR_FROM_CPU_1_REG DPORT + 0x0E0 bit 0 source 25
DPORT_CPU_INTR_FROM_CPU_2_REG DPORT + 0x0E4 bit 0 source 26
DPORT_CPU_INTR_FROM_CPU_3_REG DPORT + 0x0E8 bit 0 source 27

esp-idf’s comments assign 0 and 1 to FreeRTOS’s own cross-core yield and 2 and 3 to IPC_ISR. FlintOS uses 2, which is the one esp-idf uses for the same job — parking the other core for a flash operation.

enum Signal {
FromCpu0,
FromCpu1,
FromCpu2,
FromCpu3,
}

Which of the four signals.

Implements: Clone, Copy, Debug, Eq, PartialEq, StructuralPartialEq

unsafe fn clear(signal: Signal)

Clear signal. A handler must do this, or it re-enters forever.

Writes a DPORT register.

References: Signal

unsafe fn raise(signal: Signal)

Raise signal, interrupting whichever core has its source routed.

Written straight through rather than via dport::write: the caller is about to disable its own cache, and everything from here to the release has to be reachable without one. A plain store to a DPORT register needs none of the erratum handling a read-modify-write does.

Writes a DPORT register. Raising a signal nothing has routed sets a bit that stays set.

References: Signal