Skip to content

Instantly share code, notes, and snippets.

@denizzzka
Created August 27, 2024 10:37
Show Gist options
  • Select an option

  • Save denizzzka/29d85889a4e0fe0d90bb4df8b1702262 to your computer and use it in GitHub Desktop.

Select an option

Save denizzzka/29d85889a4e0fe0d90bb4df8b1702262 to your computer and use it in GitHub Desktop.
ESP32c3 and ILI9341 display using Dlang: wrong colors
module main;
import esp_idf_binding;
enum CONFIG_FREERTOS_HZ = 1000;
enum portTICK_PERIOD_MS = 1000 / CONFIG_FREERTOS_HZ;
void ledBlink(gpio_num_t gpio, int delayMs) nothrow
{
gpio_reset_pin(gpio);
/* Set the GPIO as a push/pull output */
gpio_set_direction(gpio, gpio_mode_t.GPIO_MODE_OUTPUT);
ubyte s_led_state;
while (1) {
gpio_set_level(gpio, s_led_state);
s_led_state = !s_led_state;
vTaskDelay(delayMs / portTICK_PERIOD_MS);
}
}
extern(C) export void d_app_main() nothrow
{
import core.thread;
try
{
auto ledBlink1 = new Thread(
() =>ledBlink(gpio_num_t.GPIO_NUM_12, 20 / portTICK_PERIOD_MS)
).start;
auto ledBlink2 = new Thread(
() =>ledBlink(gpio_num_t.GPIO_NUM_13, 30 / portTICK_PERIOD_MS)
).start;
}
catch(Exception e){}
auto displ = new Displ();
auto active_scr = displ.displ.lv_display_get_screen_active();
auto black = lv_color_t(0, 0, 0);
lv_obj_set_style_bg_color(active_scr, black, 0);
void createSquare(ref lv_style_t style, lv_align_t _align)
{
auto rect = lv_obj_create(active_scr);
lv_obj_set_size(rect , 70, 40);
lv_obj_align(rect, _align, 0, 0);
lv_obj_add_style(rect, &style, 0);
}
auto red_col = lv_color_t(0, 0, 255);
lv_style_t red_style;
lv_style_init(&red_style);
lv_style_set_border_width(&red_style, 5);
lv_style_set_outline_width(&red_style, 5);
lv_style_set_border_color(&red_style, red_col);
lv_style_set_outline_color(&red_style, black);
lv_style_set_text_color(&red_style, black);
lv_style_set_text_decor(&red_style, _lv_text_decor_t.LV_TEXT_DECOR_UNDERLINE);
lv_style_t green;
lv_style_init(&green);
lv_style_set_border_width(&green, 5);
lv_style_set_outline_width(&green, 5);
lv_style_set_border_color(&green, lv_color_t(0, 255, 0));
lv_style_set_outline_color(&green, lv_color_t(0, 255, 0));
lv_style_t blue;
lv_style_init(&blue);
lv_style_set_border_width(&blue, 5);
lv_style_set_outline_width(&blue, 5);
lv_style_set_border_color(&blue, lv_color_t(255, 0, 0));
lv_style_set_outline_color(&blue, lv_color_t(255, 0, 0));
lv_style_set_text_color(&blue, black);
createSquare(red_style, _lv_align_t.LV_ALIGN_BOTTOM_RIGHT);
createSquare(green, _lv_align_t.LV_ALIGN_BOTTOM_MID);
createSquare(blue, _lv_align_t.LV_ALIGN_BOTTOM_LEFT);
lv_obj_t* label = lv_label_create(active_scr);
lv_label_set_text(label, cast(const ubyte*) "Hello, world!");
lv_obj_align(label, _lv_align_t.LV_ALIGN_CENTER, 0, 0);
lv_obj_add_style(label, &blue, 0);
try
while(true)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
catch(Exception e){}
}
lv_color_t lv_color_hex(uint32_t c) nothrow
{
lv_color_t ret;
ret.red = (c >> 16) & 0xff;
ret.green = (c >> 8) & 0xff;
ret.blue = (c >> 0) & 0xff;
return ret;
}
void lcd_hello_world(lv_obj_t* active_scr)
{
/*Change the active screen's background color*/
static uint color = 0x003a57;
color+=100;
lv_obj_set_style_bg_color(active_scr, lv_color_hex(color), _lv_part_t.LV_PART_MAIN);
}
class Displ
{
import core.thread: Thread;
enum sizeX = 240;
enum sizeY = 320;
enum host = spi_host_device_t.SPI2_HOST;
enum cmdPin = gpio_num_t.GPIO_NUM_6;
private __gshared static Thread ticks;
private __gshared static Thread relatedTasks;
private esp_lcd_panel_t* panel;
private esp_lcd_panel_io_t* panel_handle;
private lv_display_t* displ;
private void startLvRoutines()
{
lv_tick_set_cb(&xTaskGetTickCount);
static extern(C) void delay(uint ms) => vTaskDelay(ms / portTICK_PERIOD_MS);
lv_delay_set_cb(&delay);
relatedTasks = new Thread((){
while(true)
{
auto time_till_next_ms = lv_timer_handler();
lv_delay_ms(50);
}
}).start;
}
private static void initSPI() nothrow
{
//To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
//but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this.
enum PARALLEL_LINES = 16;
spi_bus_config_t bus_cfg;
//GPIO nums meant here:
bus_cfg.miso_io_num = 10;
bus_cfg.mosi_io_num = 3;
bus_cfg.sclk_io_num = 2;
bus_cfg.quadwp_io_num = -1;
bus_cfg.quadhd_io_num = -1;
bus_cfg.max_transfer_sz = PARALLEL_LINES * sizeX * 2 + 8;
//Initialize the SPI bus
auto ret = spi_bus_initialize(host, &bus_cfg, spi_common_dma_t.SPI_DMA_CH_AUTO);
ESP_ERROR_CHECK(ret);
}
private void initEspPanelDrv() nothrow
{
esp_lcd_panel_io_spi_config_t displaySpiDevCfg = {
dc_gpio_num: cmdPin,
cs_gpio_num: 7, //CS pin
pclk_hz: 40 * 1000 * 1000,
lcd_cmd_bits: 8,
lcd_param_bits: 8,
spi_mode: 0, //not Dual or Quad SPI, etc
trans_queue_depth: 10, //TODO: We want to be able to queue 7 transactions at a time
on_color_trans_done: &notify_lvgl_flush_ready,
user_ctx: &displ,
};
//Attach the LCD to the SPI bus
ESP_ERROR_CHECK(
esp_lcd_new_panel_io_spi(host, &displaySpiDevCfg, &panel_handle)
);
assert(panel_handle !is null);
esp_lcd_panel_dev_config_t cfg = {
reset_gpio_num: gpio_num_t.GPIO_NUM_8,
bits_per_pixel: 16,
};
cfg.rgb_ele_order = lcd_rgb_element_order_t.LCD_RGB_ELEMENT_ORDER_BGR;
ESP_ERROR_CHECK(
//TODO: panel_handle -> panel_io
esp_lcd_new_panel_ili9341(panel_handle, &cfg, &panel)
);
ESP_ERROR_CHECK(
esp_lcd_panel_reset(panel)
);
ESP_ERROR_CHECK(
esp_lcd_panel_init(panel)
);
//~ ESP_ERROR_CHECK(
//~ esp_lcd_panel_invert_color(panel, true)
//~ );
ESP_ERROR_CHECK(
esp_lcd_panel_disp_on_off(panel, true)
);
ESP_ERROR_CHECK(
esp_lcd_panel_mirror(panel, true, false)
);
}
private void initLvBinding() nothrow
{
lv_init();
/* Allocate draw buffers. Use two partial buffers of 1/10th size of the screen */
const buf_size = sizeX * sizeY / 10 * lv_color_t.sizeof;
auto buf1 = lv_malloc(buf_size);
assert(buf1 !is null);
auto buf2 = lv_malloc(buf_size);
assert(buf2 !is null);
//Initialize driver
displ = lv_display_create(sizeX, sizeY);
lv_display_set_color_format(displ, cast(ubyte) _lv_color_format_t.LV_COLOR_FORMAT_RGB565);
lv_display_set_buffers(displ, buf1, buf2, buf_size, lv_display_render_mode_t.LV_DISPLAY_RENDER_MODE_PARTIAL);
lv_display_set_flush_cb(displ, &flush);
lv_display_set_user_data(displ, panel); // pass spi pointer to callback functions
}
this() nothrow
{
initSPI();
initEspPanelDrv();
initLvBinding();
displ.lv_display_set_theme = lv_theme_simple_get;
try
startLvRoutines();
catch(Exception e){ abort(); }
}
private extern(C) static void flush(lv_display_t* disp, const lv_area_t* area, ubyte* color_map)
{
auto panel = cast(esp_lcd_panel_t*) lv_display_get_user_data(disp);
// copy a buffer's content to a specific area of the display
esp_lcd_panel_draw_bitmap(panel, area.x1, area.y1, area.x2 + 1, area.y2 + 1, color_map);
}
private extern(C) static bool notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t* edata, void* user_ctx)
{
auto disp = cast(lv_display_t**) user_ctx;
lv_display_flush_ready(*disp);
return false;
}
}
void ESP_ERROR_CHECK(esp_err_t ret) nothrow
{
assert(ret == 0 /*ESP_OK*/);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment