Skip to content

Commit bd606d9

Browse files
committed
Replacing all LVGL driver I2C code with I2C Manager
See the [PR](#70) for details and discussion
1 parent cccb932 commit bd606d9

23 files changed

+841
-616
lines changed

CMakeLists.txt

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

7575
if(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI)
7676
list(APPEND SOURCES "lvgl_touch/tp_spi.c")
77-
elseif(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C)
78-
list(APPEND SOURCES "lvgl_touch/tp_i2c.c")
7977
endif()
8078
endif()
8179

80+
if(CONFIG_LV_I2C)
81+
list(APPEND SOURCES "i2c_manager/i2c_manager.c")
82+
endif()
83+
8284
idf_component_register(SRCS ${SOURCES}
8385
INCLUDE_DIRS ${LVGL_INCLUDE_DIRS}
8486
REQUIRES lvgl)
85-
87+
8688
target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_LVGL_H_INCLUDE_SIMPLE")
8789

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

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)