GR5526(1)-手表参考方案使用说明

[TOC]

1. GR5526穿戴(手表)参考

  • 请从 [开发向导] 页面获取GR5526 SDK的下载地址下载SDK,并在本地构建好开发环境。

  • 请从 [开发向导] 页面获取GR5526各种文档资料的下载地址。在进入产品开发前,花一些时间熟悉和阅读芯片相关的开发资料是必要的。

  • 请从 [开发向导] 页面获取GR5526开发过程所需要的软件和工具,方便后续开发和调试工作。

1.1 示例工程

GR5526 SDK提供了丰富的参考示例工程,涵盖Bluetooth LE(Profile、多连接、DTM)、外设使用、OS、DFU、低功耗、产品参考设计等。

针对穿戴产品,列举了部分重要的示例工程;用户参考以下示例工程,可以从零开始构建穿戴产品的各个软件模块,从外设驱动到OS、应用逻辑、Bluetooth LE Profile、DFU/OTA、休眠调试等。

工程 路径 描述
FreeRTOS模板工程 ${SDK}\projects\ble\ble_peripheral\ble_app_template_freertos 移植的FreeRTOS基础工程,支持休眠低功耗,可以基于此工程理解休眠设计和从零构建应用工程
DTM测试工程 ${SDK}\projects\ble\dtm\direct_test_mode 基于此工程进行Bluetooth LE的DTM测试
LVGL 810穿戴参考工程 ${SDK}\projects\peripheral\graphics\graphics_lvgl_810_gpu_demo 基于LVGL 810开发的穿戴参考,集成了常用的外设模块,构建了基础的UI/UX,可作为用户设计参考
LVGL 831穿戴参考工程 ${SDK}\projects\peripheral\graphics\graphics_lvgl_831_gpu_demo (454x454分辨率屏幕版本)${SDK}\projects\peripheral\graphics\graphics_lvgl_831_gpu_demo_360p (360x360分辨率屏幕版本) 基于LVGL 831开发的穿戴参考,集成了常用的外设模块,集成了Bluetooth LE Profiles和DFU,构建了基础的UI/UX,可作为用户设计参
产品升级引导参考工程 ${SDK}\projects\ble\dfu\app_bootloader 提供的Bootloader引导固件可用于产品DFU升级引导程序
DFU OTA 升级参考工程 ${SDK}\projects\ble\ble_peripheral\ble_app_template_dfu 集成OTA功能,配合app_bootloader和OTA App(GRToolbox)使用,产品开发过程中,需要将本工程的OTA部分移植到产品工程中
  • 如果能获取或购买到GR5526 SK板,可以在SK板上先行运行体验上述工程。对程序和效果的直观测试体验能帮助工程师快速建立产品和SDK的使用直觉。

  • 如果用户具备丰富的穿戴产品开发经验,上述工程可作为产品开发中的调试参考。

  • 如果用户相对缺少穿戴产品的开发经验,可考虑使用LVGL 831(或LVGL 810)工程作为模板工程,删减不需要的功能,并开发集成产品业务缺失的功能。

  • 此外,我们提供了部分参考工程的视频演示,用户可扫描下发二维码进行查看和体验。

  • GR5526 LVGL 831演示视频

  • GR5526能力演示视频

1.2 驱动参考

GR5526 SDK提供了常用芯片外设和外设模块的驱动参考程序。在产品开发中,可根据实际情况进行参考或者复用。

