Skip to content

Commit 42b1096

Browse files
committed
Added touchscreen, qwiic example
1 parent 3b6a469 commit 42b1096

File tree

2 files changed

+302
-0
lines changed

2 files changed

+302
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/**
2+
**************************************************
3+
*
4+
* @file Qwiic.ino
5+
* @brief Example demonstrating easyC/Qwiic (I2C) communication between Inkplate 6FLICK and
6+
* a Soldered BME280 or BME680 environmental sensor, using the LVGL library
7+
* for display rendering.
8+
*
9+
* This example reads temperature, humidity, and pressure data from a
10+
* Soldered BME280 sensor connected via the easyC interface and displays
11+
* it on the Inkplate 6FLICK e-paper screen using LVGL elements.
12+
*
13+
* Note: Both BME280 and BME680 sensors are supported by the same
14+
* Soldered BME280/BME680 library. In this example, the BME280 is used,
15+
* as defined in the code. The sensor communicates over easyC (I2C)
16+
* using the default 0x76 address.
17+
*
18+
* For setup instructions and more information about Inkplate 6FLICK, visit:
19+
* https://soldered.com/documentation/inkplate/6flick/overview/
20+
*
21+
* @hardware Inkplate 6FLICK (ESP32-based e-paper display)
22+
* @sensors Soldered BME280 (or BME680) via easyC connector
23+
* @library Soldered BME280/BME680 Gas Sensor Arduino Library
24+
* https://github.com/SolderedElectronics/Soldered-BME280-BME680-Gas-Sensor-Arduino-Library
25+
*
26+
* @authors Soldered
27+
* @date November 2025
28+
***************************************************/
29+
30+
#include <Inkplate-LVGL.h>
31+
#include <BME280-SOLDERED.h> // Soldered BME280/BME680 library (easyC/I2C)
32+
33+
// Inkplate in 1-bit mode (fast partial updates)
34+
Inkplate inkplate(INKPLATE_1BIT);
35+
BME280 bme280; // easyC/I2C (Soldered uses 0x76)
36+
37+
// Optional temperature calibration offset
38+
const float TEMPERATURE_OFFSET = 0.0f;
39+
40+
// UI elements
41+
static lv_obj_t *panel_data;
42+
static lv_obj_t *lbl_title;
43+
static lv_obj_t *lbl_temp;
44+
static lv_obj_t *lbl_hum;
45+
static lv_obj_t *lbl_press;
46+
static lv_obj_t *lbl_warn;
47+
48+
// Refresh policy (do a FULL every ~20 partials)
49+
static int partialCount = 0;
50+
static const int FULL_REFRESH_EVERY = 20;
51+
52+
// Helpers
53+
static inline int dispW() { auto *d = lv_display_get_default(); return lv_display_get_horizontal_resolution(d); }
54+
static inline int dispH() { auto *d = lv_display_get_default(); return lv_display_get_vertical_resolution(d); }
55+
56+
static void make_opaque(lv_obj_t *obj) {
57+
lv_obj_set_style_bg_color(obj, lv_color_hex(0xFFFFFF), 0);
58+
lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, 0);
59+
lv_obj_set_style_border_width(obj, 0, 0);
60+
}
61+
62+
// Minimal LVGL UI (no GFX icons to keep it LVGL-only)
63+
static void ui_create() {
64+
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0xFFFFFF), LV_PART_MAIN);
65+
66+
lbl_title = lv_label_create(lv_screen_active());
67+
lv_label_set_text(lbl_title, "easyC • BME280");
68+
lv_obj_set_style_text_color(lbl_title, lv_color_hex(0x000000), 0);
69+
lv_obj_set_pos(lbl_title, 8, 8);
70+
make_opaque(lbl_title);
71+
72+
panel_data = lv_obj_create(lv_screen_active());
73+
make_opaque(panel_data);
74+
lv_obj_set_style_pad_all(panel_data, 0, 0);
75+
lv_obj_set_style_border_width(panel_data, 0, 0);
76+
lv_obj_set_pos(panel_data, 0, 40);
77+
lv_obj_set_size(panel_data, dispW(), dispH() - 80);
78+
79+
lbl_temp = lv_label_create(panel_data);
80+
lv_obj_set_style_text_color(lbl_temp, lv_color_hex(0x000000), 0);
81+
lv_obj_set_pos(lbl_temp, 24, 40);
82+
83+
lbl_hum = lv_label_create(panel_data);
84+
lv_obj_set_style_text_color(lbl_hum, lv_color_hex(0x000000), 0);
85+
lv_obj_set_pos(lbl_hum, 24, 140);
86+
87+
lbl_press = lv_label_create(panel_data);
88+
lv_obj_set_style_text_color(lbl_press, lv_color_hex(0x000000), 0);
89+
lv_obj_set_pos(lbl_press, 24, 240);
90+
91+
lbl_warn = lv_label_create(panel_data); // shown only if sensor looks unresponsive
92+
lv_obj_set_style_text_color(lbl_warn, lv_color_hex(0x000000), 0);
93+
lv_obj_set_pos(lbl_warn, 24, 320);
94+
lv_label_set_text(lbl_warn, "");
95+
}
96+
97+
static void update_readings() {
98+
// Read sensor
99+
float tC = bme280.readTemperature() + TEMPERATURE_OFFSET; // °C
100+
float hum = bme280.readHumidity() / 10.0f; // library returns x10
101+
float hPa = bme280.readPressure() * 10.0f; // hPa (original style)
102+
103+
// Basic sanity check (some libs return 0 or extreme values if not connected)
104+
bool looks_bad = (hPa <= 0.0f) || (hum < 0.0f || hum > 100.0f) || (tC < -40.0f || tC > 85.0f);
105+
106+
char bufT[32], bufH[32], bufP[32];
107+
snprintf(bufT, sizeof(bufT), "Temperature: %.1f *C", tC);
108+
snprintf(bufH, sizeof(bufH), "Humidity: %.0f %%", hum);
109+
snprintf(bufP, sizeof(bufP), "Pressure: %.0f hPa", hPa);
110+
111+
lv_label_set_text(lbl_temp, bufT);
112+
lv_label_set_text(lbl_hum, bufH);
113+
lv_label_set_text(lbl_press, bufP);
114+
115+
if (looks_bad) {
116+
lv_label_set_text(lbl_warn, "Warning: sensor readings look invalid.\nCheck easyC cable and sensor power.");
117+
} else {
118+
lv_label_set_text(lbl_warn, "");
119+
}
120+
}
121+
122+
void setup() {
123+
Serial.begin(115200);
124+
125+
// LVGL + Inkplate in PARTIAL mode
126+
inkplate.begin(LV_DISP_RENDER_MODE_PARTIAL);
127+
inkplate.selectDisplayMode(INKPLATE_1BIT);
128+
129+
// Init BME280 (void return in this library)
130+
bme280.begin();
131+
132+
ui_create();
133+
update_readings();
134+
135+
// Initial FULL refresh
136+
lv_tick_inc(20);
137+
lv_timer_handler();
138+
inkplate.display();
139+
}
140+
141+
void loop() {
142+
update_readings();
143+
144+
lv_tick_inc(10);
145+
lv_timer_handler();
146+
147+
if (partialCount >= FULL_REFRESH_EVERY) {
148+
inkplate.display(); // FULL
149+
partialCount = 0;
150+
} else {
151+
inkplate.partialUpdate();
152+
partialCount++;
153+
}
154+
155+
delay(10000); // ~10 s between readings
156+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/**
2+
**************************************************
3+
*
4+
* @file SimpleTouchscreen.ino
5+
* @brief This example shows you how to use Inkplate 6 FLICK touchscreen.
6+
* Once the code is uploaded, try to touch the rectangles on the screen :)
7+
*
8+
* For info on how to quickly get started with Inkplate 6FLICK visit https://soldered.com/documentation/inkplate/6flick/overview/
9+
*
10+
* @authors Soldered
11+
* @date November 2025
12+
***************************************************/
13+
14+
// Include the Inkplate LVGL Library
15+
#include <Inkplate-LVGL.h>
16+
17+
// Create an instance of Inkplate display in 1-bit mode (change to INKPLATE_3BIT if you want grayscale)
18+
Inkplate inkplate(INKPLATE_1BIT);
19+
20+
// Create an lvgl task which will tick the lvgl timer every 5 ms
21+
// and handle any animations needed
22+
void lvgl_task(void *arg)
23+
{
24+
for (;;)
25+
{
26+
lv_tick_inc(5);
27+
lv_timer_handler();
28+
vTaskDelay(pdMS_TO_TICKS(5));
29+
}
30+
}
31+
32+
// Initialize global lvgl rectangle object
33+
static lv_obj_t *rect = NULL;
34+
35+
// Touch detect flag
36+
bool isRectangleClicked = false;
37+
38+
// Rectangle coordinates
39+
int x_position = 50;
40+
int y_position = 50;
41+
42+
static void btn_event_cb(lv_event_t *e)
43+
{
44+
lv_event_code_t code = lv_event_get_code(e);
45+
46+
if (code == LV_EVENT_CLICKED)
47+
{
48+
if (rect)
49+
{
50+
x_position += 100;
51+
y_position += 100;
52+
53+
if (y_position < 660)
54+
{
55+
lv_obj_set_pos(rect, x_position, y_position);
56+
lv_obj_invalidate(rect);
57+
isRectangleClicked = true;
58+
}
59+
else
60+
{
61+
x_position = 50;
62+
y_position = 50;
63+
64+
inkplate.clearDisplay();
65+
lv_obj_clean(lv_scr_act());
66+
lv_draw_initials();
67+
lv_obj_invalidate(lv_scr_act());
68+
for (int i = 0; i < 5; i++)
69+
{
70+
lv_timer_handler();
71+
delay(10);
72+
}
73+
inkplate.display();
74+
}
75+
}
76+
}
77+
}
78+
79+
static void lv_draw_initials()
80+
{
81+
/* Create a black label, set its text and font and align it to the center */
82+
lv_obj_t *label = lv_label_create(lv_screen_active());
83+
lv_label_set_text(label, "Touch the rectangles on screen!");
84+
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0x000000), LV_PART_MAIN);
85+
lv_obj_set_style_text_font(label, &lv_font_montserrat_48, 0);
86+
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 0);
87+
88+
/* Create a black rectangle */
89+
rect = lv_obj_create(lv_scr_act());
90+
lv_obj_set_style_bg_color(rect, lv_color_hex(0x000000), 0);
91+
lv_obj_set_size(rect, 100, 50);
92+
lv_obj_set_pos(rect, x_position, y_position);
93+
94+
// Add event callback function
95+
lv_obj_add_event_cb(rect, btn_event_cb, LV_EVENT_ALL, NULL);
96+
}
97+
98+
void setup()
99+
{
100+
Serial.begin(115200);
101+
Serial.println("Inkplate 6 FLICK Touchscreen Example.");
102+
103+
inkplate.begin(LV_DISPLAY_RENDER_MODE_PARTIAL);
104+
105+
if (inkplate.touchscreen.init(true))
106+
{
107+
Serial.println("Touchscreen initialized.");
108+
}
109+
else
110+
{
111+
Serial.println("Touchscreen initialization failed.");
112+
while (true);
113+
}
114+
115+
// Create LVGL task on core 1 to run independently from the rest of the sketch
116+
xTaskCreatePinnedToCore(
117+
lvgl_task, // Function which will be pinned
118+
"lvgl_tick", // Symbolic name
119+
16000, // Stack depth
120+
nullptr, // No parameters
121+
2, // Priority
122+
nullptr, // No buffer, it will be allocated dynamically
123+
1 // core used
124+
);
125+
126+
lv_draw_initials();
127+
128+
// Force initial render
129+
for (int i = 0; i < 5; i++)
130+
{
131+
lv_timer_handler();
132+
delay(10);
133+
}
134+
// Display content from buffer
135+
inkplate.display();
136+
}
137+
138+
void loop()
139+
{
140+
if (isRectangleClicked)
141+
{
142+
inkplate.partialUpdate(0, 1);
143+
isRectangleClicked = false;
144+
}
145+
}
146+

0 commit comments

Comments
 (0)