DMS and irq support for rp2040 lv_micropython

I’ve noticed that lv_micropython firmware for RP2040 does not support DMA (the SPI interface uses DMA for data transfer, but only in blocking mode). Also, there is no DMA IRQ support. So I modified the MicroPython source code (files: ports/rp2/machine_spi.c and extmod/machine_spi.c), but some problems occurred.

What I’ve done

I have added two extra functions to the ports/rp2/machine_spi.c file.
These functions will be used to set the DMA TX IRQ handler and enable the IRQ immediately.

I have tried three different approaches, and the ISR implementations are as follows (I placed cs.High() and flush_ready() inside the ISR):
image

1. ishard = false, using mp_irq_handler to call

In this scenario, I must call flush_ready() in flush_cb. However, cs.High() is not synchronized with the data—meaning it is called too late. If I remove flush_ready() from flush_cb, the ISR will not be triggered, and MicroPython will get blocked in flush_cb.

2. ishard = true, using mp_irq_handler to call

In this scenario, I must call flush_ready() in flush_cb, and cs.High() is triggered at the correct time. If I remove flush_ready() from flush_cb, the ISR will not be triggered, and MicroPython will get blocked in flush_cb.

3. ishard = true, using mp_call_function_1 to call (this means mp_sched_lock() and gc_lock() are not invoked)

In this scenario, flush_ready() and cs.High() are triggered at the correct time. However, MicroPython will stop responding after a few times.

Question

What happened, and how can I fix it? I think using mp_call_function_1 (without invoking mp_sched_lock() and gc_lock()) should be the correct approach, but it only works a few times.

Here you can find what I’ve done in micropython code:
http://fnos.feng-arch.cn:35128/fengqi/lv_micropython/pulls/1/files#diff-145b98f48b64fc48faaf3a8ef0f659962c5e319b

I just found I mis-spelled DMA to DMS, but It’s not important.

Through a daplink, I found method 3 might be correct solution. In this way (nlr_push and nlr_pop must be call), the firmware will work fine about 5 to 10 seconds, flush_ready will be called for several times. But it still blocked and died.

I tested DEBUG version firmware, this problem is more significant in debug firmware. IRQ function will be called 2 to 3 times, and then, it will be blocked in function where lvgl is waiting for flush_ready.