First commit with working display
This commit is contained in:
@@ -0,0 +1 @@
|
||||
7e6381b67b6e487379118368b8e91624dc87036ef5734818de1db9eb35697998
|
||||
1
managed_components/atanisoft__esp_lcd_touch_xpt2046/.gitignore
vendored
Normal file
1
managed_components/atanisoft__esp_lcd_touch_xpt2046/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.vscode
|
||||
@@ -0,0 +1,46 @@
|
||||
# Change log for esp_lcd_touch_xpt2046
|
||||
|
||||
|
||||
## v1.0.6 - new features
|
||||
|
||||
* Fixing interrupt mode via PR https://github.com/atanisoft/esp_lcd_touch_xpt2046/pull/11
|
||||
|
||||
## v1.0.5 - new features
|
||||
|
||||
* support for interrupt triggered wake-up for reading, thanks @ttt470!
|
||||
|
||||
## v1.0.4 - New features
|
||||
|
||||
* Add ability to read voltage level from Aux pin.
|
||||
* Add ability to read temperature using the TEMP0 register (one point mode).
|
||||
* Add ability to read temperature using the TEMP0 and TEMP1 registers (two point mode).
|
||||
* Enable PENIRQ pin output when touched (if configured).
|
||||
* Enable use of PENIRQ input to test for touch (if PENIRQ input pin configured).
|
||||
* Allow leaving Vref permanently on (if configured). Increases power usage but reduces SPI transactions for temperature and voltage reads.
|
||||
* Fixes battery voltage read (was scaled incorrectly).
|
||||
* Fixes coordinate averaging (fix random bad clicks).
|
||||
* Adjusts Vref voltage to reflect value in typical usage conditions.
|
||||
|
||||
## v1.0.3 - Minor Bug fixes
|
||||
|
||||
* Add new parameters to ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG macro based on IDF v5.1.2 and v5.1.3+.
|
||||
|
||||
## v1.0.2 - New features
|
||||
|
||||
* Set minimum version for esp_lcd_touch to 1.0.4.
|
||||
* Add touch interrupt callback functionality.
|
||||
* Add abilitty to read voltage level from vBat pin.
|
||||
* Enable ADC during read of X/Y coords (Z already was enabled).
|
||||
* Add IDF v5.1 esp_lcd_panel_io_spi_config_t updates.
|
||||
* Fixing interrupt gpio pin reference during initialization.
|
||||
|
||||
## v1.0.1 - Bug fix release
|
||||
|
||||
* Fixing typo in configuration options.
|
||||
* Removing usage of temporary array of coordinates.
|
||||
* Adjustments to ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG for IDF v5.0-rc1.
|
||||
* Add option to return raw coordinate data instead of converting to screen coordinates.
|
||||
|
||||
## v1.0.0 - Initial release
|
||||
|
||||
This release is the first revision of this component.
|
||||
@@ -0,0 +1 @@
|
||||
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-05-21T14:04:59.865531+00:00", "files": [{"path": "esp_lcd_touch_xpt2046.c", "size": 14414, "hash": "b5923d99652b98771ad273bf26ab8d0fe9eec0912f8817818c8347427ae5540e"}, {"path": "CMakeLists.txt", "size": 156, "hash": "6860d27cc0e82589c8b145b30b4f35320e3feea9e033eebfa81eba2eebf4dcfa"}, {"path": "LICENSE", "size": 1069, "hash": "21a7c428a2b3cd90ac1f3c9c03ec3eea7d81f4ec01875ae0aa22a00d8cdbb74a"}, {"path": "CHANGELOG.md", "size": 1800, "hash": "e72bbb3371dd7d4509d403eeacb040016a8d7d32b6dc1c107c7f8071ccb7f66e"}, {"path": "idf_component.yml", "size": 339, "hash": "609077dfccdcda8c4151e3a03a2b757aa04aaafbbe02f9cb2dcd6a88eda89261"}, {"path": "README.md", "size": 4460, "hash": "e996d9678ce36350e267c18ad78d7834ae2e4bc426eee1aa63557aff06e1b39c"}, {"path": ".gitignore", "size": 7, "hash": "27bf025903b14c7d22e5415f78b31443828f0a7ecff34a2d7e722624550282d6"}, {"path": "Kconfig.projbuild", "size": 1821, "hash": "1619cadb78906a65020ddf3509d9cfc4a472b36e6195008ee49bc6373c818511"}, {"path": "include/esp_lcd_touch_xpt2046.h", "size": 9063, "hash": "32919e82cb73cb6b412d22c5dab527adb31ac0ee707252f382005573c97ceaf3"}]}
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
idf_component_register(SRCS "esp_lcd_touch_xpt2046.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES "driver esp_lcd_touch")
|
||||
@@ -0,0 +1,44 @@
|
||||
menu "XPT2046"
|
||||
config XPT2046_Z_THRESHOLD
|
||||
int "Minimum Z pressure threshold"
|
||||
default 400
|
||||
help
|
||||
Touch pressure less than this value will be discarded as invalid
|
||||
and no touch position data collected.
|
||||
|
||||
config XPT2046_INTERRUPT_MODE
|
||||
bool "Enable Interrupt (PENIRQ) output"
|
||||
default n
|
||||
help
|
||||
Also called Full Power Mode.
|
||||
Enable this to configure the XPT2046 to output low on the PENIRQ output
|
||||
if a touch is detected.
|
||||
This mode uses more power when enabled.
|
||||
Note that this signal goes low normally when a read is active.
|
||||
|
||||
config XPT2046_VREF_ON_MODE
|
||||
bool "Keep internal Vref enabled"
|
||||
default n
|
||||
help
|
||||
Enable this to keep the internal Vref enabled between conversions.
|
||||
This uses slightly more power, but requires fewer transactions when
|
||||
reading the battery voltage, aux voltage and temperature.
|
||||
|
||||
config XPT2046_CONVERT_ADC_TO_COORDS
|
||||
bool "Convert touch coordinates to screen coordinates"
|
||||
default y
|
||||
help
|
||||
When this option is enabled the raw ADC values will be converted from
|
||||
0-4096 to 0-{screen width} or 0-{screen height}.
|
||||
When this option is disabled the process_coordinates method will need
|
||||
to be used to convert the raw ADC values into a screen coordinate.
|
||||
|
||||
config XPT2046_ENABLE_LOCKING
|
||||
bool "Enable data structure locking"
|
||||
default n
|
||||
help
|
||||
By enabling this option the XPT2046 driver will lock the touch position
|
||||
data structures when reading values from the XPT2046 and when reading
|
||||
position data via API.
|
||||
WARNING: enabling this option may result in unintended crashes.
|
||||
endmenu
|
||||
21
managed_components/atanisoft__esp_lcd_touch_xpt2046/LICENSE
Normal file
21
managed_components/atanisoft__esp_lcd_touch_xpt2046/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Mike Dunston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
127
managed_components/atanisoft__esp_lcd_touch_xpt2046/README.md
Normal file
127
managed_components/atanisoft__esp_lcd_touch_xpt2046/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# esp_lcd_touch driver for XPT2046 devices
|
||||
|
||||
Implementation of the XPT2046 Touch controller with esp_lcd_touch component.
|
||||
|
||||
| Touch controller | Communication interface | Component name | Link to datasheet |
|
||||
| :------------: | :---------------------: | :------------: | :---------------: |
|
||||
| XPT2046 | SPI | esp_lcd_touch_xpt2046 | [Specification](https://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf) |
|
||||
|
||||
## Adding this component in your project
|
||||
|
||||
This package can be added to your project in two ways:
|
||||
|
||||
1. Using [Espressif's component service](https://components.espressif.com/) as:
|
||||
```
|
||||
dependencies:
|
||||
atanisoft/esp_lcd_touch_xpt2046: "~1.0.0"
|
||||
```
|
||||
|
||||
2. Using the git repository directly:
|
||||
|
||||
```
|
||||
dependencies:
|
||||
esp_lcd_touch_xpt2046:
|
||||
git: https://github.com/atanisoft/esp_lcd_touch_xpt2046.git
|
||||
```
|
||||
|
||||
For more information on the usage of the `idf_component.yml` file please refer to [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).
|
||||
|
||||
## Supported platforms
|
||||
|
||||
At this time testing is limited to ESP32 and ESP32-S3, other ESP32 variants should work but are not tested.
|
||||
|
||||
## Configuration options
|
||||
|
||||
`Kconfig.projbuild` contains a handful of options to allow customization of the XPT2046 interface:
|
||||
|
||||
* XPT2046_Z_THRESHOLD - This is the minimum ADC threshold to use for detecting touch points.
|
||||
* XPT2046_INTERRUPT_MODE - This option enables / disables the PENIRQ output from the chip. If enabled (and the `int_gpio_num` is set) the driver can check for touch more efficiently by reading the input.
|
||||
* XPT2046_VREF_ON_MODE - This option enables / disables keeping the internal Vref permanently enabled. This uses more power, but requires fewer SPI transactions when reading the battery voltage, aux voltage and temperature.
|
||||
* XPT2046_CONVERT_ADC_TO_COORDS - This option enables / disables the conversion of raw ADC values into screen coordinates. When disabled it will be necessary to define the `process_coordinates` method in `esp_lcd_touch_config_t`. This can be useful for applying calibration or other offsets to adjust the screen coordinates.
|
||||
* XPT2046_ENABLE_LOCKING - This option enables / disables the usage of critical sections to protect internal data structures. This has been seen to cause conflicts with other components at times.
|
||||
|
||||
## Example usage
|
||||
|
||||
### Initialization
|
||||
|
||||
```
|
||||
esp_lcd_touch_handle_t tp = NULL;
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_spi_config_t tp_io_config = ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(TOUCH_CS_PIN);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI2_HOST, &tp_io_config, &tp_io_handle));
|
||||
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = CONFIG_LCD_HRES,
|
||||
.y_max = CONFIG_LCD_VRES,
|
||||
.rst_gpio_num = -1,
|
||||
.int_gpio_num = -1,
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Initialize touch controller XPT2046");
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_spi_xpt2046(tp_io_handle, &tp_cfg, &tp));
|
||||
```
|
||||
|
||||
### Updating touch point data
|
||||
|
||||
This will read new data from the touch controller and store it in SRAM. This method
|
||||
should be called on a regular basis.
|
||||
|
||||
```
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_read_data(tp));
|
||||
```
|
||||
|
||||
### Retrieving touch point(s)
|
||||
|
||||
This will retrieve the latest averaged touch point data from SRAM.
|
||||
|
||||
```
|
||||
uint16_t x[1];
|
||||
uint16_t y[1];
|
||||
uint16_t strength[1];
|
||||
uint8_t count = 0;
|
||||
|
||||
bool touchpad_pressed = esp_lcd_touch_get_coordinates(tp, x, y, strength, &count, 1);
|
||||
```
|
||||
|
||||
### Integrating with LVGL
|
||||
|
||||
This driver can be integrated with LVGL using code similar to below:
|
||||
|
||||
```
|
||||
void touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data)
|
||||
{
|
||||
uint16_t x[1];
|
||||
uint16_t y[1];
|
||||
uint16_t strength[1];
|
||||
uint8_t count = 0;
|
||||
|
||||
// Update touch point data.
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_read_data(tp));
|
||||
|
||||
data->state = LV_INDEV_STATE_REL;
|
||||
|
||||
if (esp_lcd_touch_get_coordinates(tp, x, y, strength, &count, 1))
|
||||
{
|
||||
data->point.x = x[0];
|
||||
data->point.y = y[0];
|
||||
data->state = LV_INDEV_STATE_PR;
|
||||
}
|
||||
|
||||
data->continue_reading = false;
|
||||
}
|
||||
|
||||
void initialize_input()
|
||||
{
|
||||
lv_indev_drv_t indev_drv;
|
||||
lv_indev_drv_init( &indev_drv );
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = touch_driver_read;
|
||||
lv_indev_drv_register( &indev_drv );
|
||||
}
|
||||
|
||||
```
|
||||
@@ -0,0 +1,415 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 atanisoft (github.com/atanisoft)
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_rom_gpio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
// This must be included after FreeRTOS includes due to missing include
|
||||
// for portMUX_TYPE
|
||||
#include <esp_lcd_touch.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "xpt2046";
|
||||
|
||||
#ifdef CONFIG_XPT2046_INTERRUPT_MODE
|
||||
#define XPT2046_PD0_BIT (0x00)
|
||||
#else
|
||||
#define XPT2046_PD0_BIT (0x01)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XPT2046_VREF_ON_MODE
|
||||
#define XPT2046_PD1_BIT (0x02)
|
||||
#else
|
||||
#define XPT2046_PD1_BIT (0x00)
|
||||
#endif
|
||||
|
||||
#define XPT2046_PD_BITS (XPT2046_PD1_BIT | XPT2046_PD0_BIT)
|
||||
|
||||
enum xpt2046_registers
|
||||
{
|
||||
// START ADDR MODE SER/ VREF ADC (PENIRQ)
|
||||
// 12/8b DFR INT/EXT ENA
|
||||
Z_VALUE_1 = 0xB0 | XPT2046_PD_BITS, // 1 011 0 0 X X
|
||||
Z_VALUE_2 = 0xC0 | XPT2046_PD_BITS, // 1 100 0 0 X X
|
||||
Y_POSITION = 0x90 | XPT2046_PD_BITS, // 1 001 0 0 X X
|
||||
X_POSITION = 0xD0 | XPT2046_PD_BITS, // 1 101 0 0 X X
|
||||
BATTERY = 0xA6 | XPT2046_PD_BITS, // 1 010 0 1 1 X
|
||||
AUX_IN = 0xE6 | XPT2046_PD_BITS, // 1 110 0 1 1 X
|
||||
TEMP0 = 0x86 | XPT2046_PD_BITS, // 1 000 0 1 1 X
|
||||
TEMP1 = 0xF6 | XPT2046_PD_BITS, // 1 111 0 1 1 X
|
||||
};
|
||||
|
||||
#if CONFIG_XPT2046_ENABLE_LOCKING
|
||||
#define XPT2046_LOCK(lock) portENTER_CRITICAL(lock)
|
||||
#define XPT2046_UNLOCK(lock) portEXIT_CRITICAL(lock)
|
||||
#else
|
||||
#define XPT2046_LOCK(lock)
|
||||
#define XPT2046_UNLOCK(lock)
|
||||
#endif
|
||||
|
||||
static const uint16_t XPT2046_ADC_LIMIT = 4096;
|
||||
// refer the TSC2046 datasheet https://www.ti.com/lit/ds/symlink/tsc2046.pdf rev F 2008
|
||||
// TEMP0 reads approx 599.5 mV at 25C (Refer p8 TEMP0 diode voltage vs Vcc chart)
|
||||
// Vref is approx 2.507V = 2507mV at moderate temperatures (refer p8 Vref vs Temperature chart)
|
||||
// counts@25C = TEMP0_mV / Vref_mv * XPT2046_ADC_LIMIT
|
||||
static const float XPT2046_TEMP0_COUNTS_AT_25C = (599.5 / 2507 * XPT2046_ADC_LIMIT);
|
||||
static esp_err_t xpt2046_read_data(esp_lcd_touch_handle_t tp);
|
||||
static bool xpt2046_get_xy(esp_lcd_touch_handle_t tp,
|
||||
uint16_t *x, uint16_t *y,
|
||||
uint16_t *strength,
|
||||
uint8_t *point_num,
|
||||
uint8_t max_point_num);
|
||||
static esp_err_t xpt2046_del(esp_lcd_touch_handle_t tp);
|
||||
|
||||
esp_err_t esp_lcd_touch_new_spi_xpt2046(const esp_lcd_panel_io_handle_t io,
|
||||
const esp_lcd_touch_config_t *config,
|
||||
esp_lcd_touch_handle_t *out_touch)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_lcd_touch_handle_t handle = NULL;
|
||||
|
||||
ESP_GOTO_ON_FALSE(io, ESP_ERR_INVALID_ARG, err, TAG,
|
||||
"esp_lcd_panel_io_handle_t must not be NULL");
|
||||
ESP_GOTO_ON_FALSE(config, ESP_ERR_INVALID_ARG, err, TAG,
|
||||
"esp_lcd_touch_config_t must not be NULL");
|
||||
|
||||
handle = (esp_lcd_touch_handle_t)calloc(1, sizeof(esp_lcd_touch_t));
|
||||
ESP_GOTO_ON_FALSE(handle, ESP_ERR_NO_MEM, err, TAG,
|
||||
"No memory available for XPT2046 state");
|
||||
handle->io = io;
|
||||
handle->read_data = xpt2046_read_data;
|
||||
handle->get_xy = xpt2046_get_xy;
|
||||
handle->del = xpt2046_del;
|
||||
handle->data.lock.owner = portMUX_FREE_VAL;
|
||||
memcpy(&handle->config, config, sizeof(esp_lcd_touch_config_t));
|
||||
|
||||
if (config->int_gpio_num != GPIO_NUM_NC)
|
||||
{
|
||||
ESP_GOTO_ON_FALSE(GPIO_IS_VALID_GPIO(config->int_gpio_num),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "Invalid GPIO Interrupt Pin");
|
||||
gpio_config_t cfg;
|
||||
memset(&cfg, 0, sizeof(gpio_config_t));
|
||||
esp_rom_gpio_pad_select_gpio(config->int_gpio_num);
|
||||
cfg.pin_bit_mask = BIT64(config->int_gpio_num);
|
||||
cfg.mode = GPIO_MODE_INPUT;
|
||||
cfg.intr_type = (config->levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE);
|
||||
|
||||
// If the user has provided a callback routine for the interrupt enable
|
||||
// the interrupt mode on the negative edge.
|
||||
if (config->interrupt_callback)
|
||||
{
|
||||
cfg.intr_type = GPIO_INTR_NEGEDGE;
|
||||
}
|
||||
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&cfg), err, TAG,
|
||||
"Configure GPIO for Interrupt failed");
|
||||
|
||||
// Connect the user interrupt callback routine.
|
||||
if (config->interrupt_callback)
|
||||
{
|
||||
esp_lcd_touch_register_interrupt_callback(handle, config->interrupt_callback);
|
||||
}
|
||||
|
||||
#if CONFIG_XPT2046_INTERRUPT_MODE
|
||||
// Read a register to enable Low Power mode, which is required for interrupt to work.
|
||||
uint8_t battery = 0;
|
||||
ESP_GOTO_ON_ERROR(esp_lcd_panel_io_rx_param(handle->io, BATTERY, &battery, 1), err, TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
err:
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
xpt2046_del(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*out_touch = handle;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t xpt2046_del(esp_lcd_touch_handle_t tp)
|
||||
{
|
||||
if (tp != NULL)
|
||||
{
|
||||
if (tp->config.int_gpio_num != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_reset_pin(tp->config.int_gpio_num);
|
||||
}
|
||||
}
|
||||
free(tp);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t xpt2046_read_register(esp_lcd_touch_handle_t tp, uint8_t reg, uint16_t *value)
|
||||
{
|
||||
uint8_t buf[2] = {0, 0};
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(tp->io, reg, buf, 2), TAG, "XPT2046 read error!");
|
||||
*value = ((buf[0] << 8) | (buf[1]));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t xpt2046_read_data(esp_lcd_touch_handle_t tp)
|
||||
{
|
||||
uint16_t z1 = 0, z2 = 0, z = 0;
|
||||
uint32_t x = 0, y = 0;
|
||||
uint8_t point_count = 0;
|
||||
|
||||
#ifdef CONFIG_XPT2046_INTERRUPT_MODE
|
||||
if (tp->config.int_gpio_num != GPIO_NUM_NC)
|
||||
{
|
||||
// Check the PENIRQ pin to see if there is a touch
|
||||
if (gpio_get_level(tp->config.int_gpio_num))
|
||||
{
|
||||
XPT2046_LOCK(&tp->data.lock);
|
||||
tp->data.coords[0].x = 0;
|
||||
tp->data.coords[0].y = 0;
|
||||
tp->data.coords[0].strength = 0;
|
||||
tp->data.points = 0;
|
||||
XPT2046_UNLOCK(&tp->data.lock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, Z_VALUE_1, &z1), TAG, "XPT2046 read error!");
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, Z_VALUE_2, &z2), TAG, "XPT2046 read error!");
|
||||
|
||||
// Convert the received values into a Z value.
|
||||
z = (z1 >> 3) + (XPT2046_ADC_LIMIT - (z2 >> 3));
|
||||
|
||||
// If the Z (pressure) exceeds the threshold it is likely the user has
|
||||
// pressed the screen, read in and average the positions.
|
||||
if (z >= CONFIG_XPT2046_Z_THRESHOLD)
|
||||
{
|
||||
uint16_t discard_buf = 0;
|
||||
|
||||
// read and discard a value as it is usually not reliable.
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, X_POSITION, &discard_buf),
|
||||
TAG, "XPT2046 read error!");
|
||||
|
||||
for (uint8_t idx = 0; idx < CONFIG_ESP_LCD_TOUCH_MAX_POINTS; idx++)
|
||||
{
|
||||
uint16_t x_temp = 0;
|
||||
uint16_t y_temp = 0;
|
||||
// Read X position and convert returned data to 12bit value
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, X_POSITION, &x_temp),
|
||||
TAG, "XPT2046 read error!");
|
||||
// drop lowest three bits to convert to 12-bit position
|
||||
x_temp >>= 3;
|
||||
|
||||
// Read Y position and convert returned data to 12bit value
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, Y_POSITION, &y_temp),
|
||||
TAG, "XPT2046 read error!");
|
||||
// drop lowest three bits to convert to 12-bit position
|
||||
y_temp >>= 3;
|
||||
|
||||
// Test if the readings are valid (50 < reading < max - 50)
|
||||
if ((x_temp >= 50) && (x_temp <= XPT2046_ADC_LIMIT - 50) && (y_temp >= 50) && (y_temp <= XPT2046_ADC_LIMIT - 50))
|
||||
{
|
||||
#if CONFIG_XPT2046_CONVERT_ADC_TO_COORDS
|
||||
// Convert the raw ADC value into a screen coordinate and store it
|
||||
// for averaging.
|
||||
x += ((x_temp / (double)XPT2046_ADC_LIMIT) * tp->config.x_max);
|
||||
y += ((y_temp / (double)XPT2046_ADC_LIMIT) * tp->config.y_max);
|
||||
#else
|
||||
// store the raw ADC values and let the user convert them to screen
|
||||
// coordinates.
|
||||
x += x_temp;
|
||||
y += y_temp;
|
||||
#endif // CONFIG_XPT2046_CONVERT_ADC_TO_COORDS
|
||||
point_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check we had enough valid values
|
||||
const int minimum_count = (1 == CONFIG_ESP_LCD_TOUCH_MAX_POINTS ? 1 : CONFIG_ESP_LCD_TOUCH_MAX_POINTS/2);
|
||||
if (point_count >= minimum_count)
|
||||
{
|
||||
// Average the accumulated coordinate data points.
|
||||
x /= point_count;
|
||||
y /= point_count;
|
||||
point_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
z = 0;
|
||||
point_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
XPT2046_LOCK(&tp->data.lock);
|
||||
tp->data.coords[0].x = x;
|
||||
tp->data.coords[0].y = y;
|
||||
tp->data.coords[0].strength = z;
|
||||
tp->data.points = point_count;
|
||||
XPT2046_UNLOCK(&tp->data.lock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static bool xpt2046_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y,
|
||||
uint16_t *strength, uint8_t *point_num,
|
||||
uint8_t max_point_num)
|
||||
{
|
||||
XPT2046_LOCK(&tp->data.lock);
|
||||
|
||||
// Determine how many touch points that are available.
|
||||
if (tp->data.points > max_point_num)
|
||||
{
|
||||
*point_num = max_point_num;
|
||||
}
|
||||
else
|
||||
{
|
||||
*point_num = tp->data.points;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < *point_num; i++)
|
||||
{
|
||||
x[i] = tp->data.coords[i].x;
|
||||
y[i] = tp->data.coords[i].y;
|
||||
|
||||
if (strength)
|
||||
{
|
||||
strength[i] = tp->data.coords[i].strength;
|
||||
}
|
||||
}
|
||||
|
||||
// Invalidate stored touch data.
|
||||
tp->data.points = 0;
|
||||
|
||||
XPT2046_UNLOCK(&tp->data.lock);
|
||||
|
||||
if (*point_num)
|
||||
{
|
||||
ESP_LOGD(TAG, "Touch point: %dx%d", x[0], y[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "No touch points");
|
||||
}
|
||||
|
||||
return (*point_num > 0);
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_xpt2046_read_battery_level(const esp_lcd_touch_handle_t handle, float *output)
|
||||
{
|
||||
uint16_t level;
|
||||
#ifndef CONFIG_XPT2046_VREF_ON_MODE
|
||||
// First read is to turn on the Vref, so it has extra time to stabilise before we read it for real
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, BATTERY, &level), TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
// Read the battery voltage
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, BATTERY, &level), TAG, "XPT2046 read error!");
|
||||
// drop lowest three bits to convert to 12-bit value
|
||||
level >>= 3;
|
||||
|
||||
// battery voltage is reported as 1/4 the actual voltage due to logic in
|
||||
// the chip.
|
||||
*output = level * 4.0;
|
||||
|
||||
// adjust for internal vref of 2.5v
|
||||
*output *= 2.507f;
|
||||
|
||||
// adjust for ADC bit count
|
||||
*output /= 4096.0f;
|
||||
|
||||
#ifndef CONFIG_XPT2046_VREF_ON_MODE
|
||||
// Final read is to turn the Vref off
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, Z_VALUE_1, &level), TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_xpt2046_read_aux_level(const esp_lcd_touch_handle_t handle, float *output)
|
||||
{
|
||||
uint16_t level;
|
||||
#ifndef CONFIG_XPT2046_VREF_ON_MODE
|
||||
// First read is to turn on the Vref, so it has extra time to stabilise before we read it for real
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, AUX_IN, &level), TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
// Read the aux input voltage
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, AUX_IN, &level), TAG, "XPT2046 read error!");
|
||||
// drop lowest three bits to convert to 12-bit value
|
||||
level >>= 3;
|
||||
*output = level;
|
||||
|
||||
// adjust for internal vref of 2.5v
|
||||
*output *= 2.507f;
|
||||
|
||||
// adjust for ADC bit count
|
||||
*output /= 4096.0f;
|
||||
|
||||
#ifndef CONFIG_XPT2046_VREF_ON_MODE
|
||||
// Final read is to turn on the ADC and the Vref off
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, Z_VALUE_1, &level), TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_xpt2046_read_temp0_level(const esp_lcd_touch_handle_t handle, float *output)
|
||||
{
|
||||
uint16_t temp0;
|
||||
#ifndef CONFIG_XPT2046_VREF_ON_MODE
|
||||
// First read is to turn on the Vref, so it has extra time to stabilise before we read it for real
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP0, &temp0), TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
// Read the temp0 value
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP0, &temp0), TAG, "XPT2046 read error!");
|
||||
// drop lowest three bits to convert to 12-bit value
|
||||
temp0 >>= 3;
|
||||
*output = temp0;
|
||||
// Convert to temperature in degrees C
|
||||
*output = (XPT2046_TEMP0_COUNTS_AT_25C - *output) * (2.507 / 4096.0) / 0.0021 + 25.0;
|
||||
|
||||
#ifndef CONFIG_XPT2046_VREF_ON_MODE
|
||||
// Final read is to turn on the ADC and the Vref off
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, Z_VALUE_1, &temp0), TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_xpt2046_read_temp1_level(const esp_lcd_touch_handle_t handle, float *output)
|
||||
{
|
||||
uint16_t temp0;
|
||||
uint16_t temp1;
|
||||
#ifndef CONFIG_XPT2046_VREF_ON_MODE
|
||||
// First read is to turn on the Vref, so it has extra time to stabilise before we read it for real
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP0, &temp0), TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
// Read the temp0 value
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP0, &temp0), TAG, "XPT2046 read error!");
|
||||
// Read the temp1 value
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP1, &temp1), TAG, "XPT2046 read error!");
|
||||
// drop lowest three bits to convert to 12-bit value
|
||||
temp0 >>= 3;
|
||||
temp1 >>= 3;
|
||||
*output = temp1 - temp0;
|
||||
*output = *output * 1000.0 * (2.507 / 4096.0) * 2.573 - 273.0;
|
||||
|
||||
#ifndef CONFIG_XPT2046_VREF_ON_MODE
|
||||
// Final read is to turn on the ADC and the Vref off
|
||||
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, Z_VALUE_1, &temp0), TAG, "XPT2046 read error!");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
dependencies:
|
||||
esp_lcd_touch: '>=1.0.4'
|
||||
idf: '>=4.4'
|
||||
description: esp_lcd_touch driver for XPT2046 touch controllers.
|
||||
repository: git://github.com/atanisoft/esp_lcd_touch_xpt2046.git
|
||||
repository_info:
|
||||
commit_sha: 05f4ecb82f19e4aa11b855a8e57539ba34e9629c
|
||||
path: .
|
||||
url: https://github.com/atanisoft/esp_lcd_touch_xpt2046
|
||||
version: 1.0.6
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 atanisoft (github.com/atanisoft)
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_lcd_touch.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Recommended clock for SPI read of the XPT2046
|
||||
*
|
||||
*/
|
||||
#define ESP_LCD_TOUCH_SPI_CLOCK_HZ (1 * 1000 * 1000)
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)
|
||||
|
||||
/**
|
||||
* @brief Communication SPI device IO structure
|
||||
*
|
||||
*/
|
||||
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
|
||||
{ \
|
||||
.cs_gpio_num = (gpio_num_t)touch_cs, \
|
||||
.dc_gpio_num = GPIO_NUM_NC, \
|
||||
.spi_mode = 0, \
|
||||
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
|
||||
.trans_queue_depth = 3, \
|
||||
.on_color_trans_done = NULL, \
|
||||
.user_ctx = NULL, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
.flags = \
|
||||
{ \
|
||||
.dc_as_cmd_phase = 0, \
|
||||
.dc_low_on_data = 0, \
|
||||
.octal_mode = 0, \
|
||||
.lsb_first = 0 \
|
||||
} \
|
||||
}
|
||||
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,1,0)
|
||||
|
||||
/**
|
||||
* @brief Communication SPI device IO structure
|
||||
*
|
||||
*/
|
||||
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
|
||||
{ \
|
||||
.cs_gpio_num = (gpio_num_t)touch_cs, \
|
||||
.dc_gpio_num = GPIO_NUM_NC, \
|
||||
.spi_mode = 0, \
|
||||
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
|
||||
.trans_queue_depth = 3, \
|
||||
.on_color_trans_done = NULL, \
|
||||
.user_ctx = NULL, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
.flags = \
|
||||
{ \
|
||||
.dc_low_on_data = 0, \
|
||||
.octal_mode = 0, \
|
||||
.lsb_first = 0 \
|
||||
} \
|
||||
}
|
||||
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,1,2)
|
||||
|
||||
/**
|
||||
* @brief Communication SPI device IO structure
|
||||
*
|
||||
*/
|
||||
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
|
||||
{ \
|
||||
.cs_gpio_num = (gpio_num_t)touch_cs, \
|
||||
.dc_gpio_num = GPIO_NUM_NC, \
|
||||
.spi_mode = 0, \
|
||||
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
|
||||
.trans_queue_depth = 3, \
|
||||
.on_color_trans_done = NULL, \
|
||||
.user_ctx = NULL, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
.flags = \
|
||||
{ \
|
||||
.dc_low_on_data = 0, \
|
||||
.octal_mode = 0, \
|
||||
.sio_mode = 0, \
|
||||
.lsb_first = 0, \
|
||||
.cs_high_active = 0 \
|
||||
} \
|
||||
}
|
||||
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,1,3)
|
||||
|
||||
/**
|
||||
* @brief Communication SPI device IO structure
|
||||
*
|
||||
*/
|
||||
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
|
||||
{ \
|
||||
.cs_gpio_num = (gpio_num_t)touch_cs, \
|
||||
.dc_gpio_num = GPIO_NUM_NC, \
|
||||
.spi_mode = 0, \
|
||||
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
|
||||
.trans_queue_depth = 3, \
|
||||
.on_color_trans_done = NULL, \
|
||||
.user_ctx = NULL, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
.flags = \
|
||||
{ \
|
||||
.dc_low_on_data = 0, \
|
||||
.octal_mode = 0, \
|
||||
.quad_mode = 0, \
|
||||
.sio_mode = 0, \
|
||||
.lsb_first = 0, \
|
||||
.cs_high_active = 0 \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
|
||||
/**
|
||||
* @brief Communication SPI device IO structure
|
||||
*
|
||||
*/
|
||||
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
|
||||
{ \
|
||||
.cs_gpio_num = (gpio_num_t)touch_cs, \
|
||||
.dc_gpio_num = GPIO_NUM_NC, \
|
||||
.spi_mode = 0, \
|
||||
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
|
||||
.trans_queue_depth = 3, \
|
||||
.on_color_trans_done = NULL, \
|
||||
.user_ctx = NULL, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
.flags = \
|
||||
{ \
|
||||
.dc_high_on_cmd = 0, \
|
||||
.dc_low_on_data = 0, \
|
||||
.dc_low_on_param = 0, \
|
||||
.octal_mode = 0, \
|
||||
.quad_mode = 0, \
|
||||
.sio_mode = 0, \
|
||||
.lsb_first = 0, \
|
||||
.cs_high_active = 0 \
|
||||
} \
|
||||
}
|
||||
#endif // IDF v5.1.3
|
||||
|
||||
/**
|
||||
* @brief Create a new XPT2046 touch driver
|
||||
*
|
||||
* @note The SPI communication should be initialized before use this function.
|
||||
*
|
||||
* @param io: LCD/Touch panel IO handle.
|
||||
* @param config: Touch configuration.
|
||||
* @param out_touch: XPT2046 instance handle.
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NO_MEM if there is insufficient memory for allocating main structure.
|
||||
* - ESP_ERR_INVALID_ARG if @param io or @param config are null.
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_new_spi_xpt2046(const esp_lcd_panel_io_handle_t io,
|
||||
const esp_lcd_touch_config_t *config,
|
||||
esp_lcd_touch_handle_t *out_touch);
|
||||
|
||||
/**
|
||||
* @brief Reads the voltage from the v-bat pin of the XPT2046.
|
||||
*
|
||||
* @param handle: XPT2046 instance handle.
|
||||
* @param out_level: Approximate voltage read in from the v-bat pin.
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*
|
||||
* @note The v-bat pin has a voltage range of 0.0 to 6.0 volts.
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_xpt2046_read_battery_level(const esp_lcd_touch_handle_t handle, float *out_level);
|
||||
|
||||
/**
|
||||
* @brief Reads the voltage from the aux pin of the XPT2046.
|
||||
*
|
||||
* @param handle: XPT2046 instance handle.
|
||||
* @param out_level: Approximate voltage read in from the aux pin.
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*
|
||||
* @note The aux pin has a voltage range of 0.0 to 2.5 volts.
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_xpt2046_read_aux_level(const esp_lcd_touch_handle_t handle, float *out_level);
|
||||
|
||||
/**
|
||||
* @brief Reads the temperature from the XPT2046 using a one-point reading.
|
||||
* High precision (0.3 degrees C) but low accuracy requires a
|
||||
* calibration offset for accurate results.
|
||||
*
|
||||
* @param handle: XPT2046 instance handle.
|
||||
* @param out_level: Approximate tempreature of the TSC2046 in degrees C
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_xpt2046_read_temp0_level(const esp_lcd_touch_handle_t handle, float *output);
|
||||
|
||||
/**
|
||||
* @brief Reads the temperature from the XPT2046 using a two-point reading.
|
||||
* Low precision (1.6 degrees C) but high accuracy requires no calibration.
|
||||
*
|
||||
* @param handle: XPT2046 instance handle.
|
||||
* @param out_level: Approximate tempreature of the TSC2046 in degrees C
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_xpt2046_read_temp1_level(const esp_lcd_touch_handle_t handle, float *output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f
|
||||
89
managed_components/espressif__cmake_utilities/CHANGELOG.md
Normal file
89
managed_components/espressif__cmake_utilities/CHANGELOG.md
Normal file
@@ -0,0 +1,89 @@
|
||||
## v0.5.3 - 2023-09-15
|
||||
|
||||
* fix `add_dependencies called with incorrect number of arguments` in `relinker.cmake`
|
||||
* `include(cmake_utilities)` is not suggested now, to avoid cmake_utilities dependency issue
|
||||
|
||||
## v0.5.2 - 2023-09-15
|
||||
|
||||
* Support work on older ESP-IDF, eg: 4.3.x
|
||||
|
||||
## v0.5.1 - 2023-08-22
|
||||
|
||||
* Add string 1-byte align support
|
||||
|
||||
## v0.5.0 - 2023-08-02
|
||||
|
||||
* Add GCC LTO support
|
||||
|
||||
## v0.4.8 - 2023-05-24
|
||||
|
||||
* Add unit test app
|
||||
|
||||
### Bugfix:
|
||||
|
||||
* fix customer target redefinition issue
|
||||
|
||||
## v0.4.7 - 2023-04-21
|
||||
|
||||
* gen_compressed_ota: support the addition of a v2 compressed OTA header to compressed firmware.
|
||||
|
||||
## v0.4.6 - 2023-04-20
|
||||
|
||||
* relinker: add IDF v4.3.x support
|
||||
|
||||
## v0.4.5 - 2023-04-17
|
||||
|
||||
* gen_compressed_ota: remove slash use in gen_custom_ota.py so that the script can be used in the Windows cmd terminal.
|
||||
|
||||
## v0.4.4 - 2023-04-07
|
||||
|
||||
* relinker: suppressing the creation of `__pycache__`
|
||||
* relinker: support same name objects in one library
|
||||
|
||||
## v0.4.3 - 2023-03-24
|
||||
|
||||
* relinker: support decoding to get IRAM excluded libraries
|
||||
|
||||
## v0.4.2 - 2023-03-20
|
||||
|
||||
### Bugfix:
|
||||
|
||||
* gen_compressed_ota: Fix the number of bytes reserved in the v3 compressed image header
|
||||
* gen_compressed_ota: Fix definition of MD5 length in compressed image header for different versions.
|
||||
|
||||
## v0.4.1 - 2023-03-15
|
||||
|
||||
* relinker: add option to use customized configuration files
|
||||
* relinker: add option to print error information instead of throwing exception when missing function
|
||||
* relinker: move functions of SPI flash from IRAM to flash only when enable CONFIG_SPI_FLASH_ROM_IMPL
|
||||
* relinker: move some functions of esp_timer from IRAM to flash only when disable CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
|
||||
## v0.4.0 - 2023-03-13
|
||||
|
||||
### Feature:
|
||||
|
||||
* Add command `idf.py gen_single_bin` to generate merged bin file
|
||||
* Add command `idf.py flash_single_bin` to flash generated merged bin
|
||||
* Add config `Color in diagnostics` to control the GCC color output
|
||||
|
||||
## v0.3.0 - 2023-03-10
|
||||
|
||||
* Add gen_compressed_ota functionality, please refer to [gen_compressed_ota.md](https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities/docs/gen_compressed_ota.md)
|
||||
|
||||
## v0.2.1 - 2023-03-09
|
||||
|
||||
### Bugfix:
|
||||
|
||||
* package manager: Fix the compile issue when the name of the component has `-`, just like esp-xxx
|
||||
|
||||
## v0.2.0 - 2023-02-23
|
||||
|
||||
* Add relinker functionality, please refer to [relinker.md](https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities/docs/relinker.md)
|
||||
|
||||
## v0.1.0 - 2023-01-12
|
||||
|
||||
### Feature:
|
||||
|
||||
* Add function cu_pkg_get_version
|
||||
* Add macro cu_pkg_define_version
|
||||
* Add cmake script to CMAKE_MODULE_PATH
|
||||
@@ -0,0 +1 @@
|
||||
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-05-21T16:40:48.657779+00:00", "files": [{"path": "package_manager.cmake", "size": 2125, "hash": "1e7f6ba9cdcc8fc9f0a7dde5c5e1ec03ef699c210caf381181cc4a35f95f0ca1"}, {"path": "CMakeLists.txt", "size": 25, "hash": "1b07b2a81841a6e12fc589126fca551dfa39cd6db0646f802740972b48a2cf1b"}, {"path": "CHANGELOG.md", "size": 2592, "hash": "4779bc99678035cbd48addd07e6c5246213d7a93fb34ec469eb838fb64840c63"}, {"path": "idf_component.yml", "size": 255, "hash": "8c21ccd7648224f955d0f8e694fca3e5c469db87ceea389ebbf66b6e5c5da239"}, {"path": "Kconfig", "size": 2524, "hash": "e776e604c4395f8aa8d869a363d042e08eeea372887ff0e2b57535455f1bf3c0"}, {"path": "README.md", "size": 1340, "hash": "26229d274cc1e1add77cfe70eab0997059458894aff066ee2e227bf2c1fd9b7e"}, {"path": "project_include.cmake", "size": 354, "hash": "ca2f4fbba0ae2524cabe17844a79021d587cce6ec5fef53b36c21ae4d7257972"}, {"path": "gen_single_bin.cmake", "size": 1104, "hash": "34bc2100e339538edc47e86aa63cbeb7bc98c06a93105027a4603ba7f96b1dc2"}, {"path": "relinker.cmake", "size": 3288, "hash": "52ac755b429ee9cf6a45fd22121485d69f883d56c3b9f5d8eaa325156a070ad3"}, {"path": "license.txt", "size": 11358, "hash": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"}, {"path": "cmake_utilities.cmake", "size": 137, "hash": "307c1feb59598ff2351967009f1c6424820178b1da6903f40cc01dd52eb703ef"}, {"path": "gen_compressed_ota.cmake", "size": 727, "hash": "8309efee996bd2e5da0f55d26a0df1d199efb9c562eba07e410d49744401659a"}, {"path": "gcc.cmake", "size": 3585, "hash": "47674577242d2be68d6bc1c71bbe664a7e1d0047170ee1fe78f71b987c810620"}, {"path": "test_apps/CMakeLists.txt", "size": 374, "hash": "a851b56d24811c45175a960701596367c9a575b34a6fa8b7ab01bc2c1334c129"}, {"path": "test_apps/pytest_cmake_utilities.py", "size": 583, "hash": "5f60d02cdcaed3503bc259c51cff9af0c267887c86be825c097ed8f57a6a13fa"}, {"path": "docs/gen_compressed_ota.md", "size": 1620, "hash": "c7779477fb4989379898ad18b70af7738ff2bffe624e5d549a3b776aa983ca0b"}, {"path": "docs/gcc.md", "size": 3494, "hash": "908f5108283c7e3d0a046711ab8215fe6ccd59f09924d55cef0bbaf6a5a4ff3a"}, {"path": "docs/relinker.md", "size": 2963, "hash": "0cbffe09354d7e66ac05cf6de02bcdcf76dd2db69072e998e15ee268a5dd2384"}, {"path": "scripts/gen_custom_ota.py", "size": 13418, "hash": "64822db67089a6fdcde610d5ec31369aaa62441441f09d2ed8d4aae2a396e353"}, {"path": "scripts/relinker/configuration.py", "size": 6406, "hash": "7f5c80c0dd3504bcab89b585786b805544a8e39b17b59fc0ef911cb0813fba09"}, {"path": "scripts/relinker/relinker.py", "size": 9978, "hash": "07c1ec82d9f1843d3a12ade88295610ab78cc21c2dd90b02fe314d88d9085eac"}, {"path": "scripts/relinker/examples/esp32c2/object.csv", "size": 6783, "hash": "761467fbbe3adbf544adcfaa50b2fca1a79208786070784b000961c43a23744d"}, {"path": "scripts/relinker/examples/esp32c2/library.csv", "size": 1156, "hash": "5ca43f2ded3f5b3e1d1398949c86080ac1ff7d06e7d147dc5ecf21d0ec034e61"}, {"path": "scripts/relinker/examples/esp32c2/function.csv", "size": 22369, "hash": "5d608e6d35d7a2a6f5ac317ea5e993443b5baef0ce788eb2464aca37246bcb29"}, {"path": "test_apps/main/CMakeLists.txt", "size": 157, "hash": "1b582805eb1d7d515bac70643308b0bacf18dccee565df745051267635b09c1a"}, {"path": "test_apps/main/test_cmake_utilities.c", "size": 1848, "hash": "6ff7025750c8c59bbd379af839def4427c6f59149e19885ac674740e45eccdac"}, {"path": "test_apps/components/TEST-component2/CMakeLists.txt", "size": 285, "hash": "441a6b60573d3146386d56ccbf12cf4451eeef01cac2905b18259bb2a1912b64"}, {"path": "test_apps/components/TEST-component2/idf_component.yml", "size": 230, "hash": "dbbd16387c7b0ea7378126e87cafdf8b3bc58fdcf472e7d853b38ea24d813a2b"}, {"path": "test_apps/components/TEST-component2/test_component2.h", "size": 213, "hash": "42a6a9a527a8b78a6373a432a1d2c8c540bae91d7c604bbc12be5f709a16fb37"}, {"path": "test_apps/components/TEST-component2/test_component2.c", "size": 256, "hash": "d949b85dd1ce045b724cd463ac6549b372db9935ed07dc3dad250660d3b3f27f"}, {"path": "test_apps/components/test_component1/CMakeLists.txt", "size": 285, "hash": "441a6b60573d3146386d56ccbf12cf4451eeef01cac2905b18259bb2a1912b64"}, {"path": "test_apps/components/test_component1/test_component1.h", "size": 213, "hash": "e77976253127f05cbbfae7a635c9455d584b66cceae69ef8f8465fd4ce85aadf"}, {"path": "test_apps/components/test_component1/idf_component.yml", "size": 230, "hash": "70631b0633adbaa92bb26785dee0369f889cc93bc9a22635f1553f864522607b"}, {"path": "test_apps/components/test_component1/test_component1.c", "size": 256, "hash": "fe9ce9a01d53cfbc1970f0a9ee9c8d382c399e0c9aeb93ce843af01bd70b5411"}]}
|
||||
@@ -0,0 +1 @@
|
||||
idf_component_register()
|
||||
65
managed_components/espressif__cmake_utilities/Kconfig
Normal file
65
managed_components/espressif__cmake_utilities/Kconfig
Normal file
@@ -0,0 +1,65 @@
|
||||
menu "CMake Utilities"
|
||||
|
||||
config CU_RELINKER_ENABLE
|
||||
bool "Enable relinker"
|
||||
default n
|
||||
help
|
||||
"Enable relinker to linker some IRAM functions to Flash"
|
||||
|
||||
if CU_RELINKER_ENABLE
|
||||
config CU_RELINKER_ENABLE_PRINT_ERROR_INFO_WHEN_MISSING_FUNCTION
|
||||
bool "Print error information when missing function"
|
||||
default y
|
||||
help
|
||||
"Enable this option to print error information instead of
|
||||
throwing exception when missing function"
|
||||
|
||||
config CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES
|
||||
bool "Enable customized relinker configuration files"
|
||||
default n
|
||||
help
|
||||
"Enable this option to use customized relinker configuration
|
||||
files instead of default ones"
|
||||
|
||||
if CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES
|
||||
config CU_RELINKER_CUSTOMIZED_CONFIGURATION_FILES_PATH
|
||||
string "Customized relinker configuration files path"
|
||||
default ""
|
||||
help
|
||||
"Customized relinker configuration files path. This path is
|
||||
evaluated relative to the project root directory."
|
||||
endif
|
||||
endif
|
||||
|
||||
choice CU_DIAGNOSTICS_COLOR
|
||||
prompt "Color in diagnostics"
|
||||
default CU_DIAGNOSTICS_COLOR_ALWAYS
|
||||
help
|
||||
Use color in diagnostics. "never", "always", or "auto". If "always", GCC will output
|
||||
with color defined in GCC_COLORS environment variable. If "never", only output plain
|
||||
text. If "auto", only output with color when the standard error is a terminal and when
|
||||
not executing in an emacs shell.
|
||||
|
||||
config CU_DIAGNOSTICS_COLOR_NEVER
|
||||
bool "never"
|
||||
config CU_DIAGNOSTICS_COLOR_ALWAYS
|
||||
bool "always"
|
||||
config CU_DIAGNOSTICS_COLOR_AUTO
|
||||
bool "auto"
|
||||
endchoice
|
||||
|
||||
config CU_GCC_LTO_ENABLE
|
||||
bool "Enable GCC link time optimization(LTO)"
|
||||
default n
|
||||
help
|
||||
"Enable this option, users can enable GCC link time optimization(LTO)
|
||||
feature for target components or dependencies.
|
||||
|
||||
config CU_GCC_STRING_1BYTE_ALIGN
|
||||
bool "GCC string 1-byte align"
|
||||
default n
|
||||
help
|
||||
"Enable this option, user can make string in designated components align
|
||||
by 1-byte instead 1-word(4-byte), this can reduce unnecessary filled data
|
||||
so that to reduce firmware size."
|
||||
endmenu
|
||||
31
managed_components/espressif__cmake_utilities/README.md
Normal file
31
managed_components/espressif__cmake_utilities/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Cmake utilities
|
||||
|
||||
[](https://components.espressif.com/components/espressif/cmake_utilities)
|
||||
|
||||
This component is aiming to provide some useful CMake utilities outside of ESP-IDF.
|
||||
|
||||
## Use
|
||||
|
||||
1. Add dependency of this component in your component or project's idf_component.yml.
|
||||
|
||||
```yml
|
||||
dependencies:
|
||||
espressif/cmake_utilities: "0.*"
|
||||
```
|
||||
|
||||
2. Include the CMake file you need in your component's CMakeLists.txt after `idf_component_register`, or in your project's CMakeLists.txt
|
||||
|
||||
```cmake
|
||||
// Note: should remove .cmake postfix when using include(), otherwise the requested file will not found
|
||||
// Note: should place this line after `idf_component_register` function
|
||||
// only include the one you needed.
|
||||
include(package_manager)
|
||||
```
|
||||
|
||||
3. Then you can use the corresponding CMake function which is provided by the CMake file.
|
||||
|
||||
## Supported features
|
||||
|
||||
1. [relinker](https://github.com/espressif/esp-iot-solution/blob/master/tools/cmake_utilities/docs/relinker.md)
|
||||
2. [gen_compressed_ota](https://github.com/espressif/esp-iot-solution/blob/master/tools/cmake_utilities/docs/gen_compressed_ota.md)
|
||||
3. [GCC Optimization](https://github.com/espressif/esp-iot-solution/blob/master/tools/cmake_utilities/docs/gcc.md)
|
||||
@@ -0,0 +1,7 @@
|
||||
# Include all cmake modules
|
||||
|
||||
include(gcc)
|
||||
include(gen_compressed_ota)
|
||||
include(gen_single_bin)
|
||||
include(package_manager)
|
||||
include(relinker)
|
||||
108
managed_components/espressif__cmake_utilities/docs/gcc.md
Normal file
108
managed_components/espressif__cmake_utilities/docs/gcc.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Link Time Optimization(LTO)
|
||||
|
||||
Link time optimization(LTO) improves the optimization effect of GCC, such as reducing binary size, increasing performance, and so on. For more details please refer to related [GCC documents](https://gcc.gnu.org/onlinedocs/gccint/LTO.html).
|
||||
|
||||
## Use
|
||||
|
||||
To use this feature, you need to include the required CMake file in your project's CMakeLists.txt after `project(XXXX)`.
|
||||
|
||||
```cmake
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
project(XXXX)
|
||||
|
||||
include(gcc)
|
||||
```
|
||||
|
||||
The LTO feature is disabled by default. To use it, you should enable the option `CU_GCC_LTO_ENABLE` in menuconfig. Then specify target components or dependencies to be optimized by LTO after `include(gcc)` as follows:
|
||||
|
||||
```cmake
|
||||
include(gcc)
|
||||
|
||||
cu_gcc_lto_set(COMPONENTS component_a component_b
|
||||
DEPENDS dependence_a dependence_b)
|
||||
|
||||
cu_gcc_string_1byte_align(COMPONENTS component_c component_d
|
||||
DEPENDS dependence_c dependence_d)
|
||||
```
|
||||
|
||||
Based on your requirement, set compiling optimization level in the option `COMPILER_OPTIMIZATION`.
|
||||
|
||||
* Note
|
||||
|
||||
```
|
||||
1. Reducing firmware size may decrease performance
|
||||
2. Increasing performance may increase firmware size
|
||||
3. Enable LTO cause compiling time cost increases a lot
|
||||
4. Enable LTO may increase task stack cost
|
||||
5. Enable string 1-byte align may decrease string process speed
|
||||
```
|
||||
|
||||
## Limitation
|
||||
|
||||
At the linking stage, the LTO generates new function indexes instead of the file path as follows:
|
||||
|
||||
- LTO
|
||||
|
||||
```txt
|
||||
.text 0x00000000420016f4 0x6 /tmp/ccdjwYMH.ltrans51.ltrans.o
|
||||
0x00000000420016f4 app_main
|
||||
```
|
||||
|
||||
- Without LTO
|
||||
|
||||
```txt
|
||||
.text.app_main 0x00000000420016f4 0x6 esp-idf/main/libmain.a(app_main.c.obj)
|
||||
0x00000000420016f4 app_main
|
||||
```
|
||||
|
||||
So tools used to relink functions between flash and IRAM can't affect these optimized components and dependencies again. It is recommended that users had better optimize application components and dependencies than kernel and hardware driver ones.
|
||||
|
||||
## Example
|
||||
|
||||
The example applies LTO in `light` of `esp-matter` because its application code is much larger. Add LTO configuration into project script `CMakeLists.txt` as follows:
|
||||
|
||||
```cmake
|
||||
|
||||
project(light)
|
||||
|
||||
include(gcc)
|
||||
|
||||
# Add
|
||||
set(app_lto_components main chip esp_matter)
|
||||
# Add
|
||||
set(idf_lto_components lwip wpa_supplicant nvs_flash)
|
||||
# Add
|
||||
set(lto_depends mbedcrypto)
|
||||
|
||||
# Add
|
||||
cu_gcc_lto_set(COMPONENTS ${app_lto_components} ${idf_lto_components}
|
||||
DEPENDS ${lto_depends})
|
||||
```
|
||||
|
||||
Configure `ESP32-C2` as the target platform, enable `CU_GCC_LTO_ENABLE` and `CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE`, set `COMPILER_OPTIMIZATION` to be `-Os`.
|
||||
Increase the `main` task stack size to `5120` by option `ESP_MAIN_TASK_STACK_SIZE`.
|
||||
Compile the project, and then you can see the firmware size decrease a lot:
|
||||
|
||||
Option | Firmware size | Stask cost
|
||||
|:-:|:-:|:-:|
|
||||
-Os | 1,113,376 | 2508
|
||||
-Os + LTO | 1,020,640 | 4204
|
||||
|
||||
Then add `cu_gcc_string_1byte_align` after `cu_gcc_lto_set`:
|
||||
|
||||
```cmake
|
||||
# Add
|
||||
cu_gcc_lto_set(COMPONENTS ${app_lto_components} ${idf_lto_components}
|
||||
DEPENDS ${lto_depends})
|
||||
|
||||
cu_gcc_string_1byte_align(COMPONENTS ${app_lto_components} ${idf_lto_components}
|
||||
DEPENDS ${lto_depends})
|
||||
```
|
||||
|
||||
Build the project and the firmware size is:
|
||||
|
||||
Option | Firmware size |
|
||||
|:-:|:-:|
|
||||
-Os + LTO | 1,020,640 |
|
||||
-Os + LTO + string 1-byte align | 1,018,340 |
|
||||
@@ -0,0 +1,41 @@
|
||||
# Gen Compressed OTA
|
||||
|
||||
When using the compressed OTA, we need to generate the compressed app firmware. This document mainly describes how to generate the compressed app firmware.
|
||||
|
||||
For more information about compressed OTA, refer to [bootloader_support_plus](https://github.com/espressif/esp-iot-solution/tree/master/components/bootloader_support_plus).
|
||||
|
||||
## Use
|
||||
In order to use this feature, you need to include the needed CMake file in your project's CMakeLists.txt after `project(XXXX)`.
|
||||
|
||||
```cmake
|
||||
project(XXXX)
|
||||
|
||||
include(gen_compressed_ota)
|
||||
```
|
||||
|
||||
Generate the compressed app firmware in an ESP-IDF "project" directory by running:
|
||||
|
||||
```plaintext
|
||||
idf.py gen_compressed_ota
|
||||
```
|
||||
|
||||
This command will compile your project first, then it will generate the compressed app firmware. For example, run the command under the project `simple_ota_examples` folder. If there are no errors, the `custom_ota_binaries` folder will be created and contains the following files:
|
||||
|
||||
```plaintext
|
||||
simple_ota.bin.xz
|
||||
simple_ota.bin.xz.packed
|
||||
```
|
||||
|
||||
The file named `simple_ota.bin.xz.packed` is the actual compressed app binary file to be transferred.
|
||||
|
||||
In addition, if [secure boot](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/security/secure-boot-v2.html) is enabled, the command will generate the signed compressed app binary file:
|
||||
|
||||
```plaintext
|
||||
simple_ota.bin.xz.packed.signed
|
||||
```
|
||||
|
||||
you can also use the script [gen_custom_ota.py](https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities/scripts/gen_custom_ota.py) to compress the specified app:
|
||||
|
||||
```plaintext
|
||||
python3 gen_custom_ota.py -i simple_ota.bin
|
||||
```
|
||||
@@ -0,0 +1,66 @@
|
||||
# Relinker
|
||||
|
||||
In ESP-IDF, some functions are put in SRAM when link stage, the reason is that some functions are critical, we need to put them in SRAM to speed up the program, or the functions will be executed when the cache is disabled. But actually, some functions can be put into Flash, here, we provide a script to let the user set the functions which are located in SRAM by default to put them into Flash, in order to save more SRAM which can be used as heap region later. This happens in the linker stage, so we call it as relinker.
|
||||
|
||||
## Use
|
||||
|
||||
In order to use this feature, you need to include the needed CMake file in your project's CMakeLists.txt after `project(XXXX)`.
|
||||
|
||||
```cmake
|
||||
project(XXXX)
|
||||
|
||||
include(relinker)
|
||||
```
|
||||
|
||||
The relinker feature is disabled by default, in order to use it, you need to enable the option `CU_RELINKER_ENABLE` in menuconfig.
|
||||
|
||||
Here are the default configuration files in the folder `cmake_utilities/scripts/relinker/examples/esp32c2`, it's just used as a reference. If you would like to use your own configuration files, please enable option `CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES` and set the path of your configuration files as following, this path is evaluated relative to the project root directory:
|
||||
|
||||
```
|
||||
[*] Enable customized relinker configuration files
|
||||
(path of your configuration files) Customized relinker configuration files path
|
||||
```
|
||||
|
||||
> Note: Currently only esp32c2 is supported.
|
||||
|
||||
## Configuration Files
|
||||
|
||||
You can refer to the files in the directory of `cmake_utilities/scripts/relinker/examples/esp32c2`:
|
||||
|
||||
- library.csv
|
||||
- object.csv
|
||||
- function.csv
|
||||
|
||||
For example, if you want to link function `__getreent` from SRAM to Flash, firstly you should add it to `function.csv` file as following:
|
||||
|
||||
```
|
||||
libfreertos.a,tasks.c.obj,__getreent,
|
||||
```
|
||||
|
||||
This means function `__getreent` is in object file `tasks.c.obj`, and object file `tasks.c.obj` is in library `libfreertos.a`.
|
||||
|
||||
If function `__getreent` depends on the option `FREERTOS_PLACE_FUNCTIONS_INTO_FLASH` in menuconfig, then it should be:
|
||||
|
||||
```
|
||||
libfreertos.a,tasks.c.obj,__getreent,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
```
|
||||
|
||||
This means when only `FREERTOS_PLACE_FUNCTIONS_INTO_FLASH` is enabled in menuconfig, function `__getreent` will be linked from SRAM to Flash.
|
||||
|
||||
Next step you should add the path of the object file to `object.csv`:
|
||||
|
||||
```
|
||||
libfreertos.a,tasks.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/tasks.c.obj
|
||||
```
|
||||
|
||||
This means the object file `tasks.c.obj` is in library `libfreertos.a` and its location is `esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/tasks.c.obj` relative to directory of `build`.
|
||||
|
||||
Next step you should add path of library to `library.csv`:
|
||||
|
||||
```
|
||||
libfreertos.a,./esp-idf/freertos/libfreertos.a
|
||||
```
|
||||
|
||||
This means library `libfreertos.a`'s location is `./esp-idf/freertos/libfreertos.a` relative to `build`.
|
||||
|
||||
If above related data has exists in corresponding files, please don't add this repeatedly.
|
||||
84
managed_components/espressif__cmake_utilities/gcc.cmake
Normal file
84
managed_components/espressif__cmake_utilities/gcc.cmake
Normal file
@@ -0,0 +1,84 @@
|
||||
if(CONFIG_CU_GCC_LTO_ENABLE)
|
||||
# Enable cmake interprocedural optimization(IPO) support to check if GCC supports link time optimization(LTO)
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
include(CheckIPOSupported)
|
||||
|
||||
# Compare to "ar" and "ranlib", "gcc-ar" and "gcc-ranlib" integrate GCC LTO plugin
|
||||
set(CMAKE_AR ${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar)
|
||||
set(CMAKE_RANLIB ${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib)
|
||||
|
||||
macro(cu_gcc_lto_set)
|
||||
check_ipo_supported(RESULT result)
|
||||
if(result)
|
||||
message(STATUS "GCC link time optimization(LTO) is enable")
|
||||
|
||||
set(multi_value COMPONENTS DEPENDS)
|
||||
cmake_parse_arguments(LTO "" "" "${multi_value}" ${ARGN})
|
||||
|
||||
# Use full format LTO object file
|
||||
set(GCC_LTO_OBJECT_TYPE "-ffat-lto-objects")
|
||||
# Set compression level 9(min:0, max:9)
|
||||
set(GCC_LTO_COMPRESSION_LEVEL "-flto-compression-level=9")
|
||||
# Set partition level max to removed used symbol
|
||||
set(GCC_LTO_PARTITION_LEVEL "-flto-partition=max")
|
||||
|
||||
# Set mode "auto" to increase compiling speed
|
||||
set(GCC_LTO_COMPILE_OPTIONS "-flto=auto"
|
||||
${GCC_LTO_OBJECT_TYPE}
|
||||
${GCC_LTO_COMPRESSION_LEVEL})
|
||||
|
||||
# Enable GCC LTO and plugin when linking stage
|
||||
set(GCC_LTO_LINK_OPTIONS "-flto"
|
||||
"-fuse-linker-plugin"
|
||||
${GCC_LTO_OBJECT_TYPE}
|
||||
${GCC_LTO_PARTITION_LEVEL})
|
||||
|
||||
message(STATUS "GCC LTO for components: ${LTO_COMPONENTS}")
|
||||
foreach(c ${LTO_COMPONENTS})
|
||||
idf_component_get_property(t ${c} COMPONENT_LIB)
|
||||
target_compile_options(${t} PRIVATE ${GCC_LTO_COMPILE_OPTIONS})
|
||||
endforeach()
|
||||
|
||||
message(STATUS "GCC LTO for dependencies: ${LTO_DEPENDS}")
|
||||
foreach(d ${LTO_DEPENDS})
|
||||
target_compile_options(${d} PRIVATE ${GCC_LTO_COMPILE_OPTIONS})
|
||||
endforeach()
|
||||
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "4.4")
|
||||
target_link_libraries(${project_elf} PRIVATE ${GCC_LTO_LINK_OPTIONS})
|
||||
else()
|
||||
target_link_libraries(${project_elf} ${GCC_LTO_LINK_OPTIONS})
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "GCC link time optimization(LTO) is not supported")
|
||||
endif()
|
||||
endmacro()
|
||||
else()
|
||||
macro(cu_gcc_lto_set)
|
||||
message(STATUS "GCC link time optimization(LTO) is not enable")
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
if(CONFIG_CU_GCC_STRING_1BYTE_ALIGN)
|
||||
macro(cu_gcc_string_1byte_align)
|
||||
message(STATUS "GCC string 1-byte align is enable")
|
||||
|
||||
set(multi_value COMPONENTS DEPENDS)
|
||||
cmake_parse_arguments(STR_ALIGN "" "" "${multi_value}" ${ARGN})
|
||||
|
||||
message(STATUS "GCC string 1-byte align for components: ${STR_ALIGN_COMPONENTS}")
|
||||
foreach(c ${STR_ALIGN_COMPONENTS})
|
||||
idf_component_get_property(t ${c} COMPONENT_LIB)
|
||||
target_compile_options(${t} PRIVATE "-malign-data=natural")
|
||||
endforeach()
|
||||
|
||||
message(STATUS "GCC string 1-byte align for dependencies: ${STR_ALIGN_DEPENDS}")
|
||||
foreach(d ${STR_ALIGN_DEPENDS})
|
||||
target_compile_options(${d} PRIVATE "-malign-data=natural")
|
||||
endforeach()
|
||||
endmacro()
|
||||
else()
|
||||
macro(cu_gcc_string_1byte_align)
|
||||
message(STATUS "GCC string 1-byte align is not enable")
|
||||
endmacro()
|
||||
endif()
|
||||
@@ -0,0 +1,18 @@
|
||||
if (NOT TARGET gen_compressed_ota)
|
||||
add_custom_target(gen_compressed_ota)
|
||||
|
||||
if (CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT OR CONFIG_SECURE_BOOT_V2_ENABLED)
|
||||
set(COMPRESSED_OTA_BIN_SIGN_PARA --sign_key ${PROJECT_DIR}/${CONFIG_SECURE_BOOT_SIGNING_KEY})
|
||||
else()
|
||||
set(COMPRESSED_OTA_BIN_SIGN_PARA )
|
||||
endif()
|
||||
|
||||
set(GEN_COMPRESSED_BIN_CMD ${CMAKE_CURRENT_LIST_DIR}/scripts/gen_custom_ota.py ${COMPRESSED_OTA_BIN_SIGN_PARA} --add_app_header)
|
||||
|
||||
add_custom_command(TARGET gen_compressed_ota
|
||||
POST_BUILD
|
||||
COMMAND ${PYTHON} ${GEN_COMPRESSED_BIN_CMD}
|
||||
COMMENT "The gen compresssed bin cmd is: ${GEN_COMPRESSED_BIN_CMD}"
|
||||
)
|
||||
add_dependencies(gen_compressed_ota gen_project_binary)
|
||||
endif()
|
||||
@@ -0,0 +1,27 @@
|
||||
# Extend command to idf.py
|
||||
|
||||
# Generate single bin with name ${CMAKE_PROJECT_NAME}_merged.bin
|
||||
if (NOT TARGET gen_single_bin)
|
||||
add_custom_target(
|
||||
gen_single_bin
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Merge bin files to ${CMAKE_PROJECT_NAME}_merged.bin"
|
||||
COMMAND ${ESPTOOLPY} --chip ${IDF_TARGET} merge_bin -o ${CMAKE_PROJECT_NAME}_merged.bin @flash_args
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Merge bin done"
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS gen_project_binary bootloader
|
||||
VERBATIM USES_TERMINAL
|
||||
)
|
||||
endif()
|
||||
|
||||
# Flash bin ${CMAKE_PROJECT_NAME}_merged.bin to target chip
|
||||
if (NOT TARGET flash_single_bin)
|
||||
add_custom_target(
|
||||
flash_single_bin
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Flash merged bin ${CMAKE_PROJECT_NAME}_merged.bin to address 0x0"
|
||||
COMMAND ${ESPTOOLPY} --chip ${IDF_TARGET} write_flash 0x0 ${CMAKE_PROJECT_NAME}_merged.bin
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Flash merged bin done"
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS gen_single_bin
|
||||
VERBATIM USES_TERMINAL
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,7 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=4.1'
|
||||
description: A collection of useful cmake utilities
|
||||
issues: https://github.com/espressif/esp-iot-solution/issues
|
||||
url: https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities
|
||||
version: 0.5.3
|
||||
202
managed_components/espressif__cmake_utilities/license.txt
Normal file
202
managed_components/espressif__cmake_utilities/license.txt
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,45 @@
|
||||
# cu_pkg_get_version
|
||||
#
|
||||
# @brief Get the package's version information, the package is installed by component manager.
|
||||
#
|
||||
# @param[in] pkg_path the package's path, normally it's ${CMAKE_CURRENT_LIST_DIR}.
|
||||
#
|
||||
# @param[out] ver_major the major version of the package
|
||||
# @param[out] ver_minor the minor version of the package
|
||||
# @param[out] ver_patch the patch version of the package
|
||||
function(cu_pkg_get_version pkg_path ver_major ver_minor ver_patch)
|
||||
set(yml_file "${pkg_path}/idf_component.yml")
|
||||
if(EXISTS ${yml_file})
|
||||
file(READ ${yml_file} ver)
|
||||
string(REGEX MATCH "(^|\n)version: \"?([0-9]+).([0-9]+).([0-9]+)\"?" _ ${ver})
|
||||
set(${ver_major} ${CMAKE_MATCH_2} PARENT_SCOPE)
|
||||
set(${ver_minor} ${CMAKE_MATCH_3} PARENT_SCOPE)
|
||||
set(${ver_patch} ${CMAKE_MATCH_4} PARENT_SCOPE)
|
||||
else()
|
||||
message(WARNING " ${yml_file} not exist")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# cu_pkg_define_version
|
||||
#
|
||||
# @brief Add the package's version definitions using format ${NAME}_VER_MAJOR ${NAME}_VER_MINOR ${NAME}_VER_PATCH,
|
||||
# the ${NAME} will be inferred from package path, and namespace like `espressif__` will be removed if the package download from esp-registry
|
||||
# eg. espressif__usb_stream and usb_stream will generate same version definitions USB_STREAM_VER_MAJOR ...
|
||||
#
|
||||
# @param[in] pkg_path the package's path, normally it's ${CMAKE_CURRENT_LIST_DIR}.
|
||||
#
|
||||
macro(cu_pkg_define_version pkg_path)
|
||||
cu_pkg_get_version(${pkg_path} ver_major ver_minor ver_patch)
|
||||
get_filename_component(pkg_name ${pkg_path} NAME)
|
||||
string(FIND ${pkg_name} "__" pkg_name_pos)
|
||||
if(pkg_name_pos GREATER -1)
|
||||
math(EXPR pkg_name_pos "${pkg_name_pos} + 2")
|
||||
string(SUBSTRING ${pkg_name} ${pkg_name_pos} -1 pkg_name)
|
||||
endif()
|
||||
string(TOUPPER ${pkg_name} pkg_name)
|
||||
string(REPLACE "-" "_" pkg_name ${pkg_name})
|
||||
message(STATUS "${pkg_name}: ${ver_major}.${ver_minor}.${ver_patch}")
|
||||
list(LENGTH pkg_name_list len)
|
||||
target_compile_options(${COMPONENT_LIB} PUBLIC
|
||||
-D${pkg_name}_VER_MAJOR=${ver_major} -D${pkg_name}_VER_MINOR=${ver_minor} -D${pkg_name}_VER_PATCH=${ver_patch})
|
||||
endmacro()
|
||||
@@ -0,0 +1,9 @@
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_MODULE_PATH})
|
||||
|
||||
if(CONFIG_CU_DIAGNOSTICS_COLOR_ALWAYS)
|
||||
add_compile_options(-fdiagnostics-color=always)
|
||||
elseif(CONFIG_CU_DIAGNOSTICS_COLOR_AUTO)
|
||||
add_compile_options(-fdiagnostics-color=auto)
|
||||
elseif(CONFIG_CU_DIAGNOSTICS_COLOR_NEVER)
|
||||
add_compile_options(-fdiagnostics-color=never)
|
||||
endif()
|
||||
73
managed_components/espressif__cmake_utilities/relinker.cmake
Normal file
73
managed_components/espressif__cmake_utilities/relinker.cmake
Normal file
@@ -0,0 +1,73 @@
|
||||
# @brief Link designated functions from SRAM to Flash to save SRAM
|
||||
if(CONFIG_CU_RELINKER_ENABLE)
|
||||
# project_elf variable is only in project.cmake
|
||||
if(NOT TARGET customer_sections AND DEFINED project_elf)
|
||||
message(STATUS "Relinker is enabled.")
|
||||
if(CONFIG_IDF_TARGET_ESP32C2)
|
||||
set(target "esp32c2")
|
||||
else()
|
||||
message(FATAL_ERROR "Other targets are not supported.")
|
||||
endif()
|
||||
|
||||
if(CONFIG_CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES)
|
||||
idf_build_get_property(project_dir PROJECT_DIR)
|
||||
get_filename_component(cfg_file_path "${CONFIG_CU_RELINKER_CUSTOMIZED_CONFIGURATION_FILES_PATH}"
|
||||
ABSOLUTE BASE_DIR "${project_dir}")
|
||||
|
||||
if(NOT EXISTS "${cfg_file_path}")
|
||||
message(FATAL_ERROR "Relinker Configuration files path ${cfg_file_path} is not found.")
|
||||
endif()
|
||||
else()
|
||||
set(cfg_file_path ${PROJECT_DIR}/relinker/${target})
|
||||
if(NOT EXISTS ${cfg_file_path})
|
||||
set(cfg_file_path ${CMAKE_CURRENT_LIST_DIR}/scripts/relinker/examples/${target})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Relinker configuration files: ${cfg_file_path}")
|
||||
|
||||
set(library_file "${cfg_file_path}/library.csv")
|
||||
set(object_file "${cfg_file_path}/object.csv")
|
||||
set(function_file "${cfg_file_path}/function.csv")
|
||||
set(relinker_script "${CMAKE_CURRENT_LIST_DIR}/scripts/relinker/relinker.py")
|
||||
|
||||
set(cmake_objdump "${CMAKE_OBJDUMP}")
|
||||
set(link_path "${CMAKE_BINARY_DIR}/esp-idf/esp_system/ld")
|
||||
set(link_src_file "${link_path}/sections.ld")
|
||||
set(link_dst_file "${link_path}/customer_sections.ld")
|
||||
|
||||
set(relinker_opts --input ${link_src_file}
|
||||
--output ${link_dst_file}
|
||||
--library ${library_file}
|
||||
--object ${object_file}
|
||||
--function ${function_file}
|
||||
--sdkconfig ${sdkconfig}
|
||||
--objdump ${cmake_objdump})
|
||||
|
||||
if(CONFIG_CU_RELINKER_ENABLE_PRINT_ERROR_INFO_WHEN_MISSING_FUNCTION)
|
||||
list(APPEND relinker_opts --missing_function_info True)
|
||||
endif()
|
||||
|
||||
idf_build_get_property(link_depends __LINK_DEPENDS)
|
||||
|
||||
add_custom_command(OUTPUT ${link_dst_file}
|
||||
COMMAND ${python} -B ${relinker_script}
|
||||
${relinker_opts}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${link_dst_file}
|
||||
${link_src_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
/*relinker*/ >>
|
||||
${link_dst_file}
|
||||
DEPENDS "${link_depends}"
|
||||
"${library_file}"
|
||||
"${object_file}"
|
||||
"${function_file}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(customer_sections DEPENDS ${link_dst_file})
|
||||
add_dependencies(${project_elf} customer_sections)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Relinker isn't enabled.")
|
||||
endif()
|
||||
@@ -0,0 +1,243 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import sys
|
||||
import struct
|
||||
import argparse
|
||||
import binascii
|
||||
import hashlib
|
||||
import os
|
||||
import subprocess
|
||||
import shutil
|
||||
import json
|
||||
import lzma
|
||||
|
||||
# src_file = 'hello-world.bin'
|
||||
# compressed_file = 'hello-world.bin.xz'
|
||||
# packed_compressed_file = 'hello-world.bin.xz.packed'
|
||||
# siged_packed_compressed_file = 'hello-world.bin.xz.packed.signed'
|
||||
|
||||
binary_compress_type = {'none': 0, 'xz':1}
|
||||
header_version = {'v1': 1, 'v2': 2, 'v3': 3}
|
||||
|
||||
SCRIPT_VERSION = '1.0.0'
|
||||
ORIGIN_APP_IMAGE_HEADER_LEN = 288 # sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t). See esp_app_format.h
|
||||
# At present, we calculate the checksum of the first 4KB data of the old app.
|
||||
OLD_APP_CHECK_DATA_SIZE = 4096
|
||||
|
||||
# v1 compressed data header:
|
||||
# Note: Encryption_type field is deprecated, the field is reserved for compatibility.
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------|
|
||||
# | | Magic | header | Compress | delta | Encryption | Reserved | Firmware | The length of | The MD5 of | The CRC32 for| compressed |
|
||||
# | | number | version | type | type | type | | version | compressed data| compressed data| the header | data |
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------|
|
||||
# | Size | 4 bytes | 1 byte | 4 bits | 4 bits | 1 bytes | 1 bytes | 32 bytes | 4 bytes | 32 bytes | 4 bytes | |
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------|
|
||||
# | Data | String | | | | | | String | little-endian | byte string | little-endian| |
|
||||
# | type | ended | | | | | | ended | integer | | integer | |
|
||||
# | |with ‘\0’| | | | | | with ‘\0’| | | | Binary data|
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------|
|
||||
# | Data | “ESP” | 1 | 0/1 | 0/1 | | | | | | | |
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------|
|
||||
|
||||
# v2 compressed data header
|
||||
# Note: Encryption_type field is deprecated, the field is reserved for compatibility.
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------|
|
||||
# | | Magic | header | Compress | delta | Encryption | Reserved | Firmware | The length of | The MD5 of | base app check| The CRC32 for | The CRC32 for| compressed |
|
||||
# | | number | version | type | type | type | | version | compressed data| compressed data| data len | base app data | the header | data |
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------|
|
||||
# | Size | 4 bytes | 1 byte | 4 bits | 4 bits | 1 bytes | 1 bytes | 32 bytes | 4 bytes | 32 bytes | 4 bytes | 4 bytes | 4 bytes | |
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------|
|
||||
# | Data | String | | | | | | String | little-endian | byte string | little-endian | little-endian | little-endian| |
|
||||
# | type | ended | | | | | | ended | integer | | integer | integer | integer | |
|
||||
# | |with ‘\0’| | | | | | with ‘\0’| | | | | | Binary data|
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------|
|
||||
# | Data | “ESP” | 1 | 0/1 | 0/1 | | | | | | | | | |
|
||||
# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------|
|
||||
|
||||
# v3 compressed data header:
|
||||
# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------|
|
||||
# | | Magic | header | Compress | Reserved | Reserved | The length of | The MD5 of | The CRC32 for| compressed |
|
||||
# | | number | version | type | | | compressed data| compressed data| the header | data |
|
||||
# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------|
|
||||
# | Size | 4 bytes | 1 byte | 4 bits | 4 bits | 8 bytes | 4 bytes | 16 bytes | 4 bytes | |
|
||||
# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------|
|
||||
# | Data | String | integer | | | | little-endian | byte string | little-endian| |
|
||||
# | type | ended | | | | | integer | | integer | |
|
||||
# | |with ‘\0’| | | | | | | | Binary data|
|
||||
# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------|
|
||||
# | Data | “ESP” | 3 | 0/1 | | | | | | |
|
||||
# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------|
|
||||
|
||||
def xz_compress(store_directory, in_file):
|
||||
compressed_file = ''.join([in_file,'.xz'])
|
||||
if(os.path.exists(compressed_file)):
|
||||
os.remove(compressed_file)
|
||||
|
||||
xz_compressor_filter = [
|
||||
{"id": lzma.FILTER_LZMA2, "preset": 6, "dict_size": 64*1024},
|
||||
]
|
||||
with open(in_file, 'rb') as src_f:
|
||||
data = src_f.read()
|
||||
with lzma.open(compressed_file, "wb", format=lzma.FORMAT_XZ, check=lzma.CHECK_CRC32, filters=xz_compressor_filter) as f:
|
||||
f.write(data)
|
||||
f.close()
|
||||
|
||||
if not os.path.exists(os.path.join(store_directory, os.path.split(compressed_file)[1])):
|
||||
shutil.copy(compressed_file, store_directory)
|
||||
print('copy xz file done')
|
||||
|
||||
def secure_boot_sign(sign_key, in_file, out_file):
|
||||
ret = subprocess.call('espsecure.py sign_data --version 2 --keyfile {} --output {} {}'.format(sign_key, out_file, in_file), shell = True)
|
||||
if ret:
|
||||
raise Exception('sign failed')
|
||||
|
||||
def get_app_name():
|
||||
with open('flasher_args.json') as f:
|
||||
try:
|
||||
flasher_args = json.load(f)
|
||||
return flasher_args['app']['file']
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
return ''
|
||||
|
||||
def get_script_version():
|
||||
return SCRIPT_VERSION
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-hv', '--header_ver', nargs='?', choices = ['v1', 'v2', 'v3'],
|
||||
default='v3', help='the version of the packed file header [default:v3]')
|
||||
parser.add_argument('-c', '--compress_type', nargs= '?', choices = ['none', 'xz'],
|
||||
default='xz', help='compressed type [default:xz]')
|
||||
parser.add_argument('-i', '--in_file', nargs = '?',
|
||||
default='', help='the new app firmware')
|
||||
parser.add_argument('--sign_key', nargs = '?',
|
||||
default='', help='the sign key used for secure boot')
|
||||
parser.add_argument('-fv', '--fw_ver', nargs='?',
|
||||
default='', help='the version of the compressed data(this field is deprecated in v3)')
|
||||
parser.add_argument('--add_app_header', action="store_true", help='add app header to use native esp_ota_* & esp_https_ota_* APIs')
|
||||
parser.add_argument('-v', '--version', action='version', version=get_script_version(), help='the version of the script')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
compress_type = args.compress_type
|
||||
firmware_ver = args.fw_ver
|
||||
src_file = args.in_file
|
||||
sign_key = args.sign_key
|
||||
header_ver = args.header_ver
|
||||
add_app_header = args.add_app_header
|
||||
|
||||
if src_file == '':
|
||||
origin_app_name = get_app_name()
|
||||
if(origin_app_name == ''):
|
||||
print('get origin app name fail')
|
||||
return
|
||||
|
||||
if os.path.exists(origin_app_name):
|
||||
src_file = origin_app_name
|
||||
else:
|
||||
print('origin app.bin not found')
|
||||
return
|
||||
|
||||
print('src file is: {}'.format(src_file))
|
||||
|
||||
# rebuild the cpmpressed_app directroy
|
||||
cpmoressed_app_directory = 'custom_ota_binaries'
|
||||
if os.path.exists(cpmoressed_app_directory):
|
||||
shutil.rmtree(cpmoressed_app_directory)
|
||||
|
||||
os.mkdir(cpmoressed_app_directory)
|
||||
print('The compressed file will store in {}'.format(cpmoressed_app_directory))
|
||||
|
||||
#step1: compress
|
||||
if compress_type == 'xz':
|
||||
xz_compress(cpmoressed_app_directory, os.path.abspath(src_file))
|
||||
|
||||
origin_app_name = os.path.split(src_file)[1]
|
||||
|
||||
compressed_file_name = ''.join([origin_app_name, '.xz'])
|
||||
compressed_file = os.path.join(cpmoressed_app_directory, compressed_file_name)
|
||||
else:
|
||||
compressed_file = ''.join(src_file)
|
||||
|
||||
print('compressed file is: {}'.format(compressed_file))
|
||||
|
||||
#step2: packet the compressed image header
|
||||
with open(src_file, 'rb') as s_f:
|
||||
src_image_header = bytearray(s_f.read(ORIGIN_APP_IMAGE_HEADER_LEN))
|
||||
src_image_header[1] = 0x00
|
||||
|
||||
packed_file = ''.join([compressed_file,'.packed'])
|
||||
with open(compressed_file, 'rb') as src_f:
|
||||
data = src_f.read()
|
||||
f_len = src_f.tell()
|
||||
# magic number
|
||||
bin_data = struct.pack('4s', b'ESP')
|
||||
# header version
|
||||
bin_data += struct.pack('B', header_version[header_ver])
|
||||
# Compress type
|
||||
bin_data += struct.pack('B', binary_compress_type[compress_type])
|
||||
print('compressed type: {}'.format(binary_compress_type[compress_type]))
|
||||
# in header v1/v2, there is a field "Encryption type", this field has been deprecated in v3
|
||||
if (header_version[header_ver] < 3):
|
||||
bin_data += struct.pack('B', 0)
|
||||
# Reserved
|
||||
bin_data += struct.pack('?', 0)
|
||||
# Firmware version
|
||||
bin_data += struct.pack('32s', firmware_ver.encode())
|
||||
else:
|
||||
# Reserved
|
||||
bin_data += struct.pack('10s', b'0')
|
||||
# The length of the compressed data
|
||||
bin_data += struct.pack('<I', f_len)
|
||||
print('compressed data len: {}'.format(f_len))
|
||||
# The MD5 for the compressed data
|
||||
if (header_version[header_ver] < 3):
|
||||
bin_data += struct.pack('32s', hashlib.md5(data).digest())
|
||||
if (header_version[header_ver] == 2):
|
||||
# Todo, if it's diff OTA, write base app check data len
|
||||
bin_data += struct.pack('<I', 0)
|
||||
# Todo, if it's diff OTA, write base app crc32 checksum
|
||||
bin_data += struct.pack('<I', 0)
|
||||
else:
|
||||
bin_data += struct.pack('16s', hashlib.md5(data).digest())
|
||||
# The CRC32 for the header
|
||||
bin_data += struct.pack('<I', binascii.crc32(bin_data, 0x0))
|
||||
|
||||
# write compressed data
|
||||
bin_data += data
|
||||
with open(packed_file, 'wb') as dst_f:
|
||||
# write compressed image header and compressed dada
|
||||
dst_f.write(bin_data)
|
||||
|
||||
print('packed file is: {}'.format(packed_file))
|
||||
|
||||
#step3: if need sign, then sign the packed image
|
||||
if sign_key != '':
|
||||
signed_file = ''.join([packed_file,'.signed'])
|
||||
secure_boot_sign(sign_key, packed_file, signed_file)
|
||||
print('signed_file is: {}'.format(signed_file))
|
||||
else:
|
||||
signed_file = ''.join(packed_file)
|
||||
|
||||
if (header_version[header_ver] == 3) and add_app_header:
|
||||
with open(signed_file, 'rb+') as src_f:
|
||||
packed_data = src_f.read()
|
||||
src_f.seek(0)
|
||||
# write origin app image header
|
||||
src_f.write(src_image_header)
|
||||
# write compressed image header and compressed dada
|
||||
src_f.write(packed_data)
|
||||
print('app image header has been added')
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit(2)
|
||||
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
from io import StringIO
|
||||
|
||||
OPT_MIN_LEN = 7
|
||||
|
||||
espidf_objdump = None
|
||||
espidf_missing_function_info = True
|
||||
|
||||
class sdkconfig_c:
|
||||
def __init__(self, path):
|
||||
lines = open(path).read().splitlines()
|
||||
config = dict()
|
||||
for l in lines:
|
||||
if len(l) > OPT_MIN_LEN and l[0] != '#':
|
||||
mo = re.match( r'(.*)=(.*)', l, re.M|re.I)
|
||||
if mo:
|
||||
config[mo.group(1)]=mo.group(2).replace('"', '')
|
||||
self.config = config
|
||||
|
||||
def index(self, i):
|
||||
return self.config[i]
|
||||
|
||||
def check(self, options):
|
||||
options = options.replace(' ', '')
|
||||
if '&&' in options:
|
||||
for i in options.split('&&'):
|
||||
if i[0] == '!':
|
||||
i = i[1:]
|
||||
if i in self.config:
|
||||
return False
|
||||
else:
|
||||
if i not in self.config:
|
||||
return False
|
||||
else:
|
||||
i = options
|
||||
if i[0] == '!':
|
||||
i = i[1:]
|
||||
if i in self.config:
|
||||
return False
|
||||
else:
|
||||
if i not in self.config:
|
||||
return False
|
||||
return True
|
||||
|
||||
class object_c:
|
||||
def read_dump_info(self, pathes):
|
||||
new_env = os.environ.copy()
|
||||
new_env['LC_ALL'] = 'C'
|
||||
dumps = list()
|
||||
print('pathes:', pathes)
|
||||
for path in pathes:
|
||||
try:
|
||||
dump = StringIO(subprocess.check_output([espidf_objdump, '-t', path], env=new_env).decode())
|
||||
dumps.append(dump.readlines())
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise RuntimeError('cmd:%s result:%s'%(e.cmd, e.returncode))
|
||||
return dumps
|
||||
|
||||
def get_func_section(self, dumps, func):
|
||||
for dump in dumps:
|
||||
for l in dump:
|
||||
if ' %s'%(func) in l and '*UND*' not in l:
|
||||
m = re.match(r'(\S*)\s*([glw])\s*([F|O])\s*(\S*)\s*(\S*)\s*(\S*)\s*', l, re.M|re.I)
|
||||
if m and m[6] == func:
|
||||
return m[4].replace('.text.', '')
|
||||
if espidf_missing_function_info:
|
||||
print('%s failed to find section'%(func))
|
||||
return None
|
||||
else:
|
||||
raise RuntimeError('%s failed to find section'%(func))
|
||||
|
||||
def __init__(self, name, pathes, libray):
|
||||
self.name = name
|
||||
self.libray = libray
|
||||
self.funcs = dict()
|
||||
self.pathes = pathes
|
||||
self.dumps = self.read_dump_info(pathes)
|
||||
|
||||
def append(self, func):
|
||||
section = self.get_func_section(self.dumps, func)
|
||||
if section != None:
|
||||
self.funcs[func] = section
|
||||
|
||||
def functions(self):
|
||||
nlist = list()
|
||||
for i in self.funcs:
|
||||
nlist.append(i)
|
||||
return nlist
|
||||
|
||||
def sections(self):
|
||||
nlist = list()
|
||||
for i in self.funcs:
|
||||
nlist.append(self.funcs[i])
|
||||
return nlist
|
||||
|
||||
class library_c:
|
||||
def __init__(self, name, path):
|
||||
self.name = name
|
||||
self.path = path
|
||||
self.objs = dict()
|
||||
|
||||
def append(self, obj, path, func):
|
||||
if obj not in self.objs:
|
||||
self.objs[obj] = object_c(obj, path, self.name)
|
||||
self.objs[obj].append(func)
|
||||
|
||||
class libraries_c:
|
||||
def __init__(self):
|
||||
self.libs = dict()
|
||||
|
||||
def append(self, lib, lib_path, obj, obj_path, func):
|
||||
if lib not in self.libs:
|
||||
self.libs[lib] = library_c(lib, lib_path)
|
||||
self.libs[lib].append(obj, obj_path, func)
|
||||
|
||||
def dump(self):
|
||||
for libname in self.libs:
|
||||
lib = self.libs[libname]
|
||||
for objname in lib.objs:
|
||||
obj = lib.objs[objname]
|
||||
print('%s, %s, %s, %s'%(libname, objname, obj.path, obj.funcs))
|
||||
|
||||
class paths_c:
|
||||
def __init__(self):
|
||||
self.paths = dict()
|
||||
|
||||
def append(self, lib, obj, path):
|
||||
if '$IDF_PATH' in path:
|
||||
path = path.replace('$IDF_PATH', os.environ['IDF_PATH'])
|
||||
|
||||
if lib not in self.paths:
|
||||
self.paths[lib] = dict()
|
||||
if obj not in self.paths[lib]:
|
||||
self.paths[lib][obj] = list()
|
||||
self.paths[lib][obj].append(path)
|
||||
|
||||
def index(self, lib, obj):
|
||||
if lib not in self.paths:
|
||||
return None
|
||||
if '*' in self.paths[lib]:
|
||||
obj = '*'
|
||||
return self.paths[lib][obj]
|
||||
|
||||
def generator(library_file, object_file, function_file, sdkconfig_file, missing_function_info, objdump='riscv32-esp-elf-objdump'):
|
||||
global espidf_objdump, espidf_missing_function_info
|
||||
espidf_objdump = objdump
|
||||
espidf_missing_function_info = missing_function_info
|
||||
|
||||
sdkconfig = sdkconfig_c(sdkconfig_file)
|
||||
|
||||
lib_paths = paths_c()
|
||||
for p in csv.DictReader(open(library_file, 'r')):
|
||||
lib_paths.append(p['library'], '*', p['path'])
|
||||
|
||||
obj_paths = paths_c()
|
||||
for p in csv.DictReader(open(object_file, 'r')):
|
||||
obj_paths.append(p['library'], p['object'], p['path'])
|
||||
|
||||
libraries = libraries_c()
|
||||
for d in csv.DictReader(open(function_file, 'r')):
|
||||
if d['option'] and sdkconfig.check(d['option']) == False:
|
||||
print('skip %s(%s)'%(d['function'], d['option']))
|
||||
continue
|
||||
lib_path = lib_paths.index(d['library'], '*')
|
||||
obj_path = obj_paths.index(d['library'], d['object'])
|
||||
if not obj_path:
|
||||
obj_path = lib_path
|
||||
libraries.append(d['library'], lib_path[0], d['object'], obj_path, d['function'])
|
||||
return libraries
|
||||
|
||||
def main():
|
||||
argparser = argparse.ArgumentParser(description='Libraries management')
|
||||
|
||||
argparser.add_argument(
|
||||
'--library', '-l',
|
||||
help='Library description file',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--object', '-b',
|
||||
help='Object description file',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--function', '-f',
|
||||
help='Function description file',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--sdkconfig', '-s',
|
||||
help='sdkconfig file',
|
||||
type=str)
|
||||
|
||||
args = argparser.parse_args()
|
||||
|
||||
libraries = generator(args.library, args.object, args.function, args.sdkconfig)
|
||||
# libraries.dump()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,365 @@
|
||||
library,object,function,option
|
||||
libble_app.a,ble_hw.c.o,r_ble_hw_resolv_list_get_cur_entry,
|
||||
libble_app.a,ble_ll_adv.c.o,r_ble_ll_adv_set_sched,
|
||||
libble_app.a,ble_ll_adv.c.o,r_ble_ll_adv_sync_pdu_make,
|
||||
libble_app.a,ble_ll_adv.c.o,r_ble_ll_adv_sync_calculate,
|
||||
libble_app.a,ble_ll_conn.c.o,r_ble_ll_conn_is_dev_connected,
|
||||
libble_app.a,ble_ll_ctrl.c.o,r_ble_ll_ctrl_tx_done,
|
||||
libble_app.a,ble_lll_adv.c.o,r_ble_lll_adv_aux_scannable_pdu_payload_len,
|
||||
libble_app.a,ble_lll_adv.c.o,r_ble_lll_adv_halt,
|
||||
libble_app.a,ble_lll_adv.c.o,r_ble_lll_adv_periodic_schedule_next,
|
||||
libble_app.a,ble_lll_conn.c.o,r_ble_lll_conn_cth_flow_free_credit,
|
||||
libble_app.a,ble_lll_conn.c.o,r_ble_lll_conn_update_encryption,
|
||||
libble_app.a,ble_lll_conn.c.o,r_ble_lll_conn_set_slave_flow_control,
|
||||
libble_app.a,ble_lll_conn.c.o,r_ble_lll_init_rx_pkt_isr,
|
||||
libble_app.a,ble_lll_conn.c.o,r_ble_lll_conn_get_rx_mbuf,
|
||||
libble_app.a,ble_lll_rfmgmt.c.o,r_ble_lll_rfmgmt_enable,
|
||||
libble_app.a,ble_lll_rfmgmt.c.o,r_ble_lll_rfmgmt_timer_reschedule,
|
||||
libble_app.a,ble_lll_rfmgmt.c.o,r_ble_lll_rfmgmt_timer_exp,
|
||||
libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_targeta_is_matched,
|
||||
libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_rx_isr_on_legacy,
|
||||
libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_rx_isr_on_aux,
|
||||
libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_process_rsp_in_isr,
|
||||
libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_rx_pkt_isr,
|
||||
libble_app.a,ble_lll_sched.c.o,r_ble_lll_sched_execute_check,
|
||||
libble_app.a,ble_lll_sync.c.o,r_ble_lll_sync_event_start_cb,
|
||||
libble_app.a,ble_phy.c.o,r_ble_phy_set_rxhdr,
|
||||
libble_app.a,ble_phy.c.o,r_ble_phy_update_conn_sequence,
|
||||
libble_app.a,ble_phy.c.o,r_ble_phy_set_sequence_mode,
|
||||
libble_app.a,ble_phy.c.o,r_ble_phy_txpower_round,
|
||||
libble_app.a,os_mempool.c.obj,r_os_memblock_put,
|
||||
libbootloader_support.a,bootloader_flash.c.obj,bootloader_read_flash_id,
|
||||
libbootloader_support.a,flash_encrypt.c.obj,esp_flash_encryption_enabled,
|
||||
libbt.a,bt_osi_mem.c.obj,bt_osi_mem_calloc,CONFIG_BT_ENABLED
|
||||
libbt.a,bt_osi_mem.c.obj,bt_osi_mem_malloc,CONFIG_BT_ENABLED
|
||||
libbt.a,bt_osi_mem.c.obj,bt_osi_mem_malloc_internal,CONFIG_BT_ENABLED
|
||||
libbt.a,bt_osi_mem.c.obj,bt_osi_mem_free,CONFIG_BT_ENABLED
|
||||
libbt.a,bt.c.obj,esp_reset_rpa_moudle,CONFIG_BT_ENABLED
|
||||
libbt.a,bt.c.obj,osi_assert_wrapper,CONFIG_BT_ENABLED
|
||||
libbt.a,bt.c.obj,osi_random_wrapper,CONFIG_BT_ENABLED
|
||||
libbt.a,nimble_port.c.obj,nimble_port_run,CONFIG_BT_NIMBLE_ENABLED
|
||||
libbt.a,nimble_port.c.obj,nimble_port_get_dflt_eventq,CONFIG_BT_NIMBLE_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,os_callout_timer_cb,CONFIG_BT_ENABLED && !CONFIG_BT_NIMBLE_USE_ESP_TIMER
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_event_run,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_stop,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_time_get,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_reset,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_is_active,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_get_ticks,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_remaining_ticks,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_time_delay,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_is_empty,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_mutex_pend,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_mutex_release,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_init,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_pend,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_release,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_init,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_deinit,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_event_is_queued,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_event_get_arg,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_time_ms_to_ticks32,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_time_ticks_to_ms32,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_hw_is_in_critical,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_get_time_forever,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_os_started,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_get_current_task_id,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_event_reset,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_mem_reset,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_event_init,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_get_count,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_remove,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_hw_exit_critical,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_mutex_init,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_hw_enter_critical,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_put,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_get,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_deinit,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_mutex_deinit,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_deinit,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_init,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_event_deinit,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_time_ticks_to_ms,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_time_ms_to_ticks,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_set_arg,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_event_set_arg,CONFIG_BT_ENABLED
|
||||
libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_put,CONFIG_BT_ENABLED
|
||||
libdriver.a,gpio.c.obj,gpio_intr_service,
|
||||
libesp_app_format.a,esp_app_desc.c.obj,esp_app_get_elf_sha256,
|
||||
libesp_hw_support.a,cpu.c.obj,esp_cpu_wait_for_intr,
|
||||
libesp_hw_support.a,cpu.c.obj,esp_cpu_reset,
|
||||
libesp_hw_support.a,esp_clk.c.obj,esp_clk_cpu_freq,
|
||||
libesp_hw_support.a,esp_clk.c.obj,esp_clk_apb_freq,
|
||||
libesp_hw_support.a,esp_clk.c.obj,esp_clk_xtal_freq,
|
||||
libesp_hw_support.a,esp_memory_utils.c.obj,esp_ptr_byte_accessible,
|
||||
libesp_hw_support.a,hw_random.c.obj,esp_random,
|
||||
libesp_hw_support.a,intr_alloc.c.obj,shared_intr_isr,
|
||||
libesp_hw_support.a,intr_alloc.c.obj,esp_intr_noniram_disable,
|
||||
libesp_hw_support.a,intr_alloc.c.obj,esp_intr_noniram_enable,
|
||||
libesp_hw_support.a,intr_alloc.c.obj,esp_intr_enable,
|
||||
libesp_hw_support.a,intr_alloc.c.obj,esp_intr_disable,
|
||||
libesp_hw_support.a,periph_ctrl.c.obj,wifi_bt_common_module_enable,
|
||||
libesp_hw_support.a,periph_ctrl.c.obj,wifi_bt_common_module_disable,
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_ctrl_read_reg,
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_ctrl_read_reg_mask,
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_ctrl_write_reg,
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_ctrl_write_reg_mask,
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_enter_critical,
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_exit_critical,
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_analog_cali_reg_read,
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_analog_cali_reg_write,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_32k_enable_external,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_fast_src_set,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_slow_freq_get_hz,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_slow_src_get,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_slow_src_set,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_dig_clk8m_disable,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_set_config_fast,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_8m_enable,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_8md256_enabled,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_bbpll_configure,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_bbpll_enable,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_get_config,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_mhz_to_config,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_set_config,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_to_8m,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_to_pll_mhz,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_set_xtal,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_xtal_freq_get,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_to_xtal,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_bbpll_disable,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_apb_freq_update,
|
||||
libesp_hw_support.a,rtc_clk.c.obj,clk_ll_rtc_slow_get_src,FALSE
|
||||
libesp_hw_support.a,rtc_init.c.obj,rtc_vddsdio_set_config,
|
||||
libesp_hw_support.a,rtc_module.c.obj,rtc_isr,
|
||||
libesp_hw_support.a,rtc_module.c.obj,rtc_isr_noniram_disable,
|
||||
libesp_hw_support.a,rtc_module.c.obj,rtc_isr_noniram_enable,
|
||||
libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_pu,
|
||||
libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_finish,
|
||||
libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_get_default_config,
|
||||
libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_init,
|
||||
libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_low_init,
|
||||
libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_start,
|
||||
libesp_hw_support.a,rtc_time.c.obj,rtc_clk_cal,
|
||||
libesp_hw_support.a,rtc_time.c.obj,rtc_clk_cal_internal,
|
||||
libesp_hw_support.a,rtc_time.c.obj,rtc_time_get,
|
||||
libesp_hw_support.a,rtc_time.c.obj,rtc_time_us_to_slowclk,
|
||||
libesp_hw_support.a,rtc_time.c.obj,rtc_time_slowclk_to_us,
|
||||
libesp_hw_support.a,sleep_modes.c.obj,periph_ll_periph_enabled,
|
||||
libesp_hw_support.a,sleep_modes.c.obj,flush_uarts,
|
||||
libesp_hw_support.a,sleep_modes.c.obj,suspend_uarts,
|
||||
libesp_hw_support.a,sleep_modes.c.obj,resume_uarts,
|
||||
libesp_hw_support.a,sleep_modes.c.obj,esp_sleep_start,
|
||||
libesp_hw_support.a,sleep_modes.c.obj,esp_deep_sleep_start,
|
||||
libesp_hw_support.a,sleep_modes.c.obj,esp_light_sleep_inner,
|
||||
libesp_phy.a,phy_init.c.obj,esp_phy_common_clock_enable,
|
||||
libesp_phy.a,phy_init.c.obj,esp_phy_common_clock_disable,
|
||||
libesp_phy.a,phy_init.c.obj,esp_wifi_bt_power_domain_on,
|
||||
libesp_phy.a,phy_override.c.obj,phy_i2c_enter_critical,
|
||||
libesp_phy.a,phy_override.c.obj,phy_i2c_exit_critical,
|
||||
libesp_pm.a,pm_locks.c.obj,esp_pm_lock_acquire,
|
||||
libesp_pm.a,pm_locks.c.obj,esp_pm_lock_release,
|
||||
libesp_pm.a,pm_impl.c.obj,get_lowest_allowed_mode,
|
||||
libesp_pm.a,pm_impl.c.obj,esp_pm_impl_switch_mode,
|
||||
libesp_pm.a,pm_impl.c.obj,on_freq_update,
|
||||
libesp_pm.a,pm_impl.c.obj,vApplicationSleep,CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
libesp_pm.a,pm_impl.c.obj,do_switch,
|
||||
libesp_ringbuf.a,ringbuf.c.obj,prvCheckItemAvail,
|
||||
libesp_ringbuf.a,ringbuf.c.obj,prvGetFreeSize,
|
||||
libesp_ringbuf.a,ringbuf.c.obj,prvReceiveGenericFromISR,
|
||||
libesp_ringbuf.a,ringbuf.c.obj,xRingbufferGetMaxItemSize,
|
||||
libesp_rom.a,esp_rom_systimer.c.obj,systimer_hal_init,
|
||||
libesp_rom.a,esp_rom_systimer.c.obj,systimer_hal_set_alarm_period,
|
||||
libesp_rom.a,esp_rom_systimer.c.obj,systimer_hal_set_alarm_target,
|
||||
libesp_rom.a,esp_rom_systimer.c.obj,systimer_hal_set_tick_rate_ops,
|
||||
libesp_rom.a,esp_rom_uart.c.obj,esp_rom_uart_set_clock_baudrate,
|
||||
libesp_system.a,brownout.c.obj,rtc_brownout_isr_handler,
|
||||
libesp_system.a,cache_err_int.c.obj,esp_cache_err_get_cpuid,
|
||||
libesp_system.a,cpu_start.c.obj,call_start_cpu0,
|
||||
libesp_system.a,crosscore_int.c.obj,esp_crosscore_int_send,
|
||||
libesp_system.a,crosscore_int.c.obj,esp_crosscore_int_send_yield,
|
||||
libesp_system.a,esp_system.c.obj,esp_restart,
|
||||
libesp_system.a,esp_system.c.obj,esp_system_abort,
|
||||
libesp_system.a,reset_reason.c.obj,esp_reset_reason_set_hint,
|
||||
libesp_system.a,reset_reason.c.obj,esp_reset_reason_get_hint,
|
||||
libesp_system.a,ubsan.c.obj,__ubsan_include,
|
||||
libesp_timer.a,esp_timer.c.obj,esp_timer_get_next_alarm_for_wake_up,
|
||||
libesp_timer.a,esp_timer.c.obj,timer_list_unlock,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
libesp_timer.a,esp_timer.c.obj,timer_list_lock,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
libesp_timer.a,esp_timer.c.obj,timer_armed,
|
||||
libesp_timer.a,esp_timer.c.obj,timer_remove,
|
||||
libesp_timer.a,esp_timer.c.obj,timer_insert,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
libesp_timer.a,esp_timer.c.obj,esp_timer_start_once,
|
||||
libesp_timer.a,esp_timer.c.obj,esp_timer_start_periodic,
|
||||
libesp_timer.a,esp_timer.c.obj,esp_timer_stop,
|
||||
libesp_timer.a,esp_timer.c.obj,esp_timer_get_expiry_time,
|
||||
libesp_timer.a,esp_timer_impl_systimer.c.obj,esp_timer_impl_get_time,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
libesp_timer.a,esp_timer_impl_systimer.c.obj,esp_timer_impl_set_alarm_id,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
libesp_timer.a,esp_timer_impl_systimer.c.obj,esp_timer_impl_update_apb_freq,
|
||||
libesp_timer.a,esp_timer_impl_systimer.c.obj,esp_timer_impl_get_min_period_us,
|
||||
libesp_timer.a,ets_timer_legacy.c.obj,timer_initialized,
|
||||
libesp_timer.a,ets_timer_legacy.c.obj,ets_timer_arm_us,
|
||||
libesp_timer.a,ets_timer_legacy.c.obj,ets_timer_arm,
|
||||
libesp_timer.a,ets_timer_legacy.c.obj,ets_timer_disarm,
|
||||
libesp_timer.a,system_time.c.obj,esp_system_get_time,
|
||||
libesp_wifi.a,esp_adapter.c.obj,semphr_take_from_isr_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,wifi_realloc,
|
||||
libesp_wifi.a,esp_adapter.c.obj,coex_event_duration_get_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,coex_schm_interval_set_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,esp_empty_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,wifi_calloc,
|
||||
libesp_wifi.a,esp_adapter.c.obj,wifi_zalloc_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,env_is_chip_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,is_from_isr_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,semphr_give_from_isr_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,mutex_lock_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,mutex_unlock_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,task_ms_to_tick_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,wifi_apb80m_request_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,wifi_apb80m_release_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,timer_arm_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,wifi_malloc,
|
||||
libesp_wifi.a,esp_adapter.c.obj,timer_disarm_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,timer_arm_us_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,wifi_rtc_enable_iso_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,wifi_rtc_disable_iso_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,malloc_internal_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,realloc_internal_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,calloc_internal_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,zalloc_internal_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,coex_status_get_wrapper,
|
||||
libesp_wifi.a,esp_adapter.c.obj,coex_wifi_release_wrapper,
|
||||
libfreertos.a,list.c.obj,uxListRemove,FALSE
|
||||
libfreertos.a,list.c.obj,vListInitialise,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,list.c.obj,vListInitialiseItem,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,list.c.obj,vListInsert,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,list.c.obj,vListInsertEnd,FALSE
|
||||
libfreertos.a,port.c.obj,vApplicationStackOverflowHook,FALSE
|
||||
libfreertos.a,port.c.obj,vPortYieldOtherCore,FALSE
|
||||
libfreertos.a,port.c.obj,vPortYield,
|
||||
libfreertos.a,port_common.c.obj,xPortcheckValidStackMem,
|
||||
libfreertos.a,port_common.c.obj,vApplicationGetTimerTaskMemory,
|
||||
libfreertos.a,port_common.c.obj,esp_startup_start_app_common,
|
||||
libfreertos.a,port_common.c.obj,xPortCheckValidTCBMem,
|
||||
libfreertos.a,port_common.c.obj,vApplicationGetIdleTaskMemory,
|
||||
libfreertos.a,port_systick.c.obj,vPortSetupTimer,
|
||||
libfreertos.a,port_systick.c.obj,xPortSysTickHandler,FALSE
|
||||
libfreertos.a,queue.c.obj,prvCopyDataFromQueue,
|
||||
libfreertos.a,queue.c.obj,prvGetDisinheritPriorityAfterTimeout,
|
||||
libfreertos.a,queue.c.obj,prvIsQueueEmpty,
|
||||
libfreertos.a,queue.c.obj,prvNotifyQueueSetContainer,
|
||||
libfreertos.a,queue.c.obj,xQueueReceive,
|
||||
libfreertos.a,queue.c.obj,prvUnlockQueue,
|
||||
libfreertos.a,queue.c.obj,xQueueSemaphoreTake,
|
||||
libfreertos.a,queue.c.obj,xQueueReceiveFromISR,
|
||||
libfreertos.a,queue.c.obj,uxQueueMessagesWaitingFromISR,
|
||||
libfreertos.a,queue.c.obj,xQueueIsQueueEmptyFromISR,
|
||||
libfreertos.a,queue.c.obj,xQueueGiveFromISR,
|
||||
libfreertos.a,tasks.c.obj,__getreent,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,pcTaskGetName,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,prvAddCurrentTaskToDelayedList,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,prvDeleteTLS,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,pvTaskIncrementMutexHeldCount,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,taskSelectHighestPriorityTaskSMP,FALSE
|
||||
libfreertos.a,tasks.c.obj,taskYIELD_OTHER_CORE,FALSE
|
||||
libfreertos.a,tasks.c.obj,vTaskGetSnapshot,CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,vTaskInternalSetTimeOutState,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,vTaskPlaceOnEventList,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,vTaskPlaceOnEventListRestricted,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,vTaskPlaceOnUnorderedEventList,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,vTaskPriorityDisinheritAfterTimeout,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,vTaskReleaseEventListLock,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,vTaskTakeEventListLock,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,xTaskCheckForTimeOut,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,xTaskGetCurrentTaskHandle,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,xTaskGetSchedulerState,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,xTaskGetTickCount,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,xTaskPriorityDisinherit,FALSE
|
||||
libfreertos.a,tasks.c.obj,xTaskPriorityInherit,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
libfreertos.a,tasks.c.obj,prvGetExpectedIdleTime,FALSE
|
||||
libfreertos.a,tasks.c.obj,vTaskStepTick,FALSE
|
||||
libhal.a,brownout_hal.c.obj,brownout_hal_intr_clear,
|
||||
libhal.a,efuse_hal.c.obj,efuse_hal_chip_revision,
|
||||
libhal.a,efuse_hal.c.obj,efuse_hal_get_major_chip_version,
|
||||
libhal.a,efuse_hal.c.obj,efuse_hal_get_minor_chip_version,
|
||||
libheap.a,heap_caps.c.obj,dram_alloc_to_iram_addr,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_free,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_realloc_base,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_realloc,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_calloc_base,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_calloc,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_malloc_base,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_malloc,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_malloc_default,
|
||||
libheap.a,heap_caps.c.obj,heap_caps_realloc_default,
|
||||
libheap.a,heap_caps.c.obj,find_containing_heap,
|
||||
libheap.a,multi_heap.c.obj,_multi_heap_lock,
|
||||
libheap.a,multi_heap.c.obj,multi_heap_in_rom_init,
|
||||
liblog.a,log_freertos.c.obj,esp_log_timestamp,
|
||||
liblog.a,log_freertos.c.obj,esp_log_impl_lock,
|
||||
liblog.a,log_freertos.c.obj,esp_log_impl_unlock,
|
||||
liblog.a,log_freertos.c.obj,esp_log_impl_lock_timeout,
|
||||
liblog.a,log_freertos.c.obj,esp_log_early_timestamp,
|
||||
liblog.a,log.c.obj,esp_log_write,
|
||||
libmbedcrypto.a,esp_mem.c.obj,esp_mbedtls_mem_calloc,!CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC
|
||||
libmbedcrypto.a,esp_mem.c.obj,esp_mbedtls_mem_free,!CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC
|
||||
libnewlib.a,assert.c.obj,__assert_func,
|
||||
libnewlib.a,assert.c.obj,newlib_include_assert_impl,
|
||||
libnewlib.a,heap.c.obj,_calloc_r,
|
||||
libnewlib.a,heap.c.obj,_free_r,
|
||||
libnewlib.a,heap.c.obj,_malloc_r,
|
||||
libnewlib.a,heap.c.obj,_realloc_r,
|
||||
libnewlib.a,heap.c.obj,calloc,
|
||||
libnewlib.a,heap.c.obj,cfree,
|
||||
libnewlib.a,heap.c.obj,free,
|
||||
libnewlib.a,heap.c.obj,malloc,
|
||||
libnewlib.a,heap.c.obj,newlib_include_heap_impl,
|
||||
libnewlib.a,heap.c.obj,realloc,
|
||||
libnewlib.a,locks.c.obj,_lock_try_acquire_recursive,
|
||||
libnewlib.a,locks.c.obj,lock_release_generic,
|
||||
libnewlib.a,locks.c.obj,_lock_release,
|
||||
libnewlib.a,locks.c.obj,_lock_release_recursive,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_init,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_init_recursive,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_close,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_close_recursive,
|
||||
libnewlib.a,locks.c.obj,check_lock_nonzero,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_acquire,
|
||||
libnewlib.a,locks.c.obj,lock_init_generic,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_acquire_recursive,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_try_acquire,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_try_acquire_recursive,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_release,
|
||||
libnewlib.a,locks.c.obj,__retarget_lock_release_recursive,
|
||||
libnewlib.a,locks.c.obj,_lock_close,
|
||||
libnewlib.a,locks.c.obj,lock_acquire_generic,
|
||||
libnewlib.a,locks.c.obj,_lock_acquire,
|
||||
libnewlib.a,locks.c.obj,_lock_acquire_recursive,
|
||||
libnewlib.a,locks.c.obj,_lock_try_acquire,
|
||||
libnewlib.a,reent_init.c.obj,esp_reent_init,
|
||||
libnewlib.a,time.c.obj,_times_r,
|
||||
libnewlib.a,time.c.obj,_gettimeofday_r,
|
||||
libpp.a,pp_debug.o,wifi_gpio_debug,
|
||||
libpthread.a,pthread.c.obj,pthread_mutex_lock_internal,
|
||||
libpthread.a,pthread.c.obj,pthread_mutex_lock,
|
||||
libpthread.a,pthread.c.obj,pthread_mutex_unlock,
|
||||
libriscv.a,interrupt.c.obj,intr_handler_get,
|
||||
libriscv.a,interrupt.c.obj,intr_handler_set,
|
||||
libriscv.a,interrupt.c.obj,intr_matrix_route,
|
||||
libspi_flash.a,flash_brownout_hook.c.obj,spi_flash_needs_reset_check,FALSE
|
||||
libspi_flash.a,flash_brownout_hook.c.obj,spi_flash_set_erasing_flag,FALSE
|
||||
libspi_flash.a,flash_ops.c.obj,spi_flash_guard_set,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,flash_ops.c.obj,spi_flash_malloc_internal,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,flash_ops.c.obj,spi_flash_rom_impl_init,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,flash_ops.c.obj,esp_mspi_pin_init,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,flash_ops.c.obj,spi_flash_init_chip_state,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_app.c.obj,delay_us,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_app.c.obj,get_buffer_malloc,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_app.c.obj,release_buffer_malloc,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_app.c.obj,main_flash_region_protected,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_app.c.obj,main_flash_op_status,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_app.c.obj,spi1_flash_os_check_yield,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_app.c.obj,spi1_flash_os_yield,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_noos.c.obj,start,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_noos.c.obj,end,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
libspi_flash.a,spi_flash_os_func_noos.c.obj,delay_us,CONFIG_SPI_FLASH_ROM_IMPL
|
||||
|
@@ -0,0 +1,24 @@
|
||||
library,path
|
||||
libble_app.a,$IDF_PATH/components/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a
|
||||
libpp.a,$IDF_PATH/components/esp_wifi/lib/esp32c2/libpp.a
|
||||
libbootloader_support.a,./esp-idf/bootloader_support/libbootloader_support.a
|
||||
libbt.a,./esp-idf/bt/libbt.a
|
||||
libdriver.a,./esp-idf/driver/libdriver.a
|
||||
libesp_app_format.a,./esp-idf/esp_app_format/libesp_app_format.a
|
||||
libesp_hw_support.a,./esp-idf/esp_hw_support/libesp_hw_support.a
|
||||
libesp_phy.a,./esp-idf/esp_phy/libesp_phy.a
|
||||
libesp_pm.a,./esp-idf/esp_pm/libesp_pm.a
|
||||
libesp_ringbuf.a,./esp-idf/esp_ringbuf/libesp_ringbuf.a
|
||||
libesp_rom.a,./esp-idf/esp_rom/libesp_rom.a
|
||||
libesp_system.a,./esp-idf/esp_system/libesp_system.a
|
||||
libesp_timer.a,./esp-idf/esp_timer/libesp_timer.a
|
||||
libesp_wifi.a,./esp-idf/esp_wifi/libesp_wifi.a
|
||||
libfreertos.a,./esp-idf/freertos/libfreertos.a
|
||||
libhal.a,./esp-idf/hal/libhal.a
|
||||
libheap.a,./esp-idf/heap/libheap.a
|
||||
liblog.a,./esp-idf/log/liblog.a
|
||||
libmbedcrypto.a,./esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a
|
||||
libnewlib.a,./esp-idf/newlib/libnewlib.a
|
||||
libpthread.a,./esp-idf/pthread/libpthread.a
|
||||
libriscv.a,./esp-idf/riscv/libriscv.a
|
||||
libspi_flash.a,./esp-idf/spi_flash/libspi_flash.a
|
||||
|
@@ -0,0 +1,66 @@
|
||||
library,object,path
|
||||
libbootloader_support.a,bootloader_flash.c.obj,esp-idf/bootloader_support/CMakeFiles/__idf_bootloader_support.dir/bootloader_flash/src/bootloader_flash.c.obj
|
||||
libbootloader_support.a,flash_encrypt.c.obj,esp-idf/bootloader_support/CMakeFiles/__idf_bootloader_support.dir/src/flash_encrypt.c.obj
|
||||
libbt.a,bt_osi_mem.c.obj,esp-idf/bt/CMakeFiles/__idf_bt.dir/porting/mem/bt_osi_mem.c.obj
|
||||
libbt.a,bt.c.obj,esp-idf/bt/CMakeFiles/__idf_bt.dir/controller/esp32c2/bt.c.obj
|
||||
libbt.a,npl_os_freertos.c.obj,esp-idf/bt/CMakeFiles/__idf_bt.dir/porting/npl/freertos/src/npl_os_freertos.c.obj
|
||||
libbt.a,nimble_port.c.obj,esp-idf/bt/CMakeFiles/__idf_bt.dir/host/nimble/nimble/porting/nimble/src/nimble_port.c.obj
|
||||
libdriver.a,gpio.c.obj,esp-idf/driver/CMakeFiles/__idf_driver.dir/gpio/gpio.c.obj
|
||||
libesp_app_format.a,esp_app_desc.c.obj,esp-idf/esp_app_format/CMakeFiles/__idf_esp_app_format.dir/esp_app_desc.c.obj
|
||||
libesp_hw_support.a,cpu.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/cpu.c.obj
|
||||
libesp_hw_support.a,esp_clk.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/esp_clk.c.obj
|
||||
libesp_hw_support.a,esp_memory_utils.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/esp_memory_utils.c.obj
|
||||
libesp_hw_support.a,hw_random.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/hw_random.c.obj
|
||||
libesp_hw_support.a,intr_alloc.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/intr_alloc.c.obj
|
||||
libesp_hw_support.a,periph_ctrl.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/periph_ctrl.c.obj
|
||||
libesp_hw_support.a,regi2c_ctrl.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/regi2c_ctrl.c.obj
|
||||
libesp_hw_support.a,rtc_clk.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/port/esp32c2/rtc_clk.c.obj
|
||||
libesp_hw_support.a,rtc_init.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/port/esp32c2/rtc_init.c.obj
|
||||
libesp_hw_support.a,rtc_module.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/rtc_module.c.obj
|
||||
libesp_hw_support.a,rtc_sleep.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/port/esp32c2/rtc_sleep.c.obj
|
||||
libesp_hw_support.a,rtc_time.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/port/esp32c2/rtc_time.c.obj
|
||||
libesp_hw_support.a,sleep_modes.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/sleep_modes.c.obj
|
||||
libesp_phy.a,phy_init.c.obj,esp-idf/esp_phy/CMakeFiles/__idf_esp_phy.dir/src/phy_init.c.obj
|
||||
libesp_phy.a,phy_override.c.obj,esp-idf/esp_phy/CMakeFiles/__idf_esp_phy.dir/src/phy_override.c.obj
|
||||
libesp_pm.a,pm_locks.c.obj,esp-idf/esp_pm/CMakeFiles/__idf_esp_pm.dir/pm_locks.c.obj
|
||||
libesp_pm.a,pm_impl.c.obj,esp-idf/esp_pm/CMakeFiles/__idf_esp_pm.dir/pm_impl.c.obj
|
||||
libesp_ringbuf.a,ringbuf.c.obj,esp-idf/esp_ringbuf/CMakeFiles/__idf_esp_ringbuf.dir/ringbuf.c.obj
|
||||
libesp_rom.a,esp_rom_systimer.c.obj,esp-idf/esp_rom/CMakeFiles/__idf_esp_rom.dir/patches/esp_rom_systimer.c.obj
|
||||
libesp_rom.a,esp_rom_uart.c.obj,esp-idf/esp_rom/CMakeFiles/__idf_esp_rom.dir/patches/esp_rom_uart.c.obj
|
||||
libesp_system.a,brownout.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/brownout.c.obj
|
||||
libesp_system.a,cache_err_int.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/soc/esp32c2/cache_err_int.c.obj
|
||||
libesp_system.a,cpu_start.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/cpu_start.c.obj
|
||||
libesp_system.a,crosscore_int.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/crosscore_int.c.obj
|
||||
libesp_system.a,esp_system.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/esp_system.c.obj
|
||||
libesp_system.a,reset_reason.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/soc/esp32c2/reset_reason.c.obj
|
||||
libesp_system.a,ubsan.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/ubsan.c.obj
|
||||
libesp_timer.a,esp_timer.c.obj,esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/esp_timer.c.obj
|
||||
libesp_timer.a,esp_timer_impl_systimer.c.obj,esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/esp_timer_impl_systimer.c.obj
|
||||
libesp_timer.a,ets_timer_legacy.c.obj,esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/ets_timer_legacy.c.obj
|
||||
libesp_timer.a,system_time.c.obj,esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/system_time.c.obj
|
||||
libesp_wifi.a,esp_adapter.c.obj,esp-idf/esp_wifi/CMakeFiles/__idf_esp_wifi.dir/esp32c2/esp_adapter.c.obj
|
||||
libfreertos.a,list.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/list.c.obj
|
||||
libfreertos.a,port.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/riscv/port.c.obj
|
||||
libfreertos.a,port_common.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/port_common.c.obj
|
||||
libfreertos.a,port_systick.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/port_systick.c.obj
|
||||
libfreertos.a,queue.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/queue.c.obj
|
||||
libfreertos.a,tasks.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/tasks.c.obj
|
||||
libhal.a,brownout_hal.c.obj,esp-idf/hal/CMakeFiles/__idf_hal.dir/esp32c2/brownout_hal.c.obj
|
||||
libhal.a,efuse_hal.c.obj,esp-idf/hal/CMakeFiles/__idf_hal.dir/efuse_hal.c.obj
|
||||
libhal.a,efuse_hal.c.obj,esp-idf/hal/CMakeFiles/__idf_hal.dir/esp32c2/efuse_hal.c.obj
|
||||
libheap.a,heap_caps.c.obj,esp-idf/heap/CMakeFiles/__idf_heap.dir/heap_caps.c.obj
|
||||
libheap.a,multi_heap.c.obj,./esp-idf/heap/CMakeFiles/__idf_heap.dir/multi_heap.c.obj
|
||||
liblog.a,log_freertos.c.obj,esp-idf/log/CMakeFiles/__idf_log.dir/log_freertos.c.obj
|
||||
liblog.a,log.c.obj,esp-idf/log/CMakeFiles/__idf_log.dir/log.c.obj
|
||||
libmbedcrypto.a,esp_mem.c.obj,esp-idf/mbedtls/mbedtls/library/CMakeFiles/mbedcrypto.dir/$IDF_PATH/components/mbedtls/port/esp_mem.c.obj
|
||||
libnewlib.a,assert.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/assert.c.obj
|
||||
libnewlib.a,heap.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/heap.c.obj
|
||||
libnewlib.a,locks.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/locks.c.obj
|
||||
libnewlib.a,reent_init.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/reent_init.c.obj
|
||||
libnewlib.a,time.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/time.c.obj
|
||||
libpthread.a,pthread.c.obj,esp-idf/pthread/CMakeFiles/__idf_pthread.dir/pthread.c.obj
|
||||
libriscv.a,interrupt.c.obj,esp-idf/riscv/CMakeFiles/__idf_riscv.dir/interrupt.c.obj
|
||||
libspi_flash.a,flash_brownout_hook.c.obj,esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/flash_brownout_hook.c.obj
|
||||
libspi_flash.a,flash_ops.c.obj,esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/flash_ops.c.obj
|
||||
libspi_flash.a,spi_flash_os_func_app.c.obj,esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/spi_flash_os_func_app.c.obj
|
||||
libspi_flash.a,spi_flash_os_func_noos.c.obj,esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/spi_flash_os_func_noos.c.obj
|
||||
|
@@ -0,0 +1,311 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import logging
|
||||
import argparse
|
||||
import csv
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
from io import StringIO
|
||||
import configuration
|
||||
|
||||
sys.path.append(os.environ['IDF_PATH'] + '/tools/ldgen')
|
||||
sys.path.append(os.environ['IDF_PATH'] + '/tools/ldgen/ldgen')
|
||||
from entity import EntityDB
|
||||
|
||||
espidf_objdump = None
|
||||
|
||||
def lib_secs(lib, file, lib_path):
|
||||
new_env = os.environ.copy()
|
||||
new_env['LC_ALL'] = 'C'
|
||||
dump = StringIO(subprocess.check_output([espidf_objdump, '-h', lib_path], env=new_env).decode())
|
||||
dump.name = lib
|
||||
|
||||
sections_infos = EntityDB()
|
||||
sections_infos.add_sections_info(dump)
|
||||
|
||||
secs = sections_infos.get_sections(lib, file.split('.')[0] + '.c')
|
||||
if len(secs) == 0:
|
||||
secs = sections_infos.get_sections(lib, file.split('.')[0])
|
||||
if len(secs) == 0:
|
||||
raise ValueError('Failed to get sections from lib %s'%(lib_path))
|
||||
|
||||
return secs
|
||||
|
||||
def filter_secs(secs_a, secs_b):
|
||||
new_secs = list()
|
||||
for s_a in secs_a:
|
||||
for s_b in secs_b:
|
||||
if s_b in s_a:
|
||||
new_secs.append(s_a)
|
||||
return new_secs
|
||||
|
||||
def strip_secs(secs_a, secs_b):
|
||||
secs = list(set(secs_a) - set(secs_b))
|
||||
secs.sort()
|
||||
return secs
|
||||
|
||||
def func2sect(func):
|
||||
if ' ' in func:
|
||||
func_l = func.split(' ')
|
||||
else:
|
||||
func_l = list()
|
||||
func_l.append(func)
|
||||
|
||||
secs = list()
|
||||
for l in func_l:
|
||||
if '.iram1.' not in l:
|
||||
secs.append('.literal.%s'%(l,))
|
||||
secs.append('.text.%s'%(l, ))
|
||||
else:
|
||||
secs.append(l)
|
||||
return secs
|
||||
|
||||
class filter_c:
|
||||
def __init__(self, file):
|
||||
lines = open(file).read().splitlines()
|
||||
self.libs_desc = ''
|
||||
self.libs = ''
|
||||
for l in lines:
|
||||
if ') .iram1 EXCLUDE_FILE(*' in l and ') .iram1.*)' in l:
|
||||
desc = '\(EXCLUDE_FILE\((.*)\) .iram1 '
|
||||
self.libs_desc = re.search(desc, l)[1]
|
||||
self.libs = self.libs_desc.replace('*', '')
|
||||
return
|
||||
|
||||
def match(self, lib):
|
||||
if lib in self.libs:
|
||||
print('Remove lib %s'%(lib))
|
||||
return True
|
||||
return False
|
||||
|
||||
def add(self):
|
||||
return self.libs_desc
|
||||
|
||||
class target_c:
|
||||
def __init__(self, lib, lib_path, file, fsecs):
|
||||
self.lib = lib
|
||||
self.file = file
|
||||
|
||||
self.lib_path = lib_path
|
||||
self.fsecs = func2sect(fsecs)
|
||||
self.desc = '*%s:%s.*'%(lib, file.split('.')[0])
|
||||
|
||||
secs = lib_secs(lib, file, lib_path)
|
||||
if '.iram1.' in self.fsecs[0]:
|
||||
self.secs = filter_secs(secs, ('.iram1.', ))
|
||||
else:
|
||||
self.secs = filter_secs(secs, ('.iram1.', '.text.', '.literal.'))
|
||||
self.isecs = strip_secs(self.secs, self.fsecs)
|
||||
|
||||
def __str__(self):
|
||||
s = 'lib=%s\nfile=%s\lib_path=%s\ndesc=%s\nsecs=%s\nfsecs=%s\nisecs=%s\n'%(\
|
||||
self.lib, self.file, self.lib_path, self.desc, self.secs, self.fsecs,\
|
||||
self.isecs)
|
||||
return s
|
||||
|
||||
class relink_c:
|
||||
def __init__(self, input, library_file, object_file, function_file, sdkconfig_file, missing_function_info):
|
||||
self.filter = filter_c(input)
|
||||
|
||||
libraries = configuration.generator(library_file, object_file, function_file, sdkconfig_file, missing_function_info, espidf_objdump)
|
||||
self.targets = list()
|
||||
for i in libraries.libs:
|
||||
lib = libraries.libs[i]
|
||||
|
||||
if self.filter.match(lib.name):
|
||||
continue
|
||||
|
||||
for j in lib.objs:
|
||||
obj = lib.objs[j]
|
||||
self.targets.append(target_c(lib.name, lib.path, obj.name,
|
||||
' '.join(obj.sections())))
|
||||
# for i in self.targets:
|
||||
# print(i)
|
||||
self.__transform__()
|
||||
|
||||
def __transform__(self):
|
||||
iram1_exclude = list()
|
||||
iram1_include = list()
|
||||
flash_include = list()
|
||||
|
||||
for t in self.targets:
|
||||
secs = filter_secs(t.fsecs, ('.iram1.', ))
|
||||
if len(secs) > 0:
|
||||
iram1_exclude.append(t.desc)
|
||||
|
||||
secs = filter_secs(t.isecs, ('.iram1.', ))
|
||||
if len(secs) > 0:
|
||||
iram1_include.append(' %s(%s)'%(t.desc, ' '.join(secs)))
|
||||
|
||||
secs = t.fsecs
|
||||
if len(secs) > 0:
|
||||
flash_include.append(' %s(%s)'%(t.desc, ' '.join(secs)))
|
||||
|
||||
self.iram1_exclude = ' *(EXCLUDE_FILE(%s %s) .iram1.*) *(EXCLUDE_FILE(%s %s) .iram1)' % \
|
||||
(self.filter.add(), ' '.join(iram1_exclude), \
|
||||
self.filter.add(), ' '.join(iram1_exclude))
|
||||
self.iram1_include = '\n'.join(iram1_include)
|
||||
self.flash_include = '\n'.join(flash_include)
|
||||
|
||||
logging.debug('IRAM1 Exclude: %s'%(self.iram1_exclude))
|
||||
logging.debug('IRAM1 Include: %s'%(self.iram1_include))
|
||||
logging.debug('Flash Include: %s'%(self.flash_include))
|
||||
|
||||
def __replace__(self, lines):
|
||||
def is_iram_desc(l):
|
||||
if '*(.iram1 .iram1.*)' in l or (') .iram1 EXCLUDE_FILE(*' in l and ') .iram1.*)' in l):
|
||||
return True
|
||||
return False
|
||||
|
||||
iram_start = False
|
||||
flash_done = False
|
||||
|
||||
for i in range(0, len(lines) - 1):
|
||||
l = lines[i]
|
||||
if '.iram0.text :' in l:
|
||||
logging.debug('start to process .iram0.text')
|
||||
iram_start = True
|
||||
elif '.dram0.data :' in l:
|
||||
logging.debug('end to process .iram0.text')
|
||||
iram_start = False
|
||||
elif is_iram_desc(l):
|
||||
if iram_start:
|
||||
lines[i] = '%s\n%s\n'%(self.iram1_exclude, self.iram1_include)
|
||||
elif '(.stub .gnu.warning' in l:
|
||||
if not flash_done:
|
||||
lines[i] = '%s\n\n%s'%(self.flash_include, l)
|
||||
elif self.flash_include in l:
|
||||
flash_done = True
|
||||
else:
|
||||
if iram_start:
|
||||
new_l = self._replace_func(l)
|
||||
if new_l:
|
||||
lines[i] = new_l
|
||||
|
||||
return lines
|
||||
|
||||
def _replace_func(self, l):
|
||||
for t in self.targets:
|
||||
if t.desc in l:
|
||||
S = '.literal .literal.* .text .text.*'
|
||||
if S in l:
|
||||
if len(t.isecs) > 0:
|
||||
return l.replace(S, ' '.join(t.isecs))
|
||||
else:
|
||||
return ' '
|
||||
|
||||
S = '%s(%s)'%(t.desc, ' '.join(t.fsecs))
|
||||
if S in l:
|
||||
return ' '
|
||||
|
||||
replaced = False
|
||||
for s in t.fsecs:
|
||||
s2 = s + ' '
|
||||
if s2 in l:
|
||||
l = l.replace(s2, '')
|
||||
replaced = True
|
||||
s2 = s + ')'
|
||||
if s2 in l:
|
||||
l = l.replace(s2, ')')
|
||||
replaced = True
|
||||
if '( )' in l or '()' in l:
|
||||
return ' '
|
||||
if replaced:
|
||||
return l
|
||||
else:
|
||||
index = '*%s:(EXCLUDE_FILE'%(t.lib)
|
||||
if index in l and t.file.split('.')[0] not in l:
|
||||
for m in self.targets:
|
||||
index = '*%s:(EXCLUDE_FILE'%(m.lib)
|
||||
if index in l and m.file.split('.')[0] not in l:
|
||||
l = l.replace('EXCLUDE_FILE(', 'EXCLUDE_FILE(%s '%(m.desc))
|
||||
if len(m.isecs) > 0:
|
||||
l += '\n %s(%s)'%(m.desc, ' '.join(m.isecs))
|
||||
return l
|
||||
|
||||
return False
|
||||
|
||||
def save(self, input, output):
|
||||
lines = open(input).read().splitlines()
|
||||
lines = self.__replace__(lines)
|
||||
open(output, 'w+').write('\n'.join(lines))
|
||||
|
||||
def main():
|
||||
argparser = argparse.ArgumentParser(description='Relinker script generator')
|
||||
|
||||
argparser.add_argument(
|
||||
'--input', '-i',
|
||||
help='Linker template file',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--output', '-o',
|
||||
help='Output linker script',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--library', '-l',
|
||||
help='Library description directory',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--object', '-b',
|
||||
help='Object description file',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--function', '-f',
|
||||
help='Function description file',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--sdkconfig', '-s',
|
||||
help='sdkconfig file',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--objdump', '-g',
|
||||
help='GCC objdump command',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--debug', '-d',
|
||||
help='Debug level(option is \'debug\')',
|
||||
default='no',
|
||||
type=str)
|
||||
|
||||
argparser.add_argument(
|
||||
'--missing_function_info',
|
||||
help='Print error information instead of throwing exception when missing function',
|
||||
default=False,
|
||||
type=bool)
|
||||
|
||||
args = argparser.parse_args()
|
||||
|
||||
if args.debug == 'debug':
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
logging.debug('input: %s'%(args.input))
|
||||
logging.debug('output: %s'%(args.output))
|
||||
logging.debug('library: %s'%(args.library))
|
||||
logging.debug('object: %s'%(args.object))
|
||||
logging.debug('function: %s'%(args.function))
|
||||
logging.debug('sdkconfig:%s'%(args.sdkconfig))
|
||||
logging.debug('objdump: %s'%(args.objdump))
|
||||
logging.debug('debug: %s'%(args.debug))
|
||||
logging.debug('missing_function_info: %s'%(args.missing_function_info))
|
||||
|
||||
global espidf_objdump
|
||||
espidf_objdump = args.objdump
|
||||
|
||||
relink = relink_c(args.input, args.library, args.object, args.function, args.sdkconfig, args.missing_function_info)
|
||||
relink.save(args.input, args.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,8 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
|
||||
"../../cmake_utilities")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(cmake_utilities_test_apps)
|
||||
@@ -0,0 +1,10 @@
|
||||
idf_component_register( SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES cmake_utilities)
|
||||
|
||||
include(gcc)
|
||||
include(gen_compressed_ota)
|
||||
include(gen_single_bin)
|
||||
include(package_manager)
|
||||
include(relinker)
|
||||
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
|
||||
@@ -0,0 +1,6 @@
|
||||
version: "3.2.1"
|
||||
description: Test2 for cmake utilities
|
||||
url: https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities
|
||||
issues: https://github.com/espressif/esp-iot-solution/issues
|
||||
dependencies:
|
||||
idf: ">=4.1"
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int test_component2_version_major()
|
||||
{
|
||||
return TEST_COMPONENT2_VER_MAJOR;
|
||||
}
|
||||
|
||||
int test_component2_version_minor()
|
||||
{
|
||||
return TEST_COMPONENT2_VER_MINOR;
|
||||
}
|
||||
|
||||
int test_component2_version_patch()
|
||||
{
|
||||
return TEST_COMPONENT2_VER_PATCH;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <stdio.h>
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int test_component2_version_major();
|
||||
int test_component2_version_minor();
|
||||
int test_component2_version_patch();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
idf_component_register( SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES cmake_utilities)
|
||||
|
||||
include(gcc)
|
||||
include(gen_compressed_ota)
|
||||
include(gen_single_bin)
|
||||
include(package_manager)
|
||||
include(relinker)
|
||||
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
|
||||
@@ -0,0 +1,6 @@
|
||||
version: "1.2.3"
|
||||
description: Test1 for cmake utilities
|
||||
url: https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities
|
||||
issues: https://github.com/espressif/esp-iot-solution/issues
|
||||
dependencies:
|
||||
idf: ">=4.1"
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int test_component1_version_major()
|
||||
{
|
||||
return TEST_COMPONENT1_VER_MAJOR;
|
||||
}
|
||||
|
||||
int test_component1_version_minor()
|
||||
{
|
||||
return TEST_COMPONENT1_VER_MINOR;
|
||||
}
|
||||
|
||||
int test_component1_version_patch()
|
||||
{
|
||||
return TEST_COMPONENT1_VER_PATCH;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <stdio.h>
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int test_component1_version_major();
|
||||
int test_component1_version_minor();
|
||||
int test_component1_version_patch();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES unity test_utils test_component1 TEST-component2)
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "unity.h"
|
||||
#include "test_component1.h"
|
||||
#include "test_component2.h"
|
||||
|
||||
|
||||
/* USB PIN fixed in esp32-s2, can not use io matrix */
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-400)
|
||||
|
||||
TEST_CASE("Test package manager version", "[cmake_utilities][package_manager]")
|
||||
{
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
TEST_ASSERT_EQUAL_INT(test_component1_version_major(), 1);
|
||||
TEST_ASSERT_EQUAL_INT(test_component1_version_minor(), 2);
|
||||
TEST_ASSERT_EQUAL_INT(test_component1_version_patch(), 3);
|
||||
TEST_ASSERT_EQUAL_INT(test_component2_version_major(), 3);
|
||||
TEST_ASSERT_EQUAL_INT(test_component2_version_minor(), 2);
|
||||
TEST_ASSERT_EQUAL_INT(test_component2_version_patch(), 1);
|
||||
}
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("Cmake Utilities TEST \n");
|
||||
unity_run_menu();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
'''
|
||||
Steps to run these cases:
|
||||
- Build
|
||||
- . ${IDF_PATH}/export.sh
|
||||
- pip install idf_build_apps
|
||||
- python tools/build_apps.py tools/cmake_utilities/test_apps -t esp32s2
|
||||
- Test
|
||||
- pip install -r tools/requirements/requirement.pytest.txt
|
||||
- pytest tools/cmake_utilities/test_apps --target esp32s2
|
||||
'''
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
@pytest.mark.target('esp32s3')
|
||||
@pytest.mark.env('generic')
|
||||
def test_cmake_utilities(dut: Dut)-> None:
|
||||
dut.expect_exact('Press ENTER to see the list of tests.')
|
||||
dut.write('*')
|
||||
dut.expect_unity_test_output(timeout = 1000)
|
||||
@@ -0,0 +1 @@
|
||||
840387ee0c90a473e43fdc75570f77c52f06423aa331d95479bde8b418c43547
|
||||
@@ -0,0 +1 @@
|
||||
{"version":"1.0","algorithm":"sha256","created_at":"2026-08-24T15:07:37.112366+00:00","files":[{"path":"README.md","size":4162,"hash":"f628e081511c01f85400ef26a6175e8392a4dff1cc353f5bd18f2cfb3c0186c4"},{"path":"esp_lcd_ili9341.c","size":15371,"hash":"0155a9421945bb68ad66308e7d060cfeb15f569eacb1d2bb6b0d6d5196970382"},{"path":"license.txt","size":11358,"hash":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"},{"path":"CMakeLists.txt","size":258,"hash":"d00705da6437b218fc2e0bcfa025dc771c6505cc1633aa4a6514b00215f31c8c"},{"path":"idf_component.yml","size":343,"hash":"0deecf06bcdf37798e3dac1534068e485707dec76777f73aeabc4a6e45c37f47"},{"path":"include/esp_lcd_ili9341_init_cmds_2.h","size":1014,"hash":"11f5ed0f55388721ec0a57c599ae05029bc873806fb6a52714203398e5177145"},{"path":"include/esp_lcd_ili9341_init_cmds_1.h","size":1799,"hash":"8908e0e53fa202185e33293dab16b08e22d620c0e001d6207c8d76cc3361b2cd"},{"path":"include/esp_lcd_ili9341.h","size":3911,"hash":"ebb60162c4708cfbd675b6c09a0e09e251f555156b90822fd764eff01cdd6c92"},{"path":"test_apps/CMakeLists.txt","size":264,"hash":"6743e0bf5a0e9c1fbffa4c8809aea123ad73e873071b44356c668be7ecfa7225"},{"path":"test_apps/sdkconfig.defaults","size":49,"hash":"dccb276c3ef85f8f4d6c32edf7c8b582cf2d416f42950b778d7af95a9808e7d4"},{"path":"test_apps/main/CMakeLists.txt","size":86,"hash":"9f8755b8936e38cf4b65a60babaf784c732e38bfad0f8415d887bd6a3e19181d"},{"path":"test_apps/main/test_esp_lcd_ili9341.c","size":6589,"hash":"0c4f8336571b0607059a7b21a0b725f7768a128987f59edeb9fc0507c1a18e7c"},{"path":"test_apps/main/idf_component.yml","size":150,"hash":"58d59691b0ea7488624b3274a3a6578bafc7c205714f2d1e132caa8c4e9ee738"}]}
|
||||
@@ -0,0 +1,7 @@
|
||||
idf_component_register(SRCS "esp_lcd_ili9341.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES "esp_lcd"
|
||||
PRIV_REQUIRES "driver")
|
||||
|
||||
include(package_manager)
|
||||
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
|
||||
92
managed_components/espressif__esp_lcd_ili9341/README.md
Normal file
92
managed_components/espressif__esp_lcd_ili9341/README.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# ESP LCD ILI9341
|
||||
|
||||
[](https://components.espressif.com/components/espressif/esp_lcd_ili9341)
|
||||
|
||||
Implementation of the ILI9341 LCD controller with esp_lcd component.
|
||||
|
||||
| LCD controller | Communication interface | Component name | Link to datasheet |
|
||||
| :------------: | :---------------------: | :------------: | :---------------: |
|
||||
| ILI9341 | SPI | esp_lcd_ili9341 | [Specification](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf) |
|
||||
|
||||
## Add to project
|
||||
|
||||
Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/).
|
||||
You can add them to your project via `idf.py add-dependency`, e.g.
|
||||
|
||||
```bash
|
||||
idf.py add-dependency "espressif/esp_lcd_ili9341^2.0.0"
|
||||
```
|
||||
|
||||
Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).
|
||||
|
||||
## Example use
|
||||
|
||||
```c
|
||||
ESP_LOGI(TAG, "Initialize SPI bus");
|
||||
const spi_bus_config_t bus_config = ILI9341_PANEL_BUS_SPI_CONFIG(EXAMPLE_PIN_NUM_LCD_PCLK, EXAMPLE_PIN_NUM_LCD_MOSI,
|
||||
EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(EXAMPLE_LCD_HOST, &bus_config, SPI_DMA_CH_AUTO));
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
const esp_lcd_panel_io_spi_config_t io_config = ILI9341_PANEL_IO_SPI_CONFIG(EXAMPLE_PIN_NUM_LCD_CS, EXAMPLE_PIN_NUM_LCD_DC,
|
||||
example_callback, &example_callback_ctx);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_HOST, &io_config, &io_handle));
|
||||
|
||||
/**
|
||||
* Uncomment these lines if use custom initialization commands.
|
||||
* The array should be declared as "static const" and positioned outside the function.
|
||||
*/
|
||||
// static const ili9341_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||
// // {cmd, { data }, data_size, delay_ms}
|
||||
// {0xCF, (uint8_t []){0x00, 0xAA, 0XE0}, 3, 0},
|
||||
// {0xED, (uint8_t []){0x67, 0x03, 0X12, 0X81}, 4, 0},
|
||||
// {0xE8, (uint8_t []){0x8A, 0x01, 0x78}, 3, 0},
|
||||
// ...
|
||||
// };
|
||||
|
||||
ESP_LOGI(TAG, "Install ILI9341 panel driver");
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
// ili9341_vendor_config_t vendor_config = { // Uncomment these lines if use custom initialization commands
|
||||
// .init_cmds = lcd_init_cmds,
|
||||
// .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(ili9341_lcd_init_cmd_t),
|
||||
// };
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, // Set to -1 if not use
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // RGB element order: R-G-B
|
||||
.bits_per_pixel = 16, // Implemented by LCD command `3Ah` (16/18)
|
||||
// .vendor_config = &vendor_config, // Uncomment this line if use custom initialization commands
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
```
|
||||
|
||||
There is an example in ESP-IDF with this LCD controller. Please follow this [link](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/lcd/spi_lcd_touch).
|
||||
|
||||
## Predefined init vendor commands
|
||||
|
||||
This driver contains various predefined vendor initialization commands which in some cases can improve image quality. Usage is in example below.
|
||||
|
||||
Include selected commands:
|
||||
```c
|
||||
#include "esp_lcd_ili9341_init_cmds_1.h"
|
||||
```
|
||||
|
||||
Use vendor config structure:
|
||||
```c
|
||||
...
|
||||
|
||||
ili9341_vendor_config_t vendor_config = {
|
||||
.init_cmds = ili9341_lcd_init_vendor,
|
||||
.init_cmds_size = sizeof(ili9341_lcd_init_vendor) / sizeof(ili9341_lcd_init_cmd_t),
|
||||
};
|
||||
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
...
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
|
||||
...
|
||||
```
|
||||
416
managed_components/espressif__esp_lcd_ili9341/esp_lcd_ili9341.c
Normal file
416
managed_components/espressif__esp_lcd_ili9341/esp_lcd_ili9341.c
Normal file
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
|
||||
#include "esp_lcd_ili9341.h"
|
||||
|
||||
static const char *TAG = "ili9341";
|
||||
|
||||
static esp_err_t panel_ili9341_del(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_ili9341_reset(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_ili9341_init(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_ili9341_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end,
|
||||
const void *color_data);
|
||||
static esp_err_t panel_ili9341_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
|
||||
static esp_err_t panel_ili9341_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||
static esp_err_t panel_ili9341_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);
|
||||
static esp_err_t panel_ili9341_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);
|
||||
static esp_err_t panel_ili9341_disp_on_off(esp_lcd_panel_t *panel, bool off);
|
||||
static esp_err_t panel_ili9341_disp_sleep(esp_lcd_panel_t *panel, bool sleep);
|
||||
|
||||
typedef struct {
|
||||
esp_lcd_panel_t base;
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
int reset_gpio_num;
|
||||
bool reset_level;
|
||||
int x_gap;
|
||||
int y_gap;
|
||||
uint8_t fb_bits_per_pixel;
|
||||
uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register
|
||||
uint8_t colmod_val; // save current value of LCD_CMD_COLMOD register
|
||||
const ili9341_lcd_init_cmd_t *init_cmds;
|
||||
uint16_t init_cmds_size;
|
||||
} ili9341_panel_t;
|
||||
|
||||
esp_err_t esp_lcd_new_panel_ili9341(const esp_lcd_panel_io_handle_t io,
|
||||
const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ili9341_panel_t *ili9341 = NULL;
|
||||
gpio_config_t io_conf = { 0 };
|
||||
|
||||
ESP_GOTO_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ili9341 = (ili9341_panel_t *)calloc(1, sizeof(ili9341_panel_t));
|
||||
ESP_GOTO_ON_FALSE(ili9341, ESP_ERR_NO_MEM, err, TAG, "no mem for ili9341 panel");
|
||||
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num;
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
switch (panel_dev_config->color_space) {
|
||||
case ESP_LCD_COLOR_SPACE_RGB:
|
||||
ili9341->madctl_val = 0;
|
||||
break;
|
||||
case ESP_LCD_COLOR_SPACE_BGR:
|
||||
ili9341->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color space");
|
||||
break;
|
||||
}
|
||||
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)
|
||||
switch (panel_dev_config->rgb_endian) {
|
||||
case LCD_RGB_ENDIAN_RGB:
|
||||
ili9341->madctl_val = 0;
|
||||
break;
|
||||
case LCD_RGB_ENDIAN_BGR:
|
||||
ili9341->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported rgb endian");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (panel_dev_config->rgb_ele_order) {
|
||||
case LCD_RGB_ELEMENT_ORDER_RGB:
|
||||
ili9341->madctl_val = 0;
|
||||
break;
|
||||
case LCD_RGB_ELEMENT_ORDER_BGR:
|
||||
ili9341->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported rgb element order");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (panel_dev_config->bits_per_pixel) {
|
||||
case 16: // RGB565
|
||||
ili9341->colmod_val = 0x55;
|
||||
ili9341->fb_bits_per_pixel = 16;
|
||||
break;
|
||||
case 18: // RGB666
|
||||
ili9341->colmod_val = 0x66;
|
||||
// each color component (R/G/B) should occupy the 6 high bits of a byte, which means 3 full bytes are required for a pixel
|
||||
ili9341->fb_bits_per_pixel = 24;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
|
||||
break;
|
||||
}
|
||||
|
||||
ili9341->io = io;
|
||||
ili9341->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||
ili9341->reset_level = panel_dev_config->flags.reset_active_high;
|
||||
if (panel_dev_config->vendor_config) {
|
||||
ili9341->init_cmds = ((ili9341_vendor_config_t *)panel_dev_config->vendor_config)->init_cmds;
|
||||
ili9341->init_cmds_size = ((ili9341_vendor_config_t *)panel_dev_config->vendor_config)->init_cmds_size;
|
||||
}
|
||||
ili9341->base.del = panel_ili9341_del;
|
||||
ili9341->base.reset = panel_ili9341_reset;
|
||||
ili9341->base.init = panel_ili9341_init;
|
||||
ili9341->base.draw_bitmap = panel_ili9341_draw_bitmap;
|
||||
ili9341->base.invert_color = panel_ili9341_invert_color;
|
||||
ili9341->base.set_gap = panel_ili9341_set_gap;
|
||||
ili9341->base.mirror = panel_ili9341_mirror;
|
||||
ili9341->base.swap_xy = panel_ili9341_swap_xy;
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ili9341->base.disp_off = panel_ili9341_disp_on_off;
|
||||
#else
|
||||
ili9341->base.disp_on_off = panel_ili9341_disp_on_off;
|
||||
#endif
|
||||
ili9341->base.disp_sleep = panel_ili9341_disp_sleep;
|
||||
*ret_panel = &(ili9341->base);
|
||||
ESP_LOGD(TAG, "new ili9341 panel @%p", ili9341);
|
||||
|
||||
ESP_LOGI(TAG, "LCD panel create success, version: %d.%d.%d", ESP_LCD_ILI9341_VER_MAJOR, ESP_LCD_ILI9341_VER_MINOR,
|
||||
ESP_LCD_ILI9341_VER_PATCH);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (ili9341) {
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||
}
|
||||
free(ili9341);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_del(esp_lcd_panel_t *panel)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
|
||||
if (ili9341->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(ili9341->reset_gpio_num);
|
||||
}
|
||||
ESP_LOGD(TAG, "del ili9341 panel @%p", ili9341);
|
||||
free(ili9341);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_reset(esp_lcd_panel_t *panel)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = ili9341->io;
|
||||
|
||||
// perform hardware reset
|
||||
if (ili9341->reset_gpio_num >= 0) {
|
||||
gpio_set_level(ili9341->reset_gpio_num, ili9341->reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(ili9341->reset_gpio_num, !ili9341->reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
} else { // perform software reset
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); // spec, wait at least 5ms before sending new command
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static const ili9341_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
// {cmd, { data }, data_size, delay_ms}
|
||||
/* Power contorl B, power control = 0, DC_ENA = 1 */
|
||||
{0xCF, (uint8_t []){0x00, 0xAA, 0XE0}, 3, 0},
|
||||
/* Power on sequence control,
|
||||
* cp1 keeps 1 frame, 1st frame enable
|
||||
* vcl = 0, ddvdh=3, vgh=1, vgl=2
|
||||
* DDVDH_ENH=1
|
||||
*/
|
||||
{0xED, (uint8_t []){0x67, 0x03, 0X12, 0X81}, 4, 0},
|
||||
/* Driver timing control A,
|
||||
* non-overlap=default +1
|
||||
* EQ=default - 1, CR=default
|
||||
* pre-charge=default - 1
|
||||
*/
|
||||
{0xE8, (uint8_t []){0x8A, 0x01, 0x78}, 3, 0},
|
||||
/* Power control A, Vcore=1.6V, DDVDH=5.6V */
|
||||
{0xCB, (uint8_t []){0x39, 0x2C, 0x00, 0x34, 0x02}, 5, 0},
|
||||
/* Pump ratio control, DDVDH=2xVCl */
|
||||
{0xF7, (uint8_t []){0x20}, 1, 0},
|
||||
|
||||
{0xF7, (uint8_t []){0x20}, 1, 0},
|
||||
/* Driver timing control, all=0 unit */
|
||||
{0xEA, (uint8_t []){0x00, 0x00}, 2, 0},
|
||||
/* Power control 1, GVDD=4.75V */
|
||||
{0xC0, (uint8_t []){0x23}, 1, 0},
|
||||
/* Power control 2, DDVDH=VCl*2, VGH=VCl*7, VGL=-VCl*3 */
|
||||
{0xC1, (uint8_t []){0x11}, 1, 0},
|
||||
/* VCOM control 1, VCOMH=4.025V, VCOML=-0.950V */
|
||||
{0xC5, (uint8_t []){0x43, 0x4C}, 2, 0},
|
||||
/* VCOM control 2, VCOMH=VMH-2, VCOML=VML-2 */
|
||||
{0xC7, (uint8_t []){0xA0}, 1, 0},
|
||||
/* Frame rate control, f=fosc, 70Hz fps */
|
||||
{0xB1, (uint8_t []){0x00, 0x1B}, 2, 0},
|
||||
/* Enable 3G, disabled */
|
||||
{0xF2, (uint8_t []){0x00}, 1, 0},
|
||||
/* Gamma set, curve 1 */
|
||||
{0x26, (uint8_t []){0x01}, 1, 0},
|
||||
/* Positive gamma correction */
|
||||
{0xE0, (uint8_t []){0x1F, 0x36, 0x36, 0x3A, 0x0C, 0x05, 0x4F, 0X87, 0x3C, 0x08, 0x11, 0x35, 0x19, 0x13, 0x00}, 15, 0},
|
||||
/* Negative gamma correction */
|
||||
{0xE1, (uint8_t []){0x00, 0x09, 0x09, 0x05, 0x13, 0x0A, 0x30, 0x78, 0x43, 0x07, 0x0E, 0x0A, 0x26, 0x2C, 0x1F}, 15, 0},
|
||||
/* Entry mode set, Low vol detect disabled, normal display */
|
||||
{0xB7, (uint8_t []){0x07}, 1, 0},
|
||||
/* Display function control */
|
||||
{0xB6, (uint8_t []){0x08, 0x82, 0x27}, 3, 0},
|
||||
};
|
||||
|
||||
static esp_err_t panel_ili9341_init(esp_lcd_panel_t *panel)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = ili9341->io;
|
||||
|
||||
// LCD goes into sleep mode and display will be turned off after power on reset, exit sleep mode first
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SLPOUT, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
ili9341->madctl_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t[]) {
|
||||
ili9341->colmod_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
|
||||
const ili9341_lcd_init_cmd_t *init_cmds = NULL;
|
||||
uint16_t init_cmds_size = 0;
|
||||
if (ili9341->init_cmds) {
|
||||
init_cmds = ili9341->init_cmds;
|
||||
init_cmds_size = ili9341->init_cmds_size;
|
||||
} else {
|
||||
init_cmds = vendor_specific_init_default;
|
||||
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(ili9341_lcd_init_cmd_t);
|
||||
}
|
||||
|
||||
bool is_cmd_overwritten = false;
|
||||
for (int i = 0; i < init_cmds_size; i++) {
|
||||
// Check if the command has been used or conflicts with the internal
|
||||
switch (init_cmds[i].cmd) {
|
||||
case LCD_CMD_MADCTL:
|
||||
is_cmd_overwritten = true;
|
||||
ili9341->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
case LCD_CMD_COLMOD:
|
||||
is_cmd_overwritten = true;
|
||||
ili9341->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
default:
|
||||
is_cmd_overwritten = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_cmd_overwritten) {
|
||||
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence",
|
||||
init_cmds[i].cmd);
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG,
|
||||
"send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
|
||||
}
|
||||
ESP_LOGD(TAG, "send init commands success");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end,
|
||||
const void *color_data)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
|
||||
esp_lcd_panel_io_handle_t io = ili9341->io;
|
||||
|
||||
x_start += ili9341->x_gap;
|
||||
x_end += ili9341->x_gap;
|
||||
y_start += ili9341->y_gap;
|
||||
y_end += ili9341->y_gap;
|
||||
|
||||
// define an area of frame memory where MCU can access
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_CASET, (uint8_t[]) {
|
||||
(x_start >> 8) & 0xFF,
|
||||
x_start & 0xFF,
|
||||
((x_end - 1) >> 8) & 0xFF,
|
||||
(x_end - 1) & 0xFF,
|
||||
}, 4), TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_RASET, (uint8_t[]) {
|
||||
(y_start >> 8) & 0xFF,
|
||||
y_start & 0xFF,
|
||||
((y_end - 1) >> 8) & 0xFF,
|
||||
(y_end - 1) & 0xFF,
|
||||
}, 4), TAG, "send command failed");
|
||||
// transfer frame buffer
|
||||
size_t len = (x_end - x_start) * (y_end - y_start) * ili9341->fb_bits_per_pixel / 8;
|
||||
esp_lcd_panel_io_tx_color(io, LCD_CMD_RAMWR, color_data, len);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = ili9341->io;
|
||||
int command = 0;
|
||||
if (invert_color_data) {
|
||||
command = LCD_CMD_INVON;
|
||||
} else {
|
||||
command = LCD_CMD_INVOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = ili9341->io;
|
||||
if (mirror_x) {
|
||||
ili9341->madctl_val |= LCD_CMD_MX_BIT;
|
||||
} else {
|
||||
ili9341->madctl_val &= ~LCD_CMD_MX_BIT;
|
||||
}
|
||||
if (mirror_y) {
|
||||
ili9341->madctl_val |= LCD_CMD_MY_BIT;
|
||||
} else {
|
||||
ili9341->madctl_val &= ~LCD_CMD_MY_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
ili9341->madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_swap_xy(esp_lcd_panel_t *panel, bool swap_axes)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = ili9341->io;
|
||||
if (swap_axes) {
|
||||
ili9341->madctl_val |= LCD_CMD_MV_BIT;
|
||||
} else {
|
||||
ili9341->madctl_val &= ~LCD_CMD_MV_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
ili9341->madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
ili9341->x_gap = x_gap;
|
||||
ili9341->y_gap = y_gap;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = ili9341->io;
|
||||
int command = 0;
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
on_off = !on_off;
|
||||
#endif
|
||||
|
||||
if (on_off) {
|
||||
command = LCD_CMD_DISPON;
|
||||
} else {
|
||||
command = LCD_CMD_DISPOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_ili9341_disp_sleep(esp_lcd_panel_t *panel, bool sleep)
|
||||
{
|
||||
ili9341_panel_t *ili9341 = __containerof(panel, ili9341_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = ili9341->io;
|
||||
int command = 0;
|
||||
if (sleep) {
|
||||
command = LCD_CMD_SLPIN;
|
||||
} else {
|
||||
command = LCD_CMD_SLPOUT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
dependencies:
|
||||
cmake_utilities: 0.*
|
||||
idf: '>=5.2'
|
||||
description: ESP LCD ILI9341
|
||||
repository: git://github.com/espressif/esp-bsp.git
|
||||
repository_info:
|
||||
commit_sha: 93460b932beba7022a8a4ec4186e0d6b7533d05f
|
||||
path: components/lcd/esp_lcd_ili9341
|
||||
url: https://github.com/espressif/esp-bsp/tree/master/components/lcd/esp_lcd_ili9341
|
||||
version: 2.1.0
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief ESP LCD: ILI9341
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LCD panel initialization commands.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
int cmd; /*<! The specific LCD command */
|
||||
const void *data; /*<! Buffer that holds the command specific data */
|
||||
size_t data_bytes; /*<! Size of `data` in memory, in bytes */
|
||||
unsigned int delay_ms; /*<! Delay in milliseconds after this command */
|
||||
} ili9341_lcd_init_cmd_t;
|
||||
|
||||
/**
|
||||
* @brief LCD panel vendor configuration.
|
||||
*
|
||||
* @note This structure needs to be passed to the `vendor_config` field in `esp_lcd_panel_dev_config_t`.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
const ili9341_lcd_init_cmd_t
|
||||
*init_cmds; /*!< Pointer to initialization commands array. Set to NULL if using default commands.
|
||||
* The array should be declared as `static const` and positioned outside the function.
|
||||
* Please refer to `vendor_specific_init_default` in source file.
|
||||
*/
|
||||
uint16_t init_cmds_size; /*<! Number of commands in above array */
|
||||
} ili9341_vendor_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create LCD panel for model ILI9341
|
||||
*
|
||||
* @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for initialization sequence code.
|
||||
*
|
||||
* @param[in] io LCD panel IO handle
|
||||
* @param[in] panel_dev_config general panel device configuration
|
||||
* @param[out] ret_panel Returned LCD panel handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_NO_MEM if out of memory
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_ili9341(const esp_lcd_panel_io_handle_t io,
|
||||
const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel);
|
||||
|
||||
/**
|
||||
* @brief LCD panel bus configuration structure
|
||||
*
|
||||
* @param[in] sclk SPI clock pin number
|
||||
* @param[in] mosi SPI MOSI pin number
|
||||
* @param[in] max_trans_sz Maximum transfer size in bytes
|
||||
*
|
||||
*/
|
||||
#define ILI9341_PANEL_BUS_SPI_CONFIG(sclk, mosi, max_trans_sz) \
|
||||
{ \
|
||||
.sclk_io_num = sclk, \
|
||||
.mosi_io_num = mosi, \
|
||||
.miso_io_num = -1, \
|
||||
.quadhd_io_num = -1, \
|
||||
.quadwp_io_num = -1, \
|
||||
.max_transfer_sz = max_trans_sz, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LCD panel IO configuration structure
|
||||
*
|
||||
* @param[in] cs SPI chip select pin number
|
||||
* @param[in] dc SPI data/command pin number
|
||||
* @param[in] cb Callback function when SPI transfer is done
|
||||
* @param[in] cb_ctx Callback function context
|
||||
*
|
||||
*/
|
||||
#define ILI9341_PANEL_IO_SPI_CONFIG(cs, dc, callback, callback_ctx) \
|
||||
{ \
|
||||
.cs_gpio_num = cs, \
|
||||
.dc_gpio_num = dc, \
|
||||
.spi_mode = 0, \
|
||||
.pclk_hz = 40 * 1000 * 1000, \
|
||||
.trans_queue_depth = 10, \
|
||||
.on_color_trans_done = callback, \
|
||||
.user_ctx = callback_ctx, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief ESP LCD: ILI9341 Init Commands 1
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "esp_lcd_ili9341.h"
|
||||
|
||||
static const ili9341_lcd_init_cmd_t ili9341_lcd_init_vendor[] = {
|
||||
// {cmd, { data }, data_size, delay_ms}
|
||||
/* Power control B */
|
||||
{0xCF, (uint8_t []){0x00, 0xC1, 0x30}, 3, 0},
|
||||
/* Power on sequence control */
|
||||
{0xED, (uint8_t []){0x64, 0x03, 0x12, 0x81}, 4, 0},
|
||||
/* Driver timing control A */
|
||||
{0xE8, (uint8_t []){0x85, 0x00, 0x78}, 3, 0},
|
||||
/* Power control A */
|
||||
{0xCB, (uint8_t []){0x39, 0x2C, 0x00, 0x34, 0x02}, 5, 0},
|
||||
/* Pump ratio control */
|
||||
{0xF7, (uint8_t []){0x20}, 1, 0},
|
||||
/* Driver timing control */
|
||||
{0xEA, (uint8_t []){0x00, 0x00}, 2, 0},
|
||||
/* Power control 1 */
|
||||
{0xC0, (uint8_t []){0x10}, 1, 0},
|
||||
/* Power control 2 */
|
||||
{0xC1, (uint8_t []){0x00}, 1, 0},
|
||||
/* VCOM control 1 */
|
||||
{0xC5, (uint8_t []){0x30, 0x30}, 2, 0},
|
||||
/* VCOM control 2 */
|
||||
{0xC7, (uint8_t []){0xB7}, 1, 0},
|
||||
/* Frame rate control */
|
||||
{0xB1, (uint8_t []){0x00, 0x1A}, 2, 0},
|
||||
/* Enable 3G */
|
||||
{0xF2, (uint8_t []){0x00}, 1, 0},
|
||||
/* Gamma set */
|
||||
{0x26, (uint8_t []){0x01}, 1, 0},
|
||||
/* Positive gamma correction */
|
||||
{0xE0, (uint8_t []){0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00}, 15, 0}, // Adjusted for ILI9341_2_DRIVER
|
||||
/* Negative gamma correction */
|
||||
{0xE1, (uint8_t []){0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F}, 15, 0}, // Adjusted for ILI9341_2_DRIVER
|
||||
/* Entry mode set */
|
||||
{0xB7, (uint8_t []){0x07}, 1, 0},
|
||||
/* Display function control */
|
||||
{0xB6, (uint8_t []){0x08, 0x82, 0x27}, 3, 0},
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief ESP LCD: ILI9341 Init Commands 1
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "esp_lcd_ili9341.h"
|
||||
|
||||
static const ili9341_lcd_init_cmd_t ili9341_lcd_init_vendor[] = {
|
||||
{0xC8, (uint8_t []){0xFF, 0x93, 0x42}, 3, 0},
|
||||
{0xC0, (uint8_t []){0x0E, 0x0E}, 2, 0},
|
||||
{0xC5, (uint8_t []){0xD0}, 1, 0},
|
||||
{0xC1, (uint8_t []){0x02}, 1, 0},
|
||||
{0xB4, (uint8_t []){0x02}, 1, 0},
|
||||
{0xE0, (uint8_t []){0x00, 0x03, 0x08, 0x06, 0x13, 0x09, 0x39, 0x39, 0x48, 0x02, 0x0a, 0x08, 0x17, 0x17, 0x0F}, 15, 0},
|
||||
{0xE1, (uint8_t []){0x00, 0x28, 0x29, 0x01, 0x0d, 0x03, 0x3f, 0x33, 0x52, 0x04, 0x0f, 0x0e, 0x37, 0x38, 0x0F}, 15, 0},
|
||||
|
||||
{0xB1, (uint8_t []){00, 0x1B}, 2, 0},
|
||||
{0x36, (uint8_t []){0x08}, 1, 0},
|
||||
{0x3A, (uint8_t []){0x55}, 1, 0},
|
||||
{0xB7, (uint8_t []){0x06}, 1, 0},
|
||||
|
||||
{0x11, (uint8_t []){0}, 0x80, 0},
|
||||
{0x29, (uint8_t []){0}, 0x80, 0},
|
||||
|
||||
{0, (uint8_t []){0}, 0xff, 0},
|
||||
};
|
||||
202
managed_components/espressif__esp_lcd_ili9341/license.txt
Normal file
202
managed_components/espressif__esp_lcd_ili9341/license.txt
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
set(COMPONENTS main)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(test_esp_lcd_ili9341)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(
|
||||
SRCS "test_esp_lcd_ili9341.c"
|
||||
REQUIRES unity driver
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
idf: ">=5.2"
|
||||
esp_lcd_ili9341:
|
||||
version: "*"
|
||||
override_path: "../../../esp_lcd_ili9341"
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_lcd_panel_io_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
|
||||
#include "esp_lcd_ili9341.h"
|
||||
|
||||
#define TEST_LCD_HOST SPI2_HOST
|
||||
#define TEST_LCD_H_RES (320)
|
||||
#define TEST_LCD_V_RES (240)
|
||||
#define TEST_LCD_BIT_PER_PIXEL (16)
|
||||
|
||||
#define TEST_PIN_NUM_LCD_CS (GPIO_NUM_5)
|
||||
#define TEST_PIN_NUM_LCD_PCLK (GPIO_NUM_7)
|
||||
#define TEST_PIN_NUM_LCD_DATA0 (GPIO_NUM_6)
|
||||
#define TEST_PIN_NUM_LCD_DC (GPIO_NUM_4)
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#define TEST_PIN_NUM_LCD_RST (GPIO_NUM_48)
|
||||
#else
|
||||
#define TEST_PIN_NUM_LCD_RST (GPIO_NUM_1)
|
||||
#endif
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#define TEST_PIN_NUM_LCD_BL (GPIO_NUM_45)
|
||||
#else
|
||||
#define TEST_PIN_NUM_LCD_BL (GPIO_NUM_0)
|
||||
#endif
|
||||
|
||||
#define TEST_DELAY_TIME_MS (3000)
|
||||
|
||||
static char *TAG = "ili9341_test";
|
||||
static SemaphoreHandle_t refresh_finish = NULL;
|
||||
|
||||
IRAM_ATTR static bool test_notify_refresh_ready(esp_lcd_panel_io_handle_t panel_io,
|
||||
esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
BaseType_t need_yield = pdFALSE;
|
||||
|
||||
xSemaphoreGiveFromISR(refresh_finish, &need_yield);
|
||||
return (need_yield == pdTRUE);
|
||||
}
|
||||
|
||||
static void test_draw_bitmap(esp_lcd_panel_handle_t panel_handle)
|
||||
{
|
||||
refresh_finish = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL(refresh_finish);
|
||||
|
||||
uint16_t row_line = TEST_LCD_V_RES / TEST_LCD_BIT_PER_PIXEL;
|
||||
uint8_t byte_per_pixel = TEST_LCD_BIT_PER_PIXEL / 8;
|
||||
uint8_t *color = (uint8_t *)heap_caps_calloc(1, row_line * TEST_LCD_H_RES * byte_per_pixel, MALLOC_CAP_DMA);
|
||||
TEST_ASSERT_NOT_NULL(color);
|
||||
|
||||
for (int j = 0; j < TEST_LCD_BIT_PER_PIXEL; j++) {
|
||||
for (int i = 0; i < row_line * TEST_LCD_H_RES; i++) {
|
||||
for (int k = 0; k < byte_per_pixel; k++) {
|
||||
color[i * byte_per_pixel + k] = (SPI_SWAP_DATA_TX(BIT(j), TEST_LCD_BIT_PER_PIXEL) >> (k * 8)) & 0xff;
|
||||
}
|
||||
}
|
||||
TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, j * row_line, TEST_LCD_H_RES, (j + 1) * row_line, color));
|
||||
xSemaphoreTake(refresh_finish, portMAX_DELAY);
|
||||
}
|
||||
free(color);
|
||||
vSemaphoreDelete(refresh_finish);
|
||||
}
|
||||
|
||||
TEST_CASE("test ili9341 to draw color bar with SPI interface", "[ili9341][spi]")
|
||||
{
|
||||
ESP_LOGI(TAG, "Turn on the backlight");
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = BIT64(TEST_PIN_NUM_LCD_BL),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(TEST_PIN_NUM_LCD_BL, 1);
|
||||
|
||||
ESP_LOGI(TAG, "Initialize SPI bus");
|
||||
const spi_bus_config_t buscfg = ILI9341_PANEL_BUS_SPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0,
|
||||
TEST_LCD_H_RES * 80 * TEST_LCD_BIT_PER_PIXEL / 8);
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
const esp_lcd_panel_io_spi_config_t io_config = ILI9341_PANEL_IO_SPI_CONFIG(TEST_PIN_NUM_LCD_CS, TEST_PIN_NUM_LCD_DC,
|
||||
test_notify_refresh_ready, NULL);
|
||||
// Attach the LCD to the SPI bus
|
||||
TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_LCD_HOST, &io_config, &io_handle));
|
||||
|
||||
ESP_LOGI(TAG, "Install ili9341 panel driver");
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = TEST_PIN_NUM_LCD_RST, // Shared with Touch reset
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
.color_space = ESP_LCD_COLOR_SPACE_BGR,
|
||||
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)
|
||||
.rgb_endian = LCD_RGB_ENDIAN_BGR,
|
||||
#else
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
|
||||
#endif
|
||||
.bits_per_pixel = TEST_LCD_BIT_PER_PIXEL,
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_reset(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_init(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_mirror(panel_handle, true, true));
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
TEST_ESP_OK(esp_lcd_panel_disp_off(panel_handle, false));
|
||||
#else
|
||||
TEST_ESP_OK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
#endif
|
||||
|
||||
test_draw_bitmap(panel_handle);
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS));
|
||||
|
||||
gpio_reset_pin(TEST_PIN_NUM_LCD_BL);
|
||||
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
|
||||
TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST));
|
||||
}
|
||||
|
||||
// Some resources are lazy allocated in the LCD driver, the threadhold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/**
|
||||
* _____ __ _____ ___ _____ _ _ _
|
||||
* \_ \/ / \_ \/ _ \___ /| || | / |
|
||||
* / /\/ / / /\/ (_) ||_ \| || |_| |
|
||||
* /\/ /_/ /___/\/ /_ \__, |__) |__ _| |
|
||||
* \____/\____/\____/ /_/____/ |_| |_|
|
||||
*/
|
||||
printf(" _____ __ _____ ___ _____ _ _ _\r\n");
|
||||
printf(" \\_ \\/ / \\_ \\/ _ \\___ /| || | / |\r\n");
|
||||
printf(" / /\\/ / / /\\/ (_) ||_ \\| || |_| |\r\n");
|
||||
printf("/\\/ /_/ /___/\\/ /_ \\__, |__) |__ _| |\r\n");
|
||||
printf("\\____/\\____/\\____/ /_/____/ |_| |_|\r\n");
|
||||
unity_run_menu();
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
@@ -0,0 +1 @@
|
||||
3f85a7d95af876f1a6ecca8eb90a81614890d0f03a038390804e5a77e2caf862
|
||||
@@ -0,0 +1 @@
|
||||
{"version":"1.0","algorithm":"sha256","created_at":"2025-11-30T02:16:23.671476+00:00","files":[{"path":"CMakeLists.txt","size":98,"hash":"8225b56a99e64e8b5dc0e497fa69b340dd559e7ded38a8520c18445d6b387d08"},{"path":"Kconfig","size":285,"hash":"a26e92b112c7b917e7e7b1382ef70e21db404c3d5dddbcd2dadcfe07db7e2bb6"},{"path":"README.md","size":483,"hash":"534ea088bd448300662562b5874029bbad5895afe2db8e65cf9e4f81d5a09228"},{"path":"esp_lcd_touch.c","size":11943,"hash":"c3e34cc316b7b69a80c1141672b92de8ad1b1317f4e829503126e08ba26bc782"},{"path":"idf_component.yml","size":380,"hash":"007dc69052e52d0556b410f45dded316237b2434878767fb379f2b9bd84e4616"},{"path":"license.txt","size":11358,"hash":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"},{"path":"include/esp_lcd_touch.h","size":12698,"hash":"4633fa0a66560356f23b7decc3fa392ebc40e07d59eafbbe0d87d0a8bc14193d"}]}
|
||||
@@ -0,0 +1 @@
|
||||
idf_component_register(SRCS "esp_lcd_touch.c" INCLUDE_DIRS "include" REQUIRES "driver" "esp_lcd")
|
||||
13
managed_components/espressif__esp_lcd_touch/Kconfig
Normal file
13
managed_components/espressif__esp_lcd_touch/Kconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
menu "ESP LCD TOUCH"
|
||||
|
||||
config ESP_LCD_TOUCH_MAX_POINTS
|
||||
int "Maximum count of the touch points"
|
||||
range 1 10
|
||||
default 5
|
||||
|
||||
config ESP_LCD_TOUCH_MAX_BUTTONS
|
||||
int "Maximum count of the touch buttons supported"
|
||||
range 0 10
|
||||
default 1
|
||||
|
||||
endmenu
|
||||
16
managed_components/espressif__esp_lcd_touch/README.md
Normal file
16
managed_components/espressif__esp_lcd_touch/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# ESP LCD Touch Component
|
||||
|
||||
[](https://components.espressif.com/components/espressif/esp_lcd_touch)
|
||||
|
||||
This componnent is main esp_lcd_touch component which defines main functions and types for easy adding specific touch controller component.
|
||||
|
||||
## Supported features
|
||||
|
||||
- [x] Read XY
|
||||
- [x] Swap XY
|
||||
- [x] Mirror X
|
||||
- [x] Mirror Y
|
||||
- [x] Interrupt callback
|
||||
- [x] Sleep mode
|
||||
- [ ] Calibration
|
||||
|
||||
339
managed_components/espressif__esp_lcd_touch/esp_lcd_touch.c
Normal file
339
managed_components/espressif__esp_lcd_touch/esp_lcd_touch.c
Normal file
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_lcd_touch.h"
|
||||
|
||||
static const char *TAG = "TP";
|
||||
|
||||
/*******************************************************************************
|
||||
* Function definitions
|
||||
*******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Local variables
|
||||
*******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Public API functions
|
||||
*******************************************************************************/
|
||||
|
||||
esp_err_t esp_lcd_touch_enter_sleep(esp_lcd_touch_handle_t tp)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
if (tp->enter_sleep == NULL) {
|
||||
ESP_LOGE(TAG, "Sleep mode not supported!");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return tp->enter_sleep(tp);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_exit_sleep(esp_lcd_touch_handle_t tp)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
if (tp->exit_sleep == NULL) {
|
||||
ESP_LOGE(TAG, "Sleep mode not supported!");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return tp->exit_sleep(tp);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_read_data(esp_lcd_touch_handle_t tp)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(tp->read_data != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller must be initialized");
|
||||
|
||||
return tp->read_data(tp);
|
||||
}
|
||||
|
||||
bool esp_lcd_touch_get_coordinates(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
|
||||
{
|
||||
bool touched = false;
|
||||
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, false, TAG, "Touch controller handle can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(x != NULL, false, TAG, "Pointer to the x coordinates array can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(y != NULL, false, TAG, "Pointer to the y coordinates array can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(point_num != NULL, false, TAG, "Pointer to number of touch points can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(max_point_num > 0, false, TAG, "Array size must be equal or larger than 1");
|
||||
ESP_RETURN_ON_FALSE(tp->get_xy != NULL, false, TAG, "Touch controller must be initialized");
|
||||
|
||||
touched = tp->get_xy(tp, x, y, strength, point_num, max_point_num);
|
||||
if (!touched) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Process coordinates by user */
|
||||
if (tp->config.process_coordinates != NULL) {
|
||||
tp->config.process_coordinates(tp, x, y, strength, point_num, max_point_num);
|
||||
}
|
||||
|
||||
/* Software coordinates adjustment needed */
|
||||
bool sw_adj_needed = ((tp->config.flags.mirror_x && (tp->set_mirror_x == NULL)) ||
|
||||
(tp->config.flags.mirror_y && (tp->set_mirror_y == NULL)) ||
|
||||
(tp->config.flags.swap_xy && (tp->set_swap_xy == NULL)));
|
||||
|
||||
/* Adjust all coordinates */
|
||||
for (int i = 0; (sw_adj_needed && i < *point_num); i++) {
|
||||
|
||||
/* Mirror X coordinates (if not supported by HW) */
|
||||
if (tp->config.flags.mirror_x && tp->set_mirror_x == NULL) {
|
||||
x[i] = tp->config.x_max - x[i];
|
||||
}
|
||||
|
||||
/* Mirror Y coordinates (if not supported by HW) */
|
||||
if (tp->config.flags.mirror_y && tp->set_mirror_y == NULL) {
|
||||
y[i] = tp->config.y_max - y[i];
|
||||
}
|
||||
|
||||
/* Swap X and Y coordinates (if not supported by HW) */
|
||||
if (tp->config.flags.swap_xy && tp->set_swap_xy == NULL) {
|
||||
uint16_t tmp = x[i];
|
||||
x[i] = y[i];
|
||||
y[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return touched;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_get_data(esp_lcd_touch_handle_t tp, esp_lcd_touch_point_data_t *data, uint8_t *point_cnt, uint8_t max_point_cnt)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(data != NULL, ESP_ERR_INVALID_ARG, TAG, "Pointer to the data array can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(point_cnt != NULL, ESP_ERR_INVALID_ARG, TAG, "Pointer to the count of touch points can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(tp->get_xy != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller must be initialized");
|
||||
ESP_RETURN_ON_FALSE(max_point_cnt > 0, ESP_ERR_INVALID_ARG, TAG, "Array size must be equal or larger than 1");
|
||||
|
||||
uint16_t x[max_point_cnt];
|
||||
uint16_t y[max_point_cnt];
|
||||
uint16_t strength[max_point_cnt];
|
||||
uint8_t track_id[max_point_cnt];
|
||||
|
||||
bool touched = tp->get_xy(tp, x, y, strength, point_cnt, max_point_cnt);
|
||||
|
||||
if (!touched) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Process coordinates by user */
|
||||
if (tp->config.process_coordinates != NULL) {
|
||||
tp->config.process_coordinates(tp, x, y, strength, point_cnt, max_point_cnt);
|
||||
}
|
||||
|
||||
/* Software coordinates adjustment needed */
|
||||
bool sw_adj_needed = ((tp->config.flags.mirror_x && (tp->set_mirror_x == NULL)) ||
|
||||
(tp->config.flags.mirror_y && (tp->set_mirror_y == NULL)) ||
|
||||
(tp->config.flags.swap_xy && (tp->set_swap_xy == NULL)));
|
||||
|
||||
/* Adjust all coordinates */
|
||||
for (int i = 0; (sw_adj_needed && i < *point_cnt); i++) {
|
||||
|
||||
/* Mirror X coordinates (if not supported by HW) */
|
||||
if (tp->config.flags.mirror_x && tp->set_mirror_x == NULL) {
|
||||
x[i] = tp->config.x_max - x[i];
|
||||
}
|
||||
|
||||
/* Mirror Y coordinates (if not supported by HW) */
|
||||
if (tp->config.flags.mirror_y && tp->set_mirror_y == NULL) {
|
||||
y[i] = tp->config.y_max - y[i];
|
||||
}
|
||||
|
||||
/* Swap X and Y coordinates (if not supported by HW) */
|
||||
if (tp->config.flags.swap_xy && tp->set_swap_xy == NULL) {
|
||||
uint16_t tmp = x[i];
|
||||
x[i] = y[i];
|
||||
y[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process read track IDs */
|
||||
if (tp->get_track_id != NULL && touched) {
|
||||
ESP_RETURN_ON_ERROR(tp->get_track_id(tp, track_id, *point_cnt), TAG, "Failed to read track ID from touch driver");
|
||||
}
|
||||
|
||||
/* Initialize the struct array since some features might not be available */
|
||||
memset(data, 0, sizeof(esp_lcd_touch_point_data_t) * max_point_cnt);
|
||||
|
||||
for (int i = 0; i < *point_cnt; i++) {
|
||||
data[i].x = x[i];
|
||||
data[i].y = y[i];
|
||||
data[i].strength = strength[i];
|
||||
if (tp->get_track_id != NULL) {
|
||||
data[i].track_id = track_id[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
|
||||
esp_err_t esp_lcd_touch_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(state != NULL, ESP_ERR_INVALID_ARG, TAG, "Pointer to the state array can't be NULL");
|
||||
|
||||
*state = 0;
|
||||
|
||||
if (tp->get_button_state) {
|
||||
return tp->get_button_state(tp, n, state);
|
||||
} else {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t esp_lcd_touch_set_swap_xy(esp_lcd_touch_handle_t tp, bool swap)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
|
||||
tp->config.flags.swap_xy = swap;
|
||||
|
||||
/* Is swap supported by HW? */
|
||||
if (tp->set_swap_xy) {
|
||||
return tp->set_swap_xy(tp, swap);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_get_swap_xy(esp_lcd_touch_handle_t tp, bool *swap)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(swap != NULL, ESP_ERR_INVALID_ARG, TAG, "Pointer to the swap variable can't be NULL");
|
||||
|
||||
/* Is swap supported by HW? */
|
||||
if (tp->get_swap_xy) {
|
||||
return tp->get_swap_xy(tp, swap);
|
||||
} else {
|
||||
*swap = tp->config.flags.swap_xy;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_set_mirror_x(esp_lcd_touch_handle_t tp, bool mirror)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
|
||||
tp->config.flags.mirror_x = mirror;
|
||||
|
||||
/* Is mirror supported by HW? */
|
||||
if (tp->set_mirror_x) {
|
||||
return tp->set_mirror_x(tp, mirror);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_get_mirror_x(esp_lcd_touch_handle_t tp, bool *mirror)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(mirror != NULL, ESP_ERR_INVALID_ARG, TAG, "Pointer to the mirror variable can't be NULL");
|
||||
|
||||
/* Is swap supported by HW? */
|
||||
if (tp->get_mirror_x) {
|
||||
return tp->get_mirror_x(tp, mirror);
|
||||
} else {
|
||||
*mirror = tp->config.flags.mirror_x;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_set_mirror_y(esp_lcd_touch_handle_t tp, bool mirror)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
|
||||
tp->config.flags.mirror_y = mirror;
|
||||
|
||||
/* Is mirror supported by HW? */
|
||||
if (tp->set_mirror_y) {
|
||||
return tp->set_mirror_y(tp, mirror);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_get_mirror_y(esp_lcd_touch_handle_t tp, bool *mirror)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
ESP_RETURN_ON_FALSE(mirror != NULL, ESP_ERR_INVALID_ARG, TAG, "Pointer to the mirror variable can't be NULL");
|
||||
|
||||
/* Is swap supported by HW? */
|
||||
if (tp->get_mirror_y) {
|
||||
return tp->get_mirror_y(tp, mirror);
|
||||
} else {
|
||||
*mirror = tp->config.flags.mirror_y;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_del(esp_lcd_touch_handle_t tp)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch point handler can't be NULL");
|
||||
|
||||
if (tp->del != NULL) {
|
||||
return tp->del(tp);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
|
||||
/* Interrupt pin is not selected */
|
||||
if (tp->config.int_gpio_num == GPIO_NUM_NC) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
tp->config.interrupt_callback = callback;
|
||||
|
||||
if (callback != NULL) {
|
||||
ret = gpio_install_isr_service(0);
|
||||
/* ISR service can be installed from user before, then it returns invalid state */
|
||||
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGE(TAG, "GPIO ISR install failed");
|
||||
return ret;
|
||||
}
|
||||
/* Add GPIO ISR handler */
|
||||
ret = gpio_intr_enable(tp->config.int_gpio_num);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR install failed");
|
||||
ret = gpio_isr_handler_add(tp->config.int_gpio_num, (gpio_isr_t)tp->config.interrupt_callback, tp);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR install failed");
|
||||
} else {
|
||||
/* Remove GPIO ISR handler */
|
||||
ret = gpio_isr_handler_remove(tp->config.int_gpio_num);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR remove handler failed");
|
||||
ret = gpio_intr_disable(tp->config.int_gpio_num);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR disable failed");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_lcd_touch_register_interrupt_callback_with_data(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tp != NULL, ESP_ERR_INVALID_ARG, TAG, "Touch controller handle can't be NULL");
|
||||
|
||||
tp->config.user_data = user_data;
|
||||
return esp_lcd_touch_register_interrupt_callback(tp, callback);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
dependencies:
|
||||
idf: '>=4.4.2'
|
||||
description: ESP LCD Touch - main component for using touch screen controllers
|
||||
repository: git://github.com/espressif/esp-bsp.git
|
||||
repository_info:
|
||||
commit_sha: c927778a85eed239dd403c1719d4f543ad56e693
|
||||
path: components/lcd_touch/esp_lcd_touch
|
||||
url: https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch
|
||||
version: 1.2.1
|
||||
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief ESP LCD touch
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Touch controller type
|
||||
*
|
||||
*/
|
||||
typedef struct esp_lcd_touch_s esp_lcd_touch_t;
|
||||
typedef esp_lcd_touch_t *esp_lcd_touch_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Touch controller interrupt callback type
|
||||
*
|
||||
*/
|
||||
typedef void (*esp_lcd_touch_interrupt_callback_t)(esp_lcd_touch_handle_t tp);
|
||||
|
||||
/**
|
||||
* @brief Touch Configuration Type
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t x_max; /*!< X coordinates max (for mirroring) */
|
||||
uint16_t y_max; /*!< Y coordinates max (for mirroring) */
|
||||
|
||||
gpio_num_t rst_gpio_num; /*!< GPIO number of reset pin */
|
||||
gpio_num_t int_gpio_num; /*!< GPIO number of interrupt pin */
|
||||
|
||||
struct {
|
||||
unsigned int reset: 1; /*!< Level of reset pin in reset */
|
||||
unsigned int interrupt: 1;/*!< Active Level of interrupt pin */
|
||||
} levels;
|
||||
|
||||
struct {
|
||||
unsigned int swap_xy: 1; /*!< Swap X and Y after read coordinates */
|
||||
unsigned int mirror_x: 1; /*!< Mirror X after read coordinates */
|
||||
unsigned int mirror_y: 1; /*!< Mirror Y after read coordinates */
|
||||
} flags;
|
||||
|
||||
/*!< User callback called after get coordinates from touch controller for apply user adjusting */
|
||||
void (*process_coordinates)(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
|
||||
/*!< User callback called after the touch interrupt occurred */
|
||||
esp_lcd_touch_interrupt_callback_t interrupt_callback;
|
||||
/*!< User data passed to callback */
|
||||
void *user_data;
|
||||
/*!< User data passed to driver */
|
||||
void *driver_data;
|
||||
} esp_lcd_touch_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t track_id;
|
||||
uint16_t x; /*!< X coordinate */
|
||||
uint16_t y; /*!< Y coordinate */
|
||||
uint16_t strength; /*!< Strength */
|
||||
} esp_lcd_touch_point_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t points; /*!< Count of touch points saved */
|
||||
esp_lcd_touch_point_data_t coords[CONFIG_ESP_LCD_TOUCH_MAX_POINTS];
|
||||
|
||||
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
|
||||
uint8_t buttons; /*!< Count of buttons states saved */
|
||||
|
||||
struct {
|
||||
uint8_t status; /*!< Status of button */
|
||||
} button[CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS];
|
||||
#endif
|
||||
|
||||
portMUX_TYPE lock; /*!< Lock for read/write */
|
||||
} esp_lcd_touch_data_t;
|
||||
|
||||
/**
|
||||
* @brief Declare of Touch Type
|
||||
*
|
||||
*/
|
||||
struct esp_lcd_touch_s {
|
||||
|
||||
/**
|
||||
* @brief set touch controller into sleep mode
|
||||
*
|
||||
* @note This function is usually blocking.
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*enter_sleep)(esp_lcd_touch_handle_t tp);
|
||||
|
||||
/**
|
||||
* @brief set touch controller into normal mode
|
||||
*
|
||||
* @note This function is usually blocking.
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*exit_sleep)(esp_lcd_touch_handle_t tp);
|
||||
|
||||
/**
|
||||
* @brief Read data from touch controller (mandatory)
|
||||
*
|
||||
* @note This function is usually blocking.
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*read_data)(esp_lcd_touch_handle_t tp);
|
||||
|
||||
/**
|
||||
* @brief Get coordinates from touch controller (mandatory)
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param x: Array of X coordinates
|
||||
* @param y: Array of Y coordinates
|
||||
* @param strength: Array of strengths
|
||||
* @param point_num: Count of points touched (equals with count of items in x and y array)
|
||||
* @param max_point_num: Maximum count of touched points to return (equals with max size of x and y array)
|
||||
*
|
||||
* @return
|
||||
* - Returns true, when touched and coordinates readed. Otherwise returns false.
|
||||
*/
|
||||
bool (*get_xy)(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
|
||||
|
||||
/**
|
||||
* @brief Get track ids of touch points
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param track_id: Array of track ids
|
||||
* @param point_num: Count of track IDs to return
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*get_track_id)(esp_lcd_touch_handle_t tp, uint8_t *track_id, uint8_t point_num);
|
||||
|
||||
|
||||
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
|
||||
/**
|
||||
* @brief Get button state (optional)
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param n: Button index
|
||||
* @param state: Button state
|
||||
*
|
||||
* @return
|
||||
* - Returns true, when touched and coordinates readed. Otherwise returns false.
|
||||
*/
|
||||
esp_err_t (*get_button_state)(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Swap X and Y after read coordinates (optional)
|
||||
* If set, then not used SW swapping.
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param swap: Set swap value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*set_swap_xy)(esp_lcd_touch_handle_t tp, bool swap);
|
||||
|
||||
/**
|
||||
* @brief Are X and Y coordinates swapped (optional)
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param swap: Get swap value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*get_swap_xy)(esp_lcd_touch_handle_t tp, bool *swap);
|
||||
|
||||
/**
|
||||
* @brief Mirror X after read coordinates
|
||||
* If set, then not used SW mirroring.
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param mirror: Set X mirror value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*set_mirror_x)(esp_lcd_touch_handle_t tp, bool mirror);
|
||||
|
||||
/**
|
||||
* @brief Is mirrored X (optional)
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param mirror: Get X mirror value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*get_mirror_x)(esp_lcd_touch_handle_t tp, bool *mirror);
|
||||
|
||||
/**
|
||||
* @brief Mirror Y after read coordinates
|
||||
* If set, then not used SW mirroring.
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param mirror: Set Y mirror value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*set_mirror_y)(esp_lcd_touch_handle_t tp, bool mirror);
|
||||
|
||||
/**
|
||||
* @brief Is mirrored Y (optional)
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param mirror: Get Y mirror value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*get_mirror_y)(esp_lcd_touch_handle_t tp, bool *mirror);
|
||||
|
||||
/**
|
||||
* @brief Delete Touch
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||
*/
|
||||
esp_err_t (*del)(esp_lcd_touch_handle_t tp);
|
||||
|
||||
/**
|
||||
* @brief Configuration structure
|
||||
*/
|
||||
esp_lcd_touch_config_t config;
|
||||
|
||||
/**
|
||||
* @brief Communication interface
|
||||
*/
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
|
||||
/**
|
||||
* @brief Data structure
|
||||
*/
|
||||
esp_lcd_touch_data_t data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Read data from touch controller
|
||||
*
|
||||
* @note This function is usually blocking.
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
* - ESP_FAIL sending command error, slave hasn't ACK the transfer
|
||||
* - ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode
|
||||
* - ESP_ERR_TIMEOUT operation timeout because the bus is busy
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_read_data(esp_lcd_touch_handle_t tp);
|
||||
|
||||
/**
|
||||
* @brief Get each touch point data from touch controller
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param data: Array of data structures to be filled out
|
||||
* @param point_cnt: Count of touched points (equals to count of items in x and y array)
|
||||
* @param max_point_cnt: Maximum count of touched points to return (equals with max size of x and y array)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE if parameter is uninitialized
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_get_data(esp_lcd_touch_handle_t tp, esp_lcd_touch_point_data_t *data, uint8_t *point_cnt, uint8_t max_point_cnt);
|
||||
|
||||
/**
|
||||
* @brief Read coordinates from touch controller
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param x: Array of X coordinates
|
||||
* @param y: Array of Y coordinates
|
||||
* @param strength: Array of the strengths (can be NULL)
|
||||
* @param point_num: Count of points touched (equals with count of items in x and y array)
|
||||
* @param max_point_num: Maximum count of touched points to return (equals with max size of x and y array)
|
||||
*
|
||||
* @return
|
||||
* - Returns true, when touched and coordinates readed. Otherwise returns false.
|
||||
*/
|
||||
[[deprecated("This API will be removed in version 2.0.0. Use esp_lcd_touch_get_data instead!")]]
|
||||
bool esp_lcd_touch_get_coordinates(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
|
||||
|
||||
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
|
||||
/**
|
||||
* @brief Get button state
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param n: Button index
|
||||
* @param state: Button state
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NOT_SUPPORTED if this function is not supported by controller
|
||||
* - ESP_ERR_INVALID_ARG if bad button index
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Swap X and Y after read coordinates
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param swap: Set swap value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_set_swap_xy(esp_lcd_touch_handle_t tp, bool swap);
|
||||
|
||||
/**
|
||||
* @brief Are X and Y coordinates swapped
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param swap: Get swap value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_get_swap_xy(esp_lcd_touch_handle_t tp, bool *swap);
|
||||
|
||||
/**
|
||||
* @brief Mirror X after read coordinates
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param mirror: Set X mirror value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_set_mirror_x(esp_lcd_touch_handle_t tp, bool mirror);
|
||||
|
||||
/**
|
||||
* @brief Is mirrored X
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param mirror: Get X mirror value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_get_mirror_x(esp_lcd_touch_handle_t tp, bool *mirror);
|
||||
|
||||
/**
|
||||
* @brief Mirror Y after read coordinates
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param mirror: Set Y mirror value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_set_mirror_y(esp_lcd_touch_handle_t tp, bool mirror);
|
||||
|
||||
/**
|
||||
* @brief Is mirrored Y
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param mirror: Get Y mirror value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_get_mirror_y(esp_lcd_touch_handle_t tp, bool *mirror);
|
||||
|
||||
/**
|
||||
* @brief Delete touch (free all allocated memory and restart HW)
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_del(esp_lcd_touch_handle_t tp);
|
||||
|
||||
/**
|
||||
* @brief Register user callback called after the touch interrupt occurred
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param callback: Interrupt callback
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback);
|
||||
|
||||
/**
|
||||
* @brief Register user callback called after the touch interrupt occurred with user data
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
* @param callback: Interrupt callback
|
||||
* @param user_data: User data passed to callback
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_register_interrupt_callback_with_data(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Enter sleep mode
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_enter_sleep(esp_lcd_touch_handle_t tp);
|
||||
|
||||
/**
|
||||
* @brief Exit sleep mode
|
||||
*
|
||||
* @param tp: Touch handler
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
*/
|
||||
esp_err_t esp_lcd_touch_exit_sleep(esp_lcd_touch_handle_t tp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
202
managed_components/espressif__esp_lcd_touch/license.txt
Normal file
202
managed_components/espressif__esp_lcd_touch/license.txt
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1 @@
|
||||
d3c020b45c3dfc0d1706a83b63a1c34a6eb444a6e935f9afff79f92b7b94dcef
|
||||
206
managed_components/espressif__esp_lvgl_port/CHANGELOG.md
Normal file
206
managed_components/espressif__esp_lvgl_port/CHANGELOG.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# Changelog
|
||||
|
||||
## 2.9.0
|
||||
|
||||
### Features
|
||||
|
||||
- Support for CherryUSB stack (input device)
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fixed callbacks for DPI by IDF update (`on_refresh_done` --> `on_frame_buf_complete`)
|
||||
|
||||
## 2.8.0
|
||||
|
||||
### Features
|
||||
|
||||
- Supported RGB/MIPI-DSI interfaces for chips by SOC_*
|
||||
- Added ESP32P4 support to RGB Example
|
||||
- Updated support for RGB565 swapped color format
|
||||
- Supported LCD_RGB_ISR_IRAM_SAFE for RGB panels
|
||||
|
||||
## 2.7.2
|
||||
|
||||
### Features
|
||||
|
||||
- Added a new event type for encoder events
|
||||
|
||||
### Fixes
|
||||
|
||||
- Encoder usage no longer causes unexpected touch controller readings - https://github.com/espressif/esp-bsp/issues/700
|
||||
|
||||
## 2.7.1
|
||||
|
||||
### Features
|
||||
- Added option to include a rounder callback
|
||||
|
||||
### Fixes
|
||||
- Fixed deinitialization of the task which was created with caps - https://github.com/espressif/esp-bsp/issues/680
|
||||
- Call lv_deinit() - https://github.com/espressif/esp-bsp/issues/635
|
||||
- Fixed PPA rotation for IDF6
|
||||
|
||||
## 2.7.0
|
||||
|
||||
### Features
|
||||
|
||||
- Added support for multi-touch gestures.
|
||||
|
||||
## 2.6.3
|
||||
|
||||
### Fixes
|
||||
- Improved and fixed deinit function (remove semaphore) - https://github.com/espressif/esp-bsp/issues/673
|
||||
|
||||
## 2.6.2
|
||||
|
||||
- Changed minimum IDF version to IDF5.1
|
||||
|
||||
## 2.6.1
|
||||
|
||||
### Features
|
||||
- Added option to place LVGL task stack to external RAM
|
||||
- Fixed callback for RGB display for IDF6
|
||||
|
||||
### Fixes
|
||||
- Register button callbacks only if encoder_enter is set https://github.com/espressif/esp-bsp/pull/571/files
|
||||
|
||||
## 2.6.0
|
||||
|
||||
### Features
|
||||
- Scaling feature in touch
|
||||
- Added support for PPA rotation in LVGL9 (available for ESP32-P4)
|
||||
|
||||
## 2.5.0
|
||||
|
||||
### Features (Functional change for button v4 users)
|
||||
- Updated LVGL port for using IoT button component v4 (LVGL port not anymore creating button, need to be created in app and included handle to LVGL port)
|
||||
|
||||
### Fixes
|
||||
- Fixed buffer size by selected color format
|
||||
- Fixed memory leak in LVGL8 in display removing https://github.com/espressif/esp-bsp/issues/462
|
||||
- Fixed draw buffer alignment
|
||||
|
||||
## 2.4.4
|
||||
|
||||
### Features
|
||||
- Changed queue to event group in main LVGL task for speed up https://github.com/espressif/esp-bsp/issues/492
|
||||
- Reworked handling encoder (knob) https://github.com/espressif/esp-bsp/pull/450
|
||||
|
||||
### Fixes
|
||||
- Fixed a crash when esp_lvgl_port was initialized from high priority task https://github.com/espressif/esp-bsp/issues/455
|
||||
- Allow to swap bytes when used SW rotation https://github.com/espressif/esp-bsp/issues/497
|
||||
|
||||
## 2.4.3
|
||||
|
||||
### Fixes
|
||||
- Fixed a display context pointer bug
|
||||
- Fixed I2C example for using with LVGL9
|
||||
|
||||
### Features
|
||||
- Support for LV_COLOR_FORMAT_I1 for monochromatic screen
|
||||
|
||||
## 2.4.2
|
||||
|
||||
### Fixes
|
||||
- Fixed SW rotation in LVGL9.2
|
||||
- Fixed freeing right buffers when error
|
||||
|
||||
## 2.4.1
|
||||
|
||||
### Fixes
|
||||
- Fixed the issue of the DPI callback function not being initialized.
|
||||
|
||||
## 2.4.0
|
||||
|
||||
### Features
|
||||
- Added support for direct mode and full refresh mode in the MIPI-DSI interface.
|
||||
- Optimized avoid-tear feature and LVGL task.
|
||||
|
||||
## 2.3.3
|
||||
|
||||
### Features
|
||||
- Updated RGB screen flush handling in LVGL9.
|
||||
|
||||
## 2.3.2
|
||||
|
||||
### Fixes
|
||||
- Fixed rotation type compatibility with LVGL8.
|
||||
|
||||
## 2.3.1
|
||||
|
||||
### Fixes
|
||||
- Fixed LVGL version resolution if LVGL is not a managed component
|
||||
- Fixed link error with LVGL v9.2
|
||||
- Fixed event error with LVGL v9.2
|
||||
|
||||
## 2.3.0
|
||||
|
||||
### Fixes
|
||||
- Fixed LVGL port for using with LVGL9 OS FreeRTOS enabled
|
||||
- Fixed bad handled touch due to synchronization timer task
|
||||
|
||||
### Features
|
||||
- Added support for SW rotation in LVGL9
|
||||
|
||||
## 2.2.2
|
||||
|
||||
### Fixes
|
||||
- Fixed missing callback in IDF4.4.3 and lower for LVGL port
|
||||
|
||||
## 2.2.1
|
||||
|
||||
### Fixes
|
||||
- Added missing includes
|
||||
- Fixed watchdog error in some cases in LVGL9
|
||||
|
||||
## 2.2.0
|
||||
|
||||
### Features
|
||||
- Added RGB display support
|
||||
- Added support for direct mode and full refresh mode
|
||||
|
||||
### Breaking changes
|
||||
- Removed MIPI-DSI from display configuration structure - use `lvgl_port_add_disp_dsi` instead
|
||||
|
||||
## 2.1.0
|
||||
|
||||
### Features
|
||||
- Added LVGL sleep feature: The esp_lvgl_port handling can sleep if the display and touch are inactive (only with LVGL9)
|
||||
- Added support for different display color modes (only with LVGL9)
|
||||
- Added script for generating C array images during build (depends on LVGL version)
|
||||
|
||||
### Fixes
|
||||
- Applied initial display rotation from configuration https://github.com/espressif/esp-bsp/pull/278
|
||||
- Added blocking wait for LVGL task stop during esp_lvgl_port de-initialization https://github.com/espressif/esp-bsp/issues/277
|
||||
- Added missing esp_idf_version.h include
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Features
|
||||
|
||||
- Divided into files per feature
|
||||
- Added support for LVGL9
|
||||
- Added support for MIPI-DSI display
|
||||
|
||||
## 1.4.0
|
||||
|
||||
### Features
|
||||
|
||||
- Added support for USB HID mouse/keyboard as an input device
|
||||
|
||||
## 1.3.0
|
||||
|
||||
### Features
|
||||
|
||||
- Added low power interface
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### Features
|
||||
|
||||
- Added support for encoder (knob) as an input device
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Features
|
||||
|
||||
- Added support for navigation buttons as an input device
|
||||
File diff suppressed because one or more lines are too long
156
managed_components/espressif__esp_lvgl_port/CMakeLists.txt
Normal file
156
managed_components/espressif__esp_lvgl_port/CMakeLists.txt
Normal file
@@ -0,0 +1,156 @@
|
||||
include($ENV{IDF_PATH}/tools/cmake/version.cmake) # $ENV{IDF_VERSION} was added after v4.3...
|
||||
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_LESS "4.4")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Use the cmakev2-native build when running under cmakev2. The v1 code below
|
||||
# stays as is for legacy IDF builds.
|
||||
if(IDF_BUILD_V2)
|
||||
include(CMakeLists_v2.txt)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(ADD_SRCS "")
|
||||
set(ADD_LIBS "")
|
||||
set(PRIV_REQ "")
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
if(${target} STREQUAL "esp32p4")
|
||||
list(APPEND ADD_SRCS "src/common/ppa/lcd_ppa.c")
|
||||
list(APPEND ADD_LIBS idf::esp_driver_ppa)
|
||||
list(APPEND PRIV_REQ esp_driver_ppa)
|
||||
endif()
|
||||
|
||||
# This component uses a CMake workaround, so we can compile esp_lvgl_port for both LVGL8.x and LVGL9.x
|
||||
# At the time of idf_component_register() we don't know which LVGL version is used, so we only register an INTERFACE component (with no sources)
|
||||
# Later, when we know the LVGL version, we create another CMake library called 'lvgl_port_lib' and link it to the 'esp_lvgl_port' INTERFACE component
|
||||
idf_component_register(
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "priv_include"
|
||||
REQUIRES "esp_lcd"
|
||||
PRIV_REQUIRES "${PRIV_REQ}")
|
||||
|
||||
# Get LVGL version
|
||||
idf_build_get_property(build_components BUILD_COMPONENTS)
|
||||
if(lvgl IN_LIST build_components)
|
||||
set(lvgl_name lvgl) # Local component
|
||||
set(lvgl_ver $ENV{LVGL_VERSION}) # Get the version from env variable (set from LVGL v9.2)
|
||||
else()
|
||||
set(lvgl_name lvgl__lvgl) # Managed component
|
||||
idf_component_get_property(lvgl_ver ${lvgl_name} COMPONENT_VERSION) # Get the version from esp-idf build system
|
||||
endif()
|
||||
|
||||
if("${lvgl_ver}" STREQUAL "")
|
||||
message("Could not determine LVGL version, assuming v9.x")
|
||||
set(lvgl_ver "9.0.0")
|
||||
endif()
|
||||
|
||||
# Select folder by LVGL version
|
||||
message(STATUS "LVGL version: ${lvgl_ver}")
|
||||
if(lvgl_ver VERSION_LESS "9.0.0")
|
||||
message(VERBOSE "Compiling esp_lvgl_port for LVGL8")
|
||||
set(PORT_FOLDER "lvgl8")
|
||||
else()
|
||||
message(VERBOSE "Compiling esp_lvgl_port for LVGL9")
|
||||
set(PORT_FOLDER "lvgl9")
|
||||
endif()
|
||||
|
||||
# Add LVGL port extensions
|
||||
set(PORT_PATH "src/${PORT_FOLDER}")
|
||||
|
||||
idf_build_get_property(build_components BUILD_COMPONENTS)
|
||||
if("espressif__button" IN_LIST build_components)
|
||||
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_button.c")
|
||||
list(APPEND ADD_LIBS idf::espressif__button)
|
||||
endif()
|
||||
if("button" IN_LIST build_components)
|
||||
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_button.c")
|
||||
list(APPEND ADD_LIBS idf::button)
|
||||
endif()
|
||||
if("espressif__esp_lcd_touch" IN_LIST build_components)
|
||||
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_touch.c")
|
||||
list(APPEND ADD_LIBS idf::espressif__esp_lcd_touch)
|
||||
endif()
|
||||
if("esp_lcd_touch" IN_LIST build_components)
|
||||
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_touch.c")
|
||||
list(APPEND ADD_LIBS idf::esp_lcd_touch)
|
||||
endif()
|
||||
if("espressif__knob" IN_LIST build_components)
|
||||
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_knob.c")
|
||||
list(APPEND ADD_LIBS idf::espressif__knob)
|
||||
endif()
|
||||
if("knob" IN_LIST build_components)
|
||||
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_knob.c")
|
||||
list(APPEND ADD_LIBS idf::knob)
|
||||
endif()
|
||||
if("cherry-embedded__cherryusb" IN_LIST build_components)
|
||||
idf_component_get_property(cherryusb_dir cherry-embedded__cherryusb COMPONENT_DIR)
|
||||
list(APPEND ADD_SRCS
|
||||
"${cherryusb_dir}/platform/lvgl/usbh_hid_lvgl.c"
|
||||
"${cherryusb_dir}/platform/lvgl/image_cursor.c"
|
||||
"${PORT_PATH}/esp_lvgl_port_usbhid_cherryusb.c"
|
||||
)
|
||||
list(APPEND ADD_LIBS idf::cherry-embedded__cherryusb)
|
||||
elseif("cherryusb" IN_LIST build_components)
|
||||
idf_component_get_property(cherryusb_dir cherryusb COMPONENT_DIR)
|
||||
list(APPEND ADD_SRCS
|
||||
"${cherryusb_dir}/platform/lvgl/usbh_hid_lvgl.c"
|
||||
"${cherryusb_dir}/platform/lvgl/image_cursor.c"
|
||||
"${PORT_PATH}/esp_lvgl_port_usbhid_cherryusb.c"
|
||||
)
|
||||
list(APPEND ADD_LIBS idf::cherryusb)
|
||||
elseif("espressif__usb_host_hid" IN_LIST build_components)
|
||||
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_usbhid.c" "images/${PORT_FOLDER}/img_cursor.c")
|
||||
list(APPEND ADD_LIBS idf::espressif__usb_host_hid)
|
||||
elseif("usb_host_hid" IN_LIST build_components)
|
||||
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_usbhid.c" "images/${PORT_FOLDER}/img_cursor.c")
|
||||
list(APPEND ADD_LIBS idf::usb_host_hid)
|
||||
endif()
|
||||
|
||||
# Include SIMD assembly source code for rendering, only for (9.1.0 <= LVG_version < 9.2.0) and only for esp32 and esp32s3
|
||||
if((lvgl_ver VERSION_GREATER_EQUAL "9.1.0") AND (lvgl_ver VERSION_LESS "9.2.0"))
|
||||
if(CONFIG_IDF_TARGET_ESP32 OR CONFIG_IDF_TARGET_ESP32S3)
|
||||
message(VERBOSE "Compiling SIMD")
|
||||
if(CONFIG_IDF_TARGET_ESP32S3)
|
||||
file(GLOB_RECURSE ASM_SRCS ${PORT_PATH}/simd/*_esp32s3.S) # Select only esp32s3 related files
|
||||
else()
|
||||
file(GLOB_RECURSE ASM_SRCS ${PORT_PATH}/simd/*_esp32.S) # Select only esp32 related files
|
||||
endif()
|
||||
|
||||
# Explicitly add all assembly macro files
|
||||
file(GLOB_RECURSE ASM_MACROS ${PORT_PATH}/simd/lv_macro_*.S)
|
||||
list(APPEND ADD_SRCS ${ASM_MACROS})
|
||||
list(APPEND ADD_SRCS ${ASM_SRCS})
|
||||
|
||||
# Include component libraries, so lvgl component would see lvgl_port includes
|
||||
idf_component_get_property(lvgl_lib ${lvgl_name} COMPONENT_LIB)
|
||||
target_include_directories(${lvgl_lib} PRIVATE "include")
|
||||
|
||||
# Force link .S files
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_argb8888_esp")
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_rgb565_esp")
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_rgb888_esp")
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_rgb565_blend_normal_to_rgb565_esp")
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_rgb888_blend_normal_to_rgb888_esp")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Here we create the real lvgl_port_lib
|
||||
add_library(lvgl_port_lib STATIC
|
||||
${PORT_PATH}/esp_lvgl_port.c
|
||||
${PORT_PATH}/esp_lvgl_port_disp.c
|
||||
${ADD_SRCS}
|
||||
)
|
||||
target_include_directories(lvgl_port_lib PUBLIC "include")
|
||||
target_include_directories(lvgl_port_lib PRIVATE "priv_include")
|
||||
target_link_libraries(lvgl_port_lib PUBLIC
|
||||
idf::esp_lcd
|
||||
idf::${lvgl_name}
|
||||
)
|
||||
target_link_libraries(lvgl_port_lib PRIVATE
|
||||
idf::esp_timer
|
||||
${ADD_LIBS}
|
||||
)
|
||||
|
||||
# Finally, link the lvgl_port_lib its esp-idf interface library
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE lvgl_port_lib)
|
||||
155
managed_components/espressif__esp_lvgl_port/CMakeLists_v2.txt
Normal file
155
managed_components/espressif__esp_lvgl_port/CMakeLists_v2.txt
Normal file
@@ -0,0 +1,155 @@
|
||||
# Native cmakev2 component definition for esp_lvgl_port.
|
||||
#
|
||||
# Dispatched from CMakeLists.txt when IDF_BUILD_V2 is set. No
|
||||
# idf_component_register shim: the build system derives the v1-style
|
||||
# component properties (SRCS, INCLUDE_DIRS, PRIV_INCLUDE_DIRS, REQUIRES,
|
||||
# PRIV_REQUIRES) from this target's sources and link libraries via
|
||||
# __set_component_cmakev1_properties (tools/cmakev2/component.cmake).
|
||||
|
||||
# Local helper standing in for a missing public cmakev2 API: a non-fatal
|
||||
# version of idf_component_include. The framework only provides
|
||||
# idf_component_include(<name>), which aborts the build when <name> is not
|
||||
# discovered, and __get_component_interface (underscore-prefixed, internal)
|
||||
# for a non-fatal lookup. Until idf_component_include grows an OPTIONAL flag
|
||||
# or an idf_component_get_interface gets promoted to a public API, we wrap
|
||||
# the internal call here so it appears in exactly one place.
|
||||
#
|
||||
# <name> resolves through the v2 interface cache: a short name like "button"
|
||||
# matches either the local "button" component or the managed "espressif__button"
|
||||
# variant, transparently.
|
||||
#
|
||||
# On success: <out_iface> is set to the component's INTERFACE target.
|
||||
# On miss: <out_iface> is set to the empty string, and no include happens.
|
||||
function(_lvgl_port_optional_include name out_iface)
|
||||
__get_component_interface(COMPONENT "${name}" OUTPUT _iface)
|
||||
if(_iface STREQUAL "NOTFOUND")
|
||||
set(${out_iface} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
idf_component_include("${name}")
|
||||
set(${out_iface} ${_iface} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Include LVGL up front so its CMakeLists.txt runs (populating COMPONENT_VERSION
|
||||
# and the LVGL_VERSION env var) before we decide on PORT_PATH. Capture the
|
||||
# interface target into lvgl_iface so we can link to it without caring whether
|
||||
# the install is local (idf::lvgl) or managed (idf::lvgl__lvgl).
|
||||
idf_component_include(lvgl INTERFACE lvgl_iface)
|
||||
|
||||
# LVGL version: manager-set COMPONENT_VERSION (managed install), or env var
|
||||
# from LVGL's own CMakeLists.txt (local install, LVGL >= 9.2).
|
||||
idf_component_get_property(lvgl_ver lvgl COMPONENT_VERSION)
|
||||
if(NOT lvgl_ver)
|
||||
set(lvgl_ver $ENV{LVGL_VERSION})
|
||||
endif()
|
||||
if("${lvgl_ver}" STREQUAL "")
|
||||
message("Could not determine LVGL version, assuming v9.x")
|
||||
set(lvgl_ver "9.0.0")
|
||||
endif()
|
||||
message(STATUS "LVGL version: ${lvgl_ver}")
|
||||
|
||||
if(lvgl_ver VERSION_LESS "9.0.0")
|
||||
message(VERBOSE "Compiling esp_lvgl_port for LVGL8")
|
||||
set(PORT_FOLDER "lvgl8")
|
||||
else()
|
||||
message(VERBOSE "Compiling esp_lvgl_port for LVGL9")
|
||||
set(PORT_FOLDER "lvgl9")
|
||||
endif()
|
||||
set(PORT_PATH "src/${PORT_FOLDER}")
|
||||
|
||||
# Create the library with the base sources. Subsequent blocks extend it
|
||||
# directly via target_sources / target_link_libraries.
|
||||
add_library(${COMPONENT_TARGET} STATIC
|
||||
"${PORT_PATH}/esp_lvgl_port.c"
|
||||
"${PORT_PATH}/esp_lvgl_port_disp.c"
|
||||
)
|
||||
target_include_directories(${COMPONENT_TARGET} PUBLIC "include")
|
||||
target_include_directories(${COMPONENT_TARGET} PRIVATE "priv_include")
|
||||
|
||||
# Public dep: esp_lcd. lvgl_iface was captured above.
|
||||
idf_component_include(esp_lcd)
|
||||
target_link_libraries(${COMPONENT_TARGET} PUBLIC idf::esp_lcd ${lvgl_iface})
|
||||
|
||||
# Private dep: esp_timer.
|
||||
idf_component_include(esp_timer)
|
||||
target_link_libraries(${COMPONENT_TARGET} PRIVATE idf::esp_timer)
|
||||
|
||||
# Target-specific: ESP32-P4 picks up the PPA driver.
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
if(${target} STREQUAL "esp32p4")
|
||||
idf_component_include(esp_driver_ppa)
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE "src/common/ppa/lcd_ppa.c")
|
||||
target_link_libraries(${COMPONENT_TARGET} PRIVATE idf::esp_driver_ppa)
|
||||
endif()
|
||||
|
||||
# Optional integrations.
|
||||
|
||||
# button
|
||||
_lvgl_port_optional_include(button button_iface)
|
||||
if(button_iface)
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE "${PORT_PATH}/esp_lvgl_port_button.c")
|
||||
target_link_libraries(${COMPONENT_TARGET} PRIVATE ${button_iface})
|
||||
endif()
|
||||
|
||||
# esp_lcd_touch
|
||||
_lvgl_port_optional_include(esp_lcd_touch touch_iface)
|
||||
if(touch_iface)
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE "${PORT_PATH}/esp_lvgl_port_touch.c")
|
||||
target_link_libraries(${COMPONENT_TARGET} PRIVATE ${touch_iface})
|
||||
endif()
|
||||
|
||||
# knob
|
||||
_lvgl_port_optional_include(knob knob_iface)
|
||||
if(knob_iface)
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE "${PORT_PATH}/esp_lvgl_port_knob.c")
|
||||
target_link_libraries(${COMPONENT_TARGET} PRIVATE ${knob_iface})
|
||||
endif()
|
||||
|
||||
# cherryusb HID
|
||||
_lvgl_port_optional_include(cherryusb cherryusb_iface)
|
||||
if(cherryusb_iface)
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE
|
||||
"${cherryusb_dir}/platform/lvgl/usbh_hid_lvgl.c"
|
||||
"${cherryusb_dir}/platform/lvgl/image_cursor.c"
|
||||
"${PORT_PATH}/esp_lvgl_port_usbhid_cherryusb.c"
|
||||
)
|
||||
target_link_libraries(${COMPONENT_TARGET} PRIVATE ${cherryusb_iface})
|
||||
else()
|
||||
# usb_host_hid
|
||||
_lvgl_port_optional_include(usb_host_hid usbhid_iface)
|
||||
if(usbhid_iface)
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE
|
||||
"${PORT_PATH}/esp_lvgl_port_usbhid.c"
|
||||
"images/${PORT_FOLDER}/img_cursor.c"
|
||||
)
|
||||
target_link_libraries(${COMPONENT_TARGET} PRIVATE ${usbhid_iface})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# SIMD assembly for 9.1.x on ESP32 / ESP32-S3. ASM sources, the lvgl include
|
||||
# path, and the -u link directives all live in one block now that
|
||||
# COMPONENT_TARGET is the live target.
|
||||
if((lvgl_ver VERSION_GREATER_EQUAL "9.1.0") AND (lvgl_ver VERSION_LESS "9.2.0"))
|
||||
if(CONFIG_IDF_TARGET_ESP32 OR CONFIG_IDF_TARGET_ESP32S3)
|
||||
message(VERBOSE "Compiling SIMD")
|
||||
if(CONFIG_IDF_TARGET_ESP32S3)
|
||||
file(GLOB_RECURSE ASM_SRCS "${PORT_PATH}/simd/*_esp32s3.S")
|
||||
else()
|
||||
file(GLOB_RECURSE ASM_SRCS "${PORT_PATH}/simd/*_esp32.S")
|
||||
endif()
|
||||
file(GLOB_RECURSE ASM_MACROS "${PORT_PATH}/simd/lv_macro_*.S")
|
||||
target_sources(${COMPONENT_TARGET} PRIVATE ${ASM_MACROS} ${ASM_SRCS})
|
||||
|
||||
# Expose include path to LVGL so its sources can pick up our headers.
|
||||
idf_component_get_property(lvgl_lib lvgl COMPONENT_LIB)
|
||||
target_include_directories(${lvgl_lib} PRIVATE "include")
|
||||
|
||||
# Force-link the SIMD symbols.
|
||||
set_property(TARGET ${COMPONENT_TARGET} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_argb8888_esp")
|
||||
set_property(TARGET ${COMPONENT_TARGET} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_rgb565_esp")
|
||||
set_property(TARGET ${COMPONENT_TARGET} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_rgb888_esp")
|
||||
set_property(TARGET ${COMPONENT_TARGET} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_rgb565_blend_normal_to_rgb565_esp")
|
||||
set_property(TARGET ${COMPONENT_TARGET} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_rgb888_blend_normal_to_rgb888_esp")
|
||||
endif()
|
||||
endif()
|
||||
10
managed_components/espressif__esp_lvgl_port/Kconfig
Normal file
10
managed_components/espressif__esp_lvgl_port/Kconfig
Normal file
@@ -0,0 +1,10 @@
|
||||
menu "ESP LVGL PORT"
|
||||
|
||||
config LVGL_PORT_ENABLE_PPA
|
||||
depends on SOC_PPA_SUPPORTED
|
||||
bool "Enable PPA for screen rotation"
|
||||
default n
|
||||
help
|
||||
Enables using PPA for screen rotation.
|
||||
|
||||
endmenu
|
||||
420
managed_components/espressif__esp_lvgl_port/README.md
Normal file
420
managed_components/espressif__esp_lvgl_port/README.md
Normal file
@@ -0,0 +1,420 @@
|
||||
# LVGL ESP Portation
|
||||
|
||||
[](https://components.espressif.com/components/espressif/esp_lvgl_port)
|
||||

|
||||
|
||||
This component helps with using LVGL with Espressif's LCD and touch drivers. It can be used with any project with LCD display.
|
||||
|
||||
## Features
|
||||
* Initialization of the LVGL
|
||||
* Create task and timer
|
||||
* Handle rotating
|
||||
* Power saving
|
||||
* Add/remove display (using [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html))
|
||||
* Add/remove touch input (using [`esp_lcd_touch`](https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch))
|
||||
* Add/remove navigation buttons input (using [`button`](https://github.com/espressif/esp-iot-solution/tree/master/components/button))
|
||||
* Add/remove encoder input (using [`knob`](https://github.com/espressif/esp-iot-solution/tree/master/components/knob))
|
||||
* Add/remove USB HID mouse/keyboard input (using [`usb_host_hid`](https://components.espressif.com/components/espressif/usb_host_hid))
|
||||
|
||||
## LVGL Version
|
||||
|
||||
This component supports **LVGL8** and **LVGL9**. By default, it selects the latest LVGL version. If you want to use a specific version (e.g. latest LVGL8), you can easily define this requirement in `idf_component.yml` in your project like this:
|
||||
|
||||
```
|
||||
lvgl/lvgl:
|
||||
version: "^8"
|
||||
public: true
|
||||
```
|
||||
|
||||
### LVGL Version Compatibility
|
||||
|
||||
This component is fully compatible with LVGL version 9. All types and functions are used from LVGL9. Some LVGL9 types are not supported in LVGL8 and there are retyped in [`esp_lvgl_port_compatibility.h`](include/esp_lvgl_port_compatibility.h) header file. **Please, be aware, that some draw and object functions are not compatible between LVGL8 and LVGL9.**
|
||||
|
||||
## Usage
|
||||
|
||||
### Initialization
|
||||
``` c
|
||||
const lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
esp_err_t err = lvgl_port_init(&lvgl_cfg);
|
||||
```
|
||||
|
||||
### Add screen
|
||||
|
||||
Add an LCD screen to the LVGL. It can be called multiple times for adding multiple LCD screens.
|
||||
|
||||
``` c
|
||||
static lv_disp_t * disp_handle;
|
||||
|
||||
/* LCD IO */
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t) 1, &io_config, &io_handle));
|
||||
|
||||
/* LCD driver initialization */
|
||||
esp_lcd_panel_handle_t lcd_panel_handle;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &lcd_panel_handle));
|
||||
|
||||
/* Add LCD screen */
|
||||
const lvgl_port_display_cfg_t disp_cfg = {
|
||||
.io_handle = io_handle,
|
||||
.panel_handle = lcd_panel_handle,
|
||||
.buffer_size = DISP_WIDTH*DISP_HEIGHT,
|
||||
.double_buffer = true,
|
||||
.hres = DISP_WIDTH,
|
||||
.vres = DISP_HEIGHT,
|
||||
.monochrome = false,
|
||||
.mipi_dsi = false,
|
||||
.color_format = LV_COLOR_FORMAT_RGB565,
|
||||
.rounder_cb = my_rounder_cb,
|
||||
.rotation = {
|
||||
.swap_xy = false,
|
||||
.mirror_x = false,
|
||||
.mirror_y = false,
|
||||
},
|
||||
.flags = {
|
||||
.buff_dma = true,
|
||||
.swap_bytes = false,
|
||||
}
|
||||
};
|
||||
disp_handle = lvgl_port_add_disp(&disp_cfg);
|
||||
|
||||
/* ... the rest of the initialization ... */
|
||||
|
||||
/* If deinitializing LVGL port, remember to delete all displays: */
|
||||
lvgl_port_remove_disp(disp_handle);
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> 1. For adding RGB or MIPI-DSI screen, use functions `lvgl_port_add_disp_rgb` or `lvgl_port_add_disp_dsi`.
|
||||
> 2. DMA buffer can be used only when you use color format `LV_COLOR_FORMAT_RGB565`.
|
||||
|
||||
### Add touch input
|
||||
|
||||
Add touch input to the LVGL. It can be called more times for adding more touch inputs.
|
||||
``` c
|
||||
/* Touch driver initialization */
|
||||
...
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_err_t err = esp_lcd_touch_new_i2c_gt911(io_handle, &tp_cfg, &tp);
|
||||
|
||||
/* Add touch input (for selected screen) */
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = disp_handle,
|
||||
.handle = tp,
|
||||
};
|
||||
lv_indev_t* touch_handle = lvgl_port_add_touch(&touch_cfg);
|
||||
|
||||
/* ... the rest of the initialization ... */
|
||||
|
||||
/* If deinitializing LVGL port, remember to delete all touches: */
|
||||
lvgl_port_remove_touch(touch_handle);
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> If the screen has another resolution than the touch resolution, you can use scaling by add `.scale.x` or `.scale.y` into `lvgl_port_touch_cfg_t` configuration structure.
|
||||
|
||||
### Add buttons input
|
||||
|
||||
Add buttons input to the LVGL. It can be called more times for adding more buttons inputs for different displays. This feature is available only when the component `espressif/button` was added into the project.
|
||||
``` c
|
||||
/* Buttons configuration structure */
|
||||
const button_gpio_config_t bsp_button_config[] = {
|
||||
{
|
||||
.gpio_num = GPIO_NUM_37,
|
||||
.active_level = 0,
|
||||
},
|
||||
{
|
||||
.gpio_num = GPIO_NUM_38,
|
||||
.active_level = 0,
|
||||
},
|
||||
{
|
||||
.gpio_num = GPIO_NUM_39,
|
||||
.active_level = 0,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
const button_config_t btn_cfg = {0};
|
||||
button_handle_t prev_btn_handle = NULL;
|
||||
button_handle_t next_btn_handle = NULL;
|
||||
button_handle_t enter_btn_handle = NULL;
|
||||
iot_button_new_gpio_device(&btn_cfg, &bsp_button_config[0], &prev_btn_handle);
|
||||
iot_button_new_gpio_device(&btn_cfg, &bsp_button_config[1], &next_btn_handle);
|
||||
iot_button_new_gpio_device(&btn_cfg, &bsp_button_config[2], &enter_btn_handle);
|
||||
|
||||
const lvgl_port_nav_btns_cfg_t btns = {
|
||||
.disp = disp_handle,
|
||||
.button_prev = prev_btn_handle,
|
||||
.button_next = next_btn_handle,
|
||||
.button_enter = enter_btn_handle
|
||||
};
|
||||
|
||||
/* Add buttons input (for selected screen) */
|
||||
lv_indev_t* buttons_handle = lvgl_port_add_navigation_buttons(&btns);
|
||||
|
||||
/* ... the rest of the initialization ... */
|
||||
|
||||
/* If deinitializing LVGL port, remember to delete all buttons: */
|
||||
lvgl_port_remove_navigation_buttons(buttons_handle);
|
||||
```
|
||||
> [!NOTE]
|
||||
> When you use navigation buttons for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info.
|
||||
|
||||
### Add encoder input
|
||||
|
||||
Add encoder input to the LVGL. It can be called more times for adding more encoder inputs for different displays. This feature is available only when the component `espressif/knob` was added into the project.
|
||||
``` c
|
||||
|
||||
static const button_gpio_config_t encoder_btn_config = {
|
||||
.gpio_num = GPIO_BTN_PRESS,
|
||||
.active_level = 0,
|
||||
};
|
||||
|
||||
const knob_config_t encoder_a_b_config = {
|
||||
.default_direction = 0,
|
||||
.gpio_encoder_a = GPIO_ENCODER_A,
|
||||
.gpio_encoder_b = GPIO_ENCODER_B,
|
||||
};
|
||||
|
||||
const button_config_t btn_cfg = {0};
|
||||
button_handle_t encoder_btn_handle = NULL;
|
||||
BSP_ERROR_CHECK_RETURN_NULL(iot_button_new_gpio_device(&btn_cfg, &encoder_btn_config, &encoder_btn_handle));
|
||||
|
||||
/* Encoder configuration structure */
|
||||
const lvgl_port_encoder_cfg_t encoder = {
|
||||
.disp = disp_handle,
|
||||
.encoder_a_b = &encoder_a_b_config,
|
||||
.encoder_enter = encoder_btn_handle
|
||||
};
|
||||
|
||||
/* Add encoder input (for selected screen) */
|
||||
lv_indev_t* encoder_handle = lvgl_port_add_encoder(&encoder);
|
||||
|
||||
/* ... the rest of the initialization ... */
|
||||
|
||||
/* If deinitializing LVGL port, remember to delete all encoders: */
|
||||
lvgl_port_remove_encoder(encoder_handle);
|
||||
```
|
||||
> [!NOTE]
|
||||
> When you use encoder for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info.
|
||||
|
||||
### Add USB HID keyboard and mouse input
|
||||
|
||||
Add mouse and keyboard input to the LVGL. This feature is available only when the component [usb_host_hid](https://components.espressif.com/components/espressif/usb_host_hid) was added into the project.
|
||||
|
||||
``` c
|
||||
/* USB initialization */
|
||||
usb_host_config_t host_config = {
|
||||
.skip_phy_setup = false,
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||
|
||||
...
|
||||
|
||||
/* Add mouse input device */
|
||||
const lvgl_port_hid_mouse_cfg_t mouse_cfg = {
|
||||
.disp = display,
|
||||
.sensitivity = 1, /* Sensitivity of the mouse moving */
|
||||
};
|
||||
lvgl_port_add_usb_hid_mouse_input(&mouse_cfg);
|
||||
|
||||
/* Add keyboard input device */
|
||||
const lvgl_port_hid_keyboard_cfg_t kb_cfg = {
|
||||
.disp = display,
|
||||
};
|
||||
kb_indev = lvgl_port_add_usb_hid_keyboard_input(&kb_cfg);
|
||||
```
|
||||
|
||||
Keyboard special behavior (when objects are in group):
|
||||
- **TAB**: Select next object
|
||||
- **SHIFT** + **TAB**: Select previous object
|
||||
- **ENTER**: Control object (e.g. click to button)
|
||||
- **ARROWS** or **HOME** or **END**: Move in text area
|
||||
- **DEL** or **Backspace**: Remove character in textarea
|
||||
|
||||
> [!NOTE]
|
||||
> When you use keyboard for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info.
|
||||
|
||||
### Add USB HID keyboard and mouse input (CherryUSB)
|
||||
|
||||
Add mouse and keyboard input to the LVGL. This feature is available only when the component [cherry-embedded/cherryusb](https://github.com/cherry-embedded/CherryUSB/) was added into the project.
|
||||
|
||||
``` c
|
||||
/* USB initialization */
|
||||
usbh_initialize(0, ESP_USBH_BASE, NULL);
|
||||
|
||||
...
|
||||
|
||||
/* Add mouse input device */
|
||||
const lvgl_port_hid_mouse_cfg_t mouse_cfg = {
|
||||
.disp = display, /* Display selection is supported only in LVGL9 */
|
||||
.sensitivity = 1, /* Sensitivity of the mouse moving */
|
||||
};
|
||||
lvgl_port_add_usb_hid_mouse_input(&mouse_cfg);
|
||||
|
||||
/* Add keyboard input device */
|
||||
const lvgl_port_hid_keyboard_cfg_t kb_cfg = {
|
||||
.disp = display, /* Display selection is supported only in LVGL9 */
|
||||
};
|
||||
kb_indev = lvgl_port_add_usb_hid_keyboard_input(&kb_cfg);
|
||||
```
|
||||
|
||||
Keyboard special behavior (when objects are in group):
|
||||
- **TAB**: Select next object
|
||||
- **SHIFT** + **TAB**: Select previous object
|
||||
- **ENTER**: Control object (e.g. click to button)
|
||||
- **ARROWS** or **HOME** or **END**: Move in text area
|
||||
- **DEL** or **Backspace**: Remove character in textarea
|
||||
|
||||
> [!NOTE]
|
||||
> When you use keyboard for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info.
|
||||
|
||||
### LVGL API usage
|
||||
|
||||
Every LVGL calls must be protected with these lock/unlock commands:
|
||||
``` c
|
||||
/* Wait for the other task done the screen operation */
|
||||
lvgl_port_lock(0);
|
||||
...
|
||||
lv_obj_t * screen = lv_disp_get_scr_act(disp_handle);
|
||||
lv_obj_t * obj = lv_label_create(screen);
|
||||
...
|
||||
/* Screen operation done -> release for the other task */
|
||||
lvgl_port_unlock();
|
||||
```
|
||||
|
||||
### Rotating screen
|
||||
|
||||
LVGL port supports rotation of the display. You can select whether you'd like software rotation or hardware rotation.
|
||||
Software rotation requires no additional logic in your `flush_cb` callback.
|
||||
|
||||
Rotation mode can be selected in the `lvgl_port_display_cfg_t` structure.
|
||||
``` c
|
||||
const lvgl_port_display_cfg_t disp_cfg = {
|
||||
...
|
||||
.flags = {
|
||||
...
|
||||
.sw_rotate = true / false, // true: software; false: hardware
|
||||
}
|
||||
}
|
||||
```
|
||||
Display rotation can be changed at runtime.
|
||||
|
||||
``` c
|
||||
lv_disp_set_rotation(disp_handle, LV_DISP_ROT_90);
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Software rotation consumes more RAM. Software rotation uses [PPA](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/peripherals/ppa.html) if available on the chip (e.g. ESP32P4).
|
||||
|
||||
> [!NOTE]
|
||||
> During the hardware rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. When using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. See [LVGL documentation](https://docs.lvgl.io/8.3/porting/display.html?highlight=sw_rotate) for more info.
|
||||
|
||||
### Detecting gestures
|
||||
|
||||
LVGL (version 9.4 and higher) includes support for software detection of multi-touch gestures.
|
||||
This detection can be enabled by setting the `LV_USE_GESTURE_RECOGNITION` config and having `ESP_LCD_TOUCH_MAX_POINTS` > 1.
|
||||
Example usage of the gesture callback can be found in LVGL [documentation](https://docs.lvgl.io/master/details/main-modules/indev/gestures.html).
|
||||
|
||||
The LVGL port task is responsible for passing the touch coordinates to the gesture recognizers and calling the registered callback when a gesture is detected.
|
||||
|
||||
To correctly distinguish two finger swipe from rotation, we recommend changing the default value (which is 0) for the rotation threshold.
|
||||
From our testing we recommend starting with 0.15 radians.
|
||||
|
||||
```c
|
||||
lv_indev_t indev = bsp_display_get_input_dev();
|
||||
lv_indev_set_rotation_rad_threshold(indev, 0.15f);
|
||||
```
|
||||
|
||||
### Using PSRAM canvas
|
||||
|
||||
If the SRAM is insufficient, you can use the PSRAM as a canvas and use a small trans_buffer to carry it, this makes drawing more efficient.
|
||||
``` c
|
||||
const lvgl_port_display_cfg_t disp_cfg = {
|
||||
...
|
||||
.buffer_size = DISP_WIDTH * DISP_HEIGHT, // in PSRAM, not DMA-capable
|
||||
.trans_size = size, // in SRAM, DMA-capable
|
||||
.flags = {
|
||||
.buff_spiram = true,
|
||||
.buff_dma = false,
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Generating images (C Array)
|
||||
|
||||
Images can be generated during build by adding these lines to end of the main CMakeLists.txt:
|
||||
```
|
||||
# Generate C array for each image
|
||||
lvgl_port_create_c_image("images/logo.png" "images/" "ARGB8888" "NONE")
|
||||
lvgl_port_create_c_image("images/image.png" "images/" "ARGB8888" "NONE")
|
||||
# Add generated images to build
|
||||
lvgl_port_add_images(${COMPONENT_LIB} "images/")
|
||||
```
|
||||
|
||||
Usage of create C image function:
|
||||
```
|
||||
lvgl_port_create_c_image(input_image output_folder color_format compression)
|
||||
```
|
||||
|
||||
Available color formats:
|
||||
L8,I1,I2,I4,I8,A1,A2,A4,A8,ARGB8888,XRGB8888,RGB565,RGB565A8,RGB888,TRUECOLOR,TRUECOLOR_ALPHA,AUTO
|
||||
|
||||
Available compression:
|
||||
NONE,RLE,LZ4
|
||||
|
||||
> [!NOTE]
|
||||
> Parameters `color_format` and `compression` are used only in LVGL 9.
|
||||
|
||||
## Power Saving
|
||||
|
||||
The LVGL port can be optimized for power saving mode. There are two main features.
|
||||
|
||||
### LVGL task sleep
|
||||
|
||||
For optimization power saving, the LVGL task should sleep, when it does nothing. Set `task_max_sleep_ms` to big value, the LVGL task will wait for events only.
|
||||
|
||||
The LVGL task can sleep till these situations:
|
||||
* LVGL display invalidate
|
||||
* LVGL animation in process
|
||||
* Touch interrupt
|
||||
* Button interrupt
|
||||
* Knob interrupt
|
||||
* USB mouse/keyboard interrupt
|
||||
* Timeout (`task_max_sleep_ms` in configuration structure)
|
||||
* User wake (by function `lvgl_port_task_wake`)
|
||||
|
||||
> [!WARNING]
|
||||
> This feature is available from LVGL 9.
|
||||
|
||||
> [!NOTE]
|
||||
> Don't forget to set the interrupt pin in LCD touch when you set a big time for sleep in `task_max_sleep_ms`.
|
||||
|
||||
### Stopping the timer
|
||||
|
||||
Timers can still work during light-sleep mode. You can stop LVGL timer before use light-sleep by function:
|
||||
|
||||
```
|
||||
lvgl_port_stop();
|
||||
```
|
||||
|
||||
and resume LVGL timer after wake by function:
|
||||
|
||||
```
|
||||
lvgl_port_resume();
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
Key feature of every graphical application is performance. Recommended settings for improving LCD performance is described in a separate document [here](docs/performance.md).
|
||||
|
||||
### Performance monitor
|
||||
|
||||
For show performance monitor in LVGL9, please add these lines to sdkconfig.defaults and rebuild all.
|
||||
|
||||
```
|
||||
CONFIG_LV_USE_OBSERVER=y
|
||||
CONFIG_LV_USE_SYSMON=y
|
||||
CONFIG_LV_USE_PERF_MONITOR=y
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
168
managed_components/espressif__esp_lvgl_port/docs/performance.md
Normal file
168
managed_components/espressif__esp_lvgl_port/docs/performance.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# LCD & LVGL Performance
|
||||
|
||||
This document provides steps, how to set up your LCD and LVGL port for the best performance and comparison of different settings. All settings and measurements are valid for Espressif's chips. Examples in [ESP-BSP](https://github.com/espressif/esp-bsp) are ready to use with the best performance.
|
||||
|
||||
## Performance metrics
|
||||
|
||||
In this document we will use following metrics for performance evaluation:
|
||||
|
||||
1. Measure time needed for refreshing the whole screen.
|
||||
2. Use LVGL's [lv_demo_benchmark()](https://github.com/lvgl/lvgl/tree/v8.3.6/demos/benchmark) -test suite- to measure Frames per second (weighted FPS).
|
||||
3. Use LVGL's [lv_demo_music()](https://github.com/lvgl/lvgl/tree/v8.3.6/demos/music) -demo application- to measure Frames per second (average FPS).
|
||||
|
||||
## Settings on ESP32 chips which have impact on LCD and LVGL performance
|
||||
|
||||
Following options and settings have impact on LCD performance (FPS). Some options yield only small difference in FPS (e.g. ~1 FPS), and some of them are more significant. Usually it depends on complexity of the graphical application (number of widgets...), resources (CPU time, RAM available...) and size of screen (definition and color depth).
|
||||
|
||||
Another set of key parameters are hardware related (graphical IO, frame buffer location), which are not yet covered in this document.
|
||||
|
||||
### LVGL Buffer configuration
|
||||
|
||||
**This is by far the most significant setting.** Users are encouraged to focus on correct frame buffer configuration before moving ahead with other optimizations.
|
||||
|
||||
On the other hand, the frame buffer(s) will consume significant portion of your RAM. In the graph below, you can see different frame buffer settings and resulting FPS:
|
||||
|
||||

|
||||
|
||||
Main takeaways from the graph are:
|
||||
|
||||
* The size of **LVGL buffer** and **double buffering** feature has big impact on performance.
|
||||
* Frame buffer size >25% of the screen does not bring relevant performance boost
|
||||
* Frame buffer size <10% will have severe negative effect on performance
|
||||
|
||||
*Note:* The measurements are valid for frame buffer in internal SRAM. Placing the frame buffer into external PSRAM will yield worse results.
|
||||
|
||||
### Compiler optimization level
|
||||
|
||||
Recommended level is "Performance" for good results. The "Performance" setting causes the compiled code to be larger and faster.
|
||||
|
||||
* `CONFIG_COMPILER_OPTIMIZATION_PERF=y`
|
||||
|
||||
### CPU frequency
|
||||
|
||||
The CPU frequency has a big impact on LCD performance. The recommended value is maximum -> 240 MHz.
|
||||
|
||||
* `CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`
|
||||
|
||||
### Flash frequency and mode
|
||||
|
||||
The flash clock frequency and mode (bus width) has a big impact on LCD performance. Your choices will be limited by your hardware flash configuration. The higher the frequency and bus width, the better.
|
||||
|
||||
* `CONFIG_ESPTOOLPY_FLASHFREQ_120M=y`
|
||||
* `CONFIG_ESPTOOLPY_FLASHMODE_QIO=y` or `CONFIG_ESPTOOLPY_OCT_FLASH` on supported chips
|
||||
|
||||
More information about SPI Flash configuration can be found in [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/flash_psram_config.html).
|
||||
|
||||
### Fast LVGL memory
|
||||
|
||||
This option puts the most frequently used LVGL functions into IRAM for execution speed up.
|
||||
|
||||
* `CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`
|
||||
|
||||
### Affinity main task to second core
|
||||
|
||||
The main LVGL task can be processed on the second core of the CPU. It can increase performance. (It is available only on dual-core chips)
|
||||
|
||||
* `CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1=y`
|
||||
|
||||
### Using esp-idf `memcpy` and `memset` instead LVGL's configuration
|
||||
|
||||
Native esp-idf implementation are a little (~1-3 FPS) faster (only for LVGL8).
|
||||
|
||||
* `CONFIG_LV_MEMCPY_MEMSET_STD=y`
|
||||
|
||||
### Default LVGL display refresh period
|
||||
|
||||
This setting can improve subjective performance during screen transitions (scrolling, etc.).
|
||||
|
||||
LVGL8
|
||||
* `CONFIG_LV_DISP_DEF_REFR_PERIOD=10`
|
||||
|
||||
LVGL9
|
||||
* `CONFIG_LV_DEF_REFR_PERIOD=10`
|
||||
|
||||
## Example FPS improvement vs graphical settings
|
||||
|
||||
The LVGL9 benchmark demo uses a different algorithm for measuring FPS. In this case, we used the same algorithm for measurement in LVGL8 for comparison.
|
||||
|
||||
### RGB LCD, PSRAM (octal) with GDMA - ESP32-S3-LCD-EV-BOARD
|
||||
|
||||
<img src="https://github.com/espressif/esp-bsp/blob/master/docu/pics/esp32-s3-lcd-ev-board_800x480.png?raw=true" align="right" width="300px" />
|
||||
|
||||
Default settings:
|
||||
* BSP example `display_lvgl_demos`
|
||||
* LCD: 4.3" 800x480
|
||||
* Interface: RGB
|
||||
* LVGL buffer size: 800 x 480
|
||||
* LVGL buffer mode: Direct (avoid-tearing)
|
||||
* LVGL double buffer: NO
|
||||
* Optimization: Debug
|
||||
* CPU frequency: 160 MHz
|
||||
* Flash frequency: 80 MHz
|
||||
* PSRAM frequency: 80 MHz
|
||||
* Flash mode: DIO
|
||||
* LVGL display refresh period: 30 ms
|
||||
|
||||
| Average FPS (LVGL8) | Average FPS (LVGL 9.2) | Changed settings |
|
||||
| :---: | :---: | ---------------- |
|
||||
| 12 | 9 | Default |
|
||||
| 13 | 9 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) |
|
||||
| 14 | 11 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) |
|
||||
| 14 | 11 | + Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) |
|
||||
| 15 | 11 | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
|
||||
| 16 | 11 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10` / `CONFIG_LV_DEF_REFR_PERIOD=10`) |
|
||||
|
||||
### Parallel 8080 LCD (only for LVGL8)
|
||||
|
||||
<img src="https://github.com/espressif/esp-bsp/blob/master/docu/pics/7inch-Capacitive-Touch-LCD-C_l.jpg?raw=true" align="right" width="300px" />
|
||||
|
||||
Default settings:
|
||||
* BSP example `display_lvgl_demos` with `ws_7inch` component
|
||||
* LCD: 7" 800x480
|
||||
* Intarface: 16bit parallel Intel 8080
|
||||
* LCD IO clock: 20 MHz
|
||||
* LVGL buffer size: 800 x 50
|
||||
* LVGL double buffer: YES
|
||||
* Optimization: Debug
|
||||
* CPU frequency: 160 MHz
|
||||
* Flash frequency: 80 MHz
|
||||
* Flash mode: DIO
|
||||
* LVGL display refresh period: 30 ms
|
||||
|
||||
#### Internal RAM with DMA
|
||||
|
||||
| Average FPS | Weighted FPS | Changed settings |
|
||||
| :---: | :---: | ---------------- |
|
||||
| 17 | 32 | Default |
|
||||
| 18 | 36 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) |
|
||||
| 21 | 46 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) |
|
||||
| 26 | 56 | + Flash frequency: 120 MHz, Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHFREQ_120M=y` + `CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) |
|
||||
| 28 | **60** | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
|
||||
| 41 | 55 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10`) |
|
||||
|
||||
#### PSRAM (QUAD) without DMA
|
||||
|
||||
Default changes:
|
||||
* LCD IO clock: 2 MHz
|
||||
* PSRAM frequency: 80 MHz
|
||||
|
||||
| Average FPS | Weighted FPS | Changed settings |
|
||||
| :---: | :---: | ---------------- |
|
||||
| 11 | 7 | Default |
|
||||
| 11 | 7 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) |
|
||||
| 12 | 8 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) |
|
||||
| 12 | 9 | + Flash frequency: 120 MHz, PSRAM frequency: 120 MHz, Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHFREQ_120M=y` + `CONFIG_SPIRAM_SPEED_120M=y` + `CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) |
|
||||
| 12 | 9 | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
|
||||
| 12 | 8 | + LVGL buffer size: 800 x 480 |
|
||||
| 26 | 8 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10`) |
|
||||
| 31 | 23 | + LCD clock: 10 MHz [^1] |
|
||||
|
||||
[^1]: This is not working in default and sometimes in fast changes on screen is not working properly.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The graphical performance depends on a lot of things and settings, many of which affect the whole system (Compiler, Flash, CPU, PSRAM configuration...). The user should primarily focus on trade-off between frame-buffer(s) size and RAM consumption of the buffer, before optimizing the design further.
|
||||
|
||||
Other configuration options not covered in this document are:
|
||||
* Hardware interfaces, color depth, screen definition (size), clocks, LCD controller and more.
|
||||
* Complexity of the graphical application (number of LVGL objects and their styles).
|
||||
@@ -0,0 +1,9 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(COMPONENTS main) # "Trim" the build. Include the minimal set of components; main and anything it depends on.
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(display-usb-hid)
|
||||
@@ -0,0 +1,28 @@
|
||||
# BSP: Display USB HID Example
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates usage of the USB HID (keyboard and mouse) with M5Stack Tab5 Board.
|
||||
|
||||
## How to use the example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* Board [M5Stack Tab5](https://github.com/espressif/esp-bsp/tree/master/bsp/m5stack_tab5)
|
||||
- connect 5V USB-C power connector
|
||||
- connect USB keyboard/mouse to the right "USB-A Host" connector
|
||||
|
||||
## USB Stack Selection
|
||||
|
||||
You can select between USB stacks in menuconfig `Example Configuration`:
|
||||
- Espressif's USB Stack
|
||||
- CherryUSB
|
||||
|
||||
## Build and Flash
|
||||
|
||||
To build and flash the example for a specific `{board}` and `{port}`, use the following command:
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
idf.py flash monitor
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,26 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EX_USB_STACK_IDF
|
||||
int
|
||||
default 1 if EXAMPLE_USB_STACK_IDF
|
||||
default 0
|
||||
|
||||
config EX_USB_STACK_CHERRYUSB
|
||||
int
|
||||
default 1 if EXAMPLE_USB_STACK_CHERRYUSB
|
||||
default 0
|
||||
|
||||
choice EXAMPLE_USB_STACK
|
||||
prompt "USB Stack"
|
||||
default EXAMPLE_USB_STACK_IDF
|
||||
help
|
||||
Select the USB Stack
|
||||
|
||||
config EXAMPLE_USB_STACK_IDF
|
||||
bool "Espressif's USB Stack"
|
||||
|
||||
config EXAMPLE_USB_STACK_CHERRYUSB
|
||||
bool "CherryUSB"
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,15 @@
|
||||
dependencies:
|
||||
cherry-embedded/cherryusb:
|
||||
matches:
|
||||
- if: $CONFIG{EX_USB_STACK_CHERRYUSB} == 1
|
||||
version: ^1
|
||||
esp_lvgl_port:
|
||||
version: '*'
|
||||
idf: '>=5.4'
|
||||
m5stack_tab5:
|
||||
version: '*'
|
||||
usb_host_hid:
|
||||
matches:
|
||||
- if: $CONFIG{EX_USB_STACK_IDF} == 1
|
||||
version: ^1
|
||||
description: BSP Display USB HID Example
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief BSP USB HID Example
|
||||
* @details USB HID demo (keyboard and mouse visualization using LVGL) for M5Stack Tab5 Board
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "bsp/esp-bsp.h"
|
||||
#include "lvgl.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
|
||||
#if CONFIG_EXAMPLE_USB_STACK_CHERRYUSB
|
||||
#include "usbh_core.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
static lv_disp_t *display;
|
||||
static lv_indev_t *kb_indev = NULL;
|
||||
static lv_obj_t *result = NULL;
|
||||
static lv_obj_t *ta_name = NULL;
|
||||
static lv_obj_t *ta_email = NULL;
|
||||
static lv_group_t *kb_group = NULL;
|
||||
|
||||
/*******************************************************************************
|
||||
* Private functions
|
||||
*******************************************************************************/
|
||||
static void app_lvgl_btn_back_cb(lv_event_t *e)
|
||||
{
|
||||
if (result) {
|
||||
lv_obj_clean(result);
|
||||
lv_obj_del(result);
|
||||
result = NULL;
|
||||
}
|
||||
if (kb_indev) {
|
||||
lv_indev_set_group(kb_indev, kb_group);
|
||||
}
|
||||
}
|
||||
|
||||
static void app_lvgl_btn_ok_cb(lv_event_t *e)
|
||||
{
|
||||
lv_obj_t *scr = lv_scr_act();
|
||||
const char *name = lv_textarea_get_text(ta_name);
|
||||
const char *email = lv_textarea_get_text(ta_email);
|
||||
|
||||
result = lv_obj_create(scr);
|
||||
lv_obj_set_size(result, BSP_LCD_V_RES, BSP_LCD_H_RES);
|
||||
lv_obj_align(result, LV_ALIGN_TOP_MID, 0, 0);
|
||||
lv_obj_set_flex_flow(result, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(result, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
lv_obj_t *lbl = lv_label_create(result);
|
||||
lv_label_set_text_fmt(lbl, "Your name: %s", name);
|
||||
lbl = lv_label_create(result);
|
||||
lv_label_set_text_fmt(lbl, "Your email: %s", email);
|
||||
|
||||
lv_obj_t *back_btn = lv_btn_create(result);
|
||||
lbl = lv_label_create(back_btn);
|
||||
lv_label_set_text_static(lbl, "BACK");
|
||||
/* Button event */
|
||||
lv_obj_add_event_cb(back_btn, app_lvgl_btn_back_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
if (kb_indev) {
|
||||
lv_group_t *group = lv_group_create();
|
||||
lv_group_add_obj(group, back_btn);
|
||||
lv_indev_set_group(kb_indev, group);
|
||||
}
|
||||
}
|
||||
|
||||
static void app_lvgl_display(void)
|
||||
{
|
||||
lv_obj_t *scr = lv_scr_act();
|
||||
lv_obj_t *lbl;
|
||||
bsp_display_lock(0);
|
||||
|
||||
lv_obj_t *col = lv_obj_create(scr);
|
||||
lv_obj_set_size(col, BSP_LCD_H_RES, BSP_LCD_V_RES);
|
||||
lv_obj_align(col, LV_ALIGN_TOP_MID, 0, 0);
|
||||
lv_obj_set_flex_flow(col, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(col, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
lbl = lv_label_create(col);
|
||||
lv_label_set_text(lbl, "USB HID Example");
|
||||
|
||||
lv_obj_t *cont_row = lv_obj_create(col);
|
||||
lv_obj_set_size(cont_row, BSP_LCD_H_RES - 10, 50);
|
||||
lv_obj_align(cont_row, LV_ALIGN_TOP_MID, 0, 20);
|
||||
lv_obj_set_flex_flow(cont_row, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_top(cont_row, 5, 0);
|
||||
lv_obj_set_style_pad_bottom(cont_row, 5, 0);
|
||||
lv_obj_set_style_pad_left(cont_row, 5, 0);
|
||||
lv_obj_set_style_pad_right(cont_row, 5, 0);
|
||||
lv_obj_set_flex_align(cont_row, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
lbl = lv_label_create(cont_row);
|
||||
lv_label_set_text(lbl, "Name:");
|
||||
ta_name = lv_textarea_create(cont_row);
|
||||
lv_obj_set_width(ta_name, BSP_LCD_H_RES - 100);
|
||||
lv_textarea_set_one_line(ta_name, true);
|
||||
|
||||
cont_row = lv_obj_create(col);
|
||||
lv_obj_set_size(cont_row, BSP_LCD_H_RES - 10, 50);
|
||||
lv_obj_align(cont_row, LV_ALIGN_TOP_MID, 0, 20);
|
||||
lv_obj_set_flex_flow(cont_row, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_top(cont_row, 5, 0);
|
||||
lv_obj_set_style_pad_bottom(cont_row, 5, 0);
|
||||
lv_obj_set_style_pad_left(cont_row, 5, 0);
|
||||
lv_obj_set_style_pad_right(cont_row, 5, 0);
|
||||
lv_obj_set_flex_align(cont_row, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
lbl = lv_label_create(cont_row);
|
||||
lv_label_set_text(lbl, "E-mail:");
|
||||
ta_email = lv_textarea_create(cont_row);
|
||||
lv_obj_set_width(ta_email, BSP_LCD_H_RES - 100);
|
||||
lv_textarea_set_one_line(ta_email, true);
|
||||
|
||||
/* Button OK */
|
||||
lv_obj_t *btn_ok = lv_btn_create(col);
|
||||
lbl = lv_label_create(btn_ok);
|
||||
lv_label_set_text_static(lbl, "OK");
|
||||
/* Button event */
|
||||
lv_obj_add_event_cb(btn_ok, app_lvgl_btn_ok_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
if (kb_indev) {
|
||||
kb_group = lv_group_create();
|
||||
lv_group_add_obj(kb_group, ta_name);
|
||||
lv_group_add_obj(kb_group, ta_email);
|
||||
lv_group_add_obj(kb_group, btn_ok);
|
||||
lv_indev_set_group(kb_indev, kb_group);
|
||||
ESP_LOGI(TAG, "Keyboard input device group was set.");
|
||||
}
|
||||
|
||||
bsp_display_unlock();
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/* Initialize USB */
|
||||
|
||||
#if CONFIG_EXAMPLE_USB_STACK_CHERRYUSB
|
||||
bsp_feature_enable(BSP_FEATURE_USB, true);
|
||||
usbh_initialize(0, ESP_USBH_BASE, NULL);
|
||||
#elif CONFIG_EXAMPLE_USB_STACK_IDF
|
||||
bsp_usb_host_start(BSP_USB_HOST_POWER_MODE_USB_DEV, true);
|
||||
#else
|
||||
#error USB stack is not selected!
|
||||
#endif
|
||||
|
||||
/* Initialize display and LVGL */
|
||||
display = bsp_display_start();
|
||||
|
||||
/* Set display brightness to 100% */
|
||||
bsp_display_backlight_on();
|
||||
|
||||
const lvgl_port_hid_mouse_cfg_t mouse_cfg = {
|
||||
.disp = display,
|
||||
.sensitivity = 1,
|
||||
};
|
||||
lvgl_port_add_usb_hid_mouse_input(&mouse_cfg);
|
||||
|
||||
const lvgl_port_hid_keyboard_cfg_t kb_cfg = {
|
||||
.disp = display,
|
||||
};
|
||||
kb_indev = lvgl_port_add_usb_hid_keyboard_input(&kb_cfg);
|
||||
|
||||
/* Add and show objects on display */
|
||||
app_lvgl_display();
|
||||
|
||||
ESP_LOGI(TAG, "Example initialization done.");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32p4"
|
||||
CONFIG_BSP_SELECT_M5STACK_TAB5=y
|
||||
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
|
||||
CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y
|
||||
CONFIG_CODEC_I2C_BACKWARD_COMPATIBLE=n
|
||||
CONFIG_CAM_CTRL_SPI_ENABLE=n
|
||||
|
||||
|
||||
# SPIRAM for ESP32-P4
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_200M=y
|
||||
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
||||
|
||||
|
||||
# CherryUSB
|
||||
CONFIG_CHERRYUSB=y
|
||||
CONFIG_CHERRYUSB_HOST=y
|
||||
CONFIG_CHERRYUSB_HOST_HID=y
|
||||
|
||||
|
||||
## LVGL9 ##
|
||||
CONFIG_LV_CONF_SKIP=y
|
||||
CONFIG_LV_BUILD_EXAMPLES=n
|
||||
|
||||
# CLIB default
|
||||
CONFIG_LV_USE_CLIB_MALLOC=y
|
||||
CONFIG_LV_USE_CLIB_SPRINTF=y
|
||||
CONFIG_LV_USE_CLIB_STRING=y
|
||||
|
||||
# Performance monitor
|
||||
CONFIG_LV_USE_OBSERVER=y
|
||||
CONFIG_LV_USE_SYSMON=y
|
||||
CONFIG_LV_USE_PERF_MONITOR=y
|
||||
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(i2c_oled)
|
||||
@@ -0,0 +1,73 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# I2C OLED example
|
||||
|
||||
[esp_lcd](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) supports I2C interfaced OLED LCD, whose color depth is usually 1bpp.
|
||||
|
||||
This example shows how to make use of the SSD1306 panel driver from `esp_lcd` component to facilitate the porting of LVGL library. In the end, example will display a scrolling text on the OLED screen.
|
||||
|
||||
## LVGL Version
|
||||
|
||||
This example is using the **LVGL8** version. For use it with LVGL9 version, please delete file [sdkconfig.defaults](sdkconfig.defaults) and change version to `"^9"` on this line in [idf_component.yml](main/idf_component.yml) file:
|
||||
```
|
||||
lvgl/lvgl: "^8"
|
||||
```
|
||||
|
||||
NOTE: When you are changing LVGL versions, please remove these files and folders before new build:
|
||||
- build/
|
||||
- managed_components/
|
||||
- dependencies.lock
|
||||
- sdkconfig
|
||||
|
||||
## How to use the example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* An ESP development board
|
||||
* An SSD1306 OLED LCD, with I2C interface
|
||||
* An USB cable for power supply and programming
|
||||
|
||||
### Hardware Connection
|
||||
|
||||
The connection between ESP Board and the LCD is as follows:
|
||||
|
||||
```
|
||||
ESP Board OLED LCD (I2C)
|
||||
+------------------+ +-------------------+
|
||||
| GND+--------------+GND |
|
||||
| | | |
|
||||
| 3V3+--------------+VCC |
|
||||
| | | |
|
||||
| SDA+--------------+SDA |
|
||||
| | | |
|
||||
| SCL+--------------+SCL |
|
||||
+------------------+ +-------------------+
|
||||
```
|
||||
|
||||
The GPIO number used by this example can be changed in [lvgl_example_main.c](main/i2c_oled_example_main.c). Please pay attention to the I2C hardware device address as well, you should refer to your module's spec and schematic to determine that address.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. A scrolling text will show up on the LCD as expected.
|
||||
|
||||
The first time you run `idf.py` for the example will cost extra time as the build system needs to address the component dependencies and downloads the missing components from registry into `managed_components` folder.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
### Example Output
|
||||
|
||||
```bash
|
||||
...
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (345) example: Initialize I2C bus
|
||||
I (345) example: Install panel IO
|
||||
I (345) example: Install SSD1306 panel driver
|
||||
I (455) example: Initialize LVGL library
|
||||
I (455) example: Register display driver to LVGL
|
||||
I (455) example: Install LVGL tick timer
|
||||
I (455) example: Display LVGL Scroll Text
|
||||
...
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
idf_component_register(
|
||||
SRCS "i2c_oled_example_main.c" "lvgl_demo_ui.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES driver esp_timer
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_LCD_CONTROLLER
|
||||
prompt "LCD controller model"
|
||||
default EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||
help
|
||||
Select LCD controller model
|
||||
|
||||
config EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||
bool "SSD1306"
|
||||
|
||||
config EXAMPLE_LCD_CONTROLLER_SH1107
|
||||
bool "SH1107"
|
||||
endchoice
|
||||
|
||||
if EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||
choice EXAMPLE_SSD1306_HEIGHT
|
||||
prompt "SSD1306 Height in pixels"
|
||||
default EXAMPLE_SSD1306_HEIGHT_64
|
||||
help
|
||||
Height of the display in pixels. a.k.a vertical resolution
|
||||
|
||||
config EXAMPLE_SSD1306_HEIGHT_64
|
||||
bool "64"
|
||||
config EXAMPLE_SSD1306_HEIGHT_32
|
||||
bool "32"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_SSD1306_HEIGHT
|
||||
int
|
||||
default 64 if EXAMPLE_SSD1306_HEIGHT_64
|
||||
default 32 if EXAMPLE_SSD1306_HEIGHT_32
|
||||
endif
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "lvgl.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
|
||||
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||
#include "esp_lcd_sh1107.h"
|
||||
#else
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
#define I2C_HOST 0
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (400 * 1000)
|
||||
#define EXAMPLE_PIN_NUM_SDA 18
|
||||
#define EXAMPLE_PIN_NUM_SCL 23
|
||||
#define EXAMPLE_PIN_NUM_RST -1
|
||||
#define EXAMPLE_I2C_HW_ADDR 0x3C
|
||||
|
||||
// The pixel number in horizontal and vertical
|
||||
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||
#define EXAMPLE_LCD_H_RES 128
|
||||
#define EXAMPLE_LCD_V_RES CONFIG_EXAMPLE_SSD1306_HEIGHT
|
||||
#elif CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||
#define EXAMPLE_LCD_H_RES 64
|
||||
#define EXAMPLE_LCD_V_RES 128
|
||||
#endif
|
||||
// Bit number used to represent command and parameter
|
||||
#define EXAMPLE_LCD_CMD_BITS 8
|
||||
#define EXAMPLE_LCD_PARAM_BITS 8
|
||||
|
||||
extern void example_lvgl_demo_ui(lv_disp_t *disp);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Initialize I2C bus");
|
||||
i2c_master_bus_handle_t i2c_bus = NULL;
|
||||
i2c_master_bus_config_t bus_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.i2c_port = I2C_HOST,
|
||||
.sda_io_num = EXAMPLE_PIN_NUM_SDA,
|
||||
.scl_io_num = EXAMPLE_PIN_NUM_SCL,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &i2c_bus));
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t io_config = {
|
||||
.dev_addr = EXAMPLE_I2C_HW_ADDR,
|
||||
.scl_speed_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
|
||||
.control_phase_bytes = 1, // According to SSD1306 datasheet
|
||||
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, // According to SSD1306 datasheet
|
||||
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, // According to SSD1306 datasheet
|
||||
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||
.dc_bit_offset = 6, // According to SSD1306 datasheet
|
||||
#elif CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||
.dc_bit_offset = 0, // According to SH1107 datasheet
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus, &io_config, &io_handle));
|
||||
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.bits_per_pixel = 1,
|
||||
.reset_gpio_num = EXAMPLE_PIN_NUM_RST,
|
||||
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0))
|
||||
.color_space = ESP_LCD_COLOR_SPACE_MONOCHROME,
|
||||
#endif
|
||||
};
|
||||
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,3,0))
|
||||
esp_lcd_panel_ssd1306_config_t ssd1306_config = {
|
||||
.height = EXAMPLE_LCD_V_RES,
|
||||
};
|
||||
panel_config.vendor_config = &ssd1306_config;
|
||||
#endif
|
||||
ESP_LOGI(TAG, "Install SSD1306 panel driver");
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle));
|
||||
#elif CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||
esp_lcd_panel_sh1107_config_t sh1107_config = {
|
||||
.contrast = 128,
|
||||
.offset = 0x60,
|
||||
};
|
||||
panel_config.vendor_config = &sh1107_config;
|
||||
ESP_LOGI(TAG, "Install SH1107 panel driver");
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh1107(io_handle, &panel_config, &panel_handle));
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
|
||||
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Initialize LVGL");
|
||||
const lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
lvgl_port_init(&lvgl_cfg);
|
||||
|
||||
const lvgl_port_display_cfg_t disp_cfg = {
|
||||
.io_handle = io_handle,
|
||||
.panel_handle = panel_handle,
|
||||
.buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES,
|
||||
.double_buffer = true,
|
||||
.hres = EXAMPLE_LCD_H_RES,
|
||||
.vres = EXAMPLE_LCD_V_RES,
|
||||
.monochrome = true,
|
||||
#if LVGL_VERSION_MAJOR >= 9
|
||||
.color_format = LV_COLOR_FORMAT_I1,
|
||||
#endif
|
||||
.rotation = {
|
||||
.swap_xy = false,
|
||||
.mirror_x = false,
|
||||
.mirror_y = false,
|
||||
},
|
||||
.flags = {
|
||||
#if LVGL_VERSION_MAJOR >= 9
|
||||
.swap_bytes = false,
|
||||
#endif
|
||||
.sw_rotate = false,
|
||||
}
|
||||
};
|
||||
lv_disp_t *disp = lvgl_port_add_disp(&disp_cfg);
|
||||
|
||||
ESP_LOGI(TAG, "Display LVGL Scroll Text");
|
||||
// Lock the mutex due to the LVGL APIs are not thread-safe
|
||||
if (lvgl_port_lock(0)) {
|
||||
/* Rotation of the screen */
|
||||
lv_disp_set_rotation(disp, LV_DISPLAY_ROTATION_0);
|
||||
|
||||
example_lvgl_demo_ui(disp);
|
||||
// Release the mutex
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
esp_lcd_sh1107:
|
||||
version: ^1
|
||||
esp_lvgl_port:
|
||||
version: '*'
|
||||
idf: '>=5.2'
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include "lvgl.h"
|
||||
|
||||
void example_lvgl_demo_ui(lv_disp_t *disp)
|
||||
{
|
||||
lv_obj_t *scr = lv_disp_get_scr_act(disp);
|
||||
lv_obj_t *label = lv_label_create(scr);
|
||||
lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR); /* Circular scroll */
|
||||
lv_label_set_text(label, "Hello Espressif, Hello LVGL.");
|
||||
/* Size of the screen (if you use rotation 90 or 270, please set disp->driver->ver_res) */
|
||||
#if LVGL_VERSION_MAJOR >= 9
|
||||
lv_obj_set_width(label, lv_display_get_physical_horizontal_resolution(disp));
|
||||
#else
|
||||
lv_obj_set_width(label, disp->driver->hor_res);
|
||||
#endif
|
||||
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_LV_USE_USER_DATA=y
|
||||
|
||||
# Enable this for LVGL8
|
||||
#CONFIG_LV_COLOR_DEPTH_1=y
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(rgb_lcd)
|
||||
@@ -0,0 +1,19 @@
|
||||
# ESP LVGL RGB Screen Example
|
||||
|
||||
Very simple example for demonstration of initialization and usage of the `esp_lvgl_port` component with RGB LCD. This example contains four main parts:
|
||||
|
||||
## 1. LCD HW initialization - `app_lcd_init()`
|
||||
|
||||
Standard HW initialization of the LCD using [`esp_lcd`](https://github.com/espressif/esp-idf/tree/master/components/esp_lcd) component. Settings of this example are fully compatible with [ESP32-S3-LCD-EV-Board-2](https://github.com/espressif/esp-bsp/tree/master/bsp/esp32_s3_lcd_ev_board) board.
|
||||
|
||||
## 2. Touch HW initialization - `app_touch_init()`
|
||||
|
||||
Standard HW initialization of the LCD touch using [`esp_lcd_touch`](https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch) component. Settings of this example are fully compatible with [ESP32-S3-LCD-EV-Board-2](https://github.com/espressif/esp-bsp/tree/master/bsp/esp32_s3_lcd_ev_board) board.
|
||||
|
||||
## 3. LVGL port initialization - `app_lvgl_init()`
|
||||
|
||||
Initialization of the LVGL port.
|
||||
|
||||
## 4. LVGL objects example usage - `app_main_display()`
|
||||
|
||||
Very simple demonstration code of using LVGL objects after LVGL port initialization.
|
||||
@@ -0,0 +1,11 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS "." ${LV_DEMO_DIR}
|
||||
REQUIRES driver esp_lcd)
|
||||
|
||||
lvgl_port_create_c_image("images/esp_logo.png" "images/" "ARGB8888" "NONE")
|
||||
lvgl_port_add_images(${COMPONENT_LIB} "images/")
|
||||
|
||||
set_source_files_properties(
|
||||
PROPERTIES COMPILE_OPTIONS
|
||||
"-DLV_LVGL_H_INCLUDE_SIMPLE;-Wno-format;"
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
esp_lcd_touch_gt1151:
|
||||
version: ^1
|
||||
esp_lvgl_port:
|
||||
version: '*'
|
||||
idf: '>=5.2'
|
||||
1
managed_components/espressif__esp_lvgl_port/examples/rgb_lcd/main/images/.gitignore
vendored
Normal file
1
managed_components/espressif__esp_lvgl_port/examples/rgb_lcd/main/images/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.c
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user