First commit with working display

This commit is contained in:
Ricardo LAP
2026-09-13 20:50:51 +00:00
parent a83af259b3
commit c54c68c899
6690 changed files with 1093387 additions and 2 deletions

View File

@@ -0,0 +1 @@
7e6381b67b6e487379118368b8e91624dc87036ef5734818de1db9eb35697998

View File

@@ -0,0 +1 @@
.vscode

View File

@@ -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.

View File

@@ -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"}]}

View File

@@ -0,0 +1,4 @@
idf_component_register(SRCS "esp_lcd_touch_xpt2046.c"
INCLUDE_DIRS "include"
REQUIRES "driver esp_lcd_touch")

View File

@@ -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

View 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.

View 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 );
}
```

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f

View 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

View File

@@ -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"}]}

View File

@@ -0,0 +1 @@
idf_component_register()

View 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

View File

@@ -0,0 +1,31 @@
# Cmake utilities
[![Component Registry](https://components.espressif.com/components/espressif/cmake_utilities/badge.svg)](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)

View File

@@ -0,0 +1,7 @@
# Include all cmake modules
include(gcc)
include(gen_compressed_ota)
include(gen_single_bin)
include(package_manager)
include(relinker)

View 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 |

View File

@@ -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
```

View File

@@ -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.

View 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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View 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.

View File

@@ -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()

View File

@@ -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()

View 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()

View File

@@ -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)

View File

@@ -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()

View File

@@ -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
1 library object function option
2 libble_app.a ble_hw.c.o r_ble_hw_resolv_list_get_cur_entry
3 libble_app.a ble_ll_adv.c.o r_ble_ll_adv_set_sched
4 libble_app.a ble_ll_adv.c.o r_ble_ll_adv_sync_pdu_make
5 libble_app.a ble_ll_adv.c.o r_ble_ll_adv_sync_calculate
6 libble_app.a ble_ll_conn.c.o r_ble_ll_conn_is_dev_connected
7 libble_app.a ble_ll_ctrl.c.o r_ble_ll_ctrl_tx_done
8 libble_app.a ble_lll_adv.c.o r_ble_lll_adv_aux_scannable_pdu_payload_len
9 libble_app.a ble_lll_adv.c.o r_ble_lll_adv_halt
10 libble_app.a ble_lll_adv.c.o r_ble_lll_adv_periodic_schedule_next
11 libble_app.a ble_lll_conn.c.o r_ble_lll_conn_cth_flow_free_credit
12 libble_app.a ble_lll_conn.c.o r_ble_lll_conn_update_encryption
13 libble_app.a ble_lll_conn.c.o r_ble_lll_conn_set_slave_flow_control
14 libble_app.a ble_lll_conn.c.o r_ble_lll_init_rx_pkt_isr
15 libble_app.a ble_lll_conn.c.o r_ble_lll_conn_get_rx_mbuf
16 libble_app.a ble_lll_rfmgmt.c.o r_ble_lll_rfmgmt_enable
17 libble_app.a ble_lll_rfmgmt.c.o r_ble_lll_rfmgmt_timer_reschedule
18 libble_app.a ble_lll_rfmgmt.c.o r_ble_lll_rfmgmt_timer_exp
19 libble_app.a ble_lll_scan.c.o r_ble_lll_scan_targeta_is_matched
20 libble_app.a ble_lll_scan.c.o r_ble_lll_scan_rx_isr_on_legacy
21 libble_app.a ble_lll_scan.c.o r_ble_lll_scan_rx_isr_on_aux
22 libble_app.a ble_lll_scan.c.o r_ble_lll_scan_process_rsp_in_isr
23 libble_app.a ble_lll_scan.c.o r_ble_lll_scan_rx_pkt_isr
24 libble_app.a ble_lll_sched.c.o r_ble_lll_sched_execute_check
25 libble_app.a ble_lll_sync.c.o r_ble_lll_sync_event_start_cb
26 libble_app.a ble_phy.c.o r_ble_phy_set_rxhdr
27 libble_app.a ble_phy.c.o r_ble_phy_update_conn_sequence
28 libble_app.a ble_phy.c.o r_ble_phy_set_sequence_mode
29 libble_app.a ble_phy.c.o r_ble_phy_txpower_round
30 libble_app.a os_mempool.c.obj r_os_memblock_put
31 libbootloader_support.a bootloader_flash.c.obj bootloader_read_flash_id
32 libbootloader_support.a flash_encrypt.c.obj esp_flash_encryption_enabled
33 libbt.a bt_osi_mem.c.obj bt_osi_mem_calloc CONFIG_BT_ENABLED
34 libbt.a bt_osi_mem.c.obj bt_osi_mem_malloc CONFIG_BT_ENABLED
35 libbt.a bt_osi_mem.c.obj bt_osi_mem_malloc_internal CONFIG_BT_ENABLED
36 libbt.a bt_osi_mem.c.obj bt_osi_mem_free CONFIG_BT_ENABLED
37 libbt.a bt.c.obj esp_reset_rpa_moudle CONFIG_BT_ENABLED
38 libbt.a bt.c.obj osi_assert_wrapper CONFIG_BT_ENABLED
39 libbt.a bt.c.obj osi_random_wrapper CONFIG_BT_ENABLED
40 libbt.a nimble_port.c.obj nimble_port_run CONFIG_BT_NIMBLE_ENABLED
41 libbt.a nimble_port.c.obj nimble_port_get_dflt_eventq CONFIG_BT_NIMBLE_ENABLED
42 libbt.a npl_os_freertos.c.obj os_callout_timer_cb CONFIG_BT_ENABLED && !CONFIG_BT_NIMBLE_USE_ESP_TIMER
43 libbt.a npl_os_freertos.c.obj npl_freertos_event_run CONFIG_BT_ENABLED
44 libbt.a npl_os_freertos.c.obj npl_freertos_callout_stop CONFIG_BT_ENABLED
45 libbt.a npl_os_freertos.c.obj npl_freertos_time_get CONFIG_BT_ENABLED
46 libbt.a npl_os_freertos.c.obj npl_freertos_callout_reset CONFIG_BT_ENABLED
47 libbt.a npl_os_freertos.c.obj npl_freertos_callout_is_active CONFIG_BT_ENABLED
48 libbt.a npl_os_freertos.c.obj npl_freertos_callout_get_ticks CONFIG_BT_ENABLED
49 libbt.a npl_os_freertos.c.obj npl_freertos_callout_remaining_ticks CONFIG_BT_ENABLED
50 libbt.a npl_os_freertos.c.obj npl_freertos_time_delay CONFIG_BT_ENABLED
51 libbt.a npl_os_freertos.c.obj npl_freertos_eventq_is_empty CONFIG_BT_ENABLED
52 libbt.a npl_os_freertos.c.obj npl_freertos_mutex_pend CONFIG_BT_ENABLED
53 libbt.a npl_os_freertos.c.obj npl_freertos_mutex_release CONFIG_BT_ENABLED
54 libbt.a npl_os_freertos.c.obj npl_freertos_sem_init CONFIG_BT_ENABLED
55 libbt.a npl_os_freertos.c.obj npl_freertos_sem_pend CONFIG_BT_ENABLED
56 libbt.a npl_os_freertos.c.obj npl_freertos_sem_release CONFIG_BT_ENABLED
57 libbt.a npl_os_freertos.c.obj npl_freertos_callout_init CONFIG_BT_ENABLED
58 libbt.a npl_os_freertos.c.obj npl_freertos_callout_deinit CONFIG_BT_ENABLED
59 libbt.a npl_os_freertos.c.obj npl_freertos_event_is_queued CONFIG_BT_ENABLED
60 libbt.a npl_os_freertos.c.obj npl_freertos_event_get_arg CONFIG_BT_ENABLED
61 libbt.a npl_os_freertos.c.obj npl_freertos_time_ms_to_ticks32 CONFIG_BT_ENABLED
62 libbt.a npl_os_freertos.c.obj npl_freertos_time_ticks_to_ms32 CONFIG_BT_ENABLED
63 libbt.a npl_os_freertos.c.obj npl_freertos_hw_is_in_critical CONFIG_BT_ENABLED
64 libbt.a npl_os_freertos.c.obj npl_freertos_get_time_forever CONFIG_BT_ENABLED
65 libbt.a npl_os_freertos.c.obj npl_freertos_os_started CONFIG_BT_ENABLED
66 libbt.a npl_os_freertos.c.obj npl_freertos_get_current_task_id CONFIG_BT_ENABLED
67 libbt.a npl_os_freertos.c.obj npl_freertos_event_reset CONFIG_BT_ENABLED
68 libbt.a npl_os_freertos.c.obj npl_freertos_callout_mem_reset CONFIG_BT_ENABLED
69 libbt.a npl_os_freertos.c.obj npl_freertos_event_init CONFIG_BT_ENABLED
70 libbt.a npl_os_freertos.c.obj npl_freertos_sem_get_count CONFIG_BT_ENABLED
71 libbt.a npl_os_freertos.c.obj npl_freertos_eventq_remove CONFIG_BT_ENABLED
72 libbt.a npl_os_freertos.c.obj npl_freertos_hw_exit_critical CONFIG_BT_ENABLED
73 libbt.a npl_os_freertos.c.obj npl_freertos_mutex_init CONFIG_BT_ENABLED
74 libbt.a npl_os_freertos.c.obj npl_freertos_hw_enter_critical CONFIG_BT_ENABLED
75 libbt.a npl_os_freertos.c.obj npl_freertos_eventq_put CONFIG_BT_ENABLED
76 libbt.a npl_os_freertos.c.obj npl_freertos_eventq_get CONFIG_BT_ENABLED
77 libbt.a npl_os_freertos.c.obj npl_freertos_sem_deinit CONFIG_BT_ENABLED
78 libbt.a npl_os_freertos.c.obj npl_freertos_mutex_deinit CONFIG_BT_ENABLED
79 libbt.a npl_os_freertos.c.obj npl_freertos_eventq_deinit CONFIG_BT_ENABLED
80 libbt.a npl_os_freertos.c.obj npl_freertos_eventq_init CONFIG_BT_ENABLED
81 libbt.a npl_os_freertos.c.obj npl_freertos_event_deinit CONFIG_BT_ENABLED
82 libbt.a npl_os_freertos.c.obj npl_freertos_time_ticks_to_ms CONFIG_BT_ENABLED
83 libbt.a npl_os_freertos.c.obj npl_freertos_time_ms_to_ticks CONFIG_BT_ENABLED
84 libbt.a npl_os_freertos.c.obj npl_freertos_callout_set_arg CONFIG_BT_ENABLED
85 libbt.a npl_os_freertos.c.obj npl_freertos_event_set_arg CONFIG_BT_ENABLED
86 libbt.a npl_os_freertos.c.obj npl_freertos_eventq_put CONFIG_BT_ENABLED
87 libdriver.a gpio.c.obj gpio_intr_service
88 libesp_app_format.a esp_app_desc.c.obj esp_app_get_elf_sha256
89 libesp_hw_support.a cpu.c.obj esp_cpu_wait_for_intr
90 libesp_hw_support.a cpu.c.obj esp_cpu_reset
91 libesp_hw_support.a esp_clk.c.obj esp_clk_cpu_freq
92 libesp_hw_support.a esp_clk.c.obj esp_clk_apb_freq
93 libesp_hw_support.a esp_clk.c.obj esp_clk_xtal_freq
94 libesp_hw_support.a esp_memory_utils.c.obj esp_ptr_byte_accessible
95 libesp_hw_support.a hw_random.c.obj esp_random
96 libesp_hw_support.a intr_alloc.c.obj shared_intr_isr
97 libesp_hw_support.a intr_alloc.c.obj esp_intr_noniram_disable
98 libesp_hw_support.a intr_alloc.c.obj esp_intr_noniram_enable
99 libesp_hw_support.a intr_alloc.c.obj esp_intr_enable
100 libesp_hw_support.a intr_alloc.c.obj esp_intr_disable
101 libesp_hw_support.a periph_ctrl.c.obj wifi_bt_common_module_enable
102 libesp_hw_support.a periph_ctrl.c.obj wifi_bt_common_module_disable
103 libesp_hw_support.a regi2c_ctrl.c.obj regi2c_ctrl_read_reg
104 libesp_hw_support.a regi2c_ctrl.c.obj regi2c_ctrl_read_reg_mask
105 libesp_hw_support.a regi2c_ctrl.c.obj regi2c_ctrl_write_reg
106 libesp_hw_support.a regi2c_ctrl.c.obj regi2c_ctrl_write_reg_mask
107 libesp_hw_support.a regi2c_ctrl.c.obj regi2c_enter_critical
108 libesp_hw_support.a regi2c_ctrl.c.obj regi2c_exit_critical
109 libesp_hw_support.a regi2c_ctrl.c.obj regi2c_analog_cali_reg_read
110 libesp_hw_support.a regi2c_ctrl.c.obj regi2c_analog_cali_reg_write
111 libesp_hw_support.a rtc_clk.c.obj rtc_clk_32k_enable_external
112 libesp_hw_support.a rtc_clk.c.obj rtc_clk_fast_src_set
113 libesp_hw_support.a rtc_clk.c.obj rtc_clk_slow_freq_get_hz
114 libesp_hw_support.a rtc_clk.c.obj rtc_clk_slow_src_get
115 libesp_hw_support.a rtc_clk.c.obj rtc_clk_slow_src_set
116 libesp_hw_support.a rtc_clk.c.obj rtc_dig_clk8m_disable
117 libesp_hw_support.a rtc_clk.c.obj rtc_clk_cpu_freq_set_config_fast
118 libesp_hw_support.a rtc_clk.c.obj rtc_clk_8m_enable
119 libesp_hw_support.a rtc_clk.c.obj rtc_clk_8md256_enabled
120 libesp_hw_support.a rtc_clk.c.obj rtc_clk_bbpll_configure
121 libesp_hw_support.a rtc_clk.c.obj rtc_clk_bbpll_enable
122 libesp_hw_support.a rtc_clk.c.obj rtc_clk_cpu_freq_get_config
123 libesp_hw_support.a rtc_clk.c.obj rtc_clk_cpu_freq_mhz_to_config
124 libesp_hw_support.a rtc_clk.c.obj rtc_clk_cpu_freq_set_config
125 libesp_hw_support.a rtc_clk.c.obj rtc_clk_cpu_freq_to_8m
126 libesp_hw_support.a rtc_clk.c.obj rtc_clk_cpu_freq_to_pll_mhz
127 libesp_hw_support.a rtc_clk.c.obj rtc_clk_cpu_freq_set_xtal
128 libesp_hw_support.a rtc_clk.c.obj rtc_clk_xtal_freq_get
129 libesp_hw_support.a rtc_clk.c.obj rtc_clk_cpu_freq_to_xtal
130 libesp_hw_support.a rtc_clk.c.obj rtc_clk_bbpll_disable
131 libesp_hw_support.a rtc_clk.c.obj rtc_clk_apb_freq_update
132 libesp_hw_support.a rtc_clk.c.obj clk_ll_rtc_slow_get_src FALSE
133 libesp_hw_support.a rtc_init.c.obj rtc_vddsdio_set_config
134 libesp_hw_support.a rtc_module.c.obj rtc_isr
135 libesp_hw_support.a rtc_module.c.obj rtc_isr_noniram_disable
136 libesp_hw_support.a rtc_module.c.obj rtc_isr_noniram_enable
137 libesp_hw_support.a rtc_sleep.c.obj rtc_sleep_pu
138 libesp_hw_support.a rtc_sleep.c.obj rtc_sleep_finish
139 libesp_hw_support.a rtc_sleep.c.obj rtc_sleep_get_default_config
140 libesp_hw_support.a rtc_sleep.c.obj rtc_sleep_init
141 libesp_hw_support.a rtc_sleep.c.obj rtc_sleep_low_init
142 libesp_hw_support.a rtc_sleep.c.obj rtc_sleep_start
143 libesp_hw_support.a rtc_time.c.obj rtc_clk_cal
144 libesp_hw_support.a rtc_time.c.obj rtc_clk_cal_internal
145 libesp_hw_support.a rtc_time.c.obj rtc_time_get
146 libesp_hw_support.a rtc_time.c.obj rtc_time_us_to_slowclk
147 libesp_hw_support.a rtc_time.c.obj rtc_time_slowclk_to_us
148 libesp_hw_support.a sleep_modes.c.obj periph_ll_periph_enabled
149 libesp_hw_support.a sleep_modes.c.obj flush_uarts
150 libesp_hw_support.a sleep_modes.c.obj suspend_uarts
151 libesp_hw_support.a sleep_modes.c.obj resume_uarts
152 libesp_hw_support.a sleep_modes.c.obj esp_sleep_start
153 libesp_hw_support.a sleep_modes.c.obj esp_deep_sleep_start
154 libesp_hw_support.a sleep_modes.c.obj esp_light_sleep_inner
155 libesp_phy.a phy_init.c.obj esp_phy_common_clock_enable
156 libesp_phy.a phy_init.c.obj esp_phy_common_clock_disable
157 libesp_phy.a phy_init.c.obj esp_wifi_bt_power_domain_on
158 libesp_phy.a phy_override.c.obj phy_i2c_enter_critical
159 libesp_phy.a phy_override.c.obj phy_i2c_exit_critical
160 libesp_pm.a pm_locks.c.obj esp_pm_lock_acquire
161 libesp_pm.a pm_locks.c.obj esp_pm_lock_release
162 libesp_pm.a pm_impl.c.obj get_lowest_allowed_mode
163 libesp_pm.a pm_impl.c.obj esp_pm_impl_switch_mode
164 libesp_pm.a pm_impl.c.obj on_freq_update
165 libesp_pm.a pm_impl.c.obj vApplicationSleep CONFIG_FREERTOS_USE_TICKLESS_IDLE
166 libesp_pm.a pm_impl.c.obj do_switch
167 libesp_ringbuf.a ringbuf.c.obj prvCheckItemAvail
168 libesp_ringbuf.a ringbuf.c.obj prvGetFreeSize
169 libesp_ringbuf.a ringbuf.c.obj prvReceiveGenericFromISR
170 libesp_ringbuf.a ringbuf.c.obj xRingbufferGetMaxItemSize
171 libesp_rom.a esp_rom_systimer.c.obj systimer_hal_init
172 libesp_rom.a esp_rom_systimer.c.obj systimer_hal_set_alarm_period
173 libesp_rom.a esp_rom_systimer.c.obj systimer_hal_set_alarm_target
174 libesp_rom.a esp_rom_systimer.c.obj systimer_hal_set_tick_rate_ops
175 libesp_rom.a esp_rom_uart.c.obj esp_rom_uart_set_clock_baudrate
176 libesp_system.a brownout.c.obj rtc_brownout_isr_handler
177 libesp_system.a cache_err_int.c.obj esp_cache_err_get_cpuid
178 libesp_system.a cpu_start.c.obj call_start_cpu0
179 libesp_system.a crosscore_int.c.obj esp_crosscore_int_send
180 libesp_system.a crosscore_int.c.obj esp_crosscore_int_send_yield
181 libesp_system.a esp_system.c.obj esp_restart
182 libesp_system.a esp_system.c.obj esp_system_abort
183 libesp_system.a reset_reason.c.obj esp_reset_reason_set_hint
184 libesp_system.a reset_reason.c.obj esp_reset_reason_get_hint
185 libesp_system.a ubsan.c.obj __ubsan_include
186 libesp_timer.a esp_timer.c.obj esp_timer_get_next_alarm_for_wake_up
187 libesp_timer.a esp_timer.c.obj timer_list_unlock !CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
188 libesp_timer.a esp_timer.c.obj timer_list_lock !CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
189 libesp_timer.a esp_timer.c.obj timer_armed
190 libesp_timer.a esp_timer.c.obj timer_remove
191 libesp_timer.a esp_timer.c.obj timer_insert !CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
192 libesp_timer.a esp_timer.c.obj esp_timer_start_once
193 libesp_timer.a esp_timer.c.obj esp_timer_start_periodic
194 libesp_timer.a esp_timer.c.obj esp_timer_stop
195 libesp_timer.a esp_timer.c.obj esp_timer_get_expiry_time
196 libesp_timer.a esp_timer_impl_systimer.c.obj esp_timer_impl_get_time !CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
197 libesp_timer.a esp_timer_impl_systimer.c.obj esp_timer_impl_set_alarm_id !CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
198 libesp_timer.a esp_timer_impl_systimer.c.obj esp_timer_impl_update_apb_freq
199 libesp_timer.a esp_timer_impl_systimer.c.obj esp_timer_impl_get_min_period_us
200 libesp_timer.a ets_timer_legacy.c.obj timer_initialized
201 libesp_timer.a ets_timer_legacy.c.obj ets_timer_arm_us
202 libesp_timer.a ets_timer_legacy.c.obj ets_timer_arm
203 libesp_timer.a ets_timer_legacy.c.obj ets_timer_disarm
204 libesp_timer.a system_time.c.obj esp_system_get_time
205 libesp_wifi.a esp_adapter.c.obj semphr_take_from_isr_wrapper
206 libesp_wifi.a esp_adapter.c.obj wifi_realloc
207 libesp_wifi.a esp_adapter.c.obj coex_event_duration_get_wrapper
208 libesp_wifi.a esp_adapter.c.obj coex_schm_interval_set_wrapper
209 libesp_wifi.a esp_adapter.c.obj esp_empty_wrapper
210 libesp_wifi.a esp_adapter.c.obj wifi_calloc
211 libesp_wifi.a esp_adapter.c.obj wifi_zalloc_wrapper
212 libesp_wifi.a esp_adapter.c.obj env_is_chip_wrapper
213 libesp_wifi.a esp_adapter.c.obj is_from_isr_wrapper
214 libesp_wifi.a esp_adapter.c.obj semphr_give_from_isr_wrapper
215 libesp_wifi.a esp_adapter.c.obj mutex_lock_wrapper
216 libesp_wifi.a esp_adapter.c.obj mutex_unlock_wrapper
217 libesp_wifi.a esp_adapter.c.obj task_ms_to_tick_wrapper
218 libesp_wifi.a esp_adapter.c.obj wifi_apb80m_request_wrapper
219 libesp_wifi.a esp_adapter.c.obj wifi_apb80m_release_wrapper
220 libesp_wifi.a esp_adapter.c.obj timer_arm_wrapper
221 libesp_wifi.a esp_adapter.c.obj wifi_malloc
222 libesp_wifi.a esp_adapter.c.obj timer_disarm_wrapper
223 libesp_wifi.a esp_adapter.c.obj timer_arm_us_wrapper
224 libesp_wifi.a esp_adapter.c.obj wifi_rtc_enable_iso_wrapper
225 libesp_wifi.a esp_adapter.c.obj wifi_rtc_disable_iso_wrapper
226 libesp_wifi.a esp_adapter.c.obj malloc_internal_wrapper
227 libesp_wifi.a esp_adapter.c.obj realloc_internal_wrapper
228 libesp_wifi.a esp_adapter.c.obj calloc_internal_wrapper
229 libesp_wifi.a esp_adapter.c.obj zalloc_internal_wrapper
230 libesp_wifi.a esp_adapter.c.obj coex_status_get_wrapper
231 libesp_wifi.a esp_adapter.c.obj coex_wifi_release_wrapper
232 libfreertos.a list.c.obj uxListRemove FALSE
233 libfreertos.a list.c.obj vListInitialise CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
234 libfreertos.a list.c.obj vListInitialiseItem CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
235 libfreertos.a list.c.obj vListInsert CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
236 libfreertos.a list.c.obj vListInsertEnd FALSE
237 libfreertos.a port.c.obj vApplicationStackOverflowHook FALSE
238 libfreertos.a port.c.obj vPortYieldOtherCore FALSE
239 libfreertos.a port.c.obj vPortYield
240 libfreertos.a port_common.c.obj xPortcheckValidStackMem
241 libfreertos.a port_common.c.obj vApplicationGetTimerTaskMemory
242 libfreertos.a port_common.c.obj esp_startup_start_app_common
243 libfreertos.a port_common.c.obj xPortCheckValidTCBMem
244 libfreertos.a port_common.c.obj vApplicationGetIdleTaskMemory
245 libfreertos.a port_systick.c.obj vPortSetupTimer
246 libfreertos.a port_systick.c.obj xPortSysTickHandler FALSE
247 libfreertos.a queue.c.obj prvCopyDataFromQueue
248 libfreertos.a queue.c.obj prvGetDisinheritPriorityAfterTimeout
249 libfreertos.a queue.c.obj prvIsQueueEmpty
250 libfreertos.a queue.c.obj prvNotifyQueueSetContainer
251 libfreertos.a queue.c.obj xQueueReceive
252 libfreertos.a queue.c.obj prvUnlockQueue
253 libfreertos.a queue.c.obj xQueueSemaphoreTake
254 libfreertos.a queue.c.obj xQueueReceiveFromISR
255 libfreertos.a queue.c.obj uxQueueMessagesWaitingFromISR
256 libfreertos.a queue.c.obj xQueueIsQueueEmptyFromISR
257 libfreertos.a queue.c.obj xQueueGiveFromISR
258 libfreertos.a tasks.c.obj __getreent CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
259 libfreertos.a tasks.c.obj pcTaskGetName CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
260 libfreertos.a tasks.c.obj prvAddCurrentTaskToDelayedList CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
261 libfreertos.a tasks.c.obj prvDeleteTLS CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
262 libfreertos.a tasks.c.obj pvTaskIncrementMutexHeldCount CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
263 libfreertos.a tasks.c.obj taskSelectHighestPriorityTaskSMP FALSE
264 libfreertos.a tasks.c.obj taskYIELD_OTHER_CORE FALSE
265 libfreertos.a tasks.c.obj vTaskGetSnapshot CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH
266 libfreertos.a tasks.c.obj vTaskInternalSetTimeOutState CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
267 libfreertos.a tasks.c.obj vTaskPlaceOnEventList CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
268 libfreertos.a tasks.c.obj vTaskPlaceOnEventListRestricted CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
269 libfreertos.a tasks.c.obj vTaskPlaceOnUnorderedEventList CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
270 libfreertos.a tasks.c.obj vTaskPriorityDisinheritAfterTimeout CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
271 libfreertos.a tasks.c.obj vTaskReleaseEventListLock CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
272 libfreertos.a tasks.c.obj vTaskTakeEventListLock CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
273 libfreertos.a tasks.c.obj xTaskCheckForTimeOut CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
274 libfreertos.a tasks.c.obj xTaskGetCurrentTaskHandle CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
275 libfreertos.a tasks.c.obj xTaskGetSchedulerState CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
276 libfreertos.a tasks.c.obj xTaskGetTickCount CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
277 libfreertos.a tasks.c.obj xTaskPriorityDisinherit FALSE
278 libfreertos.a tasks.c.obj xTaskPriorityInherit CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
279 libfreertos.a tasks.c.obj prvGetExpectedIdleTime FALSE
280 libfreertos.a tasks.c.obj vTaskStepTick FALSE
281 libhal.a brownout_hal.c.obj brownout_hal_intr_clear
282 libhal.a efuse_hal.c.obj efuse_hal_chip_revision
283 libhal.a efuse_hal.c.obj efuse_hal_get_major_chip_version
284 libhal.a efuse_hal.c.obj efuse_hal_get_minor_chip_version
285 libheap.a heap_caps.c.obj dram_alloc_to_iram_addr
286 libheap.a heap_caps.c.obj heap_caps_free
287 libheap.a heap_caps.c.obj heap_caps_realloc_base
288 libheap.a heap_caps.c.obj heap_caps_realloc
289 libheap.a heap_caps.c.obj heap_caps_calloc_base
290 libheap.a heap_caps.c.obj heap_caps_calloc
291 libheap.a heap_caps.c.obj heap_caps_malloc_base
292 libheap.a heap_caps.c.obj heap_caps_malloc
293 libheap.a heap_caps.c.obj heap_caps_malloc_default
294 libheap.a heap_caps.c.obj heap_caps_realloc_default
295 libheap.a heap_caps.c.obj find_containing_heap
296 libheap.a multi_heap.c.obj _multi_heap_lock
297 libheap.a multi_heap.c.obj multi_heap_in_rom_init
298 liblog.a log_freertos.c.obj esp_log_timestamp
299 liblog.a log_freertos.c.obj esp_log_impl_lock
300 liblog.a log_freertos.c.obj esp_log_impl_unlock
301 liblog.a log_freertos.c.obj esp_log_impl_lock_timeout
302 liblog.a log_freertos.c.obj esp_log_early_timestamp
303 liblog.a log.c.obj esp_log_write
304 libmbedcrypto.a esp_mem.c.obj esp_mbedtls_mem_calloc !CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC
305 libmbedcrypto.a esp_mem.c.obj esp_mbedtls_mem_free !CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC
306 libnewlib.a assert.c.obj __assert_func
307 libnewlib.a assert.c.obj newlib_include_assert_impl
308 libnewlib.a heap.c.obj _calloc_r
309 libnewlib.a heap.c.obj _free_r
310 libnewlib.a heap.c.obj _malloc_r
311 libnewlib.a heap.c.obj _realloc_r
312 libnewlib.a heap.c.obj calloc
313 libnewlib.a heap.c.obj cfree
314 libnewlib.a heap.c.obj free
315 libnewlib.a heap.c.obj malloc
316 libnewlib.a heap.c.obj newlib_include_heap_impl
317 libnewlib.a heap.c.obj realloc
318 libnewlib.a locks.c.obj _lock_try_acquire_recursive
319 libnewlib.a locks.c.obj lock_release_generic
320 libnewlib.a locks.c.obj _lock_release
321 libnewlib.a locks.c.obj _lock_release_recursive
322 libnewlib.a locks.c.obj __retarget_lock_init
323 libnewlib.a locks.c.obj __retarget_lock_init_recursive
324 libnewlib.a locks.c.obj __retarget_lock_close
325 libnewlib.a locks.c.obj __retarget_lock_close_recursive
326 libnewlib.a locks.c.obj check_lock_nonzero
327 libnewlib.a locks.c.obj __retarget_lock_acquire
328 libnewlib.a locks.c.obj lock_init_generic
329 libnewlib.a locks.c.obj __retarget_lock_acquire_recursive
330 libnewlib.a locks.c.obj __retarget_lock_try_acquire
331 libnewlib.a locks.c.obj __retarget_lock_try_acquire_recursive
332 libnewlib.a locks.c.obj __retarget_lock_release
333 libnewlib.a locks.c.obj __retarget_lock_release_recursive
334 libnewlib.a locks.c.obj _lock_close
335 libnewlib.a locks.c.obj lock_acquire_generic
336 libnewlib.a locks.c.obj _lock_acquire
337 libnewlib.a locks.c.obj _lock_acquire_recursive
338 libnewlib.a locks.c.obj _lock_try_acquire
339 libnewlib.a reent_init.c.obj esp_reent_init
340 libnewlib.a time.c.obj _times_r
341 libnewlib.a time.c.obj _gettimeofday_r
342 libpp.a pp_debug.o wifi_gpio_debug
343 libpthread.a pthread.c.obj pthread_mutex_lock_internal
344 libpthread.a pthread.c.obj pthread_mutex_lock
345 libpthread.a pthread.c.obj pthread_mutex_unlock
346 libriscv.a interrupt.c.obj intr_handler_get
347 libriscv.a interrupt.c.obj intr_handler_set
348 libriscv.a interrupt.c.obj intr_matrix_route
349 libspi_flash.a flash_brownout_hook.c.obj spi_flash_needs_reset_check FALSE
350 libspi_flash.a flash_brownout_hook.c.obj spi_flash_set_erasing_flag FALSE
351 libspi_flash.a flash_ops.c.obj spi_flash_guard_set CONFIG_SPI_FLASH_ROM_IMPL
352 libspi_flash.a flash_ops.c.obj spi_flash_malloc_internal CONFIG_SPI_FLASH_ROM_IMPL
353 libspi_flash.a flash_ops.c.obj spi_flash_rom_impl_init CONFIG_SPI_FLASH_ROM_IMPL
354 libspi_flash.a flash_ops.c.obj esp_mspi_pin_init CONFIG_SPI_FLASH_ROM_IMPL
355 libspi_flash.a flash_ops.c.obj spi_flash_init_chip_state CONFIG_SPI_FLASH_ROM_IMPL
356 libspi_flash.a spi_flash_os_func_app.c.obj delay_us CONFIG_SPI_FLASH_ROM_IMPL
357 libspi_flash.a spi_flash_os_func_app.c.obj get_buffer_malloc CONFIG_SPI_FLASH_ROM_IMPL
358 libspi_flash.a spi_flash_os_func_app.c.obj release_buffer_malloc CONFIG_SPI_FLASH_ROM_IMPL
359 libspi_flash.a spi_flash_os_func_app.c.obj main_flash_region_protected CONFIG_SPI_FLASH_ROM_IMPL
360 libspi_flash.a spi_flash_os_func_app.c.obj main_flash_op_status CONFIG_SPI_FLASH_ROM_IMPL
361 libspi_flash.a spi_flash_os_func_app.c.obj spi1_flash_os_check_yield CONFIG_SPI_FLASH_ROM_IMPL
362 libspi_flash.a spi_flash_os_func_app.c.obj spi1_flash_os_yield CONFIG_SPI_FLASH_ROM_IMPL
363 libspi_flash.a spi_flash_os_func_noos.c.obj start CONFIG_SPI_FLASH_ROM_IMPL
364 libspi_flash.a spi_flash_os_func_noos.c.obj end CONFIG_SPI_FLASH_ROM_IMPL
365 libspi_flash.a spi_flash_os_func_noos.c.obj delay_us CONFIG_SPI_FLASH_ROM_IMPL

View File

@@ -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
1 library path
2 libble_app.a $IDF_PATH/components/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a
3 libpp.a $IDF_PATH/components/esp_wifi/lib/esp32c2/libpp.a
4 libbootloader_support.a ./esp-idf/bootloader_support/libbootloader_support.a
5 libbt.a ./esp-idf/bt/libbt.a
6 libdriver.a ./esp-idf/driver/libdriver.a
7 libesp_app_format.a ./esp-idf/esp_app_format/libesp_app_format.a
8 libesp_hw_support.a ./esp-idf/esp_hw_support/libesp_hw_support.a
9 libesp_phy.a ./esp-idf/esp_phy/libesp_phy.a
10 libesp_pm.a ./esp-idf/esp_pm/libesp_pm.a
11 libesp_ringbuf.a ./esp-idf/esp_ringbuf/libesp_ringbuf.a
12 libesp_rom.a ./esp-idf/esp_rom/libesp_rom.a
13 libesp_system.a ./esp-idf/esp_system/libesp_system.a
14 libesp_timer.a ./esp-idf/esp_timer/libesp_timer.a
15 libesp_wifi.a ./esp-idf/esp_wifi/libesp_wifi.a
16 libfreertos.a ./esp-idf/freertos/libfreertos.a
17 libhal.a ./esp-idf/hal/libhal.a
18 libheap.a ./esp-idf/heap/libheap.a
19 liblog.a ./esp-idf/log/liblog.a
20 libmbedcrypto.a ./esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a
21 libnewlib.a ./esp-idf/newlib/libnewlib.a
22 libpthread.a ./esp-idf/pthread/libpthread.a
23 libriscv.a ./esp-idf/riscv/libriscv.a
24 libspi_flash.a ./esp-idf/spi_flash/libspi_flash.a

