Skip to content

Commit e521123

Browse files
committed
Replace allLVGL driver I2C code with I2C Manager
For discussion see #70
1 parent 8f1370d commit e521123

24 files changed

+898
-681
lines changed

CMakeLists.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,17 @@ if(CONFIG_LV_TOUCH_CONTROLLER)
7676

7777
if(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI)
7878
list(APPEND SOURCES "lvgl_touch/tp_spi.c")
79-
elseif(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C)
80-
list(APPEND SOURCES "lvgl_touch/tp_i2c.c")
8179
endif()
8280
endif()
8381

82+
if(CONFIG_LV_I2C)
83+
list(APPEND SOURCES "i2c_manager/i2c_manager.c")
84+
endif()
85+
8486
idf_component_register(SRCS ${SOURCES}
8587
INCLUDE_DIRS ${LVGL_INCLUDE_DIRS}
8688
REQUIRES lvgl)
87-
89+
8890
target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_LVGL_H_INCLUDE_SIMPLE")
8991

9092
else()

Kconfig

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1-
rsource "lvgl_tft/Kconfig"
2-
rsource "lvgl_touch/Kconfig"
1+
menu "LVGL ESP Drivers"
2+
3+
rsource "lvgl_tft/Kconfig"
4+
5+
rsource "lvgl_touch/Kconfig"
6+
7+
rsource "i2c_manager/Kconfig"
8+
9+
endmenu

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ For a ready to use ESP32 project take look at the [lv_port_esp32](https://github
66
- [Supported display controllers](#supported-display-controllers)
77
- [Supported indev controllers](#supported-indev-controllers)
88
- [Support for predefined development kits](#support-for-predefined-development-kits)
9+
- [Thread-safe I2C with I2C Manager](#thread-safe-i2c-with-i2c-manager)
910

1011
**NOTE:** You need to set the display horizontal and vertical size, color depth and
1112
swap of RGB565 color on the LVGL configuration menuconfig (it's not handled automatically).
@@ -35,8 +36,8 @@ swap of RGB565 color on the LVGL configuration menuconfig (it's not handled auto
3536
## Supported indev controllers
3637

3738
- XPT2046
38-
- FT3236
39-
- other FT6X36 or the FT6206 controllers should work as well (not tested)
39+
- FT3236, FT6X36
40+
- FT6206 controllers should work as well (not tested)
4041
- STMPE610
4142
- FT81x (Single, Dual, and Quad SPI)
4243

@@ -52,7 +53,7 @@ and sets the gpio numbers for the interface.
5253
|---------------------------|-----------------------|-----------|-----------|-----------|
5354
| ESP Wrover Kit v4.1 | ILI9341 | SPI | 240 | 320 |
5455
| M5Stack | ILI9341 | SPI | 240 | 320 |
55-
| M5Core2 | ILI9341 | SPI | 240 | 320 |
56+
| M5Stack Core2 | ILI9341 | SPI | 240 | 320 |
5657
| M5Stick | SH1107 | SPI | - | - |
5758
| M5StickC | ST7735S | SPI | 80 | 160 |
5859
| Adafruit 3.5 Featherwing | HX8357 | SPI | 480 | 320 |
@@ -65,3 +66,16 @@ and sets the gpio numbers for the interface.
6566

6667
**NOTE:** See [Supported display controllers](#supported-display-controllers) for more information on display configuration.
6768
**NOTE:** See [Supported indev controllers](#supported-indev-controllers) for more information about indev configuration.
69+
70+
71+
## Thread-safe I2C with I2C Manager
72+
73+
LVGL can use I2C to read from a touch sensor or write to a display, possibly
74+
many times a second. Meanwhile, other tasks may also want to read from i2c
75+
devices on the same bus. I2C using the ESP-IDF is not thread-safe.
76+
77+
I2C Manager (`i2c_manager`) is a component that will let code in multiple threads
78+
talk to devices on the I2C ports without getting in each other's way. These drivers
79+
use a built-in copy of I2C Manager to talk to the I2C port, but you can also use
80+
the I2C Manager component itself and have others play nice with LVGL and vice-versa.
81+
[Click here](i2c_manager/README.md) for details.

component.mk

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,3 @@ $(call compile_only_if,$(and $(CONFIG_LV_TOUCH_CONTROLLER),$(CONFIG_LV_TOUCH_CON
4444
$(call compile_only_if,$(and $(CONFIG_LV_TOUCH_CONTROLLER),$(CONFIG_LV_TOUCH_CONTROLLER_RA8875)), lvgl_touch/ra8875_touch.o)
4545

4646
$(call compile_only_if,$(and $(CONFIG_LV_TOUCH_CONTROLLER),$(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI)), lvgl_touch/tp_spi.o)
47-
$(call compile_only_if,$(and $(CONFIG_LV_TOUCH_CONTROLLER),$(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C)), lvgl_touch/tp_i2c.o)

i2c_manager/Kconfig

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
menu "I2C Port Settings"
2+
depends on LV_I2C && !HAVE_I2C_MANAGER
3+
4+
menu "I2C Port 0"
5+
6+
config I2C_MANAGER_0_ENABLED
7+
bool "Enable I2C port 0"
8+
9+
if I2C_MANAGER_0_ENABLED
10+
config I2C_MANAGER_0_SDA
11+
int "SDA (GPIO pin)"
12+
range 0 39 if IDF_TARGET_ESP32
13+
range 0 46 if IDF_TARGET_ESP32S2
14+
range 0 21 if IDF_TARGET_ESP32C3
15+
config I2C_MANAGER_0_SCL
16+
int "SCL (GPIO pin)"
17+
range 0 39 if IDF_TARGET_ESP32
18+
range 0 46 if IDF_TARGET_ESP32S2
19+
range 0 21 if IDF_TARGET_ESP32C3
20+
config I2C_MANAGER_0_FREQ_HZ
21+
int "Frequency (Hz)"
22+
default 400000
23+
range 100000 5000000
24+
help
25+
The clock speed in Hz. Ranges from 100000 (100 kHz) to
26+
5000000 (5 Mhz). I2C busses that involve external wires may
27+
have to be slower, and the real maximum speed the bus will
28+
support depends on the value of the pullup resistors and the
29+
design of the overall circuit.
30+
config I2C_MANAGER_0_TIMEOUT
31+
int "R/W timeout (ms)"
32+
default 20
33+
range 10 1000
34+
help
35+
Timeout for I2C read and write operations. This does not
36+
include the time waiting for a lock.
37+
config I2C_MANAGER_0_LOCK_TIMEOUT
38+
int "Stale lock override (ms)"
39+
default 50
40+
range 10 1000
41+
help
42+
Timeout at which point an operation waiting for its turn on
43+
the port will assume that whatever set the lock has died and
44+
overrides it. Set this somewhat larger than the previous
45+
timeout.
46+
config I2C_MANAGER_0_PULLUPS
47+
bool "Use ESP32 built-in bus pull-up resistors"
48+
help
49+
The I2C bus needs resistors to make sure it's in a defined
50+
state when nobody is talking. Many circuits have external
51+
pullup resistors already and turning these on will increase
52+
power consumption slightly and may limit the speed your bus
53+
can attain. Try with these off first if you don't know.
54+
endif
55+
56+
endmenu
57+
58+
59+
menu "I2C Port 1"
60+
61+
config I2C_MANAGER_1_ENABLED
62+
bool "Enable I2C port 1"
63+
64+
if I2C_MANAGER_1_ENABLED
65+
config I2C_MANAGER_1_SDA
66+
int "SDA (GPIO pin)"
67+
default 32
68+
range 0 39 if IDF_TARGET_ESP32
69+
range 0 46 if IDF_TARGET_ESP32S2
70+
range 0 21 if IDF_TARGET_ESP32C3
71+
config I2C_MANAGER_1_SCL
72+
int "SCL (GPIO pin)"
73+
default 33
74+
range 0 39 if IDF_TARGET_ESP32
75+
range 0 46 if IDF_TARGET_ESP32S2
76+
range 0 21 if IDF_TARGET_ESP32C3
77+
config I2C_MANAGER_1_FREQ_HZ
78+
int "Frequency (Hz)"
79+
default 1000000
80+
range 100000 5000000
81+
help
82+
The clock speed in Hz. Ranges from 100000 (100 kHz) to
83+
5000000 (5 Mhz). I2C busses that involve external wires may
84+
have to be slower, and the real maximum speed the bus will
85+
support depends on the value of the pullup resistors and the
86+
design of the overall circuit.
87+
config I2C_MANAGER_1_TIMEOUT
88+
int "R/W timeout (ms)"
89+
default 20
90+
range 10 1000
91+
help
92+
Timeout for I2C read and write operations. This does not
93+
include the time waiting for a lock. Default should be fine.
94+
config I2C_MANAGER_1_LOCK_TIMEOUT
95+
int "Stale lock override (ms)"
96+
default 50
97+
help
98+
Timeout at which point an operation waiting for its turn on
99+
the port will assume that whatever set the lock has died and
100+
overrides it. Set this somewhat larger than the previous
101+
timeout. Default should be fine.
102+
range 30 1000
103+
config I2C_MANAGER_1_PULLUPS
104+
bool "Use ESP32 built-in bus pull-up resistors"
105+
help
106+
The I2C bus needs resistors to make sure it's in a defined
107+
state when nobody is talking. Many circuits have external
108+
pullup resistors already and turning these on will increase
109+
power consumption slightly and may limit the speed your bus
110+
can attain. Try with these off first if you don't know.
111+
endif
112+
113+
endmenu
114+
115+
endmenu
116+

i2c_manager/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# I2C in `lvgl_esp32_drivers`
2+
3+
 
4+
5+
6+
7+
## Information for users
8+
9+
### I2C Manager support
10+
11+
`lvgl_esp32_drivers` comes with built-in I2C support by integrating I2C Manager, which is used in case your touch interface or screen uses the I2C bus. The native I2C support offered by ESP-IDF is not thread-safe. Maybe you use LVGL with a touch sensor that has an i2c port, and maybe your device also has another i2c device that needs to be read frequently, such as a 3D-accelerometer. If you read that from another task than the lvgl uses to read the touch data, you need some kind of mechanism to keep these communications from interfering.
12+
13+
If you have other components that can use I2C Manager (or Mika Tuupola's I2C HAL abstraction that I2C Manager is compatible with) then put I2C Manager in your components directory by cloning the repository from below and in your main program do:
14+
15+
```c
16+
#include "i2c_manager.h"
17+
#include "lvgl_helpers.h"
18+
19+
[...]
20+
21+
lvgl_locking(i2c_manager_locking());
22+
lv_init();
23+
lvgl_driver_init();
24+
```
25+
26+
The `lvgl_locking` part will cause the LVGL I2C driver to play nice with anything else that uses the I2C port(s) through I2C Manager.
27+
28+
See the [I2C Manager GitHub repository](https://github.com/ropg/i2c_manager) for much more information.
29+
30+
31+
 
32+
33+
34+
35+
## Information for driver developers
36+
37+
I2C support in the LVGL ESP drivers is provided exclusively by the files in this directory. Code from all over the project that was talking to the I2C hardware directly has been replaced by code that communicates through the functions provided in `lvgl_i2c.h`. I2C is handled by the I2C Manager that was built into lvlg_esp32_drivers, but the code would be the same if it was routed through I2C Manager as a separate component. If you are providing a driver, you need not worry about any of this.
38+
39+
### Using I2C in a driver, a multi-step guide
40+
41+
#### Step 1
42+
43+
The Kconfig entries for your driver only need to specify that you will be using I2C. This is done by `select LV_I2C_DISPLAY` or `select LV_I2C_TOUCH`.
44+
45+
#### Step 2
46+
47+
To use the I2C port in your code you would do something like:
48+
49+
```c
50+
#include "i2c_manager/i2c_manager.h"
51+
52+
uint8_t data[2];
53+
lvgl_i2c_read(CONFIG_LV_I2C_TOUCH_PORT, 0x23, 0x42, &data, 2);
54+
```
55+
56+
This causes a touch driver to read two bytes at register `0x42` from the IC at address `0x23`. Replace `CONFIG_LV_I2C_TOUCH_PORT` by `CONFIG_LV_I2C_DISPLAY_PORT` when this is a display instead of a touch driver. `lvgl_i2c_write` works much the same way, except writing the bytes from the buffer instead of reading them.
57+
58+
> The example above ignores it but these functions return `esp_err_t` so you can check if the i2c communication worked.
59+
60+
#### Step 3
61+
62+
There is no step 3, you are already done.
63+
64+
### Behind the scenes
65+
66+
If anything in `lvgl_esp32_drivers` uses I2C, the config system will pop up an extra menu. This will allow you to select an I2C port for screen and one for the touch driver, if applicable. An extra menu allows you to set the GPIO pins and bus speed of any port you have selected for use. It's perfectly fine for a display and a touch driver to use the same I2C port or different ones.
67+
68+
69+
## More information
70+
71+
If you need more documentation, please refer to the [I2C Manager GitHub repository](https://github.com/ropg/i2c_manager) for more detailed information on how I2C manager works.

0 commit comments

Comments
 (0)