外设模块 驱动文件或目录 使用说明
GPU ${SDK}\app\drivers\src\app_graphics_gpu.c 主要管理GPU模块的初始化、休眠、同步等,GPU的 接口,仅适用于GPU版本芯片
GPU驱动接口 ${SDK}\app\components\graphics\gfx GPU的驱动接口头文件放置
Display Controller(显示控制模块) ${SDK}\app\drivers\src\app_graphics_dc.c DC模块可用于产生SPI、3-SPI、4-SPI及QSPI的屏幕控制时序,以及处理GPU专用的压缩格式,仅适用于GPU版本芯片
OSPI PSRAM ${SDK}\app\drivers\src\app_graphics_ospi.c OSPI是接口类型Octal-SPI,PSRAM是通过OSPI DDR接口扩展的可读写RAM空间,速度比内部SRAM慢一些,但比外部的QSPI PSRAM快很多;尽可能用DMA、GPU Master大数据块方式访问 PSRAM,尽量避免使用CPU指针访问大空间的PSRAM,否则会降低访问性能;PSRAM地址空间和SRAM的一块别名地址空间连续
PSRAM堆管理 ${SDK}\app\components\libraries\app_graphics_mem\app_graphics_mem.c 将PSRAM空间视作一大块堆空间进行管理,由于SRAM/PSRAM的地址空间连续,Heap的起始地址在SRAM,初始化后首先申请2个FB空间
QSPI-Flash ${SDK}\app\components\drivers_ext\qspi_device提供了驱动参考 注意区分QSPI-Flash和XQSPI-Flash,后者是SiP在芯片内部用于代码执行的Flash,但其剩余空间也可以用来存储其他资源;软件中const定义的数据放置在XQSPI-Flash
QSPI-Flash MMAP访问 穿戴示例工程 参考示例工程下提供了使用MMAP模式访问Flash的代码
QSPI-PSRAM ${SDK}\app\components\drivers_ext\qspi_device提供了驱动参考 此为通过外部QSPI接口扩展的PSRAM,速度相比OSPI PSRAM慢很多,如果是GPU版本芯片,可以忽略这个外设
QSPI-Display ${SDK}\app\components\drivers_ext\qspi_device提供了驱动参考 SDK提供了多个屏幕的多种接口驱动设计参考,如基于QSPI硬件接口的SPI/QSPI时序驱动,以及基于DC硬件接口的SPI、3/4-SPI、QSPI时序驱动
DC-Display ${SDK}\components\drivers_ext\graphics_dc SDK提供基于Display Controller外设模块的屏幕驱动程序,涵盖XSJ和FLS等屏厂驱动
Touch 示例工程示例工程 参考示例工程下提供了Touch的一般驱动参考

1.3 LVGL GUI框架使用说明

  • 在GR5526最新版本SDK中(v1.0.2),提供了两个LVGL版本的移植优化,并分别提供一个参考工程。

  • 一般情况下,建议用户优先使用LVGL 8.3.1版本。从移植和官网支持角度看,新版本都会存在更少的Bug和更好的特性。

版本 主要优化点 源码路径 适用 SoC
LVGL 8.10 1.集成提供GPU驱动库
2.完成LVGL绘制层的移植优化(线、矩形、多边形、image、圆、弧……)
3.LVGL在32bit色深条件下同时支持RGB565、RGBA8888以及GPU压缩格式的资源
4.加入Indev输入缓存设计,改善跟手性
5.加入WMS(Window Management Service)设计,负责窗口滑动时渲染及事件的管理,引入SurfaceFlinger设计,加入窗口过渡三维动画
6.WMS2.0新增特征:
1).引入ID系统进行Window管理
2).引入Scene场景管理系统,解决一个Window在多个场景的问题
3).引入Window Stack设计,记录管理窗口栈
4).将侧键管理嵌入WMS,每个窗口根据需要进行侧键各类事件的处理;如果不处理,则系统统一处理
5).引入手势退出
7.提供多种自定义控件设计参考(如星云表盘、滑动列表等)
8.提供Watch Demo参考工程
${GR5526_SDK}\external\lvgl_8.1.0 GR5526 GPU版本
LVGL 8.31 1.集成提供GPU驱动库
2.完成LVGL绘制层的移植优化(线、矩形、多边形、image、圆、弧……)
3.LVGL在32bit色深条件下同时支持RGB565、RGBA8888以及GPU压缩格式的资源
4.加入Indev输入缓存设计,改善跟手性
5.加入WMS(Window Management Service)设计,负责窗口滑动时渲染及事件的管理,引入SurfaceFlinger设计,加入窗口过渡三维动画
6.WMS2.0新增特征:
1).引入ID系统进行Window管理
2).引入Scene场景管理系统,解决一个Window在多个场景的问题
3).引入Window Stack设计,记录管理窗口栈
4).将侧键管理嵌入WMS,每个窗口根据需要进行侧键各类事件的处理;如果不处理,则系统统一处理
5).引入手势退出
7.提供多种自定义控件设计参考(如星云表盘、滑动列表等)
8.提供Watch Demo参考工程
${GR5526_SDK}\external\lvgl_8.3.1 GR5526 GPU版本
  • 当在工程中使用LVGL GUI框架时,还需要引用如下库或配置文件:

LVGL LVGL移植库 GPU库 sct文件(ARMCC)
8.1.0 ${SDK}\platform\soc\linker\keil\graphics_lvgl_v810_lib.lib ${SDK}\platform\soc\linker\keil\graphics_sdk.lib ${SDK}\platform\soc\linker\keil\flash_scatter_graphics.sct
8.3.1 ${SDK}\platform\soc\linker\keil\graphics_lvgl_v831_lib.lib ${SDK}\platform\soc\linker\keil\graphics_sdk.lib ${SDK}\platform\soc\linker\keil\flash_scatter_graphics.sct

2. 移植使用说明

  • 本章节基于工程 graphics_lvgl_831_gpu_demo_360p 进行说明, 工程 graphics_lvgl_831_gpu_demo 同理.

2.1 典型外设适配

  • 示例工程将穿戴产品涉及的 屏幕控制、触摸处理、数据Flash 访问, 抽象出一层适配层 (Adapter), 并进行了一个参考实现. 用户可以在适配层的基础上, 根据产品情况, 进行这几类外设的重新适配

  • 默认在外设初始化时, 注册这几类外设的函数指针, 为了移植兼容性, 在应用层尽可能调用适配上层函数接口

    void app_periph_init(void)
    {
        .....
        drv_adapter_disp_register();
        drv_adapter_norflash_register();
        drv_adapter_touchpad_register();
        .....
    }
    

2.1.1 屏幕驱动的适配

  • 屏幕适配层抽象了如下函数接口, 用户需根据需要进行适配实现

上层函数 适配层函数(用户实现) 作用
drv_adapter_disp_register 如无必要,不用修改 注册适配层函数
drv_adapter_disp_init _disp_drv_init 屏幕初始化接口
drv_adapter_disp_deinit _disp_drv_deinit 屏幕反初始化接口
drv_adapter_disp_set_show_area _disp_drv_set_show_area 设置屏幕显示区域
drv_adapter_disp_wait_to_flush _disp_drv_wait_to_flush 等待刷屏, 必须等待上次刷屏完成 (一般使用信号量实现)
drv_adapter_disp_flush _disp_drv_flush 将帧缓冲区数据刷新到屏幕进行显示
drv_adapter_disp_wait_te _disp_drv_wait_te 等待 TE 同步
drv_adapter_disp_on _disp_drv_on 屏幕显示开/关
drv_adapter_disp_set_brightness _disp_drv_set_brightness 设置背光亮度
drv_adapter_disp_sleep _disp_drv_sleep 屏幕休眠, 对屏幕进行掉电,屏幕电路配置为最低功耗
drv_adapter_disp_wakeup _disp_drv_wakeup 屏幕唤醒, 配置屏幕电路及屏幕重新处于正常工作状态
  • 用户可以参考适配层函数的原型定义, 并参考示例工程的驱动, 在屏幕的驱动文件中实现上述接口功能, 并完善适配层函数.

  • 注意, drv_adapter_disp_set_show_area 函数设置显示区域的参数规则如下:

    • 如果屏幕宽高为W, H, 则传入的参数为 drv_adapter_disp_set_show_area (0, 0, W - 1, H - 1);

  • 在适配初期, 比较重要的三个函数如下, 可先行适配好点亮屏幕, 再进行其他接口的实现

    • drv_adapter_disp_init - 包括Reset、背光引脚控制, 命令时序初始化等操作, 确保屏幕达到可点亮的状态

    • drv_adapter_disp_set_show_area - 通过控制命令设置期望的显示区域

    • drv_adapter_disp_flush - 将帧数据刷新到屏幕进行显示

2.1.2 Touch 的适配

Touch 适配层抽象了如下函数接口, 用户需根据需要进行适配实现

上层函数 适配层函数(用户实现) 作用
drv_adapter_touchpad_register 如无必要,不用修改 注册适配层函数
drv_adapter_touchpad_init _touchpad_drv_init Touch初始化接口
drv_adapter_touchpad_deinit _touchpad_drv_deinit Touch反初始化接口
drv_adapter_touchpad_read_pointer _touchpad_drv_read_pointer 读取Touch 坐标点函数
drv_adapter_touchpad_sleep _touchpad_drv_sleep 设置Touch休眠, 根据产品设计, 进入休眠模式或直接掉电
drv_adapter_touchpad_wakeup _touchpad_drv_wakeup 重新设置Touch 进入唤醒工作模式
  • 用户可以参考适配层函数的原型定义, 并参考示例工程的驱动, 在Touch的驱动文件中实现上述接口功能, 并完善适配层函数.

  • 一般情况下, Touch 的驱动多基于I2C接口, 适配较简单

  • 如果Touch使用了中断唤醒IO (注意放在AON IO域),可考虑在I/O的回调函数中(比如实现信号量)唤醒系统

    /*
     * Override this function, defined as __weak in file drv_adapter_port_touchpad.c
     */
    void _touchpad_drv_irq_notify(void) {
        osal_sema_give(s_sleep_mgnt_sem);
    }
    

2.1.3 数据Nor Flash 的适配

  • 一般情况下, 市面各厂家Nor Flash 控制命令均兼容, 不需要再额外重新适配 Nor Flash 驱动,但需要考虑以下情况需要额外再适配下驱动接口:

    • 用户可能将Flash 挂载到不同的QSPI 模块下(默认挂载到QSPI0), 需要重新配置Flash的I/O; 并且需要修改图片素材的存放地址

    • 已支持的Flash 厂商中可能存在少数控制命令差异的Flash 型号

    • 默认驱动没有支持到

  • 外部 Nor Flash 适配层抽象了如下函数接口, 用户需根据需要进行适配实现

上层函数 适配层函数(用户实现) 作用
drv_adapter_norflash_register 如无必要,不用修改 注册适配层函数
drv_adapter_norflash_init _norflash_drv_init flash初始化接口
drv_adapter_norflash_deinit _norflash_drv_deinit flash反初始化接口
drv_adapter_norflash_write _norflash_drv_write 写任意长度数据接口, 要求写入地址已经提前擦除干净, 接口不会进行先读再写的数据备份
drv_adapter_norflash_read _norflash_drv_read 读任意长度数据接口
drv_adapter_norflash_update _norflash_drv_update 更新任意长度数据接口, 更新前会进行读取备份、擦除、后写入的操作, 但擦除使用的是Page擦除实现, 如果所用Flash 不支持Page擦除命令. 需要重新适配
drv_adapter_norflash_erase _norflash_drv_erase 擦除接口, 支持Page、Sector、Block、Chip等多种擦除方式
drv_adapter_norflash_set_mmap_mode _norflash_drv_set_mmap_mode 设置Flash的MMAP访问模式(开/关)
drv_adapter_norflash_sleep _norflash_drv_sleep 设置 Flash休眠
drv_adapter_norflash_wakeup _norflash_drv_wakeup 唤醒Flash回到工作状态
  • 如果电路上 外部Flash 不是挂载在 QSPI0模块, 请修改 qspi_norf_init 的入参 ID 和 PIN引脚配置

    #define NORFLASH_DEV_QSPI_ID                            APP_QSPI_ID_0                           /**< QSPI id to connect the norf */
    #define NORFLASH_DEV_CLOCK_PREESCALER                   2u                                      /**< clock prescaler for qspi */
    #define NORFLASH_DEV_PIN_CFG                            (g_qspi_pin_groups[QSPI0_PIN_GROUP_0])  /**< pin config for qspi */
    #define NORFLASH_DEV_DEV_ID                             0x0B                                    /**< 0x0B - XTX; 0x85 - PUYA */
    
  • 如果 Nor Flash 挂载到非QSPI0模块, 则资源图片的存储位置也需要调整. 用工具生成的符合GPU版本Lvgl 图片资源, 其默认基地址放在 QSPI0 的 MMAP 空间 QSPI0_XIP_BASE. 如下 (文件 lv_img_dsc_list.c) :

    #if USE_EXTERNAL_RESOURCES
    #define BINARY_RESOURCES (const uint8_t *)QSPI0_XIP_BASE
    #else
    extern const uint8_t BINARY_RESOURCES[];
    #endif // USE_EXTERNAL_RESOURCES
    
    const lv_img_dsc_t wd_img_black_clock_face = {
        .header.always_zero = 0,
        .header.cf = LV_IMG_CF_GDX_RGB565,
        .header.w = 360,
        .header.h = 360,
        .data_size = 259200,
        .data = BINARY_RESOURCES + OFFSET_BLACK_CLOCK_FACE,
    };
    
    • 如果更换为 QSPI1 挂载的Flash, 基础地址设置为 QSPI1_XIP_BASE, 以此类推

    • 如果图片资源的存放地址不是从Flash 的0地址开始, 则需要再加上具体的偏移.

2.2 Lvgl 相关

2.2.1 分辨率配置

  • 用户可以通过 lv_conf.h的下述宏配置, 将分辨率配置为产品屏幕的实际分辨率

    #ifndef DISP_HOR_RES
        #define DISP_HOR_RES                454u
    #endif
    
    #ifndef DISP_VER_RES
        #define DISP_VER_RES                454u
    #endif
    
    #define DISP_PIXEL_DEPTH            2u
    
  • 屏幕分辨率宽/高分别由 DISP_VER_RES DISP_HOR_RES定义. 默认定义的 454x454, 自定义宏值定义在 keil 配置项的预定义宏 (位于菜单: Project->Options for target -> C/C++ -> Define )

  • 为了支持GPU的过场动画, 请将分辨率的宽高定义为 偶数. (如果屏幕某边为奇数, 可以多定义或少定义一行/列)

  • 像素深度定义的2字节, 即选用格式 RGB565. 这个格式已适用于目前绝大多数显示类产品场景, 不用修改

  • 帧缓冲区的格式具体定义在下述函数:

    uint32_t lv_port_get_fb_format(void) {
    #if DISP_PIXEL_DEPTH == 2
        return HAL_GFX_RGB565;
    #elif DISP_PIXEL_DEPTH == 4
        return HAL_GFX_RGBA8888;
    #else
        #error "Not Support Now"
    #endif
    }
    

2.2.2 色彩配置

  • Lvgl 本身的绘制层, 已基于 5526 的GPU 进行优化适配, 色彩格式默认配置如下, 不建议修改:

    #define LV_COLOR_DEPTH 32
    
    • 在 lv_conf.h 中定义了色彩深度为32, 请不要修改, 基于这个颜色深度配置, 已对图片使用 RGB565、RGBA8888、TSC4、TSC6a 等格式进行了适配兼容, 已具备最大图片源格式的兼容性

  • 在代码中使用自定义色彩的时候, 请使用 lv_color_make 接口, 而规避使用 lv_color_hex 接口. 前者进行了端序匹配

2.2.3 帧缓冲区

  • Lvgl帧渲染缓冲区:

    • 在参考示例中, 使用的双帧缓冲区的软件架构, 便于 渲染和刷屏任务并行执行, 以提高帧率, 请不要修改双缓冲区的架构. 帧渲染缓冲区的像素格式使用的 RGB565

    • 分配双缓冲区的代码如下:

    void lv_port_disp_init(void)
    {
        /*-------------------------
         * Initialize your display
         * -----------------------*/
        disp_init();
    
        /*-----------------------------
         * Create two fixed frame buffers for drawing and never release it
         *----------------------------*/
        static lv_disp_draw_buf_t draw_buf_dsc;
    
        lv_color_t* _draw_buf1 = app_graphics_mem_malloc(DISP_HOR_RES * DISP_VER_RES * DISP_PIXEL_DEPTH);
        lv_color_t* _draw_buf2 = app_graphics_mem_malloc(DISP_HOR_RES * DISP_VER_RES * DISP_PIXEL_DEPTH);
        ....
     }
    
  • 帧过程动画缓冲区:

    • 在窗口切换过程中, 为了加速动画渲染提高帧率, 额外申请了2个帧动画缓冲区, 帧动画渲染缓冲区使用的像素格式为TSC4。代码如下:

      void lv_wms_transit_mem_alloc(void) {
          if(NULL == _trans_env._scrn_cache_1) {
              _trans_env._scrn_cache_1 = app_graphics_mem_malloc(_trans_env._cachebuffer_size);
          }
      
          if(NULL == _trans_env._scrn_cache_2) {
              _trans_env._scrn_cache_2 = app_graphics_mem_malloc(_trans_env._cachebuffer_size);
          }
      }
      
  • 如果遇到帧渲染异常, 需要进行缓冲区数据调试, 可从上述代码位置获取缓冲区的首地址.

2.2.4 帧格式的定义

  • 本节涉及的配置默认不需要修改

  • 工程有2处需要定义帧格式:

    • 当GPU渲染时, 需要告知GPU帧缓冲区的格式, 默认配置为 HAL_GFX_RGB565 , 代码如下:

      uint32_t lv_port_get_fb_format(void) {
      #if DISP_PIXEL_DEPTH == 2
          return HAL_GFX_RGB565;
      #elif DISP_PIXEL_DEPTH == 4
          return HAL_GFX_RGBA8888;
      #else
          #error "Not Support Now"
      #endif
      }
      
    • 当 DC(Display Controller) 刷屏时, 需要告知 DC模块帧缓冲区的格式, 配置位置在刷屏接口处, 通过 buf_format 变量传入. 目前全局会用到两种 DC 帧格式如下

      • HAL_GDC_RGB565 - 使用标准渲染帧缓冲区刷屏时候给DC模块指定的格式

      • HAL_GDC_TSC4 - 使用帧过程动画缓冲区刷屏时候给DC模块指定的格式

      void graphics_dc_st77916_flush(void *buf, uint32_t buf_format, uint16_t w, uint16_t h)
      {
          app_graphics_dc_cmd_t dc_cmd = {
              .command = ST77916_INST_WR_I1A4D4,
              .address = 0x002C00,
              .address_width = GDC_FRAME_ADDRESS_WIDTH_24BIT,
              .frame_timing = GDC_QSPI_FRAME_TIMING_1,
          };
      
          app_graphics_dc_framelayer_t dc_layer = {
              .frame_baseaddr = buf,
              .resolution_x = w,
              .resolution_y = h,
              .row_stride = -1,
              .start_x = 0,
              .start_y = 0,
              .size_x = w,
              .size_y = h,
              .alpha = 0,
              .blendmode = HAL_GDC_BL_SRC,
              .data_format = (graphics_dc_data_format_e)buf_format,
          };
      
          app_graphics_dc_send_single_frame(GRAPHICS_DC_LAYER_0, &dc_layer, &dc_cmd, GDC_ACCESS_TYPE_ASYNC);
      }
      
      • GPU 和 DC指定帧格式时候, 注意不要把枚举值搞混

2.3 用户任务说明

  • 示例工程新定义了3个用户级任务:

    • GUI Task - 用于 Lvgl 任务的渲染, Lvgl 任务线程不安全, 不能异步调用绘制类接口

    • Touch Task - 用于 Touch 事件的采集, 并将事件给 GUI任务处理

    • Event Task - 当前用于将 Key 类事件通过 Lvgl 异步接口, 发送给 Lvgl Task 执行