docs: BLE Event handling seems to contradict general guidelines for IRQ handling
Documentation URL
https://docs.micropython.org/en/latest/library/bluetooth.html#event-handling
Description
In BLE event handling a suggestion is given to create copies of the ringbuffer parameters. This however, would violate the general guidelines given for interrupt routines which specifically warn against instantiating objects.
https://github.com/micropython/micropython/blob/99ac8193ea299e6d836b076149f561e58226ede6/docs/reference/isr_rules.rst?plain=1#L102
Code of Conduct
Yes, I agree
BLE panic in V1.19.1 but not in V1.18
BLE was always working well in V1.18, handling all work inside the IRQ.
In V19.1 it starts to crash, so I made a simple program to demonstrate the issue.
I removed the code from inside the IRQ and was trying to handle the events from outside.
With this code, just connect to the device to view the problem
<details>
<summary>Sample code</summary>
from time import sleep
import ubluetooth
from machine import disable_irq
from machine import enable_irq
def register(ble):
# Nordic UART Service (NUS)
NUS_UUID = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
RX_UUID = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
TX_UUID = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
BLE_NUS = ubluetooth.UUID(NUS_UUID)
BLE_RX = (ubluetooth.UUID(RX_UUID), ubluetooth.FLAG_WRITE)
BLE_TX = (ubluetooth.UUID(TX_UUID), ubluetooth.FLAG_NOTIFY)
BLE_UART = (BLE_NUS, (BLE_TX, BLE_RX,))
SERVICES = (BLE_UART,)
((tx, rx,),) = ble.gatts_register_services(SERVICES)
return tx, rx
def advertiser(ble, name):
name = bytes(name, 'UTF-8')
ble.gap_advertise(100, bytearray('\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name)
ble_irq_event = -1
ble_irq_data = bytes()
def bt_irq(event, data):
global ble_irq_event, ble_irq_data
ble_irq_event = event
ble_irq_data = data
print(f"IRQ {event} - {data}")
def main():
global ble_irq_event, ble_irq_data
last_irq_event = -1
last_irq_data = ble_irq_data
ble = ubluetooth.BLE()
ble.active(True)
ble.irq(bt_irq)
tx, rx = register(ble)
advertiser(ble, "foo")
while True:
sleep(0.2)
try:
got_new_state: bool = False
irq_state = disable_irq()
if ble_irq_event != last_irq_event or ble_irq_data != last_irq_data:
last_irq_event = ble_irq_event
last_irq_data = ble_irq_data
got_new_state = True
enable_irq(irq_state)
if not got_new_state:
continue
print(f"New event: {last_irq_event} - {last_irq_data}")
except Exception as e:
print(f"Error processing command - {e}")
main()
</details>
In V1.18
IRQ 1 - (0, 1, <memoryview>)
New event: 1 - (0, 1, <memoryview>)
IRQ 27 - (0, 6, 0, 500, 0)
New event: 27 - (0, 6, 0, 500, 0)
IRQ 21 - (0, 256)
IRQ 27 - (0, 36, 0, 500, 0)
In v1.19.1 (checked out few days ago)
IRQ 1 - (0, 1, <memoryview>)
Guru Meditation Error: Core 0 panic'ed (Interrupt wdt timeout on CPU0).
Core 0 register dump:
PC : 0x401d286e PS : 0x00060135 A0 : 0x800d2d9e A1 : 0x3ffbcfb0
A2 : 0x3ffc578c A3 : 0x00060120 A4 : 0x8009ab14 A5 : 0x3ffbced0
A6 : 0x00000003 A7 : 0x00060023 A8 : 0x80146bb1 A9 : 0x3ffbcfa0
A10 : 0x00000003 A11 : 0x00060123 A12 : 0x00060120 A13 : 0x0000cdcd
A14 : 0x00060023 A15 : 0x00060021 SAR : 0x0000001d EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000
Backtrace:0x401d286b:0x3ffbcfb00x400d2d9b:0x3ffbcfd0 0x40098bc8:0x3ffbcff0