Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | /* * Copyright (c) 2018-2019 Jan Van Winkel <jan.van_winkel@dxplore.eu> * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/init.h> #include <zephyr/kernel.h> #include <lvgl.h> #include "lvgl_display.h" #include "lvgl_common_input.h" #ifdef CONFIG_LV_Z_USE_FILESYSTEM #include "lvgl_fs.h" #endif #ifdef CONFIG_LV_Z_MEM_POOL_SYS_HEAP #include "lvgl_mem.h" #endif #include LV_MEM_CUSTOM_INCLUDE #define LOG_LEVEL CONFIG_LV_LOG_LEVEL #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(lvgl); static lv_disp_drv_t disp_drv; struct lvgl_disp_data disp_data = { .blanking_on = false, }; #define DISPLAY_NODE DT_CHOSEN(zephyr_display) #ifdef CONFIG_LV_Z_BUFFER_ALLOC_STATIC static lv_disp_draw_buf_t disp_buf; #define DISPLAY_WIDTH DT_PROP(DISPLAY_NODE, width) #define DISPLAY_HEIGHT DT_PROP(DISPLAY_NODE, height) #define BUFFER_SIZE \ (CONFIG_LV_Z_BITS_PER_PIXEL * \ ((CONFIG_LV_Z_VDB_SIZE * DISPLAY_WIDTH * DISPLAY_HEIGHT) / 100) / 8) #define NBR_PIXELS_IN_BUFFER (BUFFER_SIZE * 8 / CONFIG_LV_Z_BITS_PER_PIXEL) /* NOTE: depending on chosen color depth buffer may be accessed using uint8_t *, * uint16_t * or uint32_t *, therefore buffer needs to be aligned accordingly to * prevent unaligned memory accesses. */ static uint8_t buf0[BUFFER_SIZE] #ifdef CONFIG_LV_Z_VBD_CUSTOM_SECTION Z_GENERIC_SECTION(.lvgl_buf) #endif __aligned(CONFIG_LV_Z_VDB_ALIGN); #ifdef CONFIG_LV_Z_DOUBLE_VDB static uint8_t buf1[BUFFER_SIZE] #ifdef CONFIG_LV_Z_VBD_CUSTOM_SECTION Z_GENERIC_SECTION(.lvgl_buf) #endif __aligned(CONFIG_LV_Z_VDB_ALIGN); #endif /* CONFIG_LV_Z_DOUBLE_VDB */ #endif /* CONFIG_LV_Z_BUFFER_ALLOC_STATIC */ #if CONFIG_LV_LOG_LEVEL != 0 /* * In LVGLv8 the signature of the logging callback has changes and it no longer * takes the log level as an integer argument. Instead, the log level is now * already part of the buffer passed to the logging callback. It's not optimal * but we need to live with it and parse the buffer manually to determine the * level and then truncate the string we actually pass to the logging framework. */ static void lvgl_log(const char *buf) { /* * This is ugly and should be done in a loop or something but as it * turned out, Z_LOG()'s first argument (that specifies the log level) * cannot be an l-value... * * We also assume lvgl is sane and always supplies the level string. */ switch (buf[1]) { case 'E': LOG_ERR("%s", buf + strlen("[Error] ")); break; case 'W': LOG_WRN("%s", buf + strlen("Warn] ")); break; case 'I': LOG_INF("%s", buf + strlen("[Info] ")); break; case 'T': LOG_DBG("%s", buf + strlen("[Trace] ")); break; } } #endif #ifdef CONFIG_LV_Z_BUFFER_ALLOC_STATIC static int lvgl_allocate_rendering_buffers(lv_disp_drv_t *disp_driver) { struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_driver->user_data; int err = 0; if (data->cap.x_resolution <= DISPLAY_WIDTH) { disp_driver->hor_res = data->cap.x_resolution; } else { LOG_ERR("Horizontal resolution is larger than maximum"); err = -ENOTSUP; } if (data->cap.y_resolution <= DISPLAY_HEIGHT) { disp_driver->ver_res = data->cap.y_resolution; } else { LOG_ERR("Vertical resolution is larger than maximum"); err = -ENOTSUP; } disp_driver->draw_buf = &disp_buf; #ifdef CONFIG_LV_Z_DOUBLE_VDB lv_disp_draw_buf_init(disp_driver->draw_buf, &buf0, &buf1, NBR_PIXELS_IN_BUFFER); #else lv_disp_draw_buf_init(disp_driver->draw_buf, &buf0, NULL, NBR_PIXELS_IN_BUFFER); #endif /* CONFIG_LV_Z_DOUBLE_VDB */ return err; } #else static int lvgl_allocate_rendering_buffers(lv_disp_drv_t *disp_driver) { void *buf0 = NULL; void *buf1 = NULL; uint16_t buf_nbr_pixels; uint32_t buf_size; struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_driver->user_data; disp_driver->hor_res = data->cap.x_resolution; disp_driver->ver_res = data->cap.y_resolution; buf_nbr_pixels = (CONFIG_LV_Z_VDB_SIZE * disp_driver->hor_res * disp_driver->ver_res) / 100; /* one horizontal line is the minimum buffer requirement for lvgl */ if (buf_nbr_pixels < disp_driver->hor_res) { buf_nbr_pixels = disp_driver->hor_res; } switch (data->cap.current_pixel_format) { case PIXEL_FORMAT_ARGB_8888: buf_size = 4 * buf_nbr_pixels; break; case PIXEL_FORMAT_RGB_888: buf_size = 3 * buf_nbr_pixels; break; case PIXEL_FORMAT_RGB_565: buf_size = 2 * buf_nbr_pixels; break; case PIXEL_FORMAT_MONO01: case PIXEL_FORMAT_MONO10: buf_size = buf_nbr_pixels / 8; buf_size += (buf_nbr_pixels % 8) == 0 ? 0 : 1; break; default: return -ENOTSUP; } buf0 = LV_MEM_CUSTOM_ALLOC(buf_size); if (buf0 == NULL) { LOG_ERR("Failed to allocate memory for rendering buffer"); return -ENOMEM; } #ifdef CONFIG_LV_Z_DOUBLE_VDB buf1 = LV_MEM_CUSTOM_ALLOC(buf_size); if (buf1 == NULL) { LV_MEM_CUSTOM_FREE(buf0); LOG_ERR("Failed to allocate memory for rendering buffer"); return -ENOMEM; } #endif disp_driver->draw_buf = LV_MEM_CUSTOM_ALLOC(sizeof(lv_disp_draw_buf_t)); if (disp_driver->draw_buf == NULL) { LV_MEM_CUSTOM_FREE(buf0); LV_MEM_CUSTOM_FREE(buf1); LOG_ERR("Failed to allocate memory to store rendering buffers"); return -ENOMEM; } lv_disp_draw_buf_init(disp_driver->draw_buf, buf0, buf1, buf_nbr_pixels); return 0; } #endif /* CONFIG_LV_Z_BUFFER_ALLOC_STATIC */ static int lvgl_init(void) { const struct device *display_dev = DEVICE_DT_GET(DISPLAY_NODE); int err = 0; if (!device_is_ready(display_dev)) { LOG_ERR("Display device not ready."); return -ENODEV; } #ifdef CONFIG_LV_Z_MEM_POOL_SYS_HEAP lvgl_heap_init(); #endif #if CONFIG_LV_LOG_LEVEL != 0 lv_log_register_print_cb(lvgl_log); #endif lv_init(); #ifdef CONFIG_LV_Z_USE_FILESYSTEM lvgl_fs_init(); #endif disp_data.display_dev = display_dev; display_get_capabilities(display_dev, &disp_data.cap); lv_disp_drv_init(&disp_drv); disp_drv.user_data = (void *)&disp_data; #ifdef CONFIG_LV_Z_FULL_REFRESH disp_drv.full_refresh = 1; #endif err = lvgl_allocate_rendering_buffers(&disp_drv); if (err != 0) { return err; } if (set_lvgl_rendering_cb(&disp_drv) != 0) { LOG_ERR("Display not supported."); return -ENOTSUP; } if (lv_disp_drv_register(&disp_drv) == NULL) { LOG_ERR("Failed to register display device."); return -EPERM; } err = lvgl_init_input_devices(); if (err < 0) { LOG_ERR("Failed to initialize input devices."); return err; } return 0; } SYS_INIT(lvgl_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); |