mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-08 04:53:42 +00:00
esp32s3: replace inline ISR with full interrupt vector handler
Replace the minimal inline ISR (which only disabled INTENABLE) with a full level-1 interrupt handler that saves/restores the interrupted context and dispatches to Go's handleInterrupt. The handler uses callx4 (not callx0) to call into Go code because: - callx0 does not set PS.CALLINC, so the Go function's entry instruction uses stale CALLINC from the interrupted code, causing wrong window rotation and a garbage stack pointer. - callx4 explicitly sets CALLINC=1, and our frame pointer (a1) is outside the callee's register window so it is preserved. Also updates the USB Serial/JTAG ISR to disable INT_ENA (peripheral level) instead of relying on INTENABLE, and adds signalInterrupt to the dispatcher so sleepTicks can be woken by any interrupt.
This commit is contained in:
@@ -112,10 +112,11 @@ func (usbdev *USB_DEVICE) ensureConfigured() {
|
||||
}
|
||||
|
||||
// handleInterrupt is called from the CPU interrupt vector when the USB
|
||||
// peripheral raises an interrupt. For now, just clear the interrupt flag.
|
||||
// The actual data drain happens in Buffered() via polling — once the ISR
|
||||
// mechanism is proven, we can move the drain here.
|
||||
// peripheral raises an interrupt. Disable INT_ENA to prevent the
|
||||
// level-triggered interrupt from re-asserting immediately (data may
|
||||
// still be in the FIFO). Buffered() re-enables after draining.
|
||||
func (usbdev *USB_DEVICE) handleInterrupt() {
|
||||
usbdev.Bus.SetINT_ENA_SERIAL_OUT_RECV_PKT_INT_ENA(0)
|
||||
usbdev.Bus.SetINT_CLR_SERIAL_OUT_RECV_PKT_INT_CLR(1)
|
||||
}
|
||||
|
||||
@@ -162,7 +163,7 @@ func (usbdev *USB_DEVICE) Write(data []byte) (n int, err error) {
|
||||
|
||||
// Buffered returns the number of bytes waiting in the receive ring buffer.
|
||||
// It drains any data sitting in the hardware FIFO and re-enables the
|
||||
// USB interrupt (which the ISR disables via INTENABLE to prevent a
|
||||
// peripheral-level USB interrupt (which the ISR disables to prevent a
|
||||
// level-triggered interrupt storm).
|
||||
func (usbdev *USB_DEVICE) Buffered() int {
|
||||
usbdev.ensureConfigured()
|
||||
@@ -171,11 +172,9 @@ func (usbdev *USB_DEVICE) Buffered() int {
|
||||
b := byte(usbdev.Bus.EP1.Get())
|
||||
usbdev.Buffer.Put(b)
|
||||
}
|
||||
// Clear pending flags and re-enable the RX interrupt.
|
||||
// Clear pending flags and re-enable the RX interrupt at the peripheral level.
|
||||
usbdev.Bus.INT_CLR.Set(0xFFFFFFFF)
|
||||
usbdev.Bus.SetINT_ENA_SERIAL_OUT_RECV_PKT_INT_ENA(1)
|
||||
// Re-enable CPU interrupt 8 in INTENABLE (the ISR clears all bits).
|
||||
interrupt.New(cpuInterruptFromUSB, usbHandleInterrupt).Enable()
|
||||
return int(usbdev.Buffer.Used())
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,9 @@ func handleInterrupt() {
|
||||
}
|
||||
}
|
||||
|
||||
// Signal to sleepTicks that an interrupt has occurred.
|
||||
signalInterrupt()
|
||||
|
||||
inInterrupt = false
|
||||
}
|
||||
|
||||
@@ -180,6 +183,9 @@ func callHandler(n int) {
|
||||
//go:linkname callHandlers runtime/interrupt.callHandlers
|
||||
func callHandlers(num int)
|
||||
|
||||
//go:linkname signalInterrupt runtime.signalInterrupt
|
||||
func signalInterrupt()
|
||||
|
||||
var errInterruptRange = constError("interrupt for ESP32-S3 must be in range 6 through 30")
|
||||
|
||||
type constError string
|
||||
|
||||
Reference in New Issue
Block a user