LVGL on Raspberry Pi Pico 2 (Arduino framework/arduino-pico) with 320x480 TFT SPI ST7796 + FT6336U Capacitive Touch
LVGL (Light and Versatile Graphics Library)
is a popular free and open-source embedded graphics library to create
beautiful UIs for any MCU, MPU and display type, supports working with the
TFT_eSPI library.
Following previous exercise "Raspberry Pi Pico 2 drive 4.0" 320x480 TFT SPI ST7796 with FT6336U
Capacitive Touch + SD, in Arduino framework", this exercise show steps to add LVGL on top of TFT_eSPI, on Raspberry Pi
Pico 2.
Install lvgl library in Arduino IDE's Library Manager.
Using LVGL with Arduino requires some extra steps:
Be sure to read the docs here: https://docs.lvgl.io/master/integration/framework/arduino.html
Follow these configuration steps:
- Go to the directory of the installed Arduino libraries
- Go to lvgl and copy lv_conf_template.h as lv_conf.h into the Arduino Libraries directory next to the lvgl library folder.
- Open lv_conf.h and change:
To enable the content of the file:
change the first #if 0 to #if 1
To use TFT_eSPI:
change LV_USE_TFT_ESPI 0 to 1
- Test with example:
> File > Examples > lvgl > arduino > LVGL_Arduino My exercise code:
pico2_LVGL_Arduino.ino
/*
lvgl exercise run on Raspberry Pi Pico 2 in Arduino framework,
with 4.0" 320x480 TFT SPI ST7796 with FT6336U Capacitive Touch.
Use TFT_eSPI to interface with ST7796.
To setup TFT_eSPI and connection, read:
https://coxxect.blogspot.com/2025/04/raspberry-pi-pico-2-drive-40-480x320.html
*/
/*Using LVGL with Arduino requires some extra steps:
*Be sure to read the docs here: https://docs.lvgl.io/master/integration/framework/arduino.html */
#include <lvgl.h>
#include "lv_conf.h"
#include <TFT_eSPI.h>
// for FT6336U cap touch
#include <Wire.h>
#define CTP_RST 14 // option, can connect to 3V3.
#define FT6336U_ADDR 0x38
/*Set to your screen resolution and rotation*/
#define TFT_HOR_RES 320 //320
#define TFT_VER_RES 480 //240
#define TFT_ROTATION LV_DISPLAY_ROTATION_0
/*LVGL draw into this buffer, 1/10 screen size usually works well. The size is in bytes*/
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
/* LVGL calls it when a rendered image needs to copied to the display*/
void my_disp_flush( lv_display_t *disp, const lv_area_t *area, uint8_t * px_map)
{
Serial.println("my_disp_flush()");
/*Copy `px map` to the `area`*/
/*Call it to tell LVGL you are ready*/
lv_display_flush_ready(disp);
}
/*Read the touchpad*/
void my_touchpad_read( lv_indev_t * indev, lv_indev_data_t * data )
{
if (get_touch_count()>0){
data->state = LV_INDEV_STATE_PRESSED;
int x, y;
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x03);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
x = (Wire.read() & 0x0f) << 8 | Wire.read();
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x05);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
y = (Wire.read() & 0x0f) << 8 | Wire.read();
data->point.x = x;
data->point.y = y;
}else{
data->state = LV_INDEV_STATE_RELEASED;
}
}
/*use Arduinos millis() as tick source*/
static uint32_t my_tick(void)
{
return millis();
}
int get_touch_count(){
// Register 0x02;
// Touch count, max 2
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x02);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 1);
return(Wire.read());
}
// Read x, y
// May be have to exchange/adjust x, y according to screen rotation.
void get_touch_point(int *x, int *y) {
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x03);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
*x = (Wire.read() & 0x0f) << 8 | Wire.read();
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x05);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
*y = (Wire.read() & 0x0f) << 8 | Wire.read();
}
void setup()
{
String LVGL_Arduino = "Hello LVGL! ";
LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
delay(2000);
Serial.begin( 115200 );
delay(1000);
Serial.println( LVGL_Arduino );
// default SDA = 4
// default SCL = 5
Serial.println("SDA " + String(SDA));
Serial.println("SCL " + String(SCL));
Wire.begin(); // I2C
delay(100);
// Optional CTS_RST
// In my test, CTS_RST can be connect to 3V3.
Serial.println("Hardware Reset on CTP_RST: ");
pinMode(CTP_RST, OUTPUT);
digitalWrite(CTP_RST, HIGH);
delay(100);
digitalWrite(CTP_RST, LOW);
delay(100);
digitalWrite(CTP_RST, HIGH);
delay(100);
lv_init();
/*Set a tick source so that LVGL will know how much time elapsed. */
lv_tick_set_cb(my_tick);
lv_display_t * disp;
//Use TFT_eSPI interface
/*TFT_eSPI can be enabled lv_conf.h to initialize the display in a simple way*/
disp = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, TFT_ROTATION);
/*Initialize the (dummy) input device driver*/
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); /*Touchpad should have POINTER type*/
lv_indev_set_read_cb(indev, my_touchpad_read);
lv_my_exercise_buttons();
Serial.println( "Setup done" );
}
void loop()
{
lv_timer_handler(); /* let the GUI do its work */
delay(100); /* let this time pass */
}
/* Callback function */
static void btn_event_cb(lv_event_t * e) {
/* Get the button object */
lv_obj_t * obj = (lv_obj_t *)lv_event_get_target(e);
/* Get user data (color) */
lv_color_t color = *(lv_color_t *)lv_event_get_user_data(e);
/* Change screen background color */
lv_obj_set_style_bg_color(lv_scr_act(), color, LV_PART_MAIN);
}
/* Function to create buttons */
lv_obj_t * create_button(lv_obj_t * parent, const char * text, lv_color_t * color) {
lv_obj_t * btn = lv_button_create(parent);
lv_obj_set_size(btn, LV_PCT(100), LV_SIZE_CONTENT);
/* Set button background color */
lv_obj_set_style_bg_color(btn, *color, LV_PART_MAIN);
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text(label, text);
lv_obj_center(label);
/* Attach the common callback and pass the color as user data */
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, color);
return btn;
}
/**
* A simple row and a column layout with flexbox
*/
void lv_my_exercise_buttons(void)
{
/*Create a container with COLUMN flex direction*/
lv_obj_t * cont_main = lv_obj_create(lv_screen_active());
lv_obj_set_size(cont_main, TFT_HOR_RES-50, TFT_VER_RES-50);
lv_obj_align(cont_main, LV_ALIGN_CENTER, 0, 0); //lv_obj_align_to(cont_col, cont_row, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
lv_obj_set_flex_flow(cont_main, LV_FLEX_FLOW_COLUMN);
lv_obj_t *label_top = lv_label_create(lv_screen_active());
lv_label_set_text(label_top, "Arduino LVGL Exercise on Pico 2");
lv_obj_align(label_top, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_t *label_bottom = lv_label_create(lv_screen_active());
lv_label_set_text(label_bottom, "coXXect.blogspot.com");
lv_obj_align(label_bottom, LV_ALIGN_BOTTOM_MID, 0, 0);
/* Define static colors */
static lv_color_t red_color = lv_palette_main(LV_PALETTE_RED);
static lv_color_t green_color = lv_palette_main(LV_PALETTE_GREEN);
static lv_color_t blue_color = lv_palette_main(LV_PALETTE_BLUE);
/* Create buttons */
create_button(cont_main, "RED", &red_color);
create_button(cont_main, "GREEN", &green_color);
create_button(cont_main, "BLUE", &blue_color);
}
More Exercise:
Create LVGL Arc(lv_arc) to control NeoPixel ring.
Connection between 8X RGB NeoPixel Ring and Raspberry Pi Pico 2:
VCC - VBUS
GND - GND
DI - GP0
pico2_LVGL_Arduino_arc_NeoPixel.ino
/*
LVGL exercise run on Raspberry Pi Pico 2 in Arduino framework,
with 4.0" 320x480 TFT SPI ST7796 with FT6336U Capacitive Touch.
Create LVGL Arc(lv_arc) to control NeoPixel ring.
Raspberry Pi Pico 2 drive 4.0" 320x480 TFT SPI ST7796 with FT6336U Capacitive Touch + SD,
in Arduino framework.
- Setup TFT_eSPI to display on ST7796 SPI TFT.
- I2C interface FT6336U cap. touch.
https://coxxect.blogspot.com/2025/04/raspberry-pi-pico-2-drive-40-480x320.html
LVGL on Raspberry Pi Pico 2 (Arduino framework/arduino-pico)
with 320x480 TFT SPI ST7796 + FT6336U Capacitive Touch.
https://coxxect.blogspot.com/2025/05/lvgl-on-raspberry-pi-pico-2-arduino.html
*/
#include <lvgl.h>
#include "lv_conf.h"
#include <TFT_eSPI.h>
#include <Adafruit_NeoPixel.h>
// for FT6336U cap touch
#include <Wire.h>
#define CTP_RST 14 // option, can connect to 3V3.
#define FT6336U_ADDR 0x38
#define PIN_NeoPixel 0
#define NUMPIXELS 8
/*Set to your screen resolution and rotation*/
#define TFT_HOR_RES 320 //320
#define TFT_VER_RES 480 //240
#define TFT_ROTATION LV_DISPLAY_ROTATION_0
/*LVGL draw into this buffer, 1/10 screen size usually works well. The size is in bytes*/
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
String LVGL_Arduino = "LVGL! ";
Adafruit_NeoPixel pixels(NUMPIXELS, PIN_NeoPixel, NEO_GRB + NEO_KHZ800);
/*Read the touchpad*/
void my_touchpad_read( lv_indev_t * indev, lv_indev_data_t * data )
{
if (get_touch_count()>0){
data->state = LV_INDEV_STATE_PRESSED;
int x, y;
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x03);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
x = (Wire.read() & 0x0f) << 8 | Wire.read();
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x05);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
y = (Wire.read() & 0x0f) << 8 | Wire.read();
data->point.x = x;
data->point.y = y;
}else{
data->state = LV_INDEV_STATE_RELEASED;
}
}
/*use Arduinos millis() as tick source*/
static uint32_t my_tick(void)
{
return millis();
}
int get_touch_count(){
// Register 0x02;
// Touch count, max 2
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x02);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 1);
return(Wire.read());
}
// Read x, y
// May be have to exchange/adjust x, y according to screen rotation.
void get_touch_point(int *x, int *y) {
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x03);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
*x = (Wire.read() & 0x0f) << 8 | Wire.read();
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x05);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
*y = (Wire.read() & 0x0f) << 8 | Wire.read();
}
void setup()
{
LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
delay(2000);
Serial.begin( 115200 );
delay(1000);
Serial.println( LVGL_Arduino );
Wire.begin(); // I2C
delay(100);
pinMode(CTP_RST, OUTPUT);
digitalWrite(CTP_RST, HIGH);
delay(100);
digitalWrite(CTP_RST, LOW);
delay(100);
digitalWrite(CTP_RST, HIGH);
delay(100);
pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
pixels.setBrightness(10);
pixels.clear();
pixels.show();
lv_init();
/*Set a tick source so that LVGL will know how much time elapsed. */
lv_tick_set_cb(my_tick);
lv_display_t * disp;
//Use TFT_eSPI interface
/*TFT_eSPI can be enabled lv_conf.h to initialize the display in a simple way*/
disp = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, TFT_ROTATION);
/*Initialize the (dummy) input device driver*/
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); /*Touchpad should have POINTER type*/
lv_indev_set_read_cb(indev, my_touchpad_read);
lv_my_exercise_arc();
Serial.println( "Setup done" );
}
void loop()
{
lv_timer_handler(); /* let the GUI do its work */
delay(100); /* let this time pass */
}
static void value_changed_event_cb(lv_event_t * e)
{
lv_obj_t * arc = lv_event_get_target_obj(e);
int16_t arc_value = lv_arc_get_value(arc);
Serial.println(arc_value);
pixels.clear();
if (arc_value>0){
for (int i=0; i < arc_value; i++){
pixels.setPixelColor(i, pixels.Color(100, 100, 100));
}
}
pixels.show();
}
/**
* A simple row and a column layout with flexbox
*/
void lv_my_exercise_arc(void)
{
/*Create a container with COLUMN flex direction*/
lv_obj_t * cont_main = lv_obj_create(lv_screen_active());
lv_obj_set_size(cont_main, TFT_HOR_RES-50, TFT_VER_RES-50);
lv_obj_align(cont_main, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_flex_flow(cont_main, LV_FLEX_FLOW_COLUMN);
lv_obj_t *label_top = lv_label_create(lv_screen_active());
lv_label_set_text(label_top, "Arduino LVGL Exercise on Pico 2");
lv_obj_align(label_top, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_t *label_bottom = lv_label_create(lv_screen_active());
lv_label_set_text(label_bottom, "coXXect.blogspot.com");
lv_obj_align(label_bottom, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_obj_t *label_lvgl = lv_label_create(cont_main);
lv_label_set_text(label_lvgl, LVGL_Arduino.c_str());
/* Create arc object */
lv_obj_t * arc_obj = lv_arc_create(cont_main);
lv_arc_set_range(arc_obj, 0, 8);
lv_arc_set_value(arc_obj, 0);
lv_arc_set_bg_start_angle(arc_obj, 90);
lv_obj_add_event_cb(arc_obj, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
}
Create LVGL grid of buttons to control NeoPixel Matrix
pico2_LVGL_Arduino_NeoPixel_matrix.ino
/*
LVGL exercise run on Raspberry Pi Pico 2 in Arduino framework,
with 4.0" 320x480 TFT SPI ST7796 with FT6336U Capacitive Touch.
Create LVGL grid of button to control NeoPixel matrix.
Raspberry Pi Pico 2 drive 4.0" 320x480 TFT SPI ST7796 with FT6336U Capacitive Touch + SD,
in Arduino framework.
- Setup TFT_eSPI to display on ST7796 SPI TFT.
- I2C interface FT6336U cap. touch.
https://coxxect.blogspot.com/2025/04/raspberry-pi-pico-2-drive-40-480x320.html
LVGL on Raspberry Pi Pico 2 (Arduino framework/arduino-pico)
with 320x480 TFT SPI ST7796 + FT6336U Capacitive Touch.
https://coxxect.blogspot.com/2025/05/lvgl-on-raspberry-pi-pico-2-arduino.html
*/
#include <lvgl.h>
#include "lv_conf.h"
#include <TFT_eSPI.h>
#include <Adafruit_NeoPixel.h>
// for FT6336U cap touch
#include <Wire.h>
#define CTP_RST 14 // option, can connect to 3V3.
#define FT6336U_ADDR 0x38
#define PIN_NeoPixel 0
#define NUMPIXELS 16
/*Set to your screen resolution and rotation*/
#define TFT_HOR_RES 320 //320
#define TFT_VER_RES 480 //240
#define TFT_ROTATION LV_DISPLAY_ROTATION_0
/*LVGL draw into this buffer, 1/10 screen size usually works well. The size is in bytes*/
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
String LVGL_Arduino = "LVGL! ";
Adafruit_NeoPixel pixels(NUMPIXELS, PIN_NeoPixel, NEO_GRB + NEO_KHZ800);
#define FRAME_WIDTH 4
#define FRAME_HEIGHT 4
byte neopixel_frame[FRAME_HEIGHT][FRAME_WIDTH] = {
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }
};
uint16_t neopixel_map[FRAME_HEIGHT][FRAME_WIDTH] = {
{ 15, 14, 13, 12 },
{ 8, 9, 10, 11 },
{ 7, 6, 5, 4 },
{ 0, 1, 2, 3 }
};
int get_touch_count(){
// Register 0x02;
// Touch count, max 2
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x02);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 1);
return(Wire.read());
}
/*Read the touchpad*/
void my_touchpad_read( lv_indev_t * indev, lv_indev_data_t * data )
{
if (get_touch_count()>0){
data->state = LV_INDEV_STATE_PRESSED;
int x, y;
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x03);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
x = (Wire.read() & 0x0f) << 8 | Wire.read();
Wire.beginTransmission(FT6336U_ADDR);
Wire.write(0x05);
Wire.endTransmission();
Wire.requestFrom(FT6336U_ADDR, 2);
y = (Wire.read() & 0x0f) << 8 | Wire.read();
data->point.x = x;
data->point.y = y;
}else{
data->state = LV_INDEV_STATE_RELEASED;
}
}
/*use Arduinos millis() as tick source*/
static uint32_t my_tick(void)
{
return millis();
}
void setup()
{
LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
delay(2000);
Serial.begin( 115200 );
delay(1000);
Serial.println( LVGL_Arduino );
Wire.begin(); // I2C
delay(100);
pinMode(CTP_RST, OUTPUT);
digitalWrite(CTP_RST, HIGH);
delay(100);
digitalWrite(CTP_RST, LOW);
delay(100);
digitalWrite(CTP_RST, HIGH);
delay(100);
pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
pixels.setBrightness(10);
pixels.clear();
pixels.show();
lv_init();
/*Set a tick source so that LVGL will know how much time elapsed. */
lv_tick_set_cb(my_tick);
lv_display_t * disp;
//Use TFT_eSPI interface
/*TFT_eSPI can be enabled lv_conf.h to initialize the display in a simple way*/
disp = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, TFT_ROTATION);
/*Initialize the (dummy) input device driver*/
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); /*Touchpad should have POINTER type*/
lv_indev_set_read_cb(indev, my_touchpad_read);
lv_my_exercise_Neopixel_matrix();
Serial.println( "Setup done" );
show_Neopixel_frame();
}
void loop()
{
lv_timer_handler(); /* let the GUI do its work */
delay(100); /* let this time pass */
}
void show_Neopixel_frame(){
pixels.clear();
for (int y=0; y < FRAME_HEIGHT; y++) {
for (int x=0; x < FRAME_WIDTH; x++) {
if (neopixel_frame[y][x] == 0) {
pixels.setPixelColor(neopixel_map[y][x],
pixels.Color(0, 0, 0));
}else{
pixels.setPixelColor(neopixel_map[y][x],
pixels.Color(0, 0, 100));
}
}
}
pixels.show();
}
// Define a struct to store the integer parameter
typedef struct {
int row;
int col;
} my_callback_data_t;
// Callback function
static void my_callback(lv_event_t * e) {
lv_obj_t * btn = (lv_obj_t *) lv_event_get_target(e); // Get the button object
bool is_checked = lv_obj_has_state(btn, LV_STATE_CHECKED); // Check if it's toggled
my_callback_data_t * data = (my_callback_data_t *) lv_event_get_user_data(e);
if(data) {
Serial.printf("Callback received value: %d %d \n", data->row, data->col);
if (is_checked){
neopixel_frame[data->row][data->col] = 1;
}else{
neopixel_frame[data->row][data->col] = 0;
}
}
show_Neopixel_frame();
}
void lv_my_exercise_Neopixel_matrix(void)
{
/*Create a container with COLUMN flex direction*/
lv_obj_t * cont_main = lv_obj_create(lv_screen_active());
lv_obj_set_size(cont_main, TFT_HOR_RES-50, TFT_VER_RES-50);
lv_obj_align(cont_main, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_flex_flow(cont_main, LV_FLEX_FLOW_COLUMN);
lv_obj_t *label_top = lv_label_create(lv_screen_active());
lv_label_set_text(label_top, "Arduino LVGL Exercise on Pico 2");
lv_obj_align(label_top, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_t *label_bottom = lv_label_create(lv_screen_active());
lv_label_set_text(label_bottom, "coXXect.blogspot.com");
lv_obj_align(label_bottom, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_obj_t *label_lvgl = lv_label_create(cont_main);
lv_label_set_text(label_lvgl, LVGL_Arduino.c_str());
create_button_grid(cont_main);
}
/**
* A grid of 4x4 buttons
*/
void create_button_grid(lv_obj_t * cont)
{
static int32_t col_dsc[] = {50, 50, 50, 50, LV_GRID_TEMPLATE_LAST};
static int32_t row_dsc[] = {50, 50, 50, 50, LV_GRID_TEMPLATE_LAST};
/*Create button grid*/
lv_obj_t *cont_button_grid = lv_obj_create(cont);
lv_obj_set_style_grid_column_dsc_array(cont_button_grid, col_dsc, 0);
lv_obj_set_style_grid_row_dsc_array(cont_button_grid, row_dsc, 0);
lv_obj_set_size(cont_button_grid, 256, 256);
lv_obj_center(cont_button_grid);
lv_obj_set_layout(cont_button_grid, LV_LAYOUT_GRID);
// Create a style for the unchecked state (Gray)
static lv_style_t style_unchecked;
lv_style_init(&style_unchecked);
lv_style_set_bg_color(&style_unchecked, lv_color_make(230, 230, 230)); // Gray color
// Create a style for the checked state (Blue)
static lv_style_t style_checked;
lv_style_init(&style_checked);
lv_style_set_bg_color(&style_checked, lv_color_make(0, 0, 255)); // Blue color
lv_obj_t * btn;
for (int row=0; row<FRAME_HEIGHT; row++){
for (int col=0; col<FRAME_WIDTH; col++){
btn = lv_button_create(cont_button_grid); // Create button
lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE); // Enable toggle mode
// Apply the styles based on state
lv_obj_add_style(btn, &style_unchecked, LV_STATE_DEFAULT);
lv_obj_add_style(btn, &style_checked, LV_STATE_CHECKED);
lv_obj_set_grid_cell(btn, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
// Allocate memory for user data
my_callback_data_t * data = (my_callback_data_t *) malloc(sizeof(my_callback_data_t));
data->row = row;
data->col = col;
lv_obj_add_event_cb(btn, my_callback, LV_EVENT_CLICKED, data);
}
}
}
Comments
Post a Comment