lvgl / lv_binding_micropython

LVGL binding for MicroPython
MIT License
237 stars 156 forks source link

event_loop not working on raspberry pi (armv7) #273

Closed daviel closed 1 year ago

daviel commented 1 year ago

I found a really weird behavior with the current master branch and raspberry pi. When starting the event loop with the call event_loop = event_loop() you get an error code 22 (invalid argument).

  File "lv_utils.py", line 95, in __init__
  File "lv_timer.py", line 142, in init
  File "lv_timer.py", line 103, in timer_create
RuntimeError: timer_create_ error: -1 (errno = 22)

I took a look at the code and found the problem lies in the lv_timer.py implementation (SIGRTMIN = __libc_current_sigrtmin()). The value comes from the C-call __libc_current_sigrtmin (returns 34 on raspberry pi). When I change this value to 1 everything works as expected. The sigrtmax value is 64 btw.

On a x86-64 debian system I did not encounter this error. I think 34 should be the expected value here as the documentation from RT-Signals says the same.

I have built the native example from librt also and it is using also the sigrtmin value of 34 but in this case working as expected.

Any idea what exactly the problem is here?

amirgon commented 1 year ago

The value comes from the C-call __libc_current_sigrtmin (returns 34 on raspberry pi). When I change this value to 1 everything works as expected.

Maybe 34 is taken by some RP service? Could you try some other values? (35,36,etc.) One possibility is to re-try signals up to sigrtmax when getting an error. A simpler option is to handle RP differently on lv_utils.py and set default_timer_id. Today we set it differently for pyboard and rp2. Try to set it to 1 or 2 for example.

https://github.com/lvgl/lv_binding_micropython/blob/e4cc7668cd6ed170d71c874ab2ba15cc8804fd4a/lib/lv_utils.py#L49-L56

I have built the native example from librt also and it is using also the sigrtmin value of 34 but in this case working as expected.

So you are saying timer 34 still works in some cases? Maybe Micropython itself reserves timer 34, so it's not available when running under Micropython.
btw does SIGRTMIN on your C code has the same value as __libc_current_sigrtmin() (both 34?)

daviel commented 1 year ago

Yes this is what gets printed out in the c example:

Establishing handler for signal 34
Blocking signal 34
timer ID is 0xf6c598
Sleeping for 1 seconds
Unblocking signal 34
Caught signal 34
    sival_ptr = 0x7ef0958c;     *sival_ptr = 0xf6c598
    overrun count = 50022060
min signal __libc_current_sigrtmin: 34

I can run the c-program without problems even if MicroPython is running in parallel so MicroPython itself does not seem to block the signal.

I also wrote a for loop and set the ID manually in a range from -1 to 65 and found out that the timer_creation is only working for the id 1 and 2 using micropython.

daviel commented 1 year ago

Okay I think I found the problem.

The struct in the lv_timer is expecting a 64 bit system:

sigval_t = {
    "sival_int": 0 | uctypes.INT32,
    "sival_ptr": (0 | uctypes.PTR, uctypes.UINT8),
}

sigevent_t = {
    "sigev_value": (0, sigval_t),
    "sigev_signo": 8 | uctypes.INT32,
    "sigev_notify": 12 | uctypes.INT32,
}

The offset a sigev_signo is set to 8 but should be 4 on a 32 bit system. I will create a pull request to get it fixed.

amirgon commented 1 year ago

Okay I think I found the problem.

The struct in the lv_timer is expecting a 64 bit system:

This is great! Thank you. Indeed, pointer size is architecture dependent. I've merged your PR.