2018-02-11 04:45 PM
I've been working on a simple UI library for my project.
I'm using the stm32F7 with LTDC configured to RGB888 color space.
Whilst I was writing a color gradient function, I noticed that my gradients looked 'choppy'
Left gradient: Dithered RGB888 bitmap
Middle gradient: non-dithered RGB888 bitmap
Right gradient: custom gradient function
My gradient code does a simple loop:
for
(uint32_t
yPos = y;
yPos < height;
yPos++) {LCD
::fillRectangle(x,
yPos,
width,
1
,
LCD
::getGradientColor(yPos,
height,
fromColor,
toColor,
(ColorFormat
)hLtdcHandler
.LayerCfg
[0
].PixelFormat
));
}which calls the getGradientFunction:
uint32_t
LCD
::getGradientColor
(uint32_t
current,
uint32_t
max,
uint32_t
fromColor,
uint32_t
toColor) {float
position = (float
) current / max;
uint8_t
red = (uint8_t
) (((1.0
- position) * (fromColor &0xff0000
>>16
)) + (position * (toColor &0xff0000
>>16
)));
uint8_t
green = (uint8_t
) (((1.0
- position) * (fromColor &0x00ff00
>>8
)) + (position * (toColor &0x00ff00
>>8
)));
uint8_t
blue = (uint8_t
) (((1.0
- position) * (fromColor &0x0000ff
)) + (position * (toColor &0x0000ff
)));
switch
(hLtdcHandler
.LayerCfg
[0
].PixelFormat
) {case
LTDC_PIXEL_FORMAT_ARGB8888
:return
((uint8_t
)0xFF
<<24
) | (red <<16
) | (green <<8
) | blue;
default
:case
LTDC_PIXEL_FORMAT_RGB565
:case
LTDC_PIXEL_FORMAT_RGB888
:return
(red <<16
) | (green <<8
) | blue;
}}
Based on my calculations, I have a 600px high display and I am drawing a full-height gradient. I expect a different color value every ~2.35 lines (600 lines / 255 grey shades). However, my display shows a color change every ~9 lines.
Does anybody have an idea where I shall start looking for the cause?
I am using DMA to draw the two bitmaps, with the appropriate input color modes for both bitmaps.
For gradient I just use a simple register to memory call for each line.
2018-02-11 10:38 PM
Assuming you have verified your gradient bar code in general, I suggest to draw larger blocks (rectangles) of different/adjacent colors side by side.
Single pixels or lines could be difficult to discern.
And don't forget, color perception is highly subjective in general.
2018-02-11 11:15 PM
In this statement;
(fromColor & 0xff0000 >> 16)
I would force the issue;
((fromColor & 0xff0000) >> 16)
Also;
I thought you had to have a break; in every case statement or the code falls through...
switch (hLtdcHandler.LayerCfg[0].PixelFormat) {
case LTDC_PIXEL_FORMAT_ARGB8888: return ((uint8_t) 0xFF << 24) | (red << 16) | (green << 8) | blue;BREAK;
default: case LTDC_PIXEL_FORMAT_RGB565: BREAK;case LTDC_PIXEL_FORMAT_RGB888:
return (red << 16) | (green << 8) | blue;BREAK;
2018-02-12 12:33 AM
Thank you for your reply!
Since I am returning within my case statements, there is no need for a break, I let 'default', RGB565 and RGB888 fall through to the same return statement on purpose
Good catch on the bit shifting though! Almost thought that that might've been the cause, but unfortunately nothing changed.
Best wishes,
2018-02-12 12:36 AM
last stab
return (uint32_t)((red << 16) | (green << 8) | blue);
or should it be:
return ((uint32_t)red << 16) | (green << 8) | blue);
can you return within a Case statement ?
2018-02-12 12:44 AM
You definitely can! Makes those long chained else/ifs more readable
The returned variable is already an uint32_t, so that wont do anything either
:(
2018-02-12 12:53 AM
but
red, green, blue are not uint32_t...
just trying to force it...
change the float to a double...
double position = (double) current / max;
((((double)1.0 - position) * (fromColor & 0xff0000 >> 16)) + (position * (toColor & 0xff0000 >> 16)));