Skip to content

Commit 5a5ff81

Browse files
authored
feat(t-dongle-s3): Move button into TDongleS3 as interrupt (#377)
* Add built-in support for configuring the button on the T-Dongle-S3 using the interrupt class, similar to qtpy and others * Fix docs * Simplify t dongle s3 example using new button API
1 parent 1302f71 commit 5a5ff81

File tree

9 files changed

+106
-39
lines changed

9 files changed

+106
-39
lines changed

components/qtpy/example/main/qtpy_example.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extern "C" void app_main(void) {
1313
logger.info("starting example");
1414

1515
//! [qtpy ex1]
16-
auto& qtpy = espp::QtPy::get();
16+
auto &qtpy = espp::QtPy::get();
1717

1818
// Initialize the Button
1919
logger.info("Initializing the button");
@@ -96,7 +96,6 @@ extern "C" void app_main(void) {
9696
} else {
9797
logger.info("Found devices at addresses: {::#02x}", found_addresses);
9898
}
99-
10099
//! [qtpy ex1]
101100

102101
while (true) {

components/qtpy/include/qtpy.hpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@ namespace espp {
1414
/// ESP32-S3 development boards.
1515
///
1616
/// The class provides access to the following features:
17+
/// - Button (boot button)
1718
/// - RGB LED
1819
/// - I2C (qwiic)
1920
///
2021
/// The class is a singleton and can be accessed using the get() method.
2122
///
2223
/// \section qtpy_example Example
23-
/// \snippet qtpy_example.cpp qtpy example
24+
/// \snippet qtpy_example.cpp qtpy ex1
2425
class QtPy : public BaseComponent {
2526
public:
27+
/// Alias for the button callback function
2628
using button_callback_t = espp::Interrupt::event_callback_fn;
2729

2830
/// @brief Access the singleton instance of the QtPy class
@@ -124,7 +126,7 @@ class QtPy : public BaseComponent {
124126
static constexpr auto qwiic_sda_io = GPIO_NUM_41;
125127
static constexpr auto qwiic_scl_io = GPIO_NUM_40;
126128
#else
127-
#error "Unsupported target"
129+
#error "Unsupported target"
128130
#endif
129131

130132
// button (boot button)

components/qtpy/src/qtpy.cpp

+5-10
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ espp::Interrupt &QtPy::interrupts() { return interrupts_; }
1313
// Button Functions //
1414
////////////////////////
1515

16-
bool QtPy::initialize_button(
17-
const QtPy::button_callback_t &callback) {
16+
bool QtPy::initialize_button(const QtPy::button_callback_t &callback) {
1817
logger_.info("Initializing button");
1918

2019
// save the callback
@@ -37,7 +36,7 @@ bool QtPy::button_state() const {
3736
// I2C Functions //
3837
////////////////////////
3938

40-
bool QtPy::initialize_qwiic_i2c(const espp::I2c::Config& i2c_config) {
39+
bool QtPy::initialize_qwiic_i2c(const espp::I2c::Config &i2c_config) {
4140
if (qwiic_i2c_) {
4241
logger_.warn("Qwiic I2C already initialized");
4342
return false;
@@ -64,19 +63,15 @@ bool QtPy::initialize_led() {
6463
}
6564

6665
logger_.info("Initializing LED");
67-
led_ = std::make_shared<espp::Neopixel>(espp::Neopixel::Config{
68-
.data_gpio = led_data_io,
69-
.power_gpio = led_power_io
70-
});
66+
led_ = std::make_shared<espp::Neopixel>(
67+
espp::Neopixel::Config{.data_gpio = led_data_io, .power_gpio = led_power_io});
7168
return true;
7269
}
7370

7471
/// Set the color of the LED
7572
/// \param hsv The color of the LED in HSV format
7673
/// \return True if the LED was set, false otherwise
77-
bool QtPy::led(const Hsv &hsv) {
78-
return led(hsv.rgb());
79-
}
74+
bool QtPy::led(const Hsv &hsv) { return led(hsv.rgb()); }
8075

8176
/// Set the color of the LED
8277
/// \param rgb The color of the LED in RGB format

components/t-dongle-s3/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
idf_component_register(
33
INCLUDE_DIRS "include"
44
SRC_DIRS "src"
5-
REQUIRES driver base_component display display_drivers i2c led_strip task
5+
REQUIRES driver base_component display display_drivers i2c interrupt led_strip task
66
REQUIRED_IDF_TARGETS "esp32s3"
77
)

components/t-dongle-s3/Kconfig

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
menu "T-Dongle-S3 Configuration"
2+
config T_DONGLE_S3_INTERRUPT_STACK_SIZE
3+
int "Interrupt stack size"
4+
default 4096
5+
help
6+
Size of the stack used for the interrupt handler. Used by the
7+
button callback.
8+
endmenu

components/t-dongle-s3/example/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ set(EXTRA_COMPONENT_DIRS
1111

1212
set(
1313
COMPONENTS
14-
"main esptool_py t-dongle-s3 button"
14+
"main esptool_py t-dongle-s3"
1515
CACHE STRING
1616
"List of components to include"
1717
)

components/t-dongle-s3/example/main/t_dongle_s3_example.cpp

+13-23
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#include <stdlib.h>
33
#include <vector>
44

5-
#include "button.hpp"
65
#include "t-dongle-s3.hpp"
76

87
using namespace std::chrono_literals;
@@ -40,28 +39,19 @@ extern "C" void app_main(void) {
4039
}
4140

4241
// initialize the button, which we'll use to cycle the rotation of the display
43-
espp::Button button(espp::Button::Config{
44-
.name = "Boot Button",
45-
.interrupt_config =
46-
espp::Interrupt::PinConfig{.gpio_num = GPIO_NUM_0,
47-
.callback =
48-
[](const auto &event) {
49-
if (event.active) {
50-
// lock the display mutex
51-
std::lock_guard<std::mutex> lock(lvgl_mutex);
52-
static auto rotation = LV_DISPLAY_ROTATION_0;
53-
rotation = static_cast<lv_display_rotation_t>(
54-
(static_cast<int>(rotation) + 1) % 4);
55-
fmt::print("Setting rotation to {}\n", (int)rotation);
56-
lv_display_t *disp = _lv_refr_get_disp_refreshing();
57-
lv_disp_set_rotation(disp, rotation);
58-
}
59-
},
60-
.active_level = espp::Interrupt::ActiveLevel::LOW,
61-
.interrupt_type = espp::Interrupt::Type::ANY_EDGE,
62-
.pullup_enabled = false,
63-
.pulldown_enabled = false},
64-
});
42+
logger.info("Initializing the button");
43+
auto on_button_pressed = [&](const auto &event) {
44+
if (event.active) {
45+
// lock the display mutex
46+
std::lock_guard<std::mutex> lock(lvgl_mutex);
47+
static auto rotation = LV_DISPLAY_ROTATION_0;
48+
rotation = static_cast<lv_display_rotation_t>((static_cast<int>(rotation) + 1) % 4);
49+
fmt::print("Setting rotation to {}\n", (int)rotation);
50+
lv_display_t *disp = _lv_refr_get_disp_refreshing();
51+
lv_disp_set_rotation(disp, rotation);
52+
}
53+
};
54+
tdongle.initialize_button(on_button_pressed);
6555

6656
// set the LED to be red
6757
espp::Hsv hsv(150.0f, 1.0f, 1.0f);

components/t-dongle-s3/include/t-dongle-s3.hpp

+48
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <hal/spi_types.h>
1010

1111
#include "base_component.hpp"
12+
#include "interrupt.hpp"
1213
#include "led_strip.hpp"
1314
#include "st7789.hpp"
1415

@@ -17,6 +18,7 @@ namespace espp {
1718
/// development board.
1819
///
1920
/// The class provides access to the following features:
21+
/// - Button (boot button)
2022
/// - Display
2123
/// - RGB LED
2224
///
@@ -26,6 +28,9 @@ namespace espp {
2628
/// \snippet t_dongle_s3_example.cpp t-dongle-s3 example
2729
class TDongleS3 : public BaseComponent {
2830
public:
31+
/// Alias for the button callback function
32+
using button_callback_t = espp::Interrupt::event_callback_fn;
33+
2934
/// Alias for the pixel type used by the T-Dongle-S3 display
3035
using Pixel = lv_color16_t;
3136

@@ -41,6 +46,23 @@ class TDongleS3 : public BaseComponent {
4146
TDongleS3(TDongleS3 &&) = delete;
4247
TDongleS3 &operator=(TDongleS3 &&) = delete;
4348

49+
/// Get a reference to the interrupts
50+
/// \return A reference to the interrupts
51+
espp::Interrupt &interrupts();
52+
53+
/////////////////////////////////////////////////////////////////////////////
54+
// Button
55+
/////////////////////////////////////////////////////////////////////////////
56+
57+
/// Initialize the button
58+
/// \param callback The callback function to call when the button is pressed
59+
/// \return true if the button was successfully initialized, false otherwise
60+
bool initialize_button(const button_callback_t &callback = nullptr);
61+
62+
/// Get the button state
63+
/// \return The button state (true = button pressed, false = button released)
64+
bool button_state() const;
65+
4466
/////////////////////////////////////////////////////////////////////////////
4567
// RGB LED
4668
/////////////////////////////////////////////////////////////////////////////
@@ -208,6 +230,32 @@ class TDongleS3 : public BaseComponent {
208230
static constexpr gpio_num_t backlight_io = GPIO_NUM_38;
209231
using DisplayDriver = espp::St7789;
210232

233+
// button (boot button)
234+
static constexpr gpio_num_t button_io = GPIO_NUM_0; // active low
235+
236+
// Interrupts
237+
espp::Interrupt::PinConfig button_interrupt_pin_{
238+
.gpio_num = button_io,
239+
.callback =
240+
[this](const auto &event) {
241+
if (button_callback_) {
242+
button_callback_(event);
243+
}
244+
},
245+
.active_level = espp::Interrupt::ActiveLevel::LOW,
246+
.interrupt_type = espp::Interrupt::Type::ANY_EDGE,
247+
.pullup_enabled = true};
248+
249+
// we'll only add each interrupt pin if the initialize method is called
250+
espp::Interrupt interrupts_{
251+
{.interrupts = {},
252+
.task_config = {.name = "t-dongle-s3 interrupts",
253+
.stack_size_bytes = CONFIG_T_DONGLE_S3_INTERRUPT_STACK_SIZE}}};
254+
255+
// button
256+
std::atomic<bool> button_initialized_{false};
257+
button_callback_t button_callback_{nullptr};
258+
211259
// led
212260
std::shared_ptr<LedStrip> led_;
213261
spi_bus_config_t led_spi_bus_config_;

components/t-dongle-s3/src/t-dongle-s3.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,31 @@ using namespace espp;
55
TDongleS3::TDongleS3()
66
: BaseComponent("TDongleS3") {}
77

8+
espp::Interrupt &TDongleS3::interrupts() { return interrupts_; }
9+
10+
///////////////////////
11+
// Button Functions //
12+
///////////////////////
13+
14+
bool TDongleS3::initialize_button(const TDongleS3::button_callback_t &callback) {
15+
logger_.info("Initializing button");
16+
17+
// save the callback
18+
button_callback_ = callback;
19+
20+
// configure the button
21+
interrupts_.add_interrupt(button_interrupt_pin_);
22+
button_initialized_ = true;
23+
return true;
24+
}
25+
26+
bool TDongleS3::button_state() const {
27+
if (!button_initialized_) {
28+
return false;
29+
}
30+
return interrupts_.is_active(button_interrupt_pin_);
31+
}
32+
833
///////////////////////
934
// RGB LED Functions //
1035
///////////////////////

0 commit comments

Comments
 (0)