View File

@@ -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
1 library object path
2 libbootloader_support.a bootloader_flash.c.obj esp-idf/bootloader_support/CMakeFiles/__idf_bootloader_support.dir/bootloader_flash/src/bootloader_flash.c.obj
3 libbootloader_support.a flash_encrypt.c.obj esp-idf/bootloader_support/CMakeFiles/__idf_bootloader_support.dir/src/flash_encrypt.c.obj
4 libbt.a bt_osi_mem.c.obj esp-idf/bt/CMakeFiles/__idf_bt.dir/porting/mem/bt_osi_mem.c.obj
5 libbt.a bt.c.obj esp-idf/bt/CMakeFiles/__idf_bt.dir/controller/esp32c2/bt.c.obj
6 libbt.a npl_os_freertos.c.obj esp-idf/bt/CMakeFiles/__idf_bt.dir/porting/npl/freertos/src/npl_os_freertos.c.obj
7 libbt.a nimble_port.c.obj esp-idf/bt/CMakeFiles/__idf_bt.dir/host/nimble/nimble/porting/nimble/src/nimble_port.c.obj
8 libdriver.a gpio.c.obj esp-idf/driver/CMakeFiles/__idf_driver.dir/gpio/gpio.c.obj
9 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
10 libesp_hw_support.a cpu.c.obj esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/cpu.c.obj
11 libesp_hw_support.a esp_clk.c.obj esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/esp_clk.c.obj
12 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
13 libesp_hw_support.a hw_random.c.obj esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/hw_random.c.obj
14 libesp_hw_support.a intr_alloc.c.obj esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/intr_alloc.c.obj
15 libesp_hw_support.a periph_ctrl.c.obj esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/periph_ctrl.c.obj
16 libesp_hw_support.a regi2c_ctrl.c.obj esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/regi2c_ctrl.c.obj
17 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
18 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
19 libesp_hw_support.a rtc_module.c.obj esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/rtc_module.c.obj
20 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
21 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
22 libesp_hw_support.a sleep_modes.c.obj esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/sleep_modes.c.obj
23 libesp_phy.a phy_init.c.obj esp-idf/esp_phy/CMakeFiles/__idf_esp_phy.dir/src/phy_init.c.obj
24 libesp_phy.a phy_override.c.obj esp-idf/esp_phy/CMakeFiles/__idf_esp_phy.dir/src/phy_override.c.obj
25 libesp_pm.a pm_locks.c.obj esp-idf/esp_pm/CMakeFiles/__idf_esp_pm.dir/pm_locks.c.obj
26 libesp_pm.a pm_impl.c.obj esp-idf/esp_pm/CMakeFiles/__idf_esp_pm.dir/pm_impl.c.obj
27 libesp_ringbuf.a ringbuf.c.obj esp-idf/esp_ringbuf/CMakeFiles/__idf_esp_ringbuf.dir/ringbuf.c.obj
28 libesp_rom.a esp_rom_systimer.c.obj esp-idf/esp_rom/CMakeFiles/__idf_esp_rom.dir/patches/esp_rom_systimer.c.obj
29 libesp_rom.a esp_rom_uart.c.obj esp-idf/esp_rom/CMakeFiles/__idf_esp_rom.dir/patches/esp_rom_uart.c.obj
30 libesp_system.a brownout.c.obj esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/brownout.c.obj
31 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
32 libesp_system.a cpu_start.c.obj esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/cpu_start.c.obj
33 libesp_system.a crosscore_int.c.obj esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/crosscore_int.c.obj
34 libesp_system.a esp_system.c.obj esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/esp_system.c.obj
35 libesp_system.a reset_reason.c.obj esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/soc/esp32c2/reset_reason.c.obj
36 libesp_system.a ubsan.c.obj esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/ubsan.c.obj
37 libesp_timer.a esp_timer.c.obj esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/esp_timer.c.obj
38 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
39 libesp_timer.a ets_timer_legacy.c.obj esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/ets_timer_legacy.c.obj
40 libesp_timer.a system_time.c.obj esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/system_time.c.obj
41 libesp_wifi.a esp_adapter.c.obj esp-idf/esp_wifi/CMakeFiles/__idf_esp_wifi.dir/esp32c2/esp_adapter.c.obj
42 libfreertos.a list.c.obj esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/list.c.obj
43 libfreertos.a port.c.obj esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/riscv/port.c.obj
44 libfreertos.a port_common.c.obj esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/port_common.c.obj
45 libfreertos.a port_systick.c.obj esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/port_systick.c.obj
46 libfreertos.a queue.c.obj esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/queue.c.obj
47 libfreertos.a tasks.c.obj esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/tasks.c.obj
48 libhal.a brownout_hal.c.obj esp-idf/hal/CMakeFiles/__idf_hal.dir/esp32c2/brownout_hal.c.obj
49 libhal.a efuse_hal.c.obj esp-idf/hal/CMakeFiles/__idf_hal.dir/efuse_hal.c.obj
50 libhal.a efuse_hal.c.obj esp-idf/hal/CMakeFiles/__idf_hal.dir/esp32c2/efuse_hal.c.obj
51 libheap.a heap_caps.c.obj esp-idf/heap/CMakeFiles/__idf_heap.dir/heap_caps.c.obj
52 libheap.a multi_heap.c.obj ./esp-idf/heap/CMakeFiles/__idf_heap.dir/multi_heap.c.obj
53 liblog.a log_freertos.c.obj esp-idf/log/CMakeFiles/__idf_log.dir/log_freertos.c.obj
54 liblog.a log.c.obj esp-idf/log/CMakeFiles/__idf_log.dir/log.c.obj
55 libmbedcrypto.a esp_mem.c.obj esp-idf/mbedtls/mbedtls/library/CMakeFiles/mbedcrypto.dir/$IDF_PATH/components/mbedtls/port/esp_mem.c.obj
56 libnewlib.a assert.c.obj esp-idf/newlib/CMakeFiles/__idf_newlib.dir/assert.c.obj
57 libnewlib.a heap.c.obj esp-idf/newlib/CMakeFiles/__idf_newlib.dir/heap.c.obj
58 libnewlib.a locks.c.obj esp-idf/newlib/CMakeFiles/__idf_newlib.dir/locks.c.obj
59 libnewlib.a reent_init.c.obj esp-idf/newlib/CMakeFiles/__idf_newlib.dir/reent_init.c.obj
60 libnewlib.a time.c.obj esp-idf/newlib/CMakeFiles/__idf_newlib.dir/time.c.obj
61 libpthread.a pthread.c.obj esp-idf/pthread/CMakeFiles/__idf_pthread.dir/pthread.c.obj
62 libriscv.a interrupt.c.obj esp-idf/riscv/CMakeFiles/__idf_riscv.dir/interrupt.c.obj
63 libspi_flash.a flash_brownout_hook.c.obj esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/flash_brownout_hook.c.obj
64 libspi_flash.a flash_ops.c.obj esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/flash_ops.c.obj
65 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
66 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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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})

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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})

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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

