Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add espp::SsRoundDisplay hardware abstraction component for the Seeed Studio Round Display #315

Merged
merged 18 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ jobs:
target: esp32
- path: 'components/button/example'
target: esp32
- path: 'components/controller/example'
- path: 'components/chsc6x/example'
target: esp32s3
- path: 'components/cli/example'
target: esp32
- path: 'components/color/example'
target: esp32
- path: 'components/controller/example'
target: esp32s3
- path: 'components/cst816/example'
target: esp32s3
- path: 'components/csv/example'
Expand Down Expand Up @@ -111,6 +113,8 @@ jobs:
target: esp32s3
- path: 'components/rtsp/example'
target: esp32
- path: 'components/seeed-studio-round-display/example'
target: esp32s3
- path: 'components/serialization/example'
target: esp32
- path: 'components/socket/example'
Expand Down
4 changes: 4 additions & 0 deletions components/chsc6x/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
idf_component_register(
INCLUDE_DIRS "include"
REQUIRES "base_peripheral"
)
21 changes: 21 additions & 0 deletions components/chsc6x/example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)

# add the component directories that we want to use
set(EXTRA_COMPONENT_DIRS
"../../../components/"
)

set(
COMPONENTS
"main esptool_py task chsc6x i2c"
CACHE STRING
"List of components to include"
)

project(chsc6x_example)

set(CMAKE_CXX_STANDARD 20)
37 changes: 37 additions & 0 deletions components/chsc6x/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# CHSC6X Example

This example shows how to use the CHSC6X touch controller with ESP32. It is
designed to run on a Seeed Studio Round Display.

## How to use example

### Hardware Required

Seeed Studio Round Display (or any other dev board with a CHSC6X touch
controller)

### Configure

```
idf.py menuconfig
```

Set the hardware configuration for the example.

### Build and Flash

Build the project and flash it to the board, then run monitor tool to view serial output:

```
idf.py -p PORT flash monitor
```

(Replace PORT with the name of the serial port to use.)

(To exit the serial monitor, type ``Ctrl-]``.)

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

## Example Output

![CleanShot 2024-08-26 at 08 21 47](https://github.com/user-attachments/assets/44ed3371-0c8f-44d1-992d-01ee1c983efc)
2 changes: 2 additions & 0 deletions components/chsc6x/example/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS ".")
39 changes: 39 additions & 0 deletions components/chsc6x/example/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
menu "Example Configuration"

choice EXAMPLE_HARDWARE
prompt "Hardware"
default EXAMPLE_HARDWARE_XIAOS3
help
Select the hardware to run this example on.

config EXAMPLE_HARDWARE_XIAOS3
depends on IDF_TARGET_ESP32S3
bool "XIAO-S3"

config EXAMPLE_HARDWARE_QTPYS3
depends on IDF_TARGET_ESP32S3
bool "QTPY ESP32 S3"

config EXAMPLE_HARDWARE_CUSTOM
bool "Custom"
endchoice

config EXAMPLE_I2C_SCL_GPIO
int "SCL GPIO Num"
range 0 50
default 6 if EXAMPLE_HARDWARE_XIAOS3
default 6 if EXAMPLE_HARDWARE_QTPYS3
default 19 if EXAMPLE_HARDWARE_CUSTOM
help
GPIO number for I2C Master clock line.

config EXAMPLE_I2C_SDA_GPIO
int "SDA GPIO Num"
range 0 50
default 5 if EXAMPLE_HARDWARE_XIAOS3
default 7 if EXAMPLE_HARDWARE_QTPYS3
default 22 if EXAMPLE_HARDWARE_CUSTOM
help
GPIO number for I2C Master data line.

endmenu
81 changes: 81 additions & 0 deletions components/chsc6x/example/main/chsc6x_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <chrono>
#include <sdkconfig.h>
#include <vector>

#include "chsc6x.hpp"
#include "i2c.hpp"
#include "task.hpp"

using namespace std::chrono_literals;

