Closed spierepf closed 4 years ago
@amirgon Can you look at this?
My first thought was limited memory size on the DOIT, so I tried to build for my LOLIN D32 PRO. I got essentially the same result Here is the script I used to build/deploy on the PRO in case thatis helpful:
#!/bin/bash
export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin
git clone --recurse-submodules https://github.com/littlevgl/lv_micropython.git
UPY_SOURCE=$HOME/lv_micropython
cd $UPY_SOURCE
ESP_IDF_HASH=`make -C ports/esp32/ | grep v3.3 | cut -d' ' -f5`
cd $HOME/esp-idf
git checkout $ESP_IDF_HASH
git submodule update --init --recursive
cd $UPY_SOURCE
cat <<EOF >ports/esp32/partitions-16MiB.csv
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 0x200000,
vfs, data, fat, 0x210000, 0xdf0000,
EOF
make PYTHON=python3 ESPIDF=$HOME/esp-idf LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_SPIRAM PART_SRC=partitions-16MiB.csv -C mpy-cross
make PYTHON=python3 ESPIDF=$HOME/esp-idf LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_SPIRAM PART_SRC=partitions-16MiB.csv -C ports/esp32 erase
make PYTHON=python3 ESPIDF=$HOME/esp-idf LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_SPIRAM PART_SRC=partitions-16MiB.csv -C ports/esp32 deploy
Thanks for reporting this @spierepf.
When micropython soft-resets, it deallocates all the ram that was allocated by gc. lvgl is taking advantage of micropython's gc but today it is not aware of the soft reset, therefore after soft reset lvgl holds invalid pointers.
I can use a callback to trigger something upon soft reset (MICROPY_PORT_DEINIT_FUNC
). After soft reset lvgl needs to be "de-initialized" in order to set lv_initialized
to false.
This way, when calling lv_init
again after soft reset, lvgl would allocate all memories again.
@kisvegabor - Do you agree to add such de-init function? I think it's important to do it on v6 to fix this bug, and it does not break backward compatibility.
@amirgon The fix doesn't sound too complicated. Assuming that @kisvegabor considers this an appropriate fix, would you mind if I take a crack at it and submttted a PR? I'd like to contribute, even in a small way.
Assuming that @kisvegabor considers this an appropriate fix, would you mind if I take a crack at it and submttted a PR? I'd like to contribute, even in a small way.
Sure, go for it!
This is not enough, though.
The following would need to be handled as well upon soft reset (a call to MICROPY_PORT_DEINIT_FUNC
):
This is not enough, though.
Looking at this again - it's a bit more complicated.
It's not enough to set lv_initialized
to false, we also need to reset all gc root variables.
In order to state all gc roots only once, it would require some preprocessor trickery.
Can't the processor just be restarted fully, like any other device? That's how most other applications would handle this. It also solves the problem of resetting LittlevGL cleanly.
Can't the processor just be restarted fully, like any other device? That's how most other applications would handle this. It also solves the problem of resetting LittlevGL cleanly.
Of course - that is called "hard reset". It works well and this is what I usually do when I want to "restart". However, this issue was opened on soft reset. Apparently there are some applications that require this instead of a hard reset (it's probably quicker)
Implemented on:
(After lvgl PR is accepted I'll push the others)
This adds support for soft reset on lvgl, lvesp32, ili9341 and xpt2046 (micropython drivers) . Every driver needs to take soft reset into account in order to free resources (such as DMA memory, SPI bus etc).
There is one open issue, however. When using ili9341 with double buffer, there is a heap corruption when trying to free the DMA memory. This only happens with double buffer, only when lvgl is actually using the buffer, so I suspect there's some code in lvgl that corrupts the heap somewhere around the display buffer when using double buffer.
In the meanwhile, for cases where soft reset is important, a workaround is to use a single buffer (I've added double_buffer
named argument to ili9341
so this could be controlled by the user).
This only happens with double buffer, only when lvgl is actually using the buffer, so I suspect there's some code in lvgl that corrupts the heap somewhere around the display buffer when using double buffer.
Do you know if this happens without MicroPython (i.e. with a C driver)?
Do you know if this happens without MicroPython (i.e. with a C driver)?
No, actually I'm only working with Micropython and a micropython driver.
On C (without micropython) there is no way to remove a driver and no point deallocating the buffer, so I wouldn't be surprised that no one ever tried this.
btw, I've noticed someone requested a deinit function on the forum, so that might be useful for C as well. At least as a way to reduce RAM consumption, since power/performance can be reduced in other ways.
(After lvgl PR is accepted I'll push the others)
Pushed to lv_binding_micropython
and lv_micropython
.
Please let me know if you see further problems.
Otherwise, I think this can be closed.
Maybe a new issue could be opened on the heap corruption, but for now I haven't proved yet this is an lvgl problem (really hard to debug that one).
I really appreciate the effort. This is a very cool project. Unfortunately I cannot check out the code any longer:
$ git clone --recurse-submodules https://github.com/littlevgl/lv_micropython.git
Cloning into 'lv_micropython'...
remote: Enumerating objects: 76715, done.
remote: Total 76715 (delta 0), reused 0 (delta 0), pack-reused 76715
Receiving objects: 100% (76715/76715), 53.04 MiB | 6.06 MiB/s, done.
Resolving deltas: 100% (55415/55415), done.
Submodule 'lib/asf4' (https://github.com/adafruit/asf4) registered for path 'lib/asf4'
Submodule 'lib/axtls' (https://github.com/pfalcon/axtls) registered for path 'lib/axtls'
Submodule 'lib/berkeley-db-1.xx' (https://github.com/pfalcon/berkeley-db-1.xx) registered for path 'lib/berkeley-db-1.xx'
Submodule 'lib/libffi' (https://github.com/atgreen/libffi) registered for path 'lib/libffi'
Submodule 'lib/lv_bindings' (https://github.com/littlevgl/lv_bindings.git) registered for path 'lib/lv_bindings'
Submodule 'lib/lwip' (https://git.savannah.gnu.org/r/lwip.git) registered for path 'lib/lwip'
Submodule 'lib/mbedtls' (https://github.com/ARMmbed/mbedtls.git) registered for path 'lib/mbedtls'
Submodule 'lib/mynewt-nimble' (https://github.com/apache/mynewt-nimble.git) registered for path 'lib/mynewt-nimble'
Submodule 'lib/nrfx' (https://github.com/NordicSemiconductor/nrfx.git) registered for path 'lib/nrfx'
Submodule 'lib/stm32lib' (https://github.com/micropython/stm32lib) registered for path 'lib/stm32lib'
Submodule 'lib/tinyusb' (https://github.com/hathach/tinyusb) registered for path 'lib/tinyusb'
Cloning into '/home/build/lv_micropython/lib/asf4'...
remote: Enumerating objects: 1520, done.
remote: Total 1520 (delta 0), reused 0 (delta 0), pack-reused 1520
Receiving objects: 100% (1520/1520), 1.75 MiB | 4.86 MiB/s, done.
Resolving deltas: 100% (928/928), done.
Cloning into '/home/build/lv_micropython/lib/axtls'...
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 3191 (delta 0), reused 1 (delta 0), pack-reused 3190
Receiving objects: 100% (3191/3191), 3.81 MiB | 5.76 MiB/s, done.
Resolving deltas: 100% (2342/2342), done.
Cloning into '/home/build/lv_micropython/lib/berkeley-db-1.xx'...
remote: Enumerating objects: 270, done.
remote: Total 270 (delta 0), reused 0 (delta 0), pack-reused 270
Receiving objects: 100% (270/270), 332.23 KiB | 1.94 MiB/s, done.
Resolving deltas: 100% (127/127), done.
Cloning into '/home/build/lv_micropython/lib/libffi'...
remote: Enumerating objects: 12491, done.
remote: Total 12491 (delta 0), reused 0 (delta 0), pack-reused 12491
Receiving objects: 100% (12491/12491), 7.37 MiB | 6.04 MiB/s, done.
Resolving deltas: 100% (7833/7833), done.
Cloning into '/home/build/lv_micropython/lib/lv_bindings'...
remote: Enumerating objects: 41, done.
remote: Counting objects: 100% (41/41), done.
remote: Compressing objects: 100% (31/31), done.
remote: Total 1100 (delta 19), reused 26 (delta 10), pack-reused 1059
Receiving objects: 100% (1100/1100), 1.14 MiB | 5.28 MiB/s, done.
Resolving deltas: 100% (649/649), done.
Cloning into '/home/build/lv_micropython/lib/lwip'...
remote: Counting objects: 53114, done.
remote: Compressing objects: 100% (12606/12606), done.
remote: Total 53114 (delta 40017), reused 52862 (delta 39850)
Receiving objects: 100% (53114/53114), 10.17 MiB | 5.86 MiB/s, done.
Resolving deltas: 100% (40017/40017), done.
Cloning into '/home/build/lv_micropython/lib/mbedtls'...
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 95218 (delta 2), reused 3 (delta 0), pack-reused 95207
Receiving objects: 100% (95218/95218), 41.92 MiB | 6.25 MiB/s, done.
Resolving deltas: 100% (73631/73631), done.
Cloning into '/home/build/lv_micropython/lib/mynewt-nimble'...
remote: Enumerating objects: 124, done.
remote: Counting objects: 100% (124/124), done.
remote: Compressing objects: 100% (111/111), done.
remote: Total 37081 (delta 70), reused 17 (delta 5), pack-reused 36957
Receiving objects: 100% (37081/37081), 10.80 MiB | 6.25 MiB/s, done.
Resolving deltas: 100% (22269/22269), done.
Cloning into '/home/build/lv_micropython/lib/nrfx'...
remote: Enumerating objects: 1882, done.
remote: Total 1882 (delta 0), reused 0 (delta 0), pack-reused 1882
Receiving objects: 100% (1882/1882), 3.16 MiB | 5.38 MiB/s, done.
Resolving deltas: 100% (1478/1478), done.
Cloning into '/home/build/lv_micropython/lib/stm32lib'...
remote: Enumerating objects: 3191, done.
remote: Total 3191 (delta 0), reused 0 (delta 0), pack-reused 3191
Receiving objects: 100% (3191/3191), 10.42 MiB | 5.70 MiB/s, done.
Resolving deltas: 100% (2449/2449), done.
Cloning into '/home/build/lv_micropython/lib/tinyusb'...
remote: Enumerating objects: 385, done.
remote: Counting objects: 100% (385/385), done.
remote: Compressing objects: 100% (214/214), done.
remote: Total 39260 (delta 208), reused 265 (delta 142), pack-reused 38875
Receiving objects: 100% (39260/39260), 27.33 MiB | 5.97 MiB/s, done.
Resolving deltas: 100% (27312/27312), done.
Submodule path 'lib/asf4': checked out 'd270f79aa16dd8fd4ae3b6c14544283dcb992e9c'
Submodule path 'lib/axtls': checked out '43a6e6bd3bbc03dc501e16b89fba0ef042ed3ea0'
Submodule path 'lib/berkeley-db-1.xx': checked out '35aaec4418ad78628a3b935885dd189d41ce779b'
Submodule path 'lib/libffi': checked out 'e9de7e35f2339598b16cbb375f9992643ed81209'
Submodule path 'lib/lv_bindings': checked out 'edf14fde6986a3cf943d25beeb06f211e94ed32e'
Submodule 'driver/png/lodepng' (https://github.com/lvandeve/lodepng.git) registered for path 'lib/lv_bindings/driver/png/lodepng'
Submodule 'lvgl' (https://github.com/littlevgl/lvgl.git) registered for path 'lib/lv_bindings/lvgl'
Submodule 'micropython/pycparser' (https://github.com/eliben/pycparser.git) registered for path 'lib/lv_bindings/pycparser'
Cloning into '/home/build/lv_micropython/lib/lv_bindings/driver/png/lodepng'...
remote: Enumerating objects: 85, done.
remote: Counting objects: 100% (85/85), done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 722 (delta 50), reused 49 (delta 27), pack-reused 637
Receiving objects: 100% (722/722), 1.04 MiB | 5.00 MiB/s, done.
Resolving deltas: 100% (479/479), done.
Cloning into '/home/build/lv_micropython/lib/lv_bindings/lvgl'...
remote: Enumerating objects: 24645, done.
remote: Total 24645 (delta 0), reused 0 (delta 0), pack-reused 24645
Receiving objects: 100% (24645/24645), 16.91 MiB | 6.01 MiB/s, done.
Resolving deltas: 100% (19692/19692), done.
Cloning into '/home/build/lv_micropython/lib/lv_bindings/pycparser'...
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 2412 (delta 0), reused 1 (delta 0), pack-reused 2407
Receiving objects: 100% (2412/2412), 1.07 MiB | 4.46 MiB/s, done.
Resolving deltas: 100% (1623/1623), done.
Submodule path 'lib/lv_bindings/driver/png/lodepng': checked out '2e541f53ebedf6ebae375a381ca2fd6d82b460bc'
error: Server does not allow request for unadvertised object bac66172ea89e3ed101548f893277b987afe58f5
Fetched in submodule path 'lib/lv_bindings/lvgl', but it did not contain bac66172ea89e3ed101548f893277b987afe58f5. Direct fetching of that commit failed.
Submodule path 'lib/lwip': checked out '159e31b689577dbf69cf0683bbaffbd71fa5ee10'
Submodule path 'lib/mbedtls': checked out '3f8d78411a26e833db18d9fbde0e2f0baeda87f0'
Submodule 'crypto' (https://github.com/ARMmbed/mbed-crypto) registered for path 'lib/mbedtls/crypto'
Cloning into '/home/build/lv_micropython/lib/mbedtls/crypto'...
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 80514 (delta 3), reused 2 (delta 0), pack-reused 80504
Receiving objects: 100% (80514/80514), 22.99 MiB | 6.22 MiB/s, done.
Resolving deltas: 100% (65106/65106), done.
Submodule path 'lib/mbedtls/crypto': checked out 'a78c958b17d75ddf63d8dd17255b6379dcbf259f'
Submodule path 'lib/mynewt-nimble': checked out '223714cb16c255cfa701929c0de6d7579bfd2cdd'
Submodule path 'lib/nrfx': checked out '7513fc9d5c10dc28b25bf2bb6ff0ba66cb2a3c3d'
Submodule path 'lib/stm32lib': checked out '668d7a9e54aea98f8fe8a858eac1d3daa80fa824'
Submodule path 'lib/tinyusb': checked out '393492823ce037a2e46d367d61fad1235859af2e'
Submodule 'hw/mcu/microchip/samd/asf4' (https://github.com/adafruit/asf4.git) registered for path 'lib/tinyusb/hw/mcu/microchip/samd/asf4'
Submodule 'hw/mcu/nordic/nrfx' (https://github.com/NordicSemiconductor/nrfx.git) registered for path 'lib/tinyusb/hw/mcu/nordic/nrfx'
Submodule 'hw/mcu/nxp/lpcopen' (https://github.com/hathach/lpcopen.git) registered for path 'lib/tinyusb/hw/mcu/nxp/lpcopen'
Submodule 'hw/mcu/st/stm32lib' (https://github.com/hathach/stm32lib.git) registered for path 'lib/tinyusb/hw/mcu/st/stm32lib'
Submodule 'tools/uf2' (https://github.com/microsoft/uf2.git) registered for path 'lib/tinyusb/tools/uf2'
Cloning into '/home/build/lv_micropython/lib/tinyusb/hw/mcu/microchip/samd/asf4'...
remote: Enumerating objects: 1520, done.
remote: Total 1520 (delta 0), reused 0 (delta 0), pack-reused 1520
Receiving objects: 100% (1520/1520), 1.75 MiB | 5.53 MiB/s, done.
Resolving deltas: 100% (928/928), done.
Cloning into '/home/build/lv_micropython/lib/tinyusb/hw/mcu/nordic/nrfx'...
remote: Enumerating objects: 1882, done.
remote: Total 1882 (delta 0), reused 0 (delta 0), pack-reused 1882
Receiving objects: 100% (1882/1882), 3.16 MiB | 5.99 MiB/s, done.
Resolving deltas: 100% (1478/1478), done.
Cloning into '/home/build/lv_micropython/lib/tinyusb/hw/mcu/nxp/lpcopen'...
remote: Enumerating objects: 1286, done.
remote: Total 1286 (delta 0), reused 0 (delta 0), pack-reused 1286
Receiving objects: 100% (1286/1286), 5.35 MiB | 5.83 MiB/s, done.
Resolving deltas: 100% (724/724), done.
Cloning into '/home/build/lv_micropython/lib/tinyusb/hw/mcu/st/stm32lib'...
remote: Enumerating objects: 2362, done.
remote: Total 2362 (delta 0), reused 0 (delta 0), pack-reused 2362
Receiving objects: 100% (2362/2362), 8.53 MiB | 6.06 MiB/s, done.
Resolving deltas: 100% (1853/1853), done.
Cloning into '/home/build/lv_micropython/lib/tinyusb/tools/uf2'...
remote: Enumerating objects: 12, done.
remote: Counting objects: 100% (12/12), done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 380 (delta 2), reused 9 (delta 0), pack-reused 368
Receiving objects: 100% (380/380), 110.91 KiB | 1.56 MiB/s, done.
Resolving deltas: 100% (193/193), done.
Submodule path 'lib/tinyusb/hw/mcu/microchip/samd/asf4': checked out '82fe3aa05bc3b9f4956ee775c748a3885443f66b'
Submodule path 'lib/tinyusb/hw/mcu/nordic/nrfx': checked out '9d68726e41c321f1772c187bd12d82f5b13104f1'
Submodule path 'lib/tinyusb/hw/mcu/nxp/lpcopen': checked out '06b4c2e509147924b66ace90f6be5ebe599af45c'
Submodule path 'lib/tinyusb/hw/mcu/st/stm32lib': checked out '1dabc2df8ed1acaf0c483b58d757ba72e8b42090'
Submodule path 'lib/tinyusb/tools/uf2': checked out '19615407727073e36d81bf239c52108ba92e7660'
Submodule 'hidapi' (https://github.com/signal11/hidapi) registered for path 'lib/tinyusb/tools/uf2/hidapi'
Cloning into '/home/build/lv_micropython/lib/tinyusb/tools/uf2/hidapi'...
remote: Enumerating objects: 2006, done.
remote: Total 2006 (delta 0), reused 0 (delta 0), pack-reused 2006
Receiving objects: 100% (2006/2006), 2.73 MiB | 5.26 MiB/s, done.
Resolving deltas: 100% (1172/1172), done.
Submodule path 'lib/tinyusb/tools/uf2/hidapi': checked out 'a6a622ffb680c55da0de787ff93b80280498330f'
Failed to recurse into submodule path 'lib/lv_bindings'
Unfortunately I cannot check out the code any longer
@spierepf Fixed. Please try again.
It works great now! I'd love to see the double buffer issue get fixed, but this is fantastic. Thanks!
@amirgon The issue with ILI9341 and double buffering was reported again, just so you know: https://forum.littlevgl.com/t/double-buffer-heap-corruption/2123
@amirgon The issue with ILI9341 and double buffering was reported again, just so you know: https://forum.littlevgl.com/t/double-buffer-heap-corruption/2123
@embeddedt Thanks for letting me know. I spent some time debugging this in the past, it looks like a nasty memory corruption.
At the moment I'm a bit busy, hopefully I'll get back to this some time in the future.
First off, I want to say that I discovered this project a few days ago, and I think it is pretty awesome. I've been playing with it in the Arduino environment and it has worked well. However, I really like micropython, so I was thrilled to see that there were bindings.
I use rshell to interact with my DOIT ESP32 DEVKIT V1 board. I believe rshell uses soft reboots before many of its on-board filesystem operations, and I've noticed that whenever I use the REPL to
import lvesp32
the subsequent soft reboot panics.To Reproduce
Expected behavior
Soft reboots should not cause crashes, no matter what libraries are imported.
Additional context
The example
lvgl
scripts that I have tested so far have worked as expected. The buttons and labels come up exactly the way they are shown in the accompanying screen shots. But they appear to leave the board in a fragile state that would probably not be stable in production.