hello_lvgl

Example of the component cube32esp/cube32_bsp v0.0.17
# hello_lvgl

Minimal LVGL v9 + touch demo for the CUBE32 board. It shows how to start LVGL through the BSP, create widgets, handle touch events and rotate the screen with a swipe.

## Features

- **LVGL start-up through the BSP**: `cube32_init()` brings up the display, LVGL and touch; the example only uses `cube32::LvglDisplay`
- **Basic widgets**: title and subtitle labels, a styled button with a pressed-state style, a counter label, status labels
- **Touch input**: tap the **Click Me!** button to increment the counter
- **Swipe to rotate**: swipe right for the next rotation, swipe left for the previous one (0 → 90 → 180 → 270°); the UI is rebuilt for the new screen size
- **Thread-safe LVGL access**: every widget update runs between `lvgl.lock()` and `lvgl.unlock()`
- **Colour animation**: the counter label changes colour continuously from the main loop
- **Footer**: shows the BSP and LVGL versions

## Hardware

- CUBE32 board (ESP32-S3) with a supported touch display (ST7789 or ST7796S, auto-detected at boot)

## Configuration

`sdkconfig.defaults` of the release example already has what the demo needs:

| Setting | Why |
|---------|-----|
| `CONFIG_CUBE32_LVGL_ENABLED=y` | LVGL display driver |
| `CONFIG_CUBE32_TOUCH_ENABLED=y` | Touch input (button and swipe) |
| `CONFIG_LV_FONT_MONTSERRAT_14=y` | Font used by all labels |
| `CONFIG_LV_FONT_MONTSERRAT_10/20/24=y` | Required by the BLE OTA UI whenever LVGL is on |

In the BSP dev project select the demo with `idf.py menuconfig` → `CUBE32 Application Selection` → `Hello LVGL Example` (it is only listed when LVGL is enabled).

## Build and run

```bash
idf.py set-target esp32s3
idf.py build
idf.py -p <port> flash monitor
```

Run `idf.py set-target esp32s3` again after deleting `sdkconfig`; otherwise the target falls back to `esp32`.

## Usage

1. Flash the example; the screen shows **CUBE32 / LVGL + Touch Demo**.
2. Tap **Click Me!**: `Count` increases by one for every tap.
3. Swipe left or right across the screen: the screen rotates and `Rotation: <deg>` is updated. The counter value is kept.
4. If touch is not available, the example shows `Touch: N/A` instead of `Swipe to rotate`.

## Console output

```
I (xxxx) hello_lvgl: ========================================
I (xxxx) hello_lvgl: CUBE32 Hello LVGL Example
I (xxxx) hello_lvgl: ========================================
I (xxxx) hello_lvgl: Touch input: Enabled
I (xxxx) hello_lvgl: Swipe left/right to rotate screen!
I (xxxx) hello_lvgl: Creating UI for 240x320 screen
I (xxxx) hello_lvgl: UI created successfully
I (xxxx) hello_lvgl: Button clicked! Count: 1
I (xxxx) hello_lvgl: Swipe right detected - rotating to next
I (xxxx) hello_lvgl: Rotating screen to 90 degrees
```

The screen size in the log depends on the detected display.

## How it works

| Part | Function |
|------|----------|
| `app_main()` | Calls `cube32_init()`, checks that LVGL is initialised, reads the current rotation, creates the UI and loops every 50 ms |
| `create_ui()` | Builds the screen under the LVGL lock |
| `btn_event_cb()` | Increments the counter and updates the label on `LV_EVENT_CLICKED` |
| `screen_gesture_cb()` | Records the press and release points; a horizontal move of more than 50 px is a swipe |
| `rotate_screen_next()` / `rotate_screen_prev()` | Call `LvglDisplay::setRotation()` and rebuild the UI with `recreate_ui()` |
| `animate_counter()` | Changes the counter label colour from the main loop |

## Notes

- LVGL runs its own rendering task, so the main loop only needs a short delay.
- If LVGL is not enabled in the configuration, the example logs the menuconfig path to enable it and exits.
- To build your own LVGL UI, start from this example and replace `create_ui()`.

To create a project from this example, run:

idf.py create-project-from-example "cube32esp/cube32_bsp=0.0.17:hello_lvgl"

or download archive (~9.77 KB)