Skip to content

RP2040 Starter

A practical starting-point for the RP2040 with a round 240 × 240 display (e.g. GC9A01 / ST7789).


Code

#include "pico/stdlib.h"
#include "LCD.h" // display specific
#include "microgui/inc/mgui_common_defs.h"
#include "microgui/inc/mgui_interface.h"

void LCD_init()
{
    if (DEV_Module_Init() != 0)
    {
        return -1;
    }

    LCD_1IN28_Init(HORIZONTAL);
    LCD_1IN28_Clear(WHITE);
    DEV_SET_PWM(60);
}

void gui_draw_pixel_hal(int16_t x, int16_t y, mgui_color_t color)
{
    gui_draw_pixel_hal_lcd(x, y, color);
}

void gui_hal_flush_buffer(mgui_color_t* buffer, uint32_t size,
                          int16_t x, int16_t y,
                          int16_t width, int16_t height)
{
    (void)size;

    if (x < 0 || y < 0) return;
    if (x + width  > SCREEN_WIDTH)  return;
    if (y + height > SCREEN_HEIGHT) return;

    LCD_1IN28_SetWindows(x, y, x + width, y + height);
    DEV_Digital_Write(LCD_DC_PIN, 1);
    static uint8_t line_buffer[SCREEN_WIDTH * 2];

    for (int row = 0; row < height; row++) {
        int offset = row * width;

        for (int col = 0; col < width; col++) {
            mgui_color_t color = buffer[offset + col];
            uint16_t c = color.value;          // get 16-bit RGB565
            line_buffer[col * 2]     = c >> 8;       // high byte
            line_buffer[col * 2 + 1] = c & 0xFF;
        }

        DEV_SPI_Write_nByte((uint8_t *)line_buffer, width * 2);
    }
}

mgui_widget_t* screen_1;
mgui_widget_t* valuelabel;

void mgui_app_init(void)
{
    mgui_init(SCREEN_WIDTH, SCREEN_HEIGHT, MGUI_BUFFER_SIZE_KB, 30);
}

