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 执行