diff --git a/.build-test-rules.yml b/.build-test-rules.yml index 157a268e..49a6f505 100644 --- a/.build-test-rules.yml +++ b/.build-test-rules.yml @@ -1,6 +1,6 @@ examples: disable: - - if: IDF_VERSION_MAJOR < 5 and CONFIG_NAME in ["esp32_c3_lcdkit", "esp32_s3_lcd_ev_board", "esp32_s3_usb_otg", "m5stack_core_s3"] + - if: IDF_VERSION_MAJOR < 5 and CONFIG_NAME in ["esp32_c3_lcdkit", "esp32_s3_lcd_ev_board", "esp32_s3_usb_otg", "m5stack_core_s3", "m5dial"] reason: Example depends on BSP, which is supported only for IDF >= 5.0 - if: IDF_VERSION_MAJOR < 5 and IDF_TARGET in ["esp32c2", "esp32p4", "esp32c5", "esp32c6"] reason: Example depends on target, which is supported only for IDF >= 5.0 diff --git a/.github/workflows/upload_component.yml b/.github/workflows/upload_component.yml index 3ccaf8c9..f52ddd01 100644 --- a/.github/workflows/upload_component.yml +++ b/.github/workflows/upload_component.yml @@ -17,7 +17,7 @@ jobs: uses: espressif/upload-components-ci-action@v1 with: directories: > - bsp/esp32_azure_iot_kit;bsp/esp32_s2_kaluga_kit;bsp/esp_wrover_kit;bsp/esp-box;bsp/esp32_s3_usb_otg;bsp/esp32_s3_eye;bsp/esp32_s3_lcd_ev_board;bsp/esp32_s3_korvo_2;bsp/esp-box-lite;bsp/esp32_lyrat;bsp/esp32_c3_lcdkit;bsp/esp-box-3;bsp/esp_bsp_generic;bsp/esp32_s3_korvo_1;bsp/esp32_p4_function_ev_board;bsp/m5stack_core_s3; + bsp/esp32_azure_iot_kit;bsp/esp32_s2_kaluga_kit;bsp/esp_wrover_kit;bsp/esp-box;bsp/esp32_s3_usb_otg;bsp/esp32_s3_eye;bsp/esp32_s3_lcd_ev_board;bsp/esp32_s3_korvo_2;bsp/esp-box-lite;bsp/esp32_lyrat;bsp/esp32_c3_lcdkit;bsp/esp-box-3;bsp/esp_bsp_generic;bsp/esp32_s3_korvo_1;bsp/esp32_p4_function_ev_board;bsp/m5stack_core_s3;bsp/m5dial; components/bh1750;components/ds18b20;components/es8311;components/es7210;components/fbm320;components/hts221;components/mag3110;components/mpu6050;components/esp_lvgl_port;components/icm42670; components/lcd_touch/esp_lcd_touch;components/lcd_touch/esp_lcd_touch_ft5x06;components/lcd_touch/esp_lcd_touch_gt911;components/lcd_touch/esp_lcd_touch_tt21100;components/lcd_touch/esp_lcd_touch_gt1151;components/lcd_touch/esp_lcd_touch_cst816s; components/lcd/esp_lcd_gc9a01;components/lcd/esp_lcd_ili9341;components/lcd/esp_lcd_ra8875;components/lcd_touch/esp_lcd_touch_stmpe610;components/lcd/esp_lcd_sh1107;components/lcd/esp_lcd_st7796;components/lcd/esp_lcd_gc9503;components/lcd/esp_lcd_ssd1681;components/lcd/esp_lcd_ili9881c; diff --git a/.github/workflows/upload_component_noglib.yml b/.github/workflows/upload_component_noglib.yml index 5a5fd7eb..428d6d8c 100644 --- a/.github/workflows/upload_component_noglib.yml +++ b/.github/workflows/upload_component_noglib.yml @@ -16,7 +16,7 @@ jobs: - name: Upload noglib version of BSPs # TODO: Extend this part to all BSPs env: - BSPs: "bsp/esp32_s3_eye bsp/esp32_p4_function_ev_board bsp/m5stack_core_s3" + BSPs: "bsp/esp32_s3_eye bsp/esp32_p4_function_ev_board bsp/m5stack_core_s3 bsp/m5dial" run: | pip install idf-component-manager py-markdown-table --upgrade python .github/ci/bsp_noglib.py ${BSPs} @@ -26,6 +26,7 @@ jobs: bsp/esp32_s3_eye_noglib; bsp/esp32_p4_function_ev_board_noglib; bsp/m5stack_core_s3_noglib; + bsp/m5dial_noglib; namespace: "espressif" api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }} dry_run: ${{ github.ref_name != 'master' || github.repository_owner != 'espressif' }} diff --git a/README.md b/README.md index f3e3c222..744c91a3 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Board support packages for development boards using Espressif's SoCs, written in | [ESP-BOX-3](bsp/esp-box-3) | ESP32-S3 | LCD display with touch, audio codec + power amplifier,
accelerometer and gyroscope | | | [ESP32-S3-KORVO-1](bsp/esp32_s3_korvo_1) | ESP32-S3 | uSD card slot, microphone, audio codec + power amplifier, RGB led strip | | | [M5Stack CoreS3](bsp/m5stack_core_s3) | ESP32-S3 | LCD display with touch, uSD card slot, microphone, audio codec | | +| [M5Dial](bsp/m5dial) | ESP32-S3 | LCD display with touch and encoder | | ## LCD displays and TOUCH | [LVGL port](components/esp_lvgl_port) | [LCD drivers](LCD.md) | @@ -53,7 +54,7 @@ Best way to start with ESP-BSP is trying one of the [examples](examples) on your * `bsp/name-of-the-bsp.h`: Main include file of the BSP with public API * `bsp/esp-bsp.h`: Convenience include file with the same name for all BPSs * `bsp/display.h` and `bsp/touch.h`: Only for BSPs with LCD or touch controller. Contain low level initialization functions for usage without LVGL graphical library - * By default, BSPs with display are shipped with LVGL, if you are interested in BSP without LVGL you can use BSP versions with `noglib` suffix (eg. `esp32_s3_eye_noglib`). + * By default, BSPs with display are shipped with LVGL, if you are interested in BSP without LVGL you can use BSP versions with `noglib` suffix (eg. `esp32_s3_eye_noglib`). > **_NOTE:_** There can be only one BSP in a single esp-idf project. diff --git a/SquareLine/boards/v9/m5dial/image.png b/SquareLine/boards/v9/m5dial/image.png new file mode 100644 index 00000000..32875ab2 Binary files /dev/null and b/SquareLine/boards/v9/m5dial/image.png differ diff --git a/SquareLine/boards/v9/m5dial/main/idf_component.yml b/SquareLine/boards/v9/m5dial/main/idf_component.yml new file mode 100644 index 00000000..9884ff05 --- /dev/null +++ b/SquareLine/boards/v9/m5dial/main/idf_component.yml @@ -0,0 +1,6 @@ +description: ESP-BSP SquareLine LVGL Example +targets: + - esp32s3 +dependencies: + idf: ">=5.0" + m5dial: "*" diff --git a/SquareLine/boards/v9/m5dial/manifest.json b/SquareLine/boards/v9/m5dial/manifest.json new file mode 100644 index 00000000..48a6c0cc --- /dev/null +++ b/SquareLine/boards/v9/m5dial/manifest.json @@ -0,0 +1,20 @@ +{ + "name":"M5Dial", + "version":"1.0.0", + "mcu":"ESP32S3", + + "screen_width":"240", + "screen_height":"240", + "screen_color_swap":true, + + "supported_lvgl_version":"9.1.*", + + "short_description":"As a versatile embedded development board, M5Dial integrates the necessary features and sensors for various smart home control applications. It features a 1.28-inch round TFT touchscreen, a rotary encoder, an RFID detection module, an RTC circuit, a buzzer, and under-screen buttons, enabling users to easily implement a wide range of creative projects.", + "long_description":"As a versatile embedded development board, M5Dial integrates the necessary features and sensors for various smart home control applications. It features a 1.28-inch round TFT touchscreen, a rotary encoder, an RFID detection module, an RTC circuit, a buzzer, and under-screen buttons, enabling users to easily implement a wide range of creative projects.", + + "placeholders": + { + "__ESP_BOARD_INCLUDE__": "bsp/esp-bsp.h", + "__ESP_BOARD_I2C_INIT__": "/* Initialize I2C (for touch and audio) */\n bsp_i2c_init();" + } +} diff --git a/SquareLine/boards/v9/m5dial/partitions.csv b/SquareLine/boards/v9/m5dial/partitions.csv new file mode 100644 index 00000000..7c211a41 --- /dev/null +++ b/SquareLine/boards/v9/m5dial/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 8M, diff --git a/SquareLine/boards/v9/m5dial/sdkconfig.defaults b/SquareLine/boards/v9/m5dial/sdkconfig.defaults new file mode 100644 index 00000000..6071db68 --- /dev/null +++ b/SquareLine/boards/v9/m5dial/sdkconfig.defaults @@ -0,0 +1,11 @@ +# 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="esp32s3" +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_LV_COLOR_16_SWAP=y +CONFIG_LV_MEM_CUSTOM=y +CONFIG_LV_MEMCPY_MEMSET_STD=y +CONFIG_LV_USE_PERF_MONITOR=y diff --git a/bsp/m5dial/CMakeLists.txt b/bsp/m5dial/CMakeLists.txt new file mode 100644 index 00000000..758a3f46 --- /dev/null +++ b/bsp/m5dial/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register( + SRCS "m5dial.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "priv_include" + REQUIRES driver spiffs + PRIV_REQUIRES fatfs esp_lcd +) diff --git a/bsp/m5dial/Kconfig b/bsp/m5dial/Kconfig new file mode 100644 index 00000000..cf9c5a32 --- /dev/null +++ b/bsp/m5dial/Kconfig @@ -0,0 +1,65 @@ +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 1 + range 0 1 + help + ESP32S3 has two I2C peripherals, pick the one you want to use. + + config BSP_I2C_FAST_MODE + bool "Enable I2C fast mode" + default n + 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 "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. + endmenu + +endmenu diff --git a/bsp/m5dial/LICENSE b/bsp/m5dial/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/bsp/m5dial/LICENSE @@ -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. diff --git a/bsp/m5dial/README.md b/bsp/m5dial/README.md new file mode 100644 index 00000000..9037cb38 --- /dev/null +++ b/bsp/m5dial/README.md @@ -0,0 +1,35 @@ +# BSP: M5SDial + +[![Component Registry](https://components.espressif.com/components/espressif/m5dial/badge.svg)](https://components.espressif.com/components/espressif/m5dial ) + +* [Hardware Reference](https://docs.m5stack.com/en/core/M5Dial) + +![image](pic.webp) + +As a versatile embedded development board, M5Dial integrates the necessary features and sensors for various smart home control applications. It features a 1.28-inch round TFT touchscreen, a rotary encoder, an RFID detection module, an RTC circuit, a buzzer, and under-screen buttons, enabling users to easily implement a wide range of creative projects. + +The main controller of M5Dial is M5StampS3, a micro module based on the ESP32-S3 chip known for its high performance and low power consumption. It supports Wi-Fi, as well as various peripheral interfaces such as SPI, I2C, UART, ADC, and more. M5StampS3 also comes with 8MB of built-in Flash, providing sufficient storage space for users. + +The standout feature of M5Dial is its rotary encoder, which accurately records the position and direction of the knob, delivering a better interactive experience. Users can adjust settings such as volume, brightness, and menu options using the knob, or control home applications like lights, air conditioning, and curtains. The device's built-in display screen allows for displaying different interaction colors and effects. + +With its compact size and lightweight design, M5Dial is suitable for various embedded applications. Whether it's controlling home devices in the smart home domain or monitoring and controlling systems in industrial automation, M5Dial can be easily integrated to provide intelligent control and interaction capabilities. + +M5Dial also features RFID detection, enabling the recognition of RFID cards and tags operating at 13.56MHz. Users can utilize this function for applications such as access control, identity verification, and payments.Furthermore, M5Dial is equipped with an RTC circuit to maintain accurate time and date. Additionally, it includes an onboard buzzer and a physical button for device sound prompts and wake-up operations. + +M5Dial provides versatile power supply options to cater to various needs. It accommodates a wide range of input voltages, accepting 6-36V DC input. Additionally, it features a battery port with a built-in charging circuit, enabling seamless connection to external Lithium batteries. This adaptability allows users to power M5Dial via USB-C, the DC interface, or an external battery for on-the-go convenience. M5Dial also reserves two PORTA and PORTB interfaces, supporting the expansion of I2C and GPIO devices. Users can connect various sensors, actuators, displays, and other peripherals through these interfaces, adding more functionality and possibilities. + + +### Capabilities and dependencies +| Capability | Available | Component | Version| +|-------------|------------------|------------------------------------------------------------------------------------------------------------|--------| +| DISPLAY |:heavy_check_mark:| [espressif/esp_lcd_gc9a01](https://components.espressif.com/components/espressif/esp_lcd_gc9a01) | ^1 | +| LVGL_PORT |:heavy_check_mark:| [espressif/esp_lvgl_port](https://components.espressif.com/components/espressif/esp_lvgl_port) | ^2 | +| TOUCH |:heavy_check_mark:|[espressif/esp_lcd_touch_ft5x06](https://components.espressif.com/components/espressif/esp_lcd_touch_ft5x06)| ^1 | +| BUTTONS |:heavy_check_mark:| [espressif/button](https://components.espressif.com/components/espressif/button) |>=2,<4.0| +| KNOB |:heavy_check_mark:| [espressif/knob](https://components.espressif.com/components/espressif/knob) | ^0.1.3 | +| AUDIO | :x: | | | +|AUDIO_SPEAKER| :x: | | | +| AUDIO_MIC | :x: | | | +| SDCARD | :x: | | | +| IMU | :x: | | | + diff --git a/bsp/m5dial/idf_component.yml b/bsp/m5dial/idf_component.yml new file mode 100644 index 00000000..5228b775 --- /dev/null +++ b/bsp/m5dial/idf_component.yml @@ -0,0 +1,26 @@ +version: "1.0.0" +description: Board Support Package (BSP) for M5Dial +url: https://github.com/espressif/esp-bsp/tree/master/bsp/m5dial + +targets: + - esp32s3 + +tags: + - bsp + +dependencies: + idf: ">=5.0" + esp_lcd_gc9a01: "^1" + esp_lcd_touch_ft5x06: "^1" + + espressif/esp_lvgl_port: + version: "^2" + public: true + + button: + public: true + version: ">=2,<4.0" + + knob: + version: "^0.1.3" + public: true diff --git a/bsp/m5dial/include/bsp/config.h b/bsp/m5dial/include/bsp/config.h new file mode 100644 index 00000000..f3cb5ebe --- /dev/null +++ b/bsp/m5dial/include/bsp/config.h @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/************************************************************************************************** + * BSP configuration + **************************************************************************************************/ +// By default, this BSP is shipped with LVGL graphical library. Enabling this option will exclude it. +// If you want to use BSP without LVGL, select BSP version with 'noglib' suffix. +#if !defined(BSP_CONFIG_NO_GRAPHIC_LIB) // Check if the symbol is not coming from compiler definitions (-D...) +#define BSP_CONFIG_NO_GRAPHIC_LIB (0) +#endif diff --git a/bsp/m5dial/include/bsp/display.h b/bsp/m5dial/include/bsp/display.h new file mode 100644 index 00000000..3429108e --- /dev/null +++ b/bsp/m5dial/include/bsp/display.h @@ -0,0 +1,123 @@ +/* + * SPDX-FileCopyrightText: 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 Initialize display's brightness + * + * Brightness is controlled with PWM signal to a pin controlling backlight. + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t bsp_display_brightness_init(void); + +/** + * @brief Set display's brightness + * + * Brightness is controlled with PWM signal to a pin controlling backlight. + * Brightness must be already initialized by calling bsp_display_brightness_init() or 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 + * + * Brightness is controlled with PWM signal to a pin controlling backlight. + * Brightness must be already initialized by calling bsp_display_brightness_init() or 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 + * + * Brightness is controlled with PWM signal to a pin controlling backlight. + * Brightness must be already initialized by calling bsp_display_brightness_init() or 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 diff --git a/bsp/m5dial/include/bsp/esp-bsp.h b/bsp/m5dial/include/bsp/esp-bsp.h new file mode 100644 index 00000000..1cb9dac4 --- /dev/null +++ b/bsp/m5dial/include/bsp/esp-bsp.h @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include "bsp/m5dial.h" diff --git a/bsp/m5dial/include/bsp/m5dial.h b/bsp/m5dial/include/bsp/m5dial.h new file mode 100644 index 00000000..476f181b --- /dev/null +++ b/bsp/m5dial/include/bsp/m5dial.h @@ -0,0 +1,229 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ESP BSP: M5Dial + */ + +#pragma once + +#include "sdkconfig.h" +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "bsp/config.h" +#include "bsp/display.h" + +#if (BSP_CONFIG_NO_GRAPHIC_LIB == 0) +#include "lvgl.h" +#include "esp_lvgl_port.h" +#endif // BSP_CONFIG_NO_GRAPHIC_LIB == 0 + +/************************************************************************************************** + * BSP Capabilities + **************************************************************************************************/ + +#define BSP_CAPS_DISPLAY 1 +#define BSP_CAPS_TOUCH 1 +#define BSP_CAPS_BUTTONS 1 +#define BSP_CAPS_KNOB 1 +#define BSP_CAPS_AUDIO 0 +#define BSP_CAPS_AUDIO_SPEAKER 0 +#define BSP_CAPS_AUDIO_MIC 0 +#define BSP_CAPS_SDCARD 0 +#define BSP_CAPS_IMU 0 + +/************************************************************************************************** + * M5Dial pinout + **************************************************************************************************/ +/* I2C */ +#define BSP_I2C_SCL (GPIO_NUM_12) +#define BSP_I2C_SDA (GPIO_NUM_11) + +/* Encoder */ +#define BSP_ENCODER_A (GPIO_NUM_41) +#define BSP_ENCODER_B (GPIO_NUM_40) + +/* Display */ +#define BSP_LCD_MOSI (GPIO_NUM_5) +#define BSP_LCD_MISO (GPIO_NUM_NC) +#define BSP_LCD_PCLK (GPIO_NUM_6) +#define BSP_LCD_CS (GPIO_NUM_7) +#define BSP_LCD_DC (GPIO_NUM_4) +#define BSP_LCD_RST (GPIO_NUM_8) +#define BSP_LCD_BACKLIGHT (GPIO_NUM_9) +#define BSP_LCD_TOUCH_INT (GPIO_NUM_14) + +/* Buttons */ +typedef enum { + BSP_BTN_PRESS = GPIO_NUM_42, +} bsp_button_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + * + * I2C interface + * + * There are multiple devices connected to I2C peripheral: + * - LCD Touch controller + **************************************************************************************************/ +#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 + * + * M5Dial is shipped with 1.28inch GC9A01 round display controller. + * It features 16-bit colors, 240x240 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 (SPI3_HOST) + + +#if (BSP_CONFIG_NO_GRAPHIC_LIB == 0) +#define BSP_LCD_DRAW_BUFF_SIZE (BSP_LCD_H_RES * 50) +#define BSP_LCD_DRAW_BUFF_DOUBLE (1) + +/** + * @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; +/** + * @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 occured + */ +lv_display_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 occured + */ +lv_display_t *bsp_display_start_with_config(const bsp_display_cfg_t *cfg); + +/** + * @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 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_display_t *disp, lv_display_rotation_t rotation); +#endif // BSP_CONFIG_NO_GRAPHIC_LIB == 0 + +#ifdef __cplusplus +} +#endif diff --git a/bsp/m5dial/include/bsp/touch.h b/bsp/m5dial/include/bsp/touch.h new file mode 100644 index 00000000..095e8ce1 --- /dev/null +++ b/bsp/m5dial/include/bsp/touch.h @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2024 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 diff --git a/bsp/m5dial/m5dial.c b/bsp/m5dial/m5dial.c new file mode 100644 index 00000000..fe4820ff --- /dev/null +++ b/bsp/m5dial/m5dial.c @@ -0,0 +1,381 @@ +/* + * SPDX-FileCopyrightText: 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 "driver/i2c.h" + +#include "bsp/m5dial.h" +#include "bsp/display.h" +#include "bsp/touch.h" +#include "iot_knob.h" +#include "esp_lcd_gc9a01.h" +#include "esp_lcd_touch_ft5x06.h" +#include "esp_lvgl_port.h" +#include "bsp_err_check.h" + +static const char *TAG = "M5Dial"; + +#if (BSP_CONFIG_NO_GRAPHIC_LIB == 0) +static lv_display_t *disp; +static lv_indev_t *disp_indev_touch = NULL; +static lv_indev_t *disp_indev_enc = NULL; +#endif // BSP_CONFIG_NO_GRAPHIC_LIB == 0 +static esp_lcd_touch_handle_t tp; // LCD touch handle +static bool i2c_initialized = false; +static bool spi_initialized = false; + +static const button_config_t bsp_encoder_btn_config = { + .type = BUTTON_TYPE_GPIO, + .gpio_button_config.active_level = false, + .gpio_button_config.gpio_num = BSP_BTN_PRESS, +}; + +static const knob_config_t bsp_encoder_a_b_config = { + .default_direction = 0, + .gpio_encoder_a = BSP_ENCODER_A, + .gpio_encoder_b = BSP_ENCODER_B, +}; + +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; +} + +static esp_err_t bsp_spi_init(uint32_t max_transfer_sz) +{ + /* SPI was initialized before */ + if (spi_initialized) { + return ESP_OK; + } + + ESP_LOGD(TAG, "Initialize SPI bus"); + const spi_bus_config_t buscfg = { + .sclk_io_num = BSP_LCD_PCLK, + .mosi_io_num = BSP_LCD_MOSI, + .miso_io_num = BSP_LCD_MISO, + .quadwp_io_num = GPIO_NUM_NC, + .quadhd_io_num = GPIO_NUM_NC, + .max_transfer_sz = max_transfer_sz, + }; + ESP_RETURN_ON_ERROR(spi_bus_initialize(BSP_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed"); + + spi_initialized = true; + + 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 + +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_LEDC_CH, + .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 < 0) { + brightness_percent = 0; + } + + ESP_LOGI(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); +} + +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); + + /* Initialize SPI */ + ESP_RETURN_ON_ERROR(bsp_spi_init(config->max_transfer_sz), TAG, ""); + + 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_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)BSP_LCD_SPI_NUM, &io_config, ret_io), err, TAG, "New panel IO failed"); + + ESP_LOGD(TAG, "Install LCD driver"); + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = BSP_LCD_RST, // Shared with Touch reset + .color_space = BSP_LCD_COLOR_SPACE, + .bits_per_pixel = BSP_LCD_BITS_PER_PIXEL, + }; + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_gc9a01(*ret_io, &panel_config, ret_panel), err, TAG, "New panel failed"); + + esp_lcd_panel_reset(*ret_panel); + esp_lcd_panel_init(*ret_panel); + esp_lcd_panel_invert_color(*ret_panel, true); + return ret; + +err: + if (*ret_panel) { + esp_lcd_panel_del(*ret_panel); + } + if (*ret_io) { + esp_lcd_panel_io_del(*ret_io); + } + spi_bus_free(BSP_LCD_SPI_NUM); + return ret; +} + +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 */ + const 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, + }, + }; + esp_lcd_panel_io_handle_t tp_io_handle = NULL; + const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG(); + 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, ""); + return esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, ret_touch); +} + +#if (BSP_CONFIG_NO_GRAPHIC_LIB == 0) +static lv_display_t *bsp_display_lcd_init(const bsp_display_cfg_t *cfg) +{ + assert(cfg != NULL); + esp_lcd_panel_io_handle_t io_handle = NULL; + esp_lcd_panel_handle_t panel_handle = NULL; + const bsp_display_config_t bsp_disp_cfg = { + .max_transfer_sz = BSP_LCD_DRAW_BUFF_SIZE * 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, +#if LVGL_VERSION_MAJOR >= 9 + .swap_bytes = (BSP_LCD_BIGENDIAN ? true : false), +#endif + } + }; + + return lvgl_port_add_disp(&disp_cfg); +} + +static lv_indev_t *bsp_display_indev_encoder_init(lv_display_t *disp) +{ + const lvgl_port_encoder_cfg_t encoder = { + .disp = disp, + .encoder_a_b = &bsp_encoder_a_b_config, + .encoder_enter = &bsp_encoder_btn_config + }; + + return lvgl_port_add_encoder(&encoder); +} + +static lv_indev_t *bsp_display_indev_touch_init(lv_display_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_display_t *bsp_display_start(void) +{ + bsp_display_cfg_t cfg = { + .lvgl_port_cfg = ESP_LVGL_PORT_INIT_CONFIG(), + .buffer_size = BSP_LCD_DRAW_BUFF_SIZE, + .double_buffer = BSP_LCD_DRAW_BUFF_DOUBLE, + .flags = { + .buff_dma = true, + .buff_spiram = false, + } + }; + return bsp_display_start_with_config(&cfg); +} + +lv_display_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_touch = bsp_display_indev_touch_init(disp), NULL); + BSP_NULL_CHECK(disp_indev_enc = bsp_display_indev_encoder_init(disp), NULL); + + return disp; +} + +lv_indev_t *bsp_display_get_input_dev(void) +{ + return disp_indev_enc; +} + +void bsp_display_rotate(lv_display_t *disp, lv_display_rotation_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(); +} +#endif // (BSP_CONFIG_NO_GRAPHIC_LIB == 0) diff --git a/bsp/m5dial/pic.webp b/bsp/m5dial/pic.webp new file mode 100644 index 00000000..81241764 Binary files /dev/null and b/bsp/m5dial/pic.webp differ diff --git a/bsp/m5dial/priv_include/bsp_err_check.h b/bsp/m5dial/priv_include/bsp_err_check.h new file mode 100644 index 00000000..cf2f36eb --- /dev/null +++ b/bsp/m5dial/priv_include/bsp_err_check.h @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2024 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 diff --git a/docu/pics/m5dial.webp b/docu/pics/m5dial.webp new file mode 100644 index 00000000..6dc6de72 Binary files /dev/null and b/docu/pics/m5dial.webp differ diff --git a/examples/bsp_ext.py b/examples/bsp_ext.py index f1be4fbf..1ed1b2c9 100644 --- a/examples/bsp_ext.py +++ b/examples/bsp_ext.py @@ -58,7 +58,8 @@ def set_bsp_callback(action: str, ctx: Context, args: PropertyDict, **kwargs: st 'esp_bsp_generic', 'esp32_s3_korvo_1', 'esp32_p4_function_ev_board', - 'm5stack_core_s3' + 'm5stack_core_s3', + 'm5dial' } if bsp == '': diff --git a/examples/display/sdkconfig.bsp.m5dial b/examples/display/sdkconfig.bsp.m5dial new file mode 100644 index 00000000..08ebacc7 --- /dev/null +++ b/examples/display/sdkconfig.bsp.m5dial @@ -0,0 +1,25 @@ +# 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="esp32s3" +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y + +## LVGL8 ## +CONFIG_LV_USE_PERF_MONITOR=y +CONFIG_LV_COLOR_16_SWAP=y +CONFIG_LV_MEM_CUSTOM=y +CONFIG_LV_MEMCPY_MEMSET_STD=y + +## LVGL9 ## +CONFIG_LV_CONF_SKIP=y + +#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 diff --git a/examples/display_lvgl_demos/sdkconfig.bsp.m5dial b/examples/display_lvgl_demos/sdkconfig.bsp.m5dial new file mode 100644 index 00000000..c4b5d537 --- /dev/null +++ b/examples/display_lvgl_demos/sdkconfig.bsp.m5dial @@ -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="esp32s3" +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_COMPILER_OPTIMIZATION_PERF=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_FREERTOS_HZ=1000 +CONFIG_LV_MEM_SIZE_KILOBYTES=48 +CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y +CONFIG_LV_FONT_MONTSERRAT_12=y +CONFIG_LV_FONT_MONTSERRAT_16=y +CONFIG_LV_USE_DEMO_WIDGETS=y +CONFIG_LV_USE_DEMO_BENCHMARK=y +CONFIG_LV_USE_DEMO_STRESS=y +CONFIG_LV_USE_DEMO_MUSIC=y +CONFIG_LV_DEMO_MUSIC_AUTO_PLAY=y +CONFIG_LV_DEMO_MUSIC_ROUND=y + +## LVGL8 ## +CONFIG_LV_USE_PERF_MONITOR=y +CONFIG_LV_COLOR_16_SWAP=y +CONFIG_LV_MEM_CUSTOM=y +CONFIG_LV_MEMCPY_MEMSET_STD=y + +## LVGL9 ## +CONFIG_LV_CONF_SKIP=y + +#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 diff --git a/examples/display_rotation/sdkconfig.bsp.m5dial b/examples/display_rotation/sdkconfig.bsp.m5dial new file mode 100644 index 00000000..08ebacc7 --- /dev/null +++ b/examples/display_rotation/sdkconfig.bsp.m5dial @@ -0,0 +1,25 @@ +# 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="esp32s3" +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y + +## LVGL8 ## +CONFIG_LV_USE_PERF_MONITOR=y +CONFIG_LV_COLOR_16_SWAP=y +CONFIG_LV_MEM_CUSTOM=y +CONFIG_LV_MEMCPY_MEMSET_STD=y + +## LVGL9 ## +CONFIG_LV_CONF_SKIP=y + +#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