feat: Initial esp32-hacking project with firmware sources and docs

This commit is contained in:
user
2026-02-04 12:59:28 +01:00
commit 298e98befb
120 changed files with 22094 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
idf_component_register(
SRCS "bsp_C5_dual_antenna.c" ${SRC_VER}
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "priv_include"
REQUIRES driver spiffs esp_wifi
PRIV_REQUIRES fatfs esp_lcd
)

View File

@@ -0,0 +1,93 @@
menu "Board Support Package"
config BSP_ERROR_CHECK
bool "Enable error check in BSP"
default y
help
Error check assert the application before returning the error code.
menu "I2C"
config BSP_I2C_NUM
int "I2C peripheral index"
default 0
range 0 1
help
ESP32C5 has two I2C peripherals, pick the one you want to use.
config BSP_I2C_FAST_MODE
bool "Enable I2C fast mode"
default y
help
I2C has two speed modes: normal (100kHz) and fast (400kHz).
config BSP_I2C_CLK_SPEED_HZ
int
default 400000 if BSP_I2C_FAST_MODE
default 100000
endmenu
menu "SPIFFS - Virtual File System"
config BSP_SPIFFS_FORMAT_ON_MOUNT_FAIL
bool "Format SPIFFS if mounting fails"
default n
help
Format SPIFFS if it fails to mount the filesystem.
config BSP_SPIFFS_MOUNT_POINT
string "SPIFFS mount point"
default "/spiffs"
help
Mount point of SPIFFS in the Virtual File System.
config BSP_SPIFFS_PARTITION_LABEL
string "Partition label of SPIFFS"
default "storage"
help
Partition label which stores SPIFFS.
config BSP_SPIFFS_MAX_FILES
int "Max files supported for SPIFFS VFS"
default 5
help
Supported max files for SPIFFS in the Virtual File System.
endmenu
menu "SD card - Virtual File System"
config BSP_SD_FORMAT_ON_MOUNT_FAIL
bool "Format SD card if mounting fails"
default n
help
The SDMMC host will format (FAT) the SD card if it fails to mount the filesystem.
config BSP_SD_MOUNT_POINT
string "SD card mount point"
default "/sdcard"
help
Mount point of the SD card in the Virtual File System
endmenu
menu "Display"
config BSP_DISPLAY_BRIGHTNESS_LEDC_CH
int "LEDC channel index"
default 1
range 0 7
help
LEDC channel is used to generate PWM signal that controls display brightness.
Set LEDC index that should be used.
config BSP_LCD_DRAW_BUF_HEIGHT
int "LCD framebuf height"
default 100
range 10 240
help
Framebuf is used for lvgl rendering output.
config BSP_LCD_DRAW_BUF_DOUBLE
bool "LCD double framebuf"
default n
help
Whether to enable double framebuf.
endmenu
endmenu

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,538 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "driver/gpio.h"
#include "driver/ledc.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_spiffs.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_vfs_fat.h"
#include "iot_button.h"
#include "bsp_C5_dual_antenna.h"
#include "esp_lcd_gc9a01.h"
#include "display.h"
#include "touch.h"
#include "esp_lcd_touch_cst816s.h"
#include "esp_lvgl_port.h"
#include "bsp_err_check.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "driver/uart.h"
#include "esp_sleep.h"
#include "esp_timer.h"
#include "led_strip.h"
#include "sdkconfig.h"
static const char *TAG = "ESP-Magnescreen";
RGB_LED_Config *rgb_led_handle;
bool rgb_task_started = false;
static led_strip_handle_t led_strip;
#if CHIP_ID == MASTER_CHIP
static lv_disp_t *disp;
static lv_indev_t *disp_indev = NULL;
static esp_lcd_touch_handle_t tp; // LCD touch handle
static esp_lcd_panel_handle_t panel_handle = NULL;
sdmmc_card_t *bsp_sdcard = NULL; // Global SD card handler
static bool i2c_initialized = false;
static button_handle_t g_btn_handle = NULL;
esp_err_t bsp_i2c_init(void)
{
/* I2C was initialized before */
if (i2c_initialized) {
return ESP_OK;
}
const i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = BSP_I2C_SDA,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = BSP_I2C_SCL,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = CONFIG_BSP_I2C_CLK_SPEED_HZ
};
BSP_ERROR_CHECK_RETURN_ERR(i2c_param_config(BSP_I2C_NUM, &i2c_conf));
BSP_ERROR_CHECK_RETURN_ERR(i2c_driver_install(BSP_I2C_NUM, i2c_conf.mode, 0, 0, 0));
i2c_initialized = true;
return ESP_OK;
}
esp_err_t bsp_i2c_deinit(void)
{
BSP_ERROR_CHECK_RETURN_ERR(i2c_driver_delete(BSP_I2C_NUM));
i2c_initialized = false;
return ESP_OK;
}
esp_err_t bsp_spiffs_mount(void)
{
esp_vfs_spiffs_conf_t conf = {
.base_path = CONFIG_BSP_SPIFFS_MOUNT_POINT,
.partition_label = CONFIG_BSP_SPIFFS_PARTITION_LABEL,
.max_files = CONFIG_BSP_SPIFFS_MAX_FILES,
#ifdef CONFIG_BSP_SPIFFS_FORMAT_ON_MOUNT_FAIL
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif
};
esp_err_t ret_val = esp_vfs_spiffs_register(&conf);
BSP_ERROR_CHECK_RETURN_ERR(ret_val);
size_t total = 0, used = 0;
ret_val = esp_spiffs_info(conf.partition_label, &total, &used);
if (ret_val != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret_val));
} else {
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
}
return ret_val;
}
esp_err_t bsp_spiffs_unmount(void)
{
return esp_vfs_spiffs_unregister(CONFIG_BSP_SPIFFS_PARTITION_LABEL);
}
// Bit number used to represent command and parameter
#define LCD_CMD_BITS 8
#define LCD_PARAM_BITS 8
#define LCD_LEDC_CH CONFIG_BSP_DISPLAY_BRIGHTNESS_LEDC_CH
static esp_err_t bsp_display_brightness_init(void)
{
// Setup LEDC peripheral for PWM backlight control
const ledc_channel_config_t LCD_backlight_channel = {
.gpio_num = BSP_LCD_BACKLIGHT,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LCD_BACKLIGHT_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = 1,
.duty = 0,
.hpoint = 0
};
const ledc_timer_config_t LCD_backlight_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = LEDC_TIMER_10_BIT,
.timer_num = 1,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK
};
BSP_ERROR_CHECK_RETURN_ERR(ledc_timer_config(&LCD_backlight_timer));
BSP_ERROR_CHECK_RETURN_ERR(ledc_channel_config(&LCD_backlight_channel));
return ESP_OK;
}
esp_err_t bsp_display_brightness_set(int brightness_percent)
{
if (brightness_percent > 100) {
brightness_percent = 100;
}
if (brightness_percent < 5) {
brightness_percent = 5;
}
ESP_LOGD(TAG, "Setting LCD backlight: %d%%", brightness_percent);
uint32_t duty_cycle = (1023 * brightness_percent) / 100; // LEDC resolution set to 10bits, thus: 100% = 1023
BSP_ERROR_CHECK_RETURN_ERR(ledc_set_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH, duty_cycle));
BSP_ERROR_CHECK_RETURN_ERR(ledc_update_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH));
return ESP_OK;
}
esp_err_t bsp_display_backlight_off(void)
{
return bsp_display_brightness_set(0);
}
esp_err_t bsp_display_backlight_on(void)
{
return bsp_display_brightness_set(100);
}
static esp_err_t bsp_lcd_enter_sleep(void)
{
assert(panel_handle);
return esp_lcd_panel_disp_on_off(panel_handle, false);
}
static esp_err_t bsp_lcd_exit_sleep(void)
{
assert(panel_handle);
return esp_lcd_panel_disp_on_off(panel_handle, true);
}
esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_handle_t *ret_panel, esp_lcd_panel_io_handle_t *ret_io)
{
esp_err_t ret = ESP_OK;
assert(config != NULL && config->max_transfer_sz > 0);
ESP_RETURN_ON_ERROR(bsp_display_brightness_init(), TAG, "Brightness init failed");
/* Initilize I2C */
BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init());
ESP_LOGI(TAG, "Initialize SPI bus");
const spi_bus_config_t bus_config = GC9A01_PANEL_BUS_SPI_CONFIG(BSP_LCD_PCLK, BSP_LCD_DATA0,
BSP_LCD_H_RES * 80 * sizeof(uint16_t));
ESP_RETURN_ON_ERROR(spi_bus_initialize(BSP_LCD_SPI_NUM, &bus_config, SPI_DMA_CH_AUTO), TAG, "SPI init failed");
ESP_LOGD(TAG, "Install panel IO");
const esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = BSP_LCD_DC,
.cs_gpio_num = BSP_LCD_CS,
.pclk_hz = BSP_LCD_PIXEL_CLOCK_HZ,
.lcd_cmd_bits = LCD_CMD_BITS,
.lcd_param_bits = LCD_PARAM_BITS,
.spi_mode = 0,
.trans_queue_depth = 10,
};
esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)BSP_LCD_SPI_NUM, &io_config, ret_io);
ESP_LOGI(TAG, "Install GC9A01 panel driver");
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = BSP_LCD_RST, // Shared with Touch reset
// .color_space = BSP_LCD_COLOR_SPACE,
.rgb_endian = LCD_RGB_ENDIAN_BGR,
.bits_per_pixel = BSP_LCD_BITS_PER_PIXEL,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(*ret_io, (const esp_lcd_panel_dev_config_t *)&panel_config, ret_panel));
esp_lcd_panel_reset(*ret_panel);
esp_lcd_panel_init(*ret_panel);
esp_lcd_panel_invert_color(*ret_panel, true);
esp_lcd_panel_disp_on_off(*ret_panel, true);
return ret;
}
static lv_disp_t *bsp_display_lcd_init(const bsp_display_cfg_t *cfg)
{
assert(cfg != NULL);
esp_lcd_panel_io_handle_t io_handle = NULL;
const bsp_display_config_t bsp_disp_cfg = {
.max_transfer_sz = (BSP_LCD_H_RES * CONFIG_BSP_LCD_DRAW_BUF_HEIGHT) * sizeof(uint16_t),
};
BSP_ERROR_CHECK_RETURN_NULL(bsp_display_new(&bsp_disp_cfg, &panel_handle, &io_handle));
esp_lcd_panel_disp_on_off(panel_handle, true);
/* Add LCD screen */
ESP_LOGD(TAG, "Add LCD screen");
const lvgl_port_display_cfg_t disp_cfg = {
.io_handle = io_handle,
.panel_handle = panel_handle,
.buffer_size = cfg->buffer_size,
.double_buffer = cfg->double_buffer,
.hres = BSP_LCD_H_RES,
.vres = BSP_LCD_V_RES,
.monochrome = false,
/* Rotation values must be same as used in esp_lcd for initial settings of the screen */
.rotation = {
.swap_xy = false,
.mirror_x = true,
.mirror_y = false,
},
.flags = {
.buff_dma = cfg->flags.buff_dma,
.buff_spiram = cfg->flags.buff_spiram,
}
};
return lvgl_port_add_disp(&disp_cfg);
}
__attribute__((weak)) esp_err_t esp_lcd_touch_enter_sleep(esp_lcd_touch_handle_t tp)
{
ESP_LOGE(TAG, "Sleep mode not supported!");
return ESP_FAIL;
}
__attribute__((weak)) esp_err_t esp_lcd_touch_exit_sleep(esp_lcd_touch_handle_t tp)
{
ESP_LOGE(TAG, "Sleep mode not supported!");
return ESP_FAIL;
}
static esp_err_t bsp_touch_enter_sleep(void)
{
assert(tp);
return esp_lcd_touch_enter_sleep(tp);
}
static esp_err_t bsp_touch_exit_sleep(void)
{
assert(tp);
return esp_lcd_touch_exit_sleep(tp);
}
esp_err_t bsp_touch_new(const bsp_touch_config_t *config, esp_lcd_touch_handle_t *ret_touch)
{
/* Initilize I2C */
BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init());
/* Initialize touch */
esp_lcd_touch_config_t tp_cfg = {
.x_max = BSP_LCD_H_RES,
.y_max = BSP_LCD_V_RES,
.rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset
.int_gpio_num = BSP_LCD_TOUCH_INT,
.levels = {
.reset = 0,
.interrupt = 0,
},
.flags = {
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
},
};
// if(tp_cfg.int_gpio_num != GPIO_NUM_NC) {
// ESP_LOGW(TAG, "Touch interrupt supported!");
// init_touch_isr_mux();
// tp_cfg.interrupt_callback = lvgl_port_touch_isr_cb;
// }
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
tp_io_config.scl_speed_hz = 0;
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)BSP_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, "");
ESP_RETURN_ON_ERROR(esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, ret_touch), TAG, "New CST816S failed");
return ESP_OK;
}
static lv_indev_t *bsp_display_indev_init(lv_disp_t *disp)
{
BSP_ERROR_CHECK_RETURN_NULL(bsp_touch_new(NULL, &tp));
assert(tp);
/* Add touch input (for selected screen) */
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = disp,
.handle = tp,
};
return lvgl_port_add_touch(&touch_cfg);
}
lv_disp_t *bsp_display_start(void)
{
bsp_display_cfg_t cfg = {
.lvgl_port_cfg = ESP_LVGL_PORT_INIT_CONFIG(),
.buffer_size = BSP_LCD_H_RES * CONFIG_BSP_LCD_DRAW_BUF_HEIGHT,
#if CONFIG_BSP_LCD_DRAW_BUF_DOUBLE
.double_buffer = 1,
#else
.double_buffer = 0,
#endif
.flags = {
.buff_dma = true,
.buff_spiram = false,
}
};
return bsp_display_start_with_config(&cfg);
}
lv_disp_t *bsp_display_start_with_config(const bsp_display_cfg_t *cfg)
{
assert(cfg != NULL);
BSP_ERROR_CHECK_RETURN_NULL(lvgl_port_init(&cfg->lvgl_port_cfg));
BSP_ERROR_CHECK_RETURN_NULL(bsp_display_brightness_init());
BSP_NULL_CHECK(disp = bsp_display_lcd_init(cfg), NULL);
BSP_NULL_CHECK(disp_indev = bsp_display_indev_init(disp), NULL);
return disp;
}
lv_indev_t *bsp_display_get_input_dev(void)
{
return disp_indev;
}
void bsp_display_rotate(lv_disp_t *disp, lv_disp_rot_t rotation)
{
lv_disp_set_rotation(disp, rotation);
}
bool bsp_display_lock(uint32_t timeout_ms)
{
return lvgl_port_lock(timeout_ms);
}
void bsp_display_unlock(void)
{
lvgl_port_unlock();
}
esp_err_t bsp_display_enter_sleep(void)
{
BSP_ERROR_CHECK_RETURN_ERR(bsp_lcd_enter_sleep());
BSP_ERROR_CHECK_RETURN_ERR(bsp_display_backlight_off());
BSP_ERROR_CHECK_RETURN_ERR(bsp_touch_enter_sleep());
return ESP_OK;
}
esp_err_t bsp_display_exit_sleep(void)
{
BSP_ERROR_CHECK_RETURN_ERR(bsp_lcd_exit_sleep());
BSP_ERROR_CHECK_RETURN_ERR(bsp_display_backlight_on());
BSP_ERROR_CHECK_RETURN_ERR(bsp_touch_exit_sleep());
return ESP_OK;
}
esp_err_t bsp_pwm_set_duty(uint8_t duty_percent)
{
if (duty_percent > 100) {
return ESP_ERR_INVALID_ARG; // 避免输入超出范围
}
// 计算实际占空比
uint32_t duty_value = (1024 * duty_percent) / 100; // 13位最大值 2^13-1 = 8191
ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL, duty_value);
ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL);
return ESP_OK;
}
esp_err_t bsp_pwm_init(void)
{
// 配置 LEDC 定时器
ledc_timer_config_t timer_conf = {
.speed_mode = LEDC_LOW_SPEED_MODE, // 低速模式80MHz / 分频)
.duty_resolution = PWM_RESOLUTION, // PWM 分辨率 (如 13 位)
.timer_num = LEDC_TIMER_0, // 使用定时器 0
.freq_hz = PWM_FREQ_HZ // PWM 频率 (如 5000 Hz)
};
ESP_ERROR_CHECK(ledc_timer_config(&timer_conf));
// 配置 LEDC 通道
ledc_channel_config_t channel_conf = {
.gpio_num = BSP_BEEP_PIN, // PWM 引脚
.speed_mode = LEDC_LOW_SPEED_MODE, // 低速模式
.channel = PWM_CHANNEL, // 通道 0
.timer_sel = LEDC_TIMER_0, // 选择定时器 0
.duty = 0, // 初始占空比为 0
.hpoint = 0, // 设置高电平起始点
};
ESP_ERROR_CHECK(ledc_channel_config(&channel_conf));
// 设置占空比并使能
ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL, 0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL);
return ESP_OK;
}
esp_err_t bsp_slave_reset(void)
{
gpio_config_t gpio_conf = {
.pin_bit_mask = ((1ULL<<BSP_RESET_SLAVE) | (1ULL<<BSP_CNT_5) | (1ULL<<BSP_CNT_6)),
.mode = GPIO_MODE_INPUT,
.pull_down_en = 0,
.pull_up_en = 0,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&gpio_conf);
return ESP_OK;
}
#else
#endif
void led_strip_task(void *arg)
{
while (rgb_task_started) {
if (rgb_led_handle->led_power) {
led_strip_set_pixel(led_strip, 0, rgb_led_handle->red, rgb_led_handle->green, rgb_led_handle->blue);
led_strip_refresh(led_strip);
} else {
led_strip_clear(led_strip);
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
esp_err_t bsp_led_init(void)
{
rgb_led_handle = calloc(1, sizeof(RGB_LED_Config));
ESP_LOGI(TAG, "configured to blink addressable LED!");
led_strip_config_t strip_config = {
.strip_gpio_num = BSP_LED_GPIO,
.max_leds = 1,
};
led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption
.resolution_hz = 10 * 1000 * 1000, // RMT counter clock frequency: 10MHz
.flags = {
.with_dma = false, // DMA feature is available on chips like ESP32-S3/P4
}
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
/* Set all LED off to clear all pixels */
led_strip_clear(led_strip);
rgb_task_started = true;
xTaskCreate(led_strip_task, "led_strip_task", 4096, NULL, 5, NULL);
ESP_LOGI(TAG, "led strip init");
return ESP_OK;
}
esp_err_t bsp_led_power_off(void)
{
rgb_led_handle->led_power = 0;
return ESP_OK;
}
esp_err_t bsp_led_set(uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
{
if (index == 0) {
rgb_led_handle->red = red;
rgb_led_handle->green = green;
rgb_led_handle->blue = blue;
rgb_led_handle->led_power = 1;
}
return ESP_OK;
}
esp_err_t bsp_led_deinit(void)
{
if (rgb_led_handle == NULL) {
ESP_LOGW(TAG, "led strip not init");
return ESP_OK;
}
rgb_task_started = false;
vTaskDelay(200 / portTICK_PERIOD_MS);
free(rgb_led_handle);
led_strip_clear(led_strip);
led_strip_del(led_strip);
ESP_LOGI(TAG, "led strip deinit");
return ESP_OK;
}

View File

@@ -0,0 +1,22 @@
targets:
- esp32c5
tags:
- bsp
dependencies:
idf: ">=4.4.5"
esp_lcd_touch_cst816s: "^1"
lvgl/lvgl: "^8"
espressif/esp_lcd_gc9a01: ^2.0.1
espressif/esp_lcd_touch: ^1.1.2
espressif/esp_lvgl_port:
version: "^2"
public: true
button:
version: ">=2.5"
public: true
espressif/led_strip: "^2.5.3"

View File

@@ -0,0 +1,283 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP BSP: ESP-Magnescreen
*/
#pragma once
#include "sdkconfig.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "lvgl.h"
#include "esp_lvgl_port.h"
#include "iot_button.h"
#include "display.h"
#include "soc/uart_pins.h"
#define MASTER_CHIP 1
#define SLAVE_CHIP 0
#define Self_Transmit_and_Receive_Mode 1
#define Single_Transmit_and_Dual_Receive_Mode 0
#if CHIP_ID == MASTER_CHIP
/* Display */
#define BSP_LCD_DATA0 (GPIO_NUM_6)
#define BSP_LCD_PCLK (GPIO_NUM_5)
#define BSP_LCD_CS (GPIO_NUM_NC)
#define BSP_LCD_DC (GPIO_NUM_4)
#define BSP_LCD_RST (GPIO_NUM_7)
#define LCD_BACKLIGHT_CHANNEL LEDC_CHANNEL_1
#define BSP_LCD_BACKLIGHT (GPIO_NUM_3)
#define BSP_LCD_TOUCH_INT (GPIO_NUM_10)
#define BSP_I2C_SCL (GPIO_NUM_8)
#define BSP_I2C_SDA (GPIO_NUM_9)
/* Buttons */
#define BSP_BUTTON (GPIO_NUM_1)
/* Beep */
#define BSP_BEEP_PIN (GPIO_NUM_0)
#define PWM_CHANNEL LEDC_CHANNEL_0
#define PWM_FREQ_HZ 2731
#define PWM_RESOLUTION LEDC_TIMER_10_BIT
/* LED */
#define BSP_LED_GPIO (GPIO_NUM_2)
/* connect */
#define BSP_RESET_SLAVE (GPIO_NUM_23)
#define BSP_CNT_1 (GPIO_NUM_24)
#define BSP_CNT_2 (GPIO_NUM_25)
#define BSP_CNT_3 (GPIO_NUM_26)
#define BSP_CNT_4 (GPIO_NUM_27)
#define BSP_CNT_5 (GPIO_NUM_10)
#define BSP_CNT_6 (GPIO_NUM_11)
#else
#define BSP_LED_GPIO (GPIO_NUM_10)
#define PIN_NUM_MISO GPIO_NUM_7
#define PIN_NUM_MOSI GPIO_NUM_5
#define PIN_NUM_CLK GPIO_NUM_6
#define PIN_NUM_CS GPIO_NUM_2
#endif
/* Buttons */
typedef enum {
BSP_BUTTON_POWER = 0,
BSP_BUTTON_NUM
} bsp_button_t;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief BSP display configuration structure
*
*/
typedef struct {
lvgl_port_cfg_t lvgl_port_cfg; /*!< LVGL port configuration */
uint32_t buffer_size; /*!< Size of the buffer for the screen in pixels */
bool double_buffer; /*!< True, if should be allocated two buffers */
struct {
unsigned int buff_dma: 1; /*!< Allocated LVGL buffer will be DMA capable */
unsigned int buff_spiram: 1; /*!< Allocated LVGL buffer will be in PSRAM */
} flags;
} bsp_display_cfg_t;
typedef struct {
uint32_t red; // 红色值
uint32_t green; // 绿色值
uint32_t blue; // 蓝色值
bool led_power; // LED 电源开关状态
} RGB_LED_Config;
/**************************************************************************************************
*
* I2C interface
*
* There are multiple devices connected to I2C peripheral:
* - Codec ES8311 (configuration only)
* - ADC ES7210 (configuration only)
* - Encryption chip ATECC608A (NOT populated on most boards)
* - LCD Touch controller
* - Inertial Measurement Unit ICM-42607-P
*
* After initialization of I2C, use BSP_I2C_NUM macro when creating I2C devices drivers ie.:
* \code{.c}
* icm42670_handle_t imu = icm42670_create(BSP_I2C_NUM, ICM42670_I2C_ADDRESS);
* \endcode
**************************************************************************************************/
#define BSP_I2C_NUM CONFIG_BSP_I2C_NUM
/**
* @brief Init I2C driver
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG I2C parameter error
* - ESP_FAIL I2C driver installation error
*
*/
esp_err_t bsp_i2c_init(void);
/**
* @brief Deinit I2C driver and free its resources
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG I2C parameter error
*
*/
esp_err_t bsp_i2c_deinit(void);
/**************************************************************************************************
*
* SPIFFS
*
* After mounting the SPIFFS, it can be accessed with stdio functions ie.:
* \code{.c}
* FILE* f = fopen(BSP_SPIFFS_MOUNT_POINT"/hello.txt", "w");
* fprintf(f, "Hello World!\n");
* fclose(f);
* \endcode
**************************************************************************************************/
#define BSP_SPIFFS_MOUNT_POINT CONFIG_BSP_SPIFFS_MOUNT_POINT
/**
* @brief Mount SPIFFS to virtual file system
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_spiffs_register was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes
*/
esp_err_t bsp_spiffs_mount(void);
/**
* @brief Unmount SPIFFS from virtual file system
*
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_FOUND if the partition table does not contain SPIFFS partition with given label
* - ESP_ERR_INVALID_STATE if esp_vfs_spiffs_unregister was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes
*/
esp_err_t bsp_spiffs_unmount(void);
/**************************************************************************************************
*
* LCD interface
*
* ESP-BOX is shipped with 2.4inch ST7789 display controller.
* It features 16-bit colors, 320x240 resolution and capacitive touch controller.
*
* LVGL is used as graphics library. LVGL is NOT thread safe, therefore the user must take LVGL mutex
* by calling bsp_display_lock() before calling and LVGL API (lv_...) and then give the mutex with
* bsp_display_unlock().
*
* Display's backlight must be enabled explicitly by calling bsp_display_backlight_on()
**************************************************************************************************/
#define BSP_LCD_PIXEL_CLOCK_HZ (40 * 1000 * 1000)
#define BSP_LCD_SPI_NUM (SPI2_HOST)
/**
* @brief Initialize display
*
* This function initializes SPI, display controller and starts LVGL handling task.
* LCD backlight must be enabled separately by calling bsp_display_brightness_set()
*
* @return Pointer to LVGL display or NULL when error occurred
*/
lv_disp_t *bsp_display_start(void);
/**
* @brief Initialize display
*
* This function initializes SPI, display controller and starts LVGL handling task.
* LCD backlight must be enabled separately by calling bsp_display_brightness_set()
*
* @param cfg display configuration
*
* @return Pointer to LVGL display or NULL when error occurred
*/
lv_disp_t *bsp_display_start_with_config(const bsp_display_cfg_t *cfg);
esp_err_t bsp_display_brightness_set(int brightness_percent);
/**
* @brief Get pointer to input device (touch, buttons, ...)
*
* @note The LVGL input device is initialized in bsp_display_start() function.
*
* @return Pointer to LVGL input device or NULL when not initialized
*/
lv_indev_t *bsp_display_get_input_dev(void);
/**
* @brief Take LVGL mutex
*
* @param timeout_ms Timeout in [ms]. 0 will block indefinitely.
* @return true Mutex was taken
* @return false Mutex was NOT taken
*/
bool bsp_display_lock(uint32_t timeout_ms);
/**
* @brief Give LVGL mutex
*
*/
void bsp_display_unlock(void);
/**
* @brief Set display enter sleep mode
*
* All the display (LCD, backlight, touch) will enter sleep mode.
*
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_SUPPORTED if this function is not supported by the panel
*/
esp_err_t bsp_display_enter_sleep(void);
/**
* @brief Set display exit sleep mode
*
* All the display (LCD, backlight, touch) will exit sleep mode.
*
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_SUPPORTED if this function is not supported by the panel
*/
esp_err_t bsp_display_exit_sleep(void);
/**
* @brief Rotate screen
*
* Display must be already initialized by calling bsp_display_start()
*
* @param[in] disp Pointer to LVGL display
* @param[in] rotation Angle of the display rotation
*/
void bsp_display_rotate(lv_disp_t *disp, lv_disp_rot_t rotation);
esp_err_t bsp_pwm_init(void);
esp_err_t bsp_pwm_set_duty(uint8_t duty_percent);
esp_err_t bsp_led_init(void);
esp_err_t bsp_led_power_off(void);
esp_err_t bsp_led_set(uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
esp_err_t bsp_led_deinit(void);
esp_err_t bsp_slave_reset(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,110 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief BSP LCD
*
* This file offers API for basic LCD control.
* It is useful for users who want to use the LCD without the default Graphical Library LVGL.
*
* For standard LCD initialization with LVGL graphical library, you can call all-in-one function bsp_display_start().
*/
#pragma once
#include "esp_lcd_types.h"
/* LCD color formats */
#define ESP_LCD_COLOR_FORMAT_RGB565 (1)
#define ESP_LCD_COLOR_FORMAT_RGB888 (2)
/* LCD display color format */
#define BSP_LCD_COLOR_FORMAT (ESP_LCD_COLOR_FORMAT_RGB565)
/* LCD display color bytes endianess */
#define BSP_LCD_BIGENDIAN (1)
/* LCD display color bits */
#define BSP_LCD_BITS_PER_PIXEL (16)
/* LCD display color space */
#define BSP_LCD_COLOR_SPACE (ESP_LCD_COLOR_SPACE_BGR)
/* LCD definition */
#define BSP_LCD_H_RES (240)
#define BSP_LCD_V_RES (240)
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief BSP display configuration structure
*
*/
typedef struct {
int max_transfer_sz; /*!< Maximum transfer size, in bytes. */
} bsp_display_config_t;
/**
* @brief Create new display panel
*
* For maximum flexibility, this function performs only reset and initialization of the display.
* You must turn on the display explicitly by calling esp_lcd_panel_disp_on_off().
* The display's backlight is not turned on either. You can use bsp_display_backlight_on/off(),
* bsp_display_brightness_set() (on supported boards) or implement your own backlight control.
*
* If you want to free resources allocated by this function, you can use esp_lcd API, ie.:
*
* \code{.c}
* esp_lcd_panel_del(panel);
* esp_lcd_panel_io_del(io);
* spi_bus_free(spi_num_from_configuration);
* \endcode
*
* @param[in] config display configuration
* @param[out] ret_panel esp_lcd panel handle
* @param[out] ret_io esp_lcd IO handle
* @return
* - ESP_OK On success
* - Else esp_lcd failure
*/
esp_err_t bsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_handle_t *ret_panel, esp_lcd_panel_io_handle_t *ret_io);
/**
* @brief Set display's brightness
*
* Brightness is controlled with PWM signal to a pin controlling backlight.
* Display must be already initialized by calling bsp_display_new()
*
* @param[in] brightness_percent Brightness in [%]
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t bsp_display_brightness_set(int brightness_percent);
/**
* @brief Turn on display backlight
*
* Display must be already initialized by calling bsp_display_new()
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t bsp_display_backlight_on(void);
/**
* @brief Turn off display backlight
*
* Display must be already initialized by calling bsp_display_new()
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t bsp_display_backlight_off(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "bsp/bsp_C5_dual_antenna.h"

View File

@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief BSP Touchscreen
*
* This file offers API for basic touchscreen initialization.
* It is useful for users who want to use the touchscreen without the default Graphical Library LVGL.
*
* For standard LCD initialization with LVGL graphical library, you can call all-in-one function bsp_display_start().
*/
#pragma once
#include "esp_lcd_touch.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief BSP touch configuration structure
*
*/
typedef struct {
void *dummy; /*!< Prepared for future use. */
} bsp_touch_config_t;
/**
* @brief Create new touchscreen
*
* If you want to free resources allocated by this function, you can use esp_lcd_touch API, ie.:
*
* \code{.c}
* esp_lcd_touch_del(tp);
* \endcode
*
* @param[in] config touch configuration
* @param[out] ret_touch esp_lcd_touch touchscreen handle
* @return
* - ESP_OK On success
* - Else esp_lcd_touch failure
*/
esp_err_t bsp_touch_new(const bsp_touch_config_t *config, esp_lcd_touch_handle_t *ret_touch);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_check.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Assert on error, if selected in menuconfig. Otherwise return error code. */
#if CONFIG_BSP_ERROR_CHECK
#define BSP_ERROR_CHECK_RETURN_ERR(x) ESP_ERROR_CHECK(x)
#define BSP_ERROR_CHECK_RETURN_NULL(x) ESP_ERROR_CHECK(x)
#define BSP_ERROR_CHECK(x, ret) ESP_ERROR_CHECK(x)
#define BSP_NULL_CHECK(x, ret) assert(x)
#define BSP_NULL_CHECK_GOTO(x, goto_tag) assert(x)
#else
#define BSP_ERROR_CHECK_RETURN_ERR(x) do { \
esp_err_t err_rc_ = (x); \
if (unlikely(err_rc_ != ESP_OK)) { \
return err_rc_; \
} \
} while(0)
#define BSP_ERROR_CHECK_RETURN_NULL(x) do { \
if (unlikely((x) != ESP_OK)) { \
return NULL; \
} \
} while(0)
#define BSP_NULL_CHECK(x, ret) do { \
if ((x) == NULL) { \
return ret; \
} \
} while(0)
#define BSP_ERROR_CHECK(x, ret) do { \
if (unlikely((x) != ESP_OK)) { \
return ret; \
} \
} while(0)
#define BSP_NULL_CHECK_GOTO(x, goto_tag) do { \
if ((x) == NULL) { \
goto goto_tag; \
} \
} while(0)
#endif
#ifdef __cplusplus
}
#endif