void screen_init()
{
    /* Screen */
    screen_1 = mgui_allocate_widget(NULL, MGUI_WIDGET_SCREEN, (mgui_area_t){0, 0, 240, 240}, ((mgui_color_t){.value = 0x0883}));

    /* TitleLabel */
    mgui_widget_t* titlelabel = mgui_allocate_widget(screen_1, MGUI_WIDGET_LABEL, (mgui_area_t){0, 0, 130, 18}, ((mgui_color_t){.value = 0x4B52}));
    mgui_widget_align(titlelabel, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(titlelabel, 0, -87);
    mgui_widget_label_set_text(titlelabel, "BRIGHTNESS");

    /* ValueLabel */
    valuelabel = mgui_allocate_widget(screen_1, MGUI_WIDGET_LABEL, (mgui_area_t){0, 0, 80, 48}, ((mgui_color_t){.value = 0xEFBF}));
    mgui_widget_align(valuelabel, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(valuelabel, 0, -12);
    mgui_widget_label_set_text(valuelabel, "0");
    mgui_widget_label_set_font_type(valuelabel, MGUI_FONT_LEXEND_24PT_2BPP);

    /* UnitLabel */
    mgui_widget_t* unitlabel = mgui_allocate_widget(screen_1, MGUI_WIDGET_LABEL, (mgui_area_t){0, 0, 100, 26}, ((mgui_color_t){.value = 0x2A4C}));
    mgui_widget_align(unitlabel, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(unitlabel, 0, 18);
    mgui_widget_label_set_text(unitlabel, "% intensity");

    /* BtnDecrease */
    mgui_widget_t* btndecrease = mgui_allocate_widget(screen_1, MGUI_WIDGET_BUTTON, (mgui_area_t){0, 0, 38, 34}, ((mgui_color_t){.value = 0x10E5}));
    mgui_widget_border_property(btndecrease, ((mgui_color_t){.value = 0x19AA}), 1);
    mgui_widget_align(btndecrease, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(btndecrease, -87, 1);
    mgui_widget_radius_property(btndecrease, 10, false);
    mgui_widget_button_text(btndecrease, "-");
    mgui_widget_button_text_color(btndecrease, ((mgui_color_t){.value = 0x549A}));

    /* BtnIncrease */
    mgui_widget_t* btnincrease = mgui_allocate_widget(screen_1, MGUI_WIDGET_BUTTON, (mgui_area_t){0, 0, 38, 34}, ((mgui_color_t){.value = 0x10E5}));
    mgui_widget_border_property(btnincrease, ((mgui_color_t){.value = 0x19AA}), 1);
    mgui_widget_align(btnincrease, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(btnincrease, 87, 1);
    mgui_widget_radius_property(btnincrease, 10, false);
    mgui_widget_button_text(btnincrease, "+");
    mgui_widget_button_text_color(btnincrease, ((mgui_color_t){.value = 0x549A}));

    /* BtnWarm */
    mgui_widget_t* btnwarm = mgui_allocate_widget(screen_1, MGUI_WIDGET_BUTTON, (mgui_area_t){0, 0, 60, 28}, ((mgui_color_t){.value = 0x18C1}));
    mgui_widget_border_property(btnwarm, ((mgui_color_t){.value = 0x3981}), 1);
    mgui_widget_align(btnwarm, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(btnwarm, -62, 52);
    mgui_widget_radius_property(btnwarm, 8, false);
    mgui_widget_button_text(btnwarm, "WARM");
    mgui_widget_button_text_color(btnwarm, ((mgui_color_t){.value = 0xFD48}));

    /* BtnCool */
    mgui_widget_t* btncool = mgui_allocate_widget(screen_1, MGUI_WIDGET_BUTTON, (mgui_area_t){0, 0, 60, 28}, ((mgui_color_t){.value = 0x08C4}));
    mgui_widget_border_property(btncool, ((mgui_color_t){.value = 0x0947}), 1);
    mgui_widget_align(btncool, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(btncool, 62, 52);
    mgui_widget_radius_property(btncool, 8, false);
    mgui_widget_button_text(btncool, "COOL");
    mgui_widget_button_text_color(btncool, ((mgui_color_t){.value = 0x465F}));

    /* PowerLabel */
    mgui_widget_t* powerlabel = mgui_allocate_widget(screen_1, MGUI_WIDGET_LABEL, (mgui_area_t){0, 0, 58, 34}, ((mgui_color_t){.value = 0x2A4C}));
    mgui_widget_align(powerlabel, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(powerlabel, 0, 49);
    mgui_widget_label_set_text(powerlabel, "POWER");

    /* PowerToggle */
    mgui_widget_t* powertoggle = mgui_allocate_widget(screen_1, MGUI_WIDGET_TOGGLE_BUTTON, (mgui_area_t){0, 0, 54, 26}, ((mgui_color_t){.value = 0x04BF}));
    mgui_widget_align(powertoggle, MGUI_ALIGN_CENTER);
    mgui_widget_set_align_offset(powertoggle, 0, 83);
    mgui_widget_toggle_button_set_checked(powertoggle, true);
    mgui_widget_toggle_button_set_colors(powertoggle, ((mgui_color_t){.value = 0x04BF}), ((mgui_color_t){.value = 0x1926}), MGUI_COLOR_WHITE);
}


void mgui_timer_tasks(void) {
    static int counter = 0;
    counter++;

    // 1 second timer
    if (counter >= 30) {
        counter = 0;

        static int value = 0;
        value = (value + 1) % 101;
        char buf[16];
        snprintf(buf, sizeof(buf), "%d", value);
        mgui_widget_label_set_text(valuelabel, buf);
    }
}

int main(void)
{
    stdio_init_all();
    LCD_init();

    mgui_app_init();
    screen_init();

    uint32_t last_gui_tick = time_us_32();

    while (true) {
        uint32_t now = time_us_32();
        if (now - last_gui_tick >= 30000) {
            last_gui_tick = now;
            mgui_task_execute();
            mgui_timer_tasks();
        }
    }
}

See Also