← index #6957PR #12837
Related · high · value 3.293
QUERY · ISSUE

rp2: Crash with hard pin IRQ

openby peterhinchopened 2021-02-24updated 2021-05-05
bugport-rp2

Measuring hard IRQ latency with this script:

from machine import Pin, PWM
from time import sleep_ms
import math
# Link 16-17, time 16-18
pin18 = Pin(18, Pin.OUT)

def callback(_):
    pin18(1)  # Trigger
    pin18(0)

pin17 = Pin(17, Pin.IN)
_ = pin17.irq(callback, trigger=Pin.IRQ_RISING, hard=True)

pwm = PWM(Pin(16))
pwm.freq(1000)
pwm.duty_u16(0xffff // 2)

while True:
    y = 0
    for x in range(100):
        y += math.sin(x * 2 * math.pi/100)  # 6.2ms of busywork
    sleep_ms(10)

The usual latency was a creditable 25μs, but I have measured 100μs. It was not practicable to measure a worst case because the the machine suffers a hard crash usually almost immediately. If I comment out the busywork, leaving just the sleep_ms(10), it runs indefinitely with about 20μs latency.

CANDIDATE · PULL REQUEST

port/rp2: Make tickless, remove 1ms timeout when idle.

mergedby projectgusopened 2023-10-31updated 2024-11-01
port-rp2

The main motivation for doing this was to reduce the latency when the system is woken by a USB interrupt. The best_effort_wfe_or_timeout() function calls into the pico-sdk dynamic timer framework which sets up a new dynamic timer instance each time, and then has to tear it down before continuing after a WFE.

Testing Python interrupt latency it seems to improved by about 12us (from average of 46us to 34us running a Pin IRQ). C-based "scheduled nodes" should see even lower latency.

Test code was:

import machine
from machine import Pin

i = Pin(2, Pin.IN, Pin.PULL_UP)
o = Pin(3, Pin.OUT)

def handler(_):
    o(1)
    print('!')
    o(0)

i.irq(handler, Pin.IRQ_FALLING)

while True:
    machine.idle()

With latency measured using logic analyzer:

LA Capture of the above in pulseview

(Channel 0 is "i", Channel is "o". Please excuse noisy CH0, was triggering with a button. Time 0 is the first falling edge of channel 0.)

The risk with this change is that it exposes cases where a driver expects execution to continue without an interrupt. Alternative is to enable the standard ARM SysTick interrupt to wake the CPU at tick intervals. (There is a branch with SysTick enabled and working, but testing shows tickless is just as functional.)

This work was funded through GitHub Sponsors.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied