I’m working on an embedded system with a real time operating system (RTEMS). I have a simple (double buffered) frame buffer driver for a hardware that can only output the frame in exactly the direction it is in memory. I don’t have a rotation option in the hardware or on the display.
I tried to use the set_px_cb() in the driver to have the pixels at the right locations. That covered all cases for the lv_draw_basic.c. But now I noted that there is another file that can update the memory: The lv_refr.c.
Now I think about a number of possibilities (not sure yet which one will be used). One is to add a display rotation functionality to LittlevGL. As a rough direction I think about the following:
find all locations in lv_draw_basic.c and lv_refr.c that draw to the buffer
modify them to allow a rotation of 0, 90, 180 and 270 degree based on
either a #ifdef (better efficiency but less universal)
or a parameter in the display driver (less efficient but nice for multi display setups; although it’s no target for me, it maybe can be extended to support runtime rotation if someone want’s to add that in the future)
Would such an option be acceptable? If no I’ll strike that possibility from my list.
Thanks for this hint. Currently my status is that I will try a quick solution like that in a first run. But I have a quite big display of 800 x 480 Pixel. So this solution might lead to a high CPU load or it will lead to tearing effects. Depending on whether the results are acceptable or not I might need another solution.
That’s the second solution on my list. With my question I wanted to find out whether such a solution would be something that could be accepted as a patch to LittlevGL or not. Depending on that (and if my first approach doesn’t work) I’ll put more work into the topic to write a clean solution or less work to just add a quick hack on a private fork.
The rotation feature was asked several times but the problem is that “thinking in lines” approach is deeply wired in lvgl. I think it’d be very difficult to add “column-based thinking” too.
Although the CPU load is quite high for a 800x480 display (about 15% of a few 100MHz CPU in case of a lot of activity on the screen), I currently can rotate in software. As long as I don’t hit the limit of my system, I’ll use that solution for now.
If there is time left in the project for optimization or if the CPU load is too high, I’ll come back to the more complex solution of implementing it in LittlevGL.
Edit: Note that I accepted the first solution suggesting a software rotation so that the post is closed.
I didn’t hit the limit of the system and the project turned out to be a lot more work at another software part. So I never had the time to come back to this topic. So it’s still a rotation in the driver for me. Sorry.
Hi to all,
I tried the code and I would say it works perfectly. I attach the link to the video.
This is a custom board with PIC32MZDA 200Mhz, RGBA intewrface 800x480 TFT
@embeddedt
Hi Embedded, ask you if can you help me, i’m trying to rotate of 270 degree and i have get this
code that rotate display of 90 degree, but i can’t undestand how modify. If you had any suggestions
thank you
void get_col(const lv_color_t * src, const lv_area_t * area, lv_coord_t y, lv_color_t * dest)
{
lv_coord_t w = lv_area_get_width(area);
lv_coord_t h = lv_area_get_height(area);
lv_coord_t i;
for(i = 0; i < h; i++) {
dest[i].full = src[y].full;
src += w ;
}
}
void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
lv_coord_t x2 = area->x2;
if(x2 >= disp_drv->ver_res) x2 = MONITOR_VER_RES - 1;
lv_color_t * dest = (lv_color_t *)monitor.tft_fb;
dest += MONITOR_HOR_RES * (MONITOR_VER_RES - 1);
dest -= MONITOR_HOR_RES * area->x1;
lv_coord_t x;
for(x = area->x1; x <= x2; x++) {
get_col(color_p, area, (x - area->x1), dest + area->y1);
dest -= MONITOR_HOR_RES;
}
}
And also take care about the frame buffer base address, which is 0xd0000000 on my system.
Change it accordingly
#define ROTATE 90
/***** get_col_270 (...) *******************/
/*! @brief Copy all source column pixels into destination area
*
* @param[in] src The pixel source buffer
* @param[in] area The rectangle (x1, y1 -> x2, y2) within the destination buffer
* @param[in] x The x pos int source area
* @param[in] dest The destination buffer address
*
* We read from the source area the same x pos for every line
* and write to destination address sequentially in positiv direction
*
*/
void get_col_270 (const lv_color_t* src, const lv_area_t* area, lv_coord_t x, lv_color_t* dest)
{
lv_coord_t col;
lv_coord_t w = lv_area_get_width (area); // The width of the source area
lv_coord_t h = lv_area_get_height (area); // The height of the source area
for (col = 0; col < h; col++) { // all source column pixels (line in destination)
dest[col].full = src[x].full; // The x pos into source area
src += w; // Set for the next source line
}
}
/***** get_col_90 (...) *******************/
/*! @brief Copy all source column pixels into destination area
*
* @param[in] src The pixel source buffer
* @param[in] area The rectangle (x1, y1 -> x2, y2) within the destination buffer
* @param[in] x The x pos int source area
* @param[in] dest The destination buffer address
*
* We read from the source area the same x pos for every line
* and write to destination address sequentially in negative direction
*
*/
void get_col_90 (const lv_color_t* src, const lv_area_t* area, lv_coord_t x, lv_color_t* dest)
{
lv_coord_t col;
lv_coord_t w = lv_area_get_width (area); // The width of the source area
lv_coord_t h = lv_area_get_height (area); // The height of the source area
for (col = 0; col < h; col++) { // all source column pixels (line in destination)
dest[-col].full = src[x].full; // The -x pos into source area
src += w; // Set for the next source line
}
}
/***** monitor_flush (...) *******************/
void monitor_flush (lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p)
{
lv_coord_t x2 = area->x2;
if (x2 >= disp_drv->hor_res) {
x2 = disp_drv->hor_res - 1;
}
#if ROTATE == 270
lv_color_t* dest = (lv_color_t*) 0xd0000000; // monitor.tft_fb; // destination buffer base address
dest += disp_drv->ver_res * (disp_drv->hor_res - 1); // calculate the start of the very last line in destination buffer
dest -= disp_drv->ver_res * area->x1; // and go back to start address of line
lv_coord_t x;
for (x = area->x1; x <= x2; x++) { // For all source columns
get_col_270 (color_p, // The pixel source buffer
area, // The destination area we should write
(x - area->x1), // The x pos related to source area (is the y for destination)
dest + area->y1); // Destination buffer start address
dest -= disp_drv->ver_res; // Next destination buffer start address (runs bottom to top)
}
#elif ROTATE == 90
lv_color_t* dest = (lv_color_t*) 0xd0000000; // monitor.tft_fb; // destination buffer base address
dest += disp_drv->ver_res * area->x1; // Start address of line
lv_coord_t x;
for (x = area->x1; x <= x2; x++) { // For all source columns
get_col_90 (color_p, // The pixel source buffer
area, // The destination area we should write
(x - area->x1), // The x pos related to source area (is the y for destination)
dest + (disp_drv->ver_res - 1 - area->y1)); // Destination buffer start address
dest += disp_drv->ver_res; // Next destination buffer start address (runs top to bottom)
}
#endif
lv_disp_flush_ready (disp_drv); // IMPORTANT! It must be called to tell the system the flush is finished
}
I have already referred the documentation. I want to rotate NXP imxrt1170 display from portrait to landscape mode(90 degree rotation). I have implemented the code as told in LVGL documentation. There is no error showing up, but no rotation happens.
For rotation, is it necessary to call the buffer and display driver?
I am using Lvgl-8. When I change the LV_HOR_RES_MAX and LV_VER_RES_MAX, the rotation happens in the simulator. But not into the imxrt display.
I am new to Lvgl. Please forgive me if I mention anything wrongly.