DOORBELL

[English]

1 功能概述

门铃的主要功能是联合多个模块,实时的进行图像采集,屏幕显示,声音的双向采集和播放。

2 代码路径

demo路径:./components/media/cli/media_cli.c, ./components/media/camera/camera_act.c, ./components/media/transfer/transfer_act.c, ./components/media/lcd/lcd_act.c

3 cli命令简介

demo支持的命令如下表:

Command

Param

Description

ap param1 param2

param1:softap_ssid

setup a softap and set name

param2:softap_key

set softap connect key

sta param1 param2

param1:station_ssid

connect a station and set name

param2:station_key

set station connect key

doorbell param1 [param2]

param1:3

open doorbell function

param2:if open uvc, choosable

set open/disopen uvc 1/0

media dvp open [param]

param:dvp resolution, choosable

set sensor resolution, and open dvp

media dvp close

NULL

close dvp sensor

media lcd open [param1] [param2]

param1:LCD PIXEL

default:480X272

param2:rotate or null

rotate open or not

media lcd close

NULL

close lcd function, and jpeg decode

media lcd dma2d_blend [param1][param2]

param1:clock,wifi,data,ver

blend icon type

param2:12:30 , 0-4

0:wifi none, 4:wifi full

media lcd dma2d_blend close [param]

NULL or wifi/clock

close all blend or one blend

media capture param

param:xxx.jpg

capture save to sdcard, and set name

media uvc open [param]

param:uvc resolution, choosable

set sensor resolution, and open uvc

media uvc close

NULL

close uvc sensor

demo运行依赖的宏配置:

NAME

Description

File

value

CONFIG_DOORBELL

support DOORBELL

middleware\soc\bk7256\bk7256.defconfig

y

CONFIG_JPEG_ENCODE

suport hw jpeg ecoder

middleware\soc\bk7256\bk7256.defconfig

y

CONFIG_CAMERA

suport use dvp camera

middleware\soc\bk7256\bk7256.defconfig

y

CONFIG_CAMERA_USE_I2C1

suport use I2C1

middleware\soc\bk7256\bk7256.defconfig

y

CONFIG_AUDIO

support audio function

middleware\soc\bk7256\bk7256.defconfig

y

CONFIG_LCD

support LCD function

middleware\soc\bk7256\bk7256.defconfig

y

CONFIG_USB_UVC

support UVC camera

middleware\soc\bk7256\bk7256.defconfig

y

CONFIG_LCD_FONT_BLEND

support font/image blend

middleware\soc\bk7256\bk7256.defconfig

y

4 演示介绍

demo执行的步骤如下:

1、准备好dvp摄像头或者UVC摄像头,LCD屏幕(rgb或者8080):

2、起一个softap:

ap doorbell_test 1234567890

3、手机连接这个ap

4、发送doorbell命令:

doorbell

5、手机app(RealtimeVideo)设置顺序和流程如下图所示:

6、如果需要显示到LCD屏幕上

media lcd open

5 app使用流程

以下流程以板子作为softap为例,介绍apk的使用,在手机连接到板子使能的ap后:

1.图1为app示意图

2.图2为app的主界面

其中,选择1可以看到图3

  • 1:设置菜单;

  • 2:更新apk和回退apk菜单;

3.图3为设置界面菜单

其中:

  • 1:为设置界面如图4所示;

  • 2:为返回主界面按钮;

4.图4为真正的设置界面

其中,设置说明如下,设置完成后返回图2主界面

  • 1:设置解决方案,当前支持video_transfer和doorbell,此处选择doorbell;

  • 2:设置数据传输模式,当前支持UDP和TCP,默认选择UDP;

  • 3:设置对端的ip地址,ap模式下默认为``192.168.0.1``不用修改,sta模式下设置为对端的ip地址;

  • 4:设置摄像头类型,当前支持DVP和UVC,根据自己使用摄像头类型进行设置;

  • 5:设置摄像头的输出分辨率;

  • 6:设置LCD输出的分辨率,根据自己使用的LCD屏幕分辨率进行设置;

5.图5为功能使能设置界面

其中,功能使能说明如下所示:

  • 1:开关视频图传;

  • 2:开关语音;

  • 3:拍照开关,当前暂不支持;

  • 4:开关LCD屏幕显示;

备注

在图4中设置对端IP地址,当板子为softap时,默认为``192.168.0.1``,当板子作为staion时,手机和板子连接同一个ap,填入的IP地址可以通过命令``ip``获得。 另外该app还支持手机图传功能,即命令``video_transfer -a|s ssid key``,但是必须将图4步骤1设置为``video_transfer``模式。 apk的下载地址如下:http://dl.bekencorp.com/apk/RealtimeVideo.apk

RealtimeVideo_app

Figure 1. doorbell apk

RealtimeVideo_app_screen

Figure 2. RealtimeVideo_app Main screen

RealtimeVideo_app_set_menu

Figure 3. RealtimeVideo_app Set menu

RealtimeVideo_app_set

Figure 4. RealtimeVideo_app set

RealtimeVideo_function_set

Figure 5. RealtimeVideo_function set

6 新增屏幕适配

doorbel工程可以根据用户的需求增加新的屏幕驱动以适应不同的产品需求,新增屏幕驱动代码请参考 ./middleware/driver/lcd 路径下新增lcd_xxx.c, 比如lcd_st7282.c;

客户可以将任一文件拷贝,重命名为新增屏幕名,在新增驱动代码中主要做以下配置:

1) cmake 添加新增的lcd_xxx.c文件,使lcd_xxx.c文件参与编译 在 ./middleware/driver 目录下打开CMakeLists.txt, 在CONFIG_LCD的宏控下添加文件:

if (CONFIG_LCD)
        list(APPEND srcs
                "lcd/lcd_driver.c"
                "lcd/lcd_hx8282.c"
                "lcd/lcd_st7282.c"
                "lcd/lcd_st7796s.c"
                "lcd/lcd_gc9503v.c"
                "lcd/lcd_nt35512.c"
                "lcd/lcd_h050iwv.c"
                "lcd/lcd_md0430r.c"
                "lcd/lcd_md0700r.c"
                "lcd/lcd_spi.c"
                "lcd/lcd_nt35510.c"
                "lcd/lcd_xxx.c"         //新增lcd_xxx.c
                )
endif()
  1. 针对RGB屏幕需要根据lcd spec 修改hsync/vsync proch,取值范围参考 ./include/lcd_types.h 结构体lcd_rgb_t注释。

static const lcd_rgb_t lcd_rgb =
{
        .clk = LCD_20M,          //lcd 工作合适的时钟
        .data_out_clk_edge = NEGEDGE_OUTPUT, //rgb输出数据时钟边沿

        .hsync_pulse_width = 2,
        .vsync_pulse_width = 2,
        .hsync_back_porch = 40,
        .hsync_front_porch = 5,
        .vsync_back_porch = 8,
        .vsync_front_porch = 8,
};
RealtimeVideo_app

Figure 6. rgb sync params config

  1. 背光接口配置

如果屏幕的背光由PWM控制,则用户需要初始化PWM引脚,调节PWM的输出占空比

static void lcd_backlight_open(void)
{
#if CONFIG_PWM
        lcd_driver_backlight_init(LCD_RGB_PWM_BACKLIGHT, 100);
#endif
}

static void lcd_set_backlight(uint8_t percent)
{
#if CONFIG_PWM
        pwm_period_duty_config_t config = {0};

        if (percent > 100)
        {
                percent  = 100;
        }

        config.period_cycle = 100;
        config.duty_cycle = percent;

        bk_pwm_set_period_duty(LCD_RGB_PWM_BACKLIGHT, &config);
#endif
}

如果屏幕的背光控制是由GPIO(比如GPIO34)口控制:

static void lcd_gc9503v_backlight_io_init(void)
{
        gpio_dev_unmap(34);
        bk_gpio_set_capacity(34, 0);
        BK_LOG_ON_ERR(bk_gpio_enable_output(34));
        BK_LOG_ON_ERR(bk_gpio_pull_down(34));
}

static void gc9503v_lcd_backlight_open(void)
{
        BK_LOG_ON_ERR(bk_gpio_pull_up(34));
        // pull up gpio34, enable lcd backlight control
        bk_gpio_set_output_high(34);
}

static void gc9503v_lcd_backlight_close(void)
{
        bk_gpio_set_output_low(34);
}
  1. 初始化屏幕结构体参数

类似lcd_st7282屏幕不需要初始化,其结构体参数初始化如下:

const lcd_device_t lcd_device_st7282 =
{
        .id = LCD_DEVICE_ST7282,   //屏幕ID num
        .name = "st7282",          //屏幕 name
        .type = LCD_TYPE_RGB565,    //屏幕接口类型
        .ppi = PPI_480X272,         //屏幕分辨率
        .rgb = &lcd_rgb,             //RGB屏幕的参数配置
        .backlight_open = lcd_backlight_open,//注册背光初始化
        .backlight_set = lcd_set_backlight,  //注册赔光调节函数
        .init = NULL,                        //不需要初始化
        .backlight_close = lcd_backlight_close,//注册关闭背光函数
        .lcd_off = NULL,                       //屏幕没有关闭命令或关闭引脚
};

其中屏幕分辨率未定义,需要在 ./include/driver/media_types.h 中定义。 新增的屏幕ID需要在 ./include/driver/lcd_types.h 中定义,如下:

typedef enum {
LCD_DEVICE_UNKNOW,
LCD_DEVICE_ST7282,  /**< 480X270  RGB */
LCD_DEVICE_HX8282,  /**< 1024X600 RGB  */
LCD_DEVICE_GC9503V, /**< 480X800 RGB  */
LCD_DEVICE_ST7796S, /**< 320X480 MCU  */
LCD_DEVICE_NT35512,
} lcd_device_id_t;

该屏幕结构需要在 ./middleware/driver/lcd/lcd_driver.c 中定义, 并在 ./middleware/driver/lcd/lcd_device.h 中声明:

const lcd_device_t *lcd_devices[] =
{
        &lcd_device_st7282,
        &lcd_device_hx8282,
        &lcd_device_st7796s,
        &lcd_device_gc9503v,
        &lcd_device_nt35512
};

extern const lcd_device_t lcd_device_st7282;
extern const lcd_device_t lcd_device_hx8282;
extern const lcd_device_t lcd_device_st7796s;
extern const lcd_device_t lcd_device_gc9503v;
extern const lcd_device_t lcd_device_nt35512;

类似lcd_gc9503v屏幕需要初始化,其结构体中需要注册初始化函数:

.init = lcd_gc9503v_init,

lcd_gc9503v_init函数一般是屏幕厂商提供,需要硬件接口模拟SPI或I2C接口,所以需要初始化GPIO,以及根据初始化命令适配对应的SPI或I2C协议,目前SDK中已适配了SPI3线和4线协议。

void lcd_spi_init_gpio(void)
{
        gpio_dev_unmap(LCD_SPI_RST);
        bk_gpio_set_capacity(LCD_SPI_RST, 0);
        BK_LOG_ON_ERR(bk_gpio_disable_input(LCD_SPI_RST));
        BK_LOG_ON_ERR(bk_gpio_enable_output(LCD_SPI_RST));

        gpio_dev_unmap(LCD_SPI_CLK_GPIO);
        bk_gpio_set_capacity(LCD_SPI_CLK_GPIO, 0);
        BK_LOG_ON_ERR(bk_gpio_disable_input(LCD_SPI_CLK_GPIO));
        BK_LOG_ON_ERR(bk_gpio_enable_output(LCD_SPI_CLK_GPIO));

        gpio_dev_unmap(LCD_SPI_CSX_GPIO);
        bk_gpio_set_capacity(LCD_SPI_CSX_GPIO, 0);
        BK_LOG_ON_ERR(bk_gpio_disable_input(LCD_SPI_CSX_GPIO));
        BK_LOG_ON_ERR(bk_gpio_enable_output(LCD_SPI_CSX_GPIO));

        gpio_dev_unmap(LCD_SPI_SDA_GPIO);
        bk_gpio_set_capacity(LCD_SPI_SDA_GPIO, 0);
        BK_LOG_ON_ERR(bk_gpio_disable_input(LCD_SPI_SDA_GPIO));
        BK_LOG_ON_ERR(bk_gpio_enable_output(LCD_SPI_SDA_GPIO));

        bk_gpio_set_output_high(LCD_SPI_CLK_GPIO);
        bk_gpio_set_output_high(LCD_SPI_CSX_GPIO);
        delay_us(200);
}

至此,屏幕驱动的适配已经完成。

接下来的一个简单的适配是确保用户输入命令或传参(屏幕分辨率或名字),SDK中可以找到相应的设备:

  1. 获取LCD设备名的判断,在media_cli.c中添加新增屏幕名字的判断

char * get_string_to_name(char *string, char * pre)
{
        char* value = pre;
        if (os_strcmp(string, "nt35512") == 0)
        {
                value = "nt35512";
        }

        .....

        if (os_strcmp(string, "nt35510") == 0)
        {
                value = "nt35510";
        }

        ......

        return value;
}
  1. 获取LCD设备像素的判断,在media_cli.c中添加新增像素的判断

uint32_t get_string_to_ppi(char *string, uint32_t pre)
{
        uint32_t value = pre;

        if (os_strcmp(string, "1280X720") == 0)
        {
                value = PPI_1280X720;
        }

        .....

        if (os_strcmp(string, "480X854") == 0)
        {
                value = PPI_480X854;
        }

        return value;
}

至此, 屏幕驱动的适配和调用参数一适配完成

接下来就可以使用新屏幕显示啦!

lcd_open_t lcd_open;
lcd_open.device_ppi = 480X800;
lcd_open.device_name = "nt35512";
ret = media_app_lcd_open(&lcd_open);
另外,有一点需要特别注意:
  • 对于lcd设备有多个设备有相同的分辨率的情况下,必须添加使用名字传参, 不然只有分辨率不能找到指定的屏幕。

  • 对于设备中的分辨率是唯一的(没有其他LCD有相同的分辨率),使用分辨率或者名字之一也可以找到指定的屏幕。

7 图标融合

  1. 关于DMA2D的使用指南请参考 html/bk7256/zh_CN/latest/examples/video/dma2d.html 里面详细介绍了前景图标的数据格式支持的类型,本文档就常见的ARGB8888以及RGB565的数据展开说明。

  2. 准备需要融合的小图标的png图片或者jpg图片(又称前景图片).

3) 将png转换为rgba8888的数据,该转换可以实现保持png的透明度,适合融合背景是透明的图标。 判断图片背景是否透明,可以用photoshop查看背景是否是镂空。

  • 工具路径: components/media/tools/ffmpeg_bat/png2argb 将所有的png图片访在该路径下,双击run.bat.

RealtimeVideo_app

Figure 7. png to rgba8888.rgb

或将jpg转换为rgb565(大端)的数据,该转换过程中将所有不透明的jpg像素默认转换为不透明,适合融合背景和图标背景相近的图标,或对背景框没有要求的融合。

  • 工具路径: components/media/tools/ffmpeg_bat/jpeg2rgb565 将所有的jpg图片访在该路径下,双击run.bat.

RealtimeVideo_app

Figure 8. png to rgb565le.rgb

  1. 使用 “HxD”或其他工具将rgb数据转成const数组并保存到flash中。

在 “components/media/include/blend_logo.h” 中定义前景图片,以及前景图片的长和宽:

#define WIFI_LOGO_W 32
#define WIFI_LOGO_H 36

const unsigned char wifi_full_rgb565[2304] = {
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        ....
};

如果想要将前景图标融合在LCD屏幕的固定位置,还需要设置前景融合的坐标 比如:想要将版本号的前景图标(16x36)从屏幕(480x800)的第500行,居中的位置开始融合,可以这样设置:

#define VERSION_POSTION_Y   500   //HIGH 800
#define VERSION_POSTION_X   144   //WIDTH 480 "BK7 V1.23.45"  (480-(12*16))/2    12个字节, 图标宽16
  1. DMA2D实现融合

准备好了图片数据以及融合的位置,接下来就配置实际融合的参数,请参考lcd_act.c 中API 接口:lcd_blend_handler

比如要融合的wifi图标在在屏幕的右上角,即屏幕坐标(lcd_width-logo_width,0)处开始融合,其 lcd_blend.pbg_addr 就要设置 地址偏移量(frame->frame + (frame->width - WIFI_LOGO_W) * 2。 如何设置偏移在DMA2D的用例指南有详细介绍。

if ((g_blend_data.lcd_blend_type & LCD_BLEND_WIFI) != 0)
{
        LOGD("lcd wifi blend level =%d \n", g_blend_data.wifi_data);
        lcd_blend.pfg_addr = (uint8_t *)wifi_logo[g_blend_data.wifi_data];
        lcd_blend.pbg_addr = (uint8_t *)(frame->frame + (frame->width - WIFI_LOGO_W) * 2);
        lcd_blend.fg_offline = 0;
        lcd_blend.bg_offline = frame->width - WIFI_LOGO_W;
        lcd_blend.xsize = WIFI_LOGO_W;
        lcd_blend.ysize = WIFI_LOGO_H;
        lcd_blend.fg_alpha_value = FG_ALPHA;
        lcd_blend.fg_data_format = ARGB8888;
        lcd_driver_blend(&lcd_blend);
}

8 新增摄像头配置

在应用过程中使用的摄像头不仅仅是当前支持的这些,肯定还需要适配其他的dvp摄像头或者uvc摄像头,下面分开来说明一下针对两种不同类型的摄像头如何适配

  • 1.dvp摄像头的适配

    dvp摄像头是通过I2C通信来配置摄像头的输出,主要是配置sensor寄存器的值,达到预期的图像效果(分辨率、帧率等)

    1)参考驱动代码:middleware/driver/camera/dvp_gc0328c.c,首先需要适配dvp摄像头的参数结构体:dvp_sensor_config_t;

typedef struct
{
        char *name;  /**< 摄像头的名字 */
        media_ppi_t def_ppi;  /**< 摄像头默认的分辨率,一般采用经常使用的分辨率 */
        sensor_fps_t def_fps;  /**< 摄像头默认的帧率,一般采用经常使用的帧率*/
        uint16 id;  /**< 摄像头类型(枚举值,需要自己添加), 参考枚举类型sensor_id_t */
        uint8 clk;  /**< 摄像头协议规定的输入MCLK,而这个MCLK是从JPEG模块的CLK分出来,需要自己配置 */
        /**@example
        * JPEG_96M_MCLK_24M:表示这个摄像头协议规定MCLK输入的是24MHz,而此时JPEG模块工作的时钟是96MHz,96MHz四分频可以得到24MHz
        * 另外需要注意的是,JPEG的工作时钟是在CLK(480MHz和320MHz)中分出来的,分频系数范围F=[0, 15],分频计算公式JPEG_CLK=CLK/(1+F);
        * 而JPEG内部支持分频的只有:0:4分频,1:6分频,2:2分频,3:3分频
        **/
        uint16 address;  /**< 摄像头通过I2C配置寄存器的地址,一般datasheet上会告知 */
        uint16 fps_cap;  /**< 摄像头支持配置的帧率,根据需求输出不同的帧率 */
        uint16 ppi_cap;  /**< 摄像头支持配置的分辨率,根据不同场景输出不同的分辨率 */
        bool (*detect)(const dvp_camera_i2c_callback_t *cb);  /**< 自动检测摄像头函数,是读取摄像头的标识(比如CHIP_ID)是否与当前摄像头一致*/
        int (*init)(const dvp_camera_i2c_callback_t *cb);  /**< 配置摄像头初始化寄存表,其他调整(比如:分辨率、帧率、白平衡等)必须在这个基础上 */
        int (*set_ppi)(const dvp_camera_i2c_callback_t *cb, media_ppi_t ppi);  /**< 设置摄像头分辨率的寄存器表,一般会支持不同的分辨率输出 */
        int (*set_fps)(const dvp_camera_i2c_callback_t *cb, sensor_fps_t fps);  /**< 设置摄像头帧率的寄存器,一般会支持不同帧率的输出 */
        int (*power_down)(const dvp_camera_i2c_callback_t *cb);  /**< 设置寄存器来配置摄像头的使能 */
        int (*dump_register)(const dvp_camera_i2c_callback_t *cb, media_ppi_t ppi);  /**< 调试接口,查看所有寄存器配置的值 */
        void (*read_register)(bool enable);  /**< 使能寄存器检查接口,在配置的过程中检查配置寄存器的值与期望的值一致*/
} dvp_sensor_config_t;

2)参考使能摄像头驱动代码:middleware/driver/camera/dvp_camera.c,在函数:bk_dvp_camera_driver_init(),可能需要增加新摄像头的MCLK输入配置;

switch (current_sensor->clk)
{
        case JPEG_96M_MCLK_16M:
                jpeg_config.sys_clk_div = 4;
                jpeg_config.mclk_div = 1;
                break;

        case JPEG_96M_MCLK_24M:
                jpeg_config.sys_clk_div = 4;
                jpeg_config.mclk_div = 0;
                break;

        case JPEG_120M_MCLK_20M:
                jpeg_config.sys_clk_div = 3;
                jpeg_config.mclk_div = 1;
                break;

        case JPEG_120M_MCLK_30M:
                jpeg_config.sys_clk_div = 3;
                jpeg_config.mclk_div = 0;
                break;

        default:
                break;
}

备注

注意:上面JPEG的注视中默认选择的是480MHz,当前并没有开放SDK接口来配置选择480MHz或者320MHz。如果需要选用320MHz,请参考JPEG驱动代码:middleware/driver/jpeg_enc/jpeg_driver.c.

static void jpeg_power_config_set(const jpeg_config_t *config)
{
        sys_drv_set_jpeg_clk_sel(1);//0:320MHz, 1:480MHz
        sys_drv_set_clk_div_mode1_clkdiv_jpeg(config->sys_clk_div);
        sys_drv_set_jpeg_disckg(1);
        bk_pm_clock_ctrl(PM_CLK_ID_JPEG, CLK_PWR_CTRL_PWR_UP);
}

2.uvc摄像头的适配

uvc唯一需要适配的是其支持的分辨率,uvc输出的分辨率千变万化,当前只适配了一些常规的分辨率,客户如有特殊的分辨率,需要自己添加。

1)当前暂不支持客户独立添加新的分辨率,后续会修改,因为当前增加新的分辨率需要开发人员单独给客户新的libusb.a文件,替换路径:components/bk_libs/bk7256_app/libs/libusb.a

2)替换好新的libusb.a文件后,参考头文件:include/driver/media_types.h,枚举类型``media_ppi_t``,里面的参数需要添加,如果没有。

3.命令行增加新的分辨率

如果需要采用doorbell自带的cli命令,需要让新增加的分辨率可以生效,否则跳过这一步

参考doorbell命令行:components/media/cli/media_cli.c,适配新的命令,在函数:get_string_to_ppi(),中增加新的分辨率;

备注

注意: 摄像头的分辨率的width 要能被16整除(比如864/16), height 要被8(比如 480/8)整除。否则硬件解码会失败。

9 图像旋转

当屏幕和图片像素相反,比如屏幕是480X800, 摄像头是800X480,可以进行图像旋转显示。

10 字库融合

SDK中支持字库的抗锯齿融合,字库以内部库的方式提供给用户,目前支持的字库有:

#define FONT_ANTI4BPP_ROBOTO_53           1   /* 罗马数字*/
#define FONT_ANTI4BPP_BLACK24             1   /* 黑体*/
#define FONT_ANTI4BPP_BLACK48             1   /* 黑体*/
#define FONT_ANTI4BPP_SOURCE_HAN_SANS17   0   /* 思源黑体*/
#define FONT_ANTI4BPP_SOURCE_HAN_SANS42   0   /* 思源黑体*/

#if FONT_ANTI4BPP_ROBOTO_53
extern const gui_font_digit_struct *const font_digit_Roboto53;
#endif
#if FONT_ANTI4BPP_SOURCE_HAN_SANS17
extern const gui_font_digit_struct *const font_digitSource_Han_Sans17;
#endif
#if FONT_ANTI4BPP_SOURCE_HAN_SANS42
extern const gui_font_digit_struct *const font_digitSource_Han_Sans42;
#endif
#if FONT_ANTI4BPP_BLACK24
extern const gui_font_digit_struct *const font_digit_black24;
#endif
#if FONT_ANTI4BPP_BLACK48
extern const gui_font_digit_struct *const font_digit_black48;
#endif

目前字的添加是根据不同的客户需求所添加,如果不满足客户需求,请联系支持。

字库融合的代码请参考 middleware/driver/lcd_driver.c API:lcd_driver_font_blend

font_t font;
font.info = (ui_display_info_struct){rgb565_data,0,lcd_font->ysize,0,{0}};
font.width = lcd_font->xsize;
font.height = lcd_font->ysize;
font.font_fmt = lcd_font->font_format;
for(int i = 0; i < lcd_font->str_num; i++)
{
        font.digit_info = lcd_font->str[i].font_digit_type;
        font.s = lcd_font->str[i].str;
        font.font_color = lcd_font->str[i].font_color;
        font.x_pos = lcd_font->str[i].x_pos;
        font.y_pos = lcd_font->str[i].y_pos;
        lcd_draw_font(&font);
}

各参数的值输入如下:

//融合位置的配置
frame_addr_offset = ((start_y + VERSION_POSTION_Y) * frame->width + start_x + VERSION_POSTION_X) * 2;
lcd_font_config.pbg_addr = (uint8_t *)(frame->frame + frame_addr_offset);       //地址偏移
lcd_font_config.bg_offline = frame->width - CLOCK_LOGO_W;
lcd_font_config.xsize = CLOCK_LOGO_W;       ///融合区域的宽,根据汉字的宽决定
lcd_font_config.ysize = CLOCK_LOGO_H;       ///融合区域的高,根据汉字的高决定
lcd_font_config.str_num = 2;                ///一次融合几个字符串
#if 1  ///font yuv data to bg yuv image
if (frame->fmt == PIXEL_FMT_VUYY)           ///将汉字融合到YUV数据中
        lcd_font_config.font_format = FONT_VUYY;
else
        lcd_font_config.font_format = FONT_YUYV;
#else  ///font rgb data to bg yuv image
lcd_font_config.font_format = FONT_RGB565;  ///将汉字融合到RGB565数据中
#endif

///白色字体,字号,融合到区域的起始坐标
lcd_font_config.str[0] = (font_str_t){(const char *)("晴转多云, 27℃"), FONT_WHITE, font_digit_black24, 0, 2};
lcd_font_config.str[1] = (font_str_t){(const char *)("2022-12-12 星期三"), FONT_WHITE, font_digit_black24, 0, 26};

lcd_font_config.bg_data_format = frame->fmt;  ///背景数据格式
lcd_font_config.bg_width = frame->width;      ///背景图片size
lcd_font_config.bg_height = frame->height;
lcd_driver_font_blend(&lcd_font_config);