View File

@@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES unity test_utils test_component1 TEST-component2)

View File

@@ -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();
}

View File

@@ -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)

View File

@@ -0,0 +1 @@
840387ee0c90a473e43fdc75570f77c52f06423aa331d95479bde8b418c43547

View File

@@ -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"}]}

View File

@@ -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})

View File

@@ -0,0 +1,92 @@
# ESP LCD ILI9341
[![Component Registry](https://components.espressif.com/components/espressif/esp_lcd_ili9341/badge.svg)](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,
};
...
```

View 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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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},
};

View File

@@ -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},
};

View 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.

View File

@@ -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)

View File

@@ -0,0 +1,4 @@
idf_component_register(
SRCS "test_esp_lcd_ili9341.c"
REQUIRES unity driver
)

View File

@@ -0,0 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
idf: ">=5.2"
esp_lcd_ili9341:
version: "*"
override_path: "../../../esp_lcd_ili9341"

View File

@@ -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();
}

View File

@@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n

View File

@@ -0,0 +1 @@
3f85a7d95af876f1a6ecca8eb90a81614890d0f03a038390804e5a77e2caf862

View File

@@ -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"}]}

View File

@@ -0,0 +1 @@
idf_component_register(SRCS "esp_lcd_touch.c" INCLUDE_DIRS "include" REQUIRES "driver" "esp_lcd")

View 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

View File

@@ -0,0 +1,16 @@
# ESP LCD Touch Component
[![Component Registry](https://components.espressif.com/components/espressif/esp_lcd_touch/badge.svg)](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

View 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);
}

View File

@@ -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

View File

@@ -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

View 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.

View File

@@ -0,0 +1 @@
d3c020b45c3dfc0d1706a83b63a1c34a6eb444a6e935f9afff79f92b7b94dcef

View 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

View 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)

View 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()

View 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

View File

@@ -0,0 +1,420 @@
# LVGL ESP Portation
[![Component Registry](https://components.espressif.com/components/espressif/esp_lvgl_port/badge.svg)](https://components.espressif.com/components/espressif/esp_lvgl_port)
![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg)
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

View 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:
![FPS vs Frame buffer size](frame_buffer_settings.png)
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).

View File

@@ -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)

View File

@@ -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
```

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")

View File

@@ -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

View File

@@ -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

View File

@@ -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.");
}

View File

@@ -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

View File

@@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(i2c_oled)

View File

@@ -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
...
```

View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "i2c_oled_example_main.c" "lvgl_demo_ui.c"
INCLUDE_DIRS "."
REQUIRES driver esp_timer
)

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -0,0 +1,6 @@
dependencies:
esp_lcd_sh1107:
version: ^1
esp_lvgl_port:
version: '*'
idf: '>=5.2'

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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.

View File

@@ -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;"
)

View File

@@ -0,0 +1,6 @@
dependencies:
esp_lcd_touch_gt1151:
version: ^1
esp_lvgl_port:
version: '*'
idf: '>=5.2'

Some files were not shown because too many files have changed in this diff Show More