Close

Making "Hello World" with ESP-IDF

A project log for BEAD: A Tiny Speed eReader

Compact book reader that can be a bead on your keychain or something more

alexAlex 08/28/2024 at 15:170 Comments

I couldn't find any simple examples of working with the ESP-IDF display, so I asked chatGPT to make such an example for me from a LilyGo-Display-IDF demo.  All changes affected the main.cpp file.

Here's a simplified version of the main.cpp file:

/**
 * @file      main.cpp
 * @brief     Simplified display initialization and LVGL setup for ESP32
 */

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "lvgl.h"
#include "tft_driver.h"
#include "product_pins.h"

static const char *TAG = "main";
#define LVGL_TICK_PERIOD_MS 2
#define LVGL_TASK_STACK_SIZE (4 * 1024)

static lv_disp_draw_buf_t disp_buf;
lv_disp_drv_t disp_drv;

// Flush callback to send buffer to display
static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
    display_push_colors(area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1, (uint16_t *)color_map);
    lv_disp_flush_ready(drv);
}

// LVGL tick increment callback
static void lvgl_tick_inc(void *arg)
{
    lv_tick_inc(LVGL_TICK_PERIOD_MS);
}

// LVGL task handler
static void lvgl_task(void *arg)
{
    while (true) {
        lv_task_handler();
        vTaskDelay(pdMS_TO_TICKS(LVGL_TICK_PERIOD_MS));
    }
}

extern "C" void app_main(void)
{
    ESP_LOGI(TAG, "Initialize DISPLAY and LVGL library.");
    display_init();
    lv_init();

    // Allocate display buffers
    lv_color_t *buf1 = (lv_color_t *)heap_caps_malloc(AMOLED_HEIGHT * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    lv_color_t *buf2 = (lv_color_t *)heap_caps_malloc(AMOLED_HEIGHT * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, AMOLED_HEIGHT * 20);

    // Set up and register display driver
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = AMOLED_HEIGHT;
    disp_drv.ver_res = AMOLED_WIDTH;
    disp_drv.flush_cb = lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    // Install LVGL tick timer
    esp_timer_handle_t lvgl_tick_timer;
    const esp_timer_create_args_t tick_timer_args = { .callback = &lvgl_tick_inc, .name = "lvgl_tick" };
    esp_timer_create(&tick_timer_args, &lvgl_tick_timer);
    esp_timer_start_periodic(lvgl_tick_timer, LVGL_TICK_PERIOD_MS * 1000);

    // Create and display label
    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello, ESP32-S3!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

    // Create LVGL task
    xTaskCreate(lvgl_task, "LVGL", LVGL_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
}

Here’s a line-by-line explanation of the simplified main.cpp file:

Includes:

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "lvgl.h"
#include "tft_driver.h"
#include "product_pins.h"

These are preprocessor directives that include various libraries and headers:


TAG Declaration:

static const char *TAG = "main";

Defines a static constant string TAG used as a tag for logging purposes, helping to identify the source of log messages.


Macro Definitions:

#define LVGL_TICK_PERIOD_MS 2
#define LVGL_TASK_STACK_SIZE (4 * 1024)


Display Buffer and Driver Declaration:

static lv_disp_draw_buf_t disp_buf;
lv_disp_drv_t disp_drv;


Flush Callback Function:

static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
    display_push_colors(area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1, (uint16_t *)color_map);
    lv_disp_flush_ready(drv);
}


Tick Increment Function:

static void lvgl_tick_inc(void *arg)
{
    lv_tick_inc(LVGL_TICK_PERIOD_MS);
}

LVGL Task Function:

static void lvgl_task(void *arg)
{
    while (true) {
        lv_task_handler();
        vTaskDelay(pdMS_TO_TICKS(LVGL_TICK_PERIOD_MS));
    }
}

Main Application Function:

extern "C" void app_main(void)
{

Initialization:

    ESP_LOGI(TAG, "Initialize DISPLAY and LVGL library.");
    display_init();
    lv_init(); 

Display Buffer Allocation and Initialization:

    lv_color_t *buf1 = (lv_color_t *)heap_caps_malloc(AMOLED_HEIGHT * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    lv_color_t *buf2 = (lv_color_t *)heap_caps_malloc(AMOLED_HEIGHT * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, AMOLED_HEIGHT * 20);

Display Driver Setup:

    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = AMOLED_HEIGHT;
    disp_drv.ver_res = AMOLED_WIDTH;
    disp_drv.flush_cb = lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    lv_disp_drv_register(&disp_drv);

LVGL Tick Timer Setup:

    esp_timer_handle_t lvgl_tick_timer;
    const esp_timer_create_args_t tick_timer_args = { .callback = &lvgl_tick_inc, .name = "lvgl_tick" };
    esp_timer_create(&tick_timer_args, &lvgl_tick_timer);
    esp_timer_start_periodic(lvgl_tick_timer, LVGL_TICK_PERIOD_MS * 1000);

Label Creation and Alignment:

    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello, ESP32-S3!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); 

LVGL Task Creation:

    xTaskCreate(lvgl_task, "LVGL", LVGL_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
}

Discussions