extern "C" void app_main(void) {
{
std::atomic<bool> quit_test = false;
fmt::print("Starting chsc6x example\n");
//! [chsc6x example]
// make the I2C that we'll use to communicate
espp::I2c i2c({
.port = I2C_NUM_0,
.sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
.scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.timeout_ms = 100,
.clk_speed = 400 * 1000,
});

bool has_chsc6x = i2c.probe_device(espp::Chsc6x::DEFAULT_ADDRESS);
fmt::print("Touchpad probe: {}\n", has_chsc6x);

// now make the chsc6x which decodes the data
espp::Chsc6x chsc6x({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3),
.read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3),
.log_level = espp::Logger::Verbosity::WARN});

// and finally, make the task to periodically poll the chsc6x and print
// the state
auto task_fn = [&chsc6x](std::mutex &m, std::condition_variable &cv) {
std::error_code ec;
// update the state
bool new_data = chsc6x.update(ec);
if (ec) {
fmt::print("Could not update state\n");
return false;
}
if (!new_data) {
return false; // don't stop the task
}
// get the state
uint8_t num_touch_points = 0;
uint16_t x = 0, y = 0;
chsc6x.get_touch_point(&num_touch_points, &x, &y);
if (ec) {
fmt::print("Could not get touch point\n");
return false;
}
fmt::print("num_touch_points: {}, x: {}, y: {}\n", num_touch_points, x, y);
// NOTE: sleeping in this way allows the sleep to exit early when the
// task is being stopped / destroyed
{
std::unique_lock<std::mutex> lk(m);
cv.wait_for(lk, 50ms);
}
return false; // don't stop the task
};
auto task = espp::Task(
{.name = "Chsc6x Task", .callback = task_fn, .log_level = espp::Logger::Verbosity::WARN});
task.start();
//! [chsc6x example]
while (true) {
std::this_thread::sleep_for(100ms);
}
}

fmt::print("Chsc6x example complete!\n");

while (true) {
std::this_thread::sleep_for(1s);
}
}
6 changes: 6 additions & 0 deletions components/chsc6x/example/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CONFIG_IDF_TARGET="esp32s3"

# Common ESP-related
#
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
80 changes: 80 additions & 0 deletions components/chsc6x/include/chsc6x.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#pragma once

#include <atomic>
#include <functional>

#include "base_peripheral.hpp"

namespace espp {
/// @brief Driver for the Chsc6x touch controller
///
/// \section Example
/// \snippet chsc6x_example.cpp chsc6x example
class Chsc6x : public BasePeripheral<> {
public:
/// Default address for the CHSC6X chip
static constexpr uint8_t DEFAULT_ADDRESS = 0x2E;

/// @brief Configuration for the CHSC6X driver
struct Config {
BasePeripheral::write_fn write; ///< Function for writing to the CHSC6X chip
BasePeripheral::read_fn read; ///< Function for reading from the CHSC6X chip
uint8_t address = DEFAULT_ADDRESS; ///< Which address to use for this chip?
espp::Logger::Verbosity log_level{
espp::Logger::Verbosity::WARN}; ///< Log verbosity for the input driver.
};

/// @brief Constructor for the CHSC6X driver
/// @param config The configuration for the driver
explicit Chsc6x(const Config &config)
: BasePeripheral({.address = config.address, .write = config.write, .read = config.read},
"Chsc6x", config.log_level) {}

/// @brief Update the state of the CHSC6X driver
/// @param ec Error code to set if an error occurs
/// @return True if the CHSC6X has new data, false otherwise
bool update(std::error_code &ec) {
static constexpr size_t DATA_LEN = 5;
static uint8_t data[DATA_LEN];
read_many_from_register(0, data, DATA_LEN, ec);
if (ec)
return false;

// first byte is non-zero when touched, 3rd byte is x, 5th byte is y
if (data[0] == 0) {
x_ = 0;
y_ = 0;
num_touch_points_ = 0;
return true;
}
x_ = data[2];
y_ = data[4];
num_touch_points_ = 1;
logger_.debug("Touch at ({}, {})", x_, y_);
return true;
}

/// @brief Get the number of touch points
/// @return The number of touch points as of the last update
/// @note This is a cached value from the last update() call
uint8_t get_num_touch_points() const { return num_touch_points_; }

/// @brief Get the touch point data
/// @param num_touch_points The number of touch points as of the last update
/// @param x The x coordinate of the touch point
/// @param y The y coordinate of the touch point
/// @note This is a cached value from the last update() call
void get_touch_point(uint8_t *num_touch_points, uint16_t *x, uint16_t *y) const {
*num_touch_points = get_num_touch_points();
if (*num_touch_points != 0) {
*x = x_;
*y = y_;
}
}

protected:
std::atomic<uint8_t> num_touch_points_;
std::atomic<uint16_t> x_;
std::atomic<uint16_t> y_;
}; // class Chsc6x
} // namespace espp
3 changes: 1 addition & 2 deletions components/display_drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
idf_component_register(
INCLUDE_DIRS "include"
SRC_DIRS "src"
PRIV_REQUIRES display driver esp_lcd
REQUIRES led
REQUIRES display driver esp_lcd led
)
2 changes: 1 addition & 1 deletion components/esp-box/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
idf_component_register(
INCLUDE_DIRS "include"
SRC_DIRS "src"
REQUIRES driver esp_lcd base_component codec display display_drivers i2c input_drivers interrupt gt911 task tt21100
REQUIRES driver base_component codec display display_drivers i2c input_drivers interrupt gt911 task tt21100
REQUIRED_IDF_TARGETS "esp32s3"
)
4 changes: 3 additions & 1 deletion components/esp-box/example/sdkconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ CONFIG_ESP_TIMER_TASK_STACK_SIZE=6144
# set the functions into IRAM
CONFIG_SPI_MASTER_IN_IRAM=y

CONFIG_LV_DEF_REFR_PERIOD=16

#
# LVGL configuration - # Themes
#
CONFIG_LV_USE_THEME_DEFAULT=y
CONFIG_LV_THEME_DEFAULT_DARK=y
CONFIG_LV_THEME_DEFAULT_GROW=y
CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME=80
CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME=30
2 changes: 1 addition & 1 deletion components/matouch-rotary-display/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
idf_component_register(
INCLUDE_DIRS "include"
SRC_DIRS "src"
REQUIRES driver esp_lcd base_component cst816 encoder display display_drivers i2c input_drivers interrupt task
REQUIRES driver base_component cst816 encoder display display_drivers i2c input_drivers interrupt task
REQUIRED_IDF_TARGETS "esp32s3"
)
4 changes: 3 additions & 1 deletion components/matouch-rotary-display/example/sdkconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ CONFIG_ESP_TIMER_TASK_STACK_SIZE=6144
# set the functions into IRAM
CONFIG_SPI_MASTER_IN_IRAM=y

CONFIG_LV_DEF_REFR_PERIOD=16

#
# LVGL configuration - # Themes
#
CONFIG_LV_USE_THEME_DEFAULT=y
CONFIG_LV_THEME_DEFAULT_DARK=y
CONFIG_LV_THEME_DEFAULT_GROW=y
CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME=80
CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME=30
5 changes: 5 additions & 0 deletions components/seeed-studio-round-display/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
idf_component_register(
INCLUDE_DIRS "include"
SRC_DIRS "src"
REQUIRES driver base_component display display_drivers i2c input_drivers interrupt task chsc6x
)
8 changes: 8 additions & 0 deletions components/seeed-studio-round-display/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
menu "Seeed Studio Round Display Configuration"
config SEEED_STUDIO_ROUND_DISPLAY_INTERRUPT_STACK_SIZE
int "Interrupt stack size"
default 4096
help
Size of the stack used for the interrupt handler. Used by the touch
callback.
endmenu
21 changes: 21 additions & 0 deletions components/seeed-studio-round-display/example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)

# add the component directories that we want to use
set(EXTRA_COMPONENT_DIRS
"../../../components/"
)

set(
COMPONENTS
"main esptool_py seeed-studio-round-display"
CACHE STRING
"List of components to include"
)

project(seeed_studio_roudn_display_example)

set(CMAKE_CXX_STANDARD 20)
Loading
Loading