Description
Display driver for a small OLED of 0.96" (64*128) monochrome developed. Orientation change in compile time is working depicted in a photo below. The essential code to do this is shown at the end of this post.
What MCU/Processor/Board and compiler are you using?
STM32L432
What LVGL version are you using?
Version 7.2.0
What do you want to achieve?
Want to go one step further to change the orientation in runtime just like a smartphone. Will install an accelerometer for this feature.
Code to reproduce
In lv_conf.h
#define LV_SCREEN_ROTATE_270 //change this for different orientation
#if defined (LV_SCREEN_ROTATE_90) || defined (LV_SCREEN_ROTATE_270)
#define LV_HOR_RES_MAX (128)
#define LV_VER_RES_MAX (64)
#else
#define LV_HOR_RES_MAX (64)
#define LV_VER_RES_MAX (128)
#endif
my_flush_cb() is like:
void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/**
* variables dev_y1 and dev_y2 in device space, in the sense that it always follow the
* scanning direction of the OLED
*/
lv_coord_t dev_y1, dev_y2;
#if defined (LV_SCREEN_ROTATE_270)
dev_y1 = (LV_HOR_RES_MAX-1)-(area->x1);
dev_y2 = (LV_HOR_RES_MAX-1)-(area->x2);
#elif defined (LV_SCREEN_ROTATE_180)
dev_y1 = (LV_VER_RES_MAX-1)-(area->y1);
dev_y2 = (LV_VER_RES_MAX-1)-(area->y2);
#elif defined (LV_SCREEN_ROTATE_90)
dev_y1 = area->x1;
dev_y2 = area->x2;
#else
dev_y1 = area->y1; //in native orientation of the OLED, dev_y = area->y always
dev_y2 = area->y2;
#endif
//flush display by DMA
//dev_x1/_x2 is not relevant because we are updating the entire OLED_HOR_RES
framebuf_fill_area(0, dev_y1, OLED_HOR_RES-1, dev_y2, (const color_t *)color_p, 0);
}
void my_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) {
(void) disp_drv;
(void) buf_w;
(void) opa;
lv_coord_t dev_x, dev_y;
/**
* @note: dev_x or _y always on device space, following the same scanning direction of the OLED
* (x,y) in virtual space, following the screen orientation defined in LVGL.
* So we need to think like this: what is the value of dev_x in device space if we have a pixel at x in VDB?
*/
//now only in compile time
#if defined (LV_SCREEN_ROTATE_270)
dev_x = y;
dev_y = (LV_HOR_RES_MAX-1)-x;
#elif defined (LV_SCREEN_ROTATE_180)
dev_x = (LV_HOR_RES_MAX-1)-x;
dev_y = (LV_VER_RES_MAX-1)-y;
#elif defined (LV_SCREEN_ROTATE_90)
dev_x = (LV_VER_RES_MAX-1)-y;
dev_y = x;
#else
dev_x = x;
dev_y = y;
#endif
if (lv_color_to1(color) == 1) {
buf[BUFIDX(dev_x, dev_y)] |= PIXIDX(dev_x); //Set VDB pixel bit to 1 for other colors than BLACK
} else {
buf[BUFIDX(dev_x, dev_y)] &= ~PIXIDX(dev_x); //Set VDB pixel bit to 0 for BLACK color
}
}
What is the difficulty?
There is a member rotated
in lv_disp_drv_t
. Setting lv_disp_drv.rotated
to a different value will swap hor_res
vs ver_res
but there is no callback function to let LVGL know that the screen orientation has changed. I tried to call lv_refr_now(lv_disp)
in the main loop to force screen update but there is no change in screen orientation, until there is a touch event that calls my_flush_cb()
.
Need an interface (similar to input devices like an encoder) for the accelerometer sensor to pump messages containing screen orientation, so that LVGL will refresh the screen with new screen orientation.
Any suggestion is welcome.