sci-bots / m5-lvgl

M5Stack LittlevGL MicroPython drivers
BSD 3-Clause "New" or "Revised" License
10 stars 2 forks source link

Can't mount SD card and display at the same time (SPI host already in use) #1

Open ryanfobel opened 4 years ago

ryanfobel commented 4 years ago

Summary

The m5stack development boards share the same SPI bus between their display (ili9341) and SD card interface. This leads to an SPI bus conflict when trying to use the display and SD card simultaneously, as previously reported by others using the same display.

Steps to reproduce

The following example boot.py demonstrates the problem when interpreted by this micropython release:

import machine
import os
import lvgl as lv
import lvesp32
import ili9341

# Mount the SD card (note that this initializes the SPI bus)
os.mount(machine.SDCard(slot=3, sck=18, mosi=23, miso=19, cs=4), '/sd')

# Create display driver
lv.init()
disp = ili9341.ili9341(spihost=1, miso=19, mosi=23, clk=18, cs=14, dc=27,
                       rst=33, backlight=32, mhz=25)

Here's the error message:

E (410) spi: SPI2 already claimed by spi master.
E (410) spi_master: spi_bus_initialize(242): host already in use
Traceback (most recent call last):
  File "boot.py", line 12, in <module>
  File "ili9341.py", line 108, in __init__
  File "ili9341.py", line 264, in init
  File "ili9341.py", line 181, in disp_spi_init
RuntimeError: Failed initializing SPI bus

A similar error occurs if the display is initialized before trying to mount the SD card.

ryanfobel commented 4 years ago

Note that @miketeachman came up with a nice workaround for his project that uses an ESP32 and ili9341 display (though not an m5stack). Inspired by his work, this commit adds 2 custom build flags that enable compiling the ILI9341 C module so that the m5stack display can be properly configured and added to a pre-initialized SPI bus:

To build it, you'll need to uncomment a couple of lines in /ports/esp32/mpconfigport.h, since the C module is no longer included by default since the release of the ili9341 python hybrid module.

diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index a958ccc8f..a24a1a070 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -201,14 +201,14 @@ extern const struct _mp_obj_module_t mp_module_espidf;
 extern const struct _mp_obj_module_t mp_module_lvesp32;
 extern const struct _mp_obj_module_t mp_module_rtch;
 extern const struct _mp_obj_module_t mp_module_lodepng;
-// extern const struct _mp_obj_module_t mp_module_ILI9341;
+extern const struct _mp_obj_module_t mp_module_ILI9341;
 // extern const struct _mp_obj_module_t mp_module_xpt2046;

 #if MICROPY_PY_LVGL
 #define MICROPY_PORT_LVGL_DEF \
     { MP_OBJ_NEW_QSTR(MP_QSTR_lvgl), (mp_obj_t)&mp_module_lvgl }, \
-    { MP_OBJ_NEW_QSTR(MP_QSTR_lvesp32), (mp_obj_t)&mp_module_lvesp32 },
-//    { MP_OBJ_NEW_QSTR(MP_QSTR_ILI9341), (mp_obj_t)&mp_module_ILI9341 },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_lvesp32), (mp_obj_t)&mp_module_lvesp32 }, \
+    { MP_OBJ_NEW_QSTR(MP_QSTR_ILI9341), (mp_obj_t)&mp_module_ILI9341 },
 //    { MP_OBJ_NEW_QSTR(MP_QSTR_xpt2046), (mp_obj_t)&mp_module_xpt2046 },
 #else
 #define MICROPY_PORT_LVGL_DEF

Then follow the standard steps to compile micropython with LittlevGL bindings, but use the following build flags:

make -C ports/esp32 LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1 \
-DLV_ILI9341_SHARE_SPI_BUS -DLV_M5STACK" BOARD=GENERIC PYTHON=python2

Or you can download this pre-compiled firmware. The following boot.py provides a minimal example of using an m5stack display and SD card simultaneously:

import machine
import os
import lvgl as lv
import lvesp32
import ILI9341

os.mount(machine.SDCard(slot=3, sck=18, mosi=23, miso=19, cs=4), '/sd')

lv.init()
disp = ILI9341.display(spihost=1, miso=19, mosi=23, clk=18, cs=14, dc=27,
                       rst=33, backlight=32, mhz=25)
disp.init()

disp_buf1 = lv.disp_buf_t()
buf1_1 = bytearray(480*10)
lv.disp_buf_init(disp_buf1,buf1_1, None, len(buf1_1)//4)
disp_drv = lv.disp_drv_t()
lv.disp_drv_init(disp_drv)
disp_drv.buffer = disp_buf1
disp_drv.flush_cb = disp.flush
disp_drv.hor_res = 320
disp_drv.ver_res = 240
disp_drv.rotated = 0
lv.disp_drv_register(disp_drv)

scr = lv.obj()
btn = lv.btn(scr)
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Button")
lv.scr_load(scr)

print(os.listdir('/sd'))
GC-RnD commented 4 years ago

Made edits to mpconfigport.h started build with...

make -C ports/esp32 LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1 \ -DLV_ILI9341_SHARE_SPI_BUS " BOARD=GENERIC PYTHON=python2

and got build error..

mkdir -p build-GENERIC/bootloader//mnt/c/tpi-dev/IDF4/esp/esp-idf/components/spi_flash/
CC /mnt/c/tpi-dev/IDF4/esp/esp-idf/components/bootloader_support/src/bootloader_clock.c
xtensa-esp32-elf-gcc: error:  -DLV_ILI9341_SHARE_SPI_BUS: No such file or directory
Makefile:977: recipe for target 'build-GENERIC/bootloader//mnt/c/tpi-dev/IDF4/esp/esp-idf/components/bootloader_support/src/bootloader_clock.o' failed
make: *** [build-GENERIC/bootloader//mnt/c/tpi-dev/IDF4/esp/esp-idf/components/bootloader_support/src/bootloader_clock.o] Error 1
make: Leaving directory '/mnt/c/tpi-dev/IDF4/lv_micropython/ports/esp32'

related post https://forum.micropython.org/viewtopic.php?f=18&t=8352&sid=f84883e0f709647d29736932a8c92973

GC-RnD commented 4 years ago

My error... needed to remove "\"

GC-RnD commented 4 years ago

Were you able to get the pure/hybrid ili9341 driver to work?