This post was last edited by qinyunti on 2023-11-1 22:03
Preface
Previously, we implemented UVC display in NV12 format. Based on this, we can implement the framebuffer mechanism, read and write the color of any point, and then transplant LVGL for GUI development. Since the use of YUV format requires format conversion and interpolation based on sampling, it is inconvenient to directly modify the color of a point, so we use RGB format, and use RGB565 format to reduce the cache size.
YUV-RGB565-FRAMEBUFFER
usbd_video.c modifies the descriptor GUID to
DBVAL(0xe436eb7b),
WBVAL(0x524f),
WBVAL(0x11ce),
0x9f,0x53,
0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70,
UVC_BITS_PER_PIXEL, /* bBitsPerPixel : Number of bits per pixel 16*/
usbd_video_if_template.c modify size
extern uint8_t s_framebuffer[H_SIZE*V_SIZE*2];
const uint8_t *tImagesList[] = {s_framebuffer};
uint32_t tImagesSizes[] = {H_SIZE*V_SIZE*2};
The framebuffer is implemented in framebuffer.c, where the framebuffer_update test uses RGB wheel display
#include <stdint.h>
#include "stm32f7xx_hal.h"
#include "encode_dma.h"
#include "framebuffer.h"
uint8_t s_framebuffer[H_SIZE*V_SIZE*2];
uint32_t color_table[] =
{
0xFF0000, /* */
0x00FF00, /* */
0x0000FF, /* */
};
void framebuffer_set(uint32_t xpos, uint32_t ypos, uint8_t r, uint8_t g, uint8_t b)
{
uint16_t color = (((uint16_t)r&0xF8)<<8) | (((uint16_t)g&0xFC)<<3) | (((uint16_t)b&0xF8)>>3);
uint8_t* p = s_framebuffer + (xpos*H_SIZE+ypos)*2;
*(uint16_t*)p = color;
}
void framebuffer_init(void)
{
}
void framebuffer_update(void)
{
static unsigned int index = 0;
uint8_t* p = (uint8_t*)s_framebuffer;
uint8_t r;
uint8_t g;
uint8_t b;
if(index >= sizeof(color_table)/sizeof(color_table[0]))
{
index = 0;
}
r = (color_table[index] >> 16) & 0xFF;
g = (color_table[index] >> 8) & 0xFF;
b = (color_table[index] >> 0) & 0xFF;
for(int x=0; x<H_SIZE; x++)
{
for(int y=0; y<V_SIZE; y++)
{
framebuffer_set(x, y, r, g, b);
}
}
index++;
}
Art picture test
Based on arbitrary write point functions, interesting pictures are generated through some mathematical formulas.
code show as below
#include <stdint.h>
#include "stm32f7xx_hal.h"
#include "encode_dma.h"
#include "framebuffer.h"
#include <math.h>
uint8_t s_framebuffer[H_SIZE*V_SIZE*2];
#define DIM H_SIZE
#define DM1 (DIM-1)
#define _sq(x) ((x)*(x))
#define _cb(x) abs((x)*(x)*(x))
#define _cr(x) (unsigned short)(pow((x),1.0/3.0))
unsigned char RD(int i,int j){
return (char)(_sq(cos(atan2(j-65,i-65)/2))*255);
}
unsigned char GR(int i,int j){
return (char)(_sq(cos(atan2(j-65,i-65)/2-2*acos(-1)/3))*255);
}
unsigned char BL(int i,int j){
return (char)(_sq(cos(atan2(j-65,i-65)/2+2*acos(-1)/3))*255);
}
unsigned char RD0(int i,int j)
{
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return ((int)((i+DIM)*s+y)%2+(int)((DIM*2-i)*s+y)%2)*127;
}
unsigned char GR0(int i,int j){
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return ((int)(5*((i+DIM)*s+y))%2+(int)(5*((DIM*2-i)*s+y))%2)*127;
}
unsigned char BL0(int i,int j){
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return ((int)(29*((i+DIM)*s+y))%2+(int)(29*((DIM*2-i)*s+y))%2)*127;
}
unsigned char RD1(int i, int j) {
#define r(n)(rand()%n)
static char c[DIM][DIM]; return!c[i][j] ? c[i][j] = !r(999) ? r(256) : RD((i + r(2)) % 1024, (j + r(2)) % 1024) : c[i][j];
}
unsigned char GR1(int i, int j) {
static char c[DIM][DIM]; return!c[i][j] ? c[i][j] = !r(999) ? r(256) : GR((i + r(2)) % 1024, (j + r(2)) % 1024) : c[i][j];
}
unsigned char BL1(int i, int j) {
static char c[DIM][DIM]; return!c[i][j] ? c[i][j] = !r(999) ? r(256) : BL((i + r(2)) % 1024, (j + r(2)) % 1024) : c[i][j];
}
unsigned char RD2(int i, int j) {
static double k; k += rand() / 1. / 0x7FFF; int l = k; l %= 512; return l > 255 ? 511 - l : l;
}
unsigned char GR2(int i, int j) {
static double k; k += rand() / 1. / 0x7FFF; int l = k; l %= 512; return l > 255 ? 511 - l : l;
}
unsigned char BL2(int i, int j) {
static double k; k += rand() / 1. / 0x7FFF; int l = k; l %= 512; return l > 255 ? 511 - l : l;
}
unsigned char RD3(int i, int j) {
return (unsigned char)sqrt((double)(_sq(i - DIM / 2) * _sq(j - DIM / 2)) * 2.0);
}
unsigned char GR3(int i, int j) {
return (unsigned char)sqrt((double)(
(_sq(i - DIM / 2) | _sq(j - DIM / 2)) *
(_sq(i - DIM / 2) & _sq(j - DIM / 2))
));
}
unsigned char BL3(int i, int j) {
return (unsigned char)sqrt((double)(_sq(i - DIM / 2) & _sq(j - DIM / 2)) * 2.0);
}
unsigned char RD4(int i, int j) {
static int r[DIM]; int p = rand() % 9 - 4; r[i] = i & r[i] ? (r[i] + r[i - 1]) / 2 : i ? r[i - 1] : 512; r[i] += r[i] + p > 0 ? p : 0; return r[i] ? r[i] < DIM ? r[i] : DM1 : 0;
}
unsigned char GR4(int i, int j) {
static int r[DIM]; int p = rand() % 7 - 3; r[i] = i & r[i] ? (r[i] + r[i - 1]) / 2 : i ? r[i - 1] : 512; r[i] += r[i] + p > 0 ? p : 0; return r[i] ? r[i] < DIM ? r[i] : DM1 : 0;
}
unsigned char BL4(int i, int j) {
static int r[DIM]; int p = rand() % 15 - 7; r[i] = i & r[i] ? (r[i] + r[i - 1]) / 2 : i ? r[i - 1] : 512; r[i] += r[i] + p > 0 ? p : 0; return r[i] ? r[i] < DIM ? r[i] : DM1 : 0;
}
void test0(void)
{
for(int i=0;i<H_SIZE;i++)
{
for(int j=0;j<V_SIZE;j++)
{
static unsigned short color[3];
color[0] = RD(i,j)&255;
color[1] = GR(i,j)&255;
color[2] = BL(i,j)&255;
framebuffer_set(i, j, color[0], color[1], color[2]);
}
}
}
void test1(void)
{
for(int i=0;i<H_SIZE;i++)
{
for(int j=0;j<V_SIZE;j++)
{
static unsigned short color[3];
color[0] = RD1(i,j)&255;
color[1] = GR1(i,j)&255;
color[2] = BL1(i,j)&255;
framebuffer_set(i, j, color[0], color[1], color[2]);
}
}
}
void test2(void)
{
for(int i=0;i<H_SIZE;i++)
{
for(int j=0;j<V_SIZE;j++)
{
static unsigned short color[3];
color[0] = RD2(i,j)&255;
color[1] = GR2(i,j)&255;
color[2] = BL2(i,j)&255;
framebuffer_set(i, j, color[0], color[1], color[2]);
}
}
}
void test3(void)
{
for(int i=0;i<H_SIZE;i++)
{
for(int j=0;j<V_SIZE;j++)
{
static unsigned short color[3];
color[0] = RD3(i,j)&255;
color[1] = GR3(i,j)&255;
color[2] = BL3(i,j)&255;
framebuffer_set(i, j, color[0], color[1], color[2]);
}
}
}
void test4(void)
{
for(int i=0;i<H_SIZE;i++)
{
for(int j=0;j<V_SIZE;j++)
{
static unsigned short color[3];
color[0] = RD4(i,j)&255;
color[1] = GR4(i,j)&255;
color[2] = BL4(i,j)&255;
framebuffer_set(i, j, color[0], color[1], color[2]);
}
}
}
uint32_t color_table[] =
{
0xFF0000, /* */
0x00FF00, /* */
0x0000FF, /* */
};
typedef void (*test_pf)(void);
test_pf pf_table[] =
{
test0, /* */
test1, /* */
test2, /* */
test3, /* */
test4, /* */
};
void framebuffer_set(uint32_t xpos, uint32_t ypos, uint8_t r, uint8_t g, uint8_t b)
{
uint16_t color = (((uint16_t)r&0xF8)<<8) | (((uint16_t)g&0xFC)<<3) | (((uint16_t)b&0xF8)>>3);
uint8_t* p = s_framebuffer + (xpos*H_SIZE+ypos)*2;
*(uint16_t*)p = color;
}
void framebuffer_init(void)
{
}
void framebuffer_update(void)
{
#if 0
static unsigned int index = 0;
uint8_t* p = (uint8_t*)s_framebuffer;
uint8_t r;
uint8_t g;
uint8_t b;
if(index >= sizeof(color_table)/sizeof(color_table[0]))
{
index = 0;
}
r = (color_table[index] >> 16) & 0xFF;
g = (color_table[index] >> 8) & 0xFF;
b = (color_table[index] >> 0) & 0xFF;
for(int x=0; x<H_SIZE; x++)
{
for(int y=0; y<V_SIZE; y++)
{
framebuffer_set(x, y, r, g, b);
}
}
index++;
#else
static unsigned int index = 0;
if(index >= sizeof(pf_table)/sizeof(pf_table[0]))
{
index = 0;
}
pf_table[2]();
//pf_table[index]();
index++;
#endif
}
Summarize
The above implementation of UVC-based FRAMEBUFFER allows arbitrary writing of points, and an interesting art picture generation test is performed.