JL703N SSD1306 OLED(128x64) 点阵屏移植说明
目标平台:JL703N / br27
目标SDK: JL703N_le_audio_2.0.0_patch_01_11
参考实现:
demo_701_142_oled_pixscoll\sdk(JL701N/br28,OLED 可正常工作)效果:SSD1306 128x64 正常点亮,SOUNDBOX 风格 UI 显示,中文字库正常,音乐模式歌名可显示。
遗留:PC 模式界面因资源未画全而不完整(见 §8)。
部分UI界面效果



一、背景:703 SDK 里并存两套互斥的 UI 框架
这是整个移植的核心。JL703N SDK 内同时保留了新旧两套 UI 框架,用 EXPORT_DOT_UI_ENABLE 二选一,
但原厂只做了源码层的开关,没有把库和头文件的切换做进构建系统,导致点阵屏那套没有编不进去。
| 点阵屏(OLED) | 彩屏(默认) | |
|---|---|---|
| 静态库 | ui_dot.a ui_draw.a res.a font.a ui_cpu.a |
ui_new.a ui_draw_new.a res_new.a font_new.a |
| 头文件路径 | interface/utils/ui |
interface/ui/jl_ui |
| 框架代码 | apps/common/ui/interface/*(软件 SPI 推屏) |
cpu/br27/ui_driver/*(IMD 硬件推屏) |
| 屏驱注册宏 | REGISTER_LCD_DEVICE() → 全局变量 lcd_drive |
REGISTER_LCD_DEVICE_NEW() → .lcd_device_info 段 |
| 屏驱文件 | oled_spi_ssd1306_128x64.c |
lcd_spi_st7789v_240x240.c 等 |
两套框架的屏驱注册方式不兼容,且都会注册 lcd_interface 到 .lcd_if_info 段,必须严格二选一。
二、问题与处理过程
问题 1:编译报大量 undefined reference
现象
undefined reference to `platform_get_file' / `ui_draw' / `ui_platform_init'
undefined reference to `ui_file_check_valid' / `ui_upgrade_file_check_valid'
根因
实际是:
cpu/br27/ui_driver/interface/ui_platform.c:3271: error: use of undeclared identifier 'STRPIC_1'
该文件末尾的 "ui test demo" 段无条件引用了 STRPIC_1/PNG_PIC/TEXT_1 等控件 ID,
而这些 ID 只在 CONFIG_UI_STYLE == STYLE_JL_SOUNDBOX 时定义。编译失败 → 没生成 .o → 链接时符号全缺。
处理:给该 demo 段加风格条件编译(见改动 9)。
教训:
make -j出现 undefined reference 时,先往前翻找真正的error:,别被链接错误误导。
问题 2:ASSERT lcd_device_begin != lcd_device_end
现象
log打印出现:
find logo st7789v
ASSERT-FAILD: lcd_device_begin != lcd_device_end don't find lcd device!
根因
屏驱注册表 .lcd_device_info 段为空:
- 编译进来的 3 个彩屏驱动各自被
TCFG_LCD_SPI_ST7789V_ENABLE等宏包住,而这些宏均为 0 → 文件全空; - SSD1306 屏驱属于点阵屏那套,而
EXPORT_DOT_UI_ENABLE从未被定义过,整段不参与编译。
处理:切换到点阵屏框架(改动 1~5)。
问题 3:切换框架后 33 个编译错误
现象 :切到 apps/common/ui 后报缺头文件、函数参数个数不符、结构体字段不存在。
根因
用新库的头文件 去编译老框架的代码 。这套代码配套的是 interface/utils/ui(老 UI 库),
而 include_dir.txt 里只挂了 interface/ui/jl_ui(新库)。
处理 :头文件路径和静态库一起切到老库(改动 1、2)。切换后编译错误 33 → 1。
问题 4:链接缺 ui_page_* 等 13 个符号
现象
编译出现:
undefined reference to `ui_page_init' / `ui_page_add' / `get_direction' / `g_cur_left' ...
根因
lcd_ui_api.c 里的卡片滑动翻页 功能依赖新库 ui_new.a 才有的接口,老库 ui_dot.a 不提供。
参考 SDK 里这段代码是包在 #if (CONFIG_UI_STYLE == STYLE_JL_WTACH_NEW) 内的,703N 版本把条件去掉了。
处理 :加 UI_CARD_SLIDE_ENABLE 开关(改动 7)。点阵屏无触摸屏,用不上该功能。
问题 5:ui_core_malloc ASSERT / open_resfile fail!
现象
log出现:
open faild!
open_resfile fail!
ASSERT-FAILD: p != NULL ui_core_malloc (ui_core_dot.c:127)
根因
ui_resources_manager.c:191 把资源路径硬编码 为 RES_PATH"JL/JL.res"(即 flash/res/JL/JL.res),
而 download.bat 打包的是 JL_OLED 目录 → 烧进去是 flash/res/JL_OLED/JL.res,路径对不上。
资源打不开 → jlui_load_window() 读到垃圾 window.len → malloc 失败 → ASSERT。
处理 :打包前先把选中屏型的资源同步到 JL 目录,统一打包 JL(改动 6)。
问题 6:UI 只有几个模式文字,没有完整界面
根因
703N 自带的 JL_OLED 资源是近乎空的占位包:
| 文件 | 703N 原始 | 701 参考 |
|---|---|---|
JL.res(图片) |
41708 | 30057 |
JL.str(文字) |
28 | 24336 |
JL.sty(页面布局) |
6392 | 41480 |
| 控件 ID 数 | 76 | 471 |
处理 :移植 701 的 128x64 UI 工程与资源,风格切到 STYLE_JL_SOUNDBOX(改动 3、10、11、12)。
移植前验证过可行性:703N 的 STYLE_SOUNDBOX 业务代码引用 208 个控件 ID,
其中 189 个(91%)在 701 资源表中已有 ,缺的 19 个里 18 个是 SPDIF(701 无此模式)、1 个是触摸 demo 用的 PNG_PIC,
而这两部分对应的源文件本来就不参与编译(TCFG_APP_SPDIF_EN=0、触摸 demo 已排除)。
问题 7:打包报文件名超长
现象
ERROR: The length(16) of the file name "JL.res.bak_empty" exceeds 15 characters.
根因 :备份文件放在了会被打包的资源目录里,xcopy *.* 把它一起复制进 JL/。
处理 :备份移出资源目录;同步改为只复制 JL.res/JL.str/JL.sty 三个文件(改动 6)。
注意:资源目录内的文件名不得超过 15 字符,且不要放任何无关文件。
问题 8:歌曲名不显示(无任何报错)
现象 :日志证明链路完全正常,但屏上就是不显示歌名。
log打印:
__FUNCTION__ =music_start type =show_lyric 0 ← 消息到达
>>>[ui test]:filename = 10kHz_sin_10min.wav, len = 19 ← 文件名取到
music start is_unicode = 1 ← 走宽字符渲染
31 00 30 00 6B 00 48 00 7A 00 ... ← UTF-16LE 数据正确
(之后无任何输出,也无报错)
根因 (ui_synthesis_oled.c:772)
c
info = font_open(NULL, language);
ASSERT(info, "font_open fail!"); // 未触发,所以日志毫无异常
if (info && (FT_ERROR_NONE == (info->sta & (~FT_ERROR_NOTABFILE | FT_ERROR_NOPIXFILE)))) {
... 真正画字 ... // 被静默跳过
}
font/ 目录只有 F_UNIC.PIX,缺配套的 .TAB 索引文件 。
font_open 返回非 NULL(不触发 ASSERT),但 info->sta 带 FT_ERROR_NOTABFILE 标志,
导致整个渲染分支被跳过 ------ 表现为"文字不显示且日志无任何报错"。
模式名等文字能显示,是因为它们走 JL.str 里的字符串图片,不经过字库。
处理 :补入 F_GB2312.PIX + F_GB2312.TAB(改动 14)。
日志中 language:1 对应 Chinese_Simplified(见 font/language_list.h),正好匹配 GB2312 字库。
字库文件必须
.PIX与.TAB成对存在,否则文字静默不渲染。
问题 9:PC模式界面左右各缺一块、电量图标无格数
现象:PC 模式首页左右两侧各缺一块内容,只有中间正常;电量图标不显示具体电量。两个 SDK 都有。
排查过程
第一层原因:703N 的 STYLE_SOUNDBOX 目录里没有 pc_action.c (701 的 STYLE_02 有)。
该文件负责 PC_VOL_LAYOUT 的"按音量键弹出、3 秒后自动收起":
c
case UI_KEY_VOLUME_INC:
case UI_KEY_VOLUME_DEC:
ui_show(PC_VOL_LAYOUT); // 按键才显示
static void pc_vol_lay_timeout(void *p) {
if (ui_get_disp_status_by_id(id) == TRUE) ui_hide(id); // 3秒后收起
}
缺该文件时音量布局按资源默认状态常驻,压在界面上。移植后(见改动 13)该问题解决,但左右缺块依旧。
第二层原因(根本原因):统计各页面控件数后真相明确 ------
| 页面 | 控件数 | 页面 | 控件数 |
|---|---|---|---|
| PAGE_7 SYS | 132 | PAGE_10 REC | 45 |
| PAGE_4 MUSIC | 95 | PAGE_9 LINEIN | 43 |
| PAGE_3 CLOCK | 46 | PAGE_2 FM | 26 |
| PAGE_1 BT | 45 | PAGE_8 PC | 7 |
ui_128_64_JL02 工程里 PAGE_8 只画了骨架 (PC_LAYER/PC_LAYOUT/PC_PIC/PC_BAT/PC_VOL_LAYOUT/PC_VOL_PIC/PC_VOL_NUM),
没有状态栏、EQ、菜单等其它页面都有的元素。左右两侧在资源里压根没有内容,代码补不出来。
电量方面:pc_action.c 与 bt_action.c 的 battery_onchange 代码逐字相同
(都是 ui_battery_set_level(battery, get_vbat_percent(), incharge) + 1 秒定时刷新),
所以代码无误,嫌疑同样在 PC_BAT 的资源配置(ui_battery 需绑定各电量档位图片)。
处理 :移植 pc_action.c(解决音量布局常驻);界面补全需用 UI 绘图工具改工程,见 §8 已知限制。
判断"是代码问题还是资源问题"的快捷方法:统计目标页面的控件数,与同类页面横向对比。
差一个数量级基本可断定是资源没画。
三、改动总览
3.1 修改/新增的代码文件(14 个)
编号与「§4 修改内容详解」一致,可直接对照查看改动细节。
| # | 文件 | 改动内容 | 分类 |
|---|---|---|---|
| 1 | build/Makefile.mk |
UI 静态库切到点阵屏版本(含原本从未链接的 ui_cpu.a) |
构建 |
| 2 | build/include_dir.txt |
UI 头文件路径 interface/ui/jl_ui → interface/utils/ui(原位替换) |
构建 |
| 3 | apps/soundbox/include/app_config.h |
新增 USE_SSD1306_OLED 覆盖块 + EXPORT_DOT_UI_ENABLE 定义 |
构建 |
| 4 | build/genFileList.c |
SSD1306 屏驱移出彩屏分支;OLED 下排除触摸 demo | 构建 |
| 5 | build/fileList.c |
彩屏框架加 #ifndef EXPORT_DOT_UI_ENABLE 互斥保护(该文件实为死代码,仅为语义一致) |
构建 |
| 6 | cpu/br27/tools/download.c |
打包前同步资源到 JL 目录,统一打包 JL |
构建 |
| 7 | apps/common/ui/lcd/lcd_ui_api.c |
新增 UI_CARD_SLIDE_ENABLE 开关;平台数据补 .spi_cfg |
源码 |
| 8 | apps/common/ui/interface/ui_pushScreen_manager.c |
asm/spi.h→spi.h;spi_dev→hw_spi_dev |
源码 |
| 8b | apps/soundbox/device_config.c |
#if SUPPORT_SPI2 → #if SUPPORT_SPI2 && TCFG_HW_SPI2_ENABLE |
源码 |
| 9 | cpu/br27/ui_driver/interface/ui_platform.c |
末尾 ui test demo 段加风格条件编译 | 源码 |
| 10 | apps/soundbox/include/ui/style_jl02.h |
控件 ID 表换成 701 的 471 个 ID(保留风格条件包裹) | 源码 |
| 11 | apps/soundbox/include/ui/ui_style.h |
ID_WINDOW_SPDIF/ID_WINDOW_SINK 在 PAGE_11/12 不存在时降级为 (-1) |
源码 |
| 12 | apps/soundbox/include/ui/res_config.h |
表盘功能按屏类型开关;补 #include "app_config.h" |
源码 |
| 13 | apps/soundbox/ui/lcd/STYLE_SOUNDBOX/pc_action.c |
新增: 从701移植PC模式UI(音量布局弹出/收起、电量刷新) | 源码 |
| --- | apps/soundbox/board/br27/sdk_config.h |
在 JLStudio 工具端设置(屏型、SPI1、引脚),勿手改,见 §5 | 工具 |
3.2 替换的资源文件(6 个)
| 路径 | 原大小 | 新大小 | 说明 |
|---|---|---|---|
cpu/br27/tools/JL_OLED/JL.res |
41708 | 30057 | 图片资源(来自 701) |
cpu/br27/tools/JL_OLED/JL.str |
28 | 24336 | 字符串图片,原为空壳 |
cpu/br27/tools/JL_OLED/JL.sty |
6392 | 41480 | 页面布局,原为空壳 |
cpu/br27/tools/JL/JL.res |
41708 | 30057 | ↓ 以下 3 个由 download.bat 自动同步 |
cpu/br27/tools/JL/JL.str |
28 | 24336 | 无需手动维护 |
cpu/br27/tools/JL/JL.sty |
6392 | 41480 | 无需手动维护 |
3.3 新增的文件与文件夹(5 项)
| 类型 | 路径 | 大小 | 说明 |
|---|---|---|---|
| 文件 | cpu/br27/tools/font/F_GB2312.PIX |
261702 | 简体中文字库(对应 language=1) |
| 文件 | cpu/br27/tools/font/F_GB2312.TAB |
45008 | 字库索引表,缺它文字静默不渲染 |
| 文件夹 | cpu/br27/tools/LCD_UI工程/ui_128_64_JL02/ |
--- | 128x64 UI 绘图工程(含 project.bin/ename.h/工具脚本),从 701 复制 |
| 文件 | apps/soundbox/ui/lcd/STYLE_SOUNDBOX/pc_action.c |
--- | PC模式UI,从701的 STYLE_02 移植并适配703N接口 |
| 文件 | doc_SSD1306_OLED移植说明.md |
--- | 本文档 |
3.4 自动生成,无需手动维护
这些文件也会出现在 git status 里,但都是工具或构建产生的:
| 路径 | 来源 |
|---|---|
cpu/br27/tools/download.bat |
由 download.c 预处理生成 |
build/fileList.mk、build/fileList.dumy |
由 genFileList.c / fileList.c 生成 |
cpu/br27/sdk.ld |
由 sdk_ld.c 生成 |
apps/soundbox/movable/section.txt、sdk_used_list.used |
由对应 .c 预处理生成 |
apps/soundbox/board/br27/sdk_config.c、jlstream_node_cfg.h |
JLStudio 工具生成 |
cpu/br27/tools/ 下 *.bin *.elf *.map *.bc *.ufw 等 |
编译/打包产物 |
四、修改内容详解
构建配置
1. build/Makefile.mk --- UI 静态库切换到点阵屏版本
diff
- cpu/br27/liba/res_new.a \
- cpu/br27/liba/ui_draw_new.a \
- cpu/br27/liba/font_new.a \
- cpu/br27/liba/ui_new.a \
+ cpu/br27/liba/res.a \
+ cpu/br27/liba/ui_draw.a \
+ cpu/br27/liba/font.a \
+ cpu/br27/liba/ui_dot.a \
+ cpu/br27/liba/ui_cpu.a \
注意 ui_cpu.a 是原 Makefile 从未链接过的,缺它会缺 imd_wait 等符号。
2. build/include_dir.txt --- UI 头文件路径切换(保持原有顺序位置,勿置顶)
diff
--Iinterface/ui/jl_ui
--Iinterface/ui/jl_ui/ui/cpu/br27
+-Iinterface/utils/ui
+-Iinterface/utils/ui/ui/cpu/br27
必须替换在原位置。若置于文件开头,老库的
includes.h会覆盖interface/system/includes.h,导致
late_initcall等宏失效,全工程报错。
3. apps/soundbox/include/app_config.h --- 屏配置覆盖 + 框架选择
c
#define USE_SSD1306_OLED 1
#if USE_SSD1306_OLED
#undef CONFIG_UI_STYLE
#define CONFIG_UI_STYLE STYLE_JL_SOUNDBOX
#undef TCFG_LCD_OLED_ENABLE
#define TCFG_LCD_OLED_ENABLE 1
#undef TCFG_OLED_SPI_SSD1306_ENABLE
#define TCFG_OLED_SPI_SSD1306_ENABLE 1
#undef TCFG_SPI_LCD_ENABLE
#define TCFG_SPI_LCD_ENABLE 0
#undef TCFG_LCD_SPI_ST7789V_ENABLE
#define TCFG_LCD_SPI_ST7789V_ENABLE 0
#endif
#if TCFG_LCD_OLED_ENABLE
#define EXPORT_DOT_UI_ENABLE 1
#endif
不要直接改
sdk_config.h------ 它由 JLStudio 工具从src/UI配置.json生成并双向同步,手改会被覆盖。排查过程中就遇到工具把 OLED 配置覆写回彩屏、导致构建突然失败的情况。
EXPORT_DOT_UI_ENABLE用#ifndef判断,不用时必须整个不定义,不能定义为 0。
4. build/genFileList.c --- SSD1306 屏驱移出彩屏分支 + 排除触摸 demo
c
// 屏驱挂到 OLED 开关下,否则选 OLED 时屏驱不编译,链接缺 lcd_drive
#if TCFG_OLED_SPI_SSD1306_ENABLE
c_SRC_FILES += apps/common/ui/lcd_drive/lcd_spi/oled_spi_ssd1306_128x64.c
#endif
// 触摸 demo 引用的 PNG_PIC 不在点阵屏 UI 工程中,点阵屏无触摸屏
#if (!TCFG_LCD_OLED_ENABLE)
c_SRC_FILES += apps/soundbox/ui/lcd/STYLE_SOUNDBOX/ui_touch_demo.c
#endif
5. build/fileList.c --- 彩屏框架加互斥保护
c
#ifndef EXPORT_DOT_UI_ENABLE
objs += $(ROOT)/cpu/br27/ui_driver/interface/ui_platform.o \
$(ROOT)/cpu/br27/ui_driver/lcd_drive/lcd_drive.o \
...
#endif
注意 :
fileList.c实为死代码。顶层Makefile:208先用genFileList.c生成fileList.mk,
Makefile.mk:143include 它取得c_SRC_FILES(链接实际使用的是它);之后Makefile.mk的 pre_build才用
fileList.c覆盖该文件,对本次构建已无影响。真正生效的是genFileList.c。这里改它只为保持两个文件语义一致,避免后人误读。
6. cpu/br27/tools/download.c --- 资源目录同步与打包路径对齐
bat
if %LCD_SOURCE_ENABLE%A==2A (
if exist JL_OLED\JL.res copy /Y JL_OLED\JL.res JL\ >nul
if exist JL_OLED\JL.str copy /Y JL_OLED\JL.str JL\ >nul
if exist JL_OLED\JL.sty copy /Y JL_OLED\JL.sty JL\ >nul
set LCD_SOURCE_FILES=%LCD_SOURCE_FILES% font JL
)
彩屏分支同样处理。逐个文件复制而非通配符,避免把无关文件打包进去。
源码适配
7. apps/common/ui/lcd/lcd_ui_api.c --- 卡片滑动翻页开关
c
#ifdef EXPORT_DOT_UI_ENABLE
#define UI_CARD_SLIDE_ENABLE 0
#else
#define UI_CARD_SLIDE_ENABLE 1
#endif
用它包住 g_cur_left/page_auto_scroll/ui_card_*/ui_page_* 相关代码段,
以及 3 处 #if 1 ui_card_ontouch(&t); #else ui_event_ontouch(&t); #endif 的分发开关。
8. apps/common/ui/interface/ui_pushScreen_manager.c --- 新旧 SDK 的 API 差异
diff
-#include "asm/spi.h"
+#include "spi.h" // 本SDK硬件SPI接口头位于 interface/driver/cpu/periph
-int __spi_dma_send(spi_dev spi, ...)
+int __spi_dma_send(hw_spi_dev spi, ...)
8b. apps/soundbox/device_config.c --- SPI2 配置的连带修复
diff
-#if SUPPORT_SPI2
+#if SUPPORT_SPI2 && TCFG_HW_SPI2_ENABLE
开启 TCFG_HW_SPI1_ENABLE 后 spix_p_data[] 才参与编译,其中的 SPI2 分支会引用未定义的
TCFG_HW_SPI2_PORT_CLK 等宏,需补上使能判断。
9. cpu/br27/ui_driver/interface/ui_platform.c --- demo 段风格隔离
把文件末尾 "ui test demo" 段(ui_test_cb/ui_test_demo/TEXT1_onchange/REGISTER_UI_EVENT_HANDLER(TEXT_1))
包进 #if (CONFIG_UI_STYLE == STYLE_JL_SOUNDBOX),保留其外的 REGISTER_UI_STYLE。
(该文件在 OLED 配置下已不参与编译,此修复是为彩屏配置保留正确性)
10. apps/soundbox/include/ui/style_jl02.h --- 控件 ID 表替换
用 701 的 style_jl02.h(471 个控件 ID ,由 ui_128_64_JL02 工程导出)替换原有的表,
外层保留 #if (CONFIG_UI_STYLE == STYLE_JL_SOUNDBOX) 包裹。
必须保留风格条件,否则会与
style_soundbar.h产生 880 个宏重定义警告(
ui_style.h会同时 include 两个头文件)。
11. apps/soundbox/include/ui/ui_style.h --- SPDIF/SINK 页面降级
c
#ifdef PAGE_11
#define ID_WINDOW_SPDIF PAGE_11
#else
#define ID_WINDOW_SPDIF (-1) // ui_128_64_JL02 工程只画到 PAGE_10
#endif
ID_WINDOW_SINK 同理。模式功能仍可用,只是没有对应 UI 页面。
12. apps/soundbox/include/ui/res_config.h --- 表盘功能按屏类型关闭
c
#if TCFG_LCD_OLED_ENABLE
#define UI_WATCH_RES_ENABLE 0//表盘功能
#else
#define UI_WATCH_RES_ENABLE 1//表盘功能
#endif
并补 #include "app_config.h"。
表盘功能(watch1~5 多表盘 + 表盘升级)只适用于彩屏手表产品,点阵屏开启会去加载不存在的 watch 资源,
并引用已废弃的
VM_WATCH_SELECT等接口。注意 :
FONT_PATH等路径定义要保持在#if (TCFG_UI_ENABLE)分支内不变。若整体切到简版分支,
FONT_PATH会丢掉font/子目录,导致字库也找不到。
13. apps/soundbox/ui/lcd/STYLE_SOUNDBOX/pc_action.c (新增)--- PC模式UI
从 701 的 STYLE_02/pc_action.c 移植,负责 PC 页面的音量布局弹出/收起、电量定时刷新、按键处理。
移植时需适配 701→703N 的三处接口差异:
| 项目 | 701 | 703N |
|---|---|---|
| 按键常量 | KEY_MENU/KEY_OK/KEY_UP... |
UI_KEY_* 前缀(14 处) |
| 按键动作 | app_task_put_key_msg(KEY_MUSIC_PP, 0) |
app_send_message(APP_MSG_MUSIC_PP, 0)(5 处) |
| 关机 | power_off_deal(NULL, e->value - KEY_POWER_START) |
power_off_deal(APP_MSG_KEY_POWER_OFF) 单参数 |
老的按键消息枚举在 703N 的
key_event_deal.h:7里整个被#if 0禁用,必须换成APP_MSG_*;PC 模式的按键消息表
mode/pc/pc_key_msg_table.c用的正是这套,语义一致。
另需补 #include "app_msg.h"、"idle.h",并把编译条件加上模式使能:
c
#if (TCFG_UI_ENABLE && (CONFIG_UI_STYLE == STYLE_JL_SOUNDBOX) && TCFG_PC_ENABLE)
资源与字库
14. cpu/br27/tools/font/ --- 补入简体中文字库
+ F_GB2312.PIX 261702 (简体中文字库,对应 language=1)
+ F_GB2312.TAB 45008 (索引表,缺它文字静默不渲染)
15. cpu/br27/tools/JL_OLED/ 与 JL/ --- 替换为 701 的完整 128x64 资源
JL.res 41708 → 30057
JL.str 28 → 24336
JL.sty 6392 → 41480
16. cpu/br27/tools/LCD_UI工程/ui_128_64_JL02/ (新增目录)
从 701 复制的 128x64 UI 绘图工程,含 project.bin、ename.h、imagelist.txt
及绘图/资源生成工具启动脚本,后续可直接用它调整界面。
五、板级硬件配置(sdk_config.h,工具端设置)
c
TCFG_HW_SPI1_ENABLE 1
TCFG_HW_SPI1_PORT_CLK IO_PORTA_07 // → OLED D0/SCL
TCFG_HW_SPI1_PORT_DO IO_PORTA_08 // → OLED D1/SDA
TCFG_HW_SPI1_BAUD 24000000
TCFG_TFT_LCD_DEV_SPI_HW_NUM 1 // 即 HW_SPI1
TCFG_LCD_PIN_RESET IO_PORTA_01 // RES
TCFG_LCD_PIN_CS IO_PORTA_02 // CS
TCFG_LCD_PIN_DC IO_PORTA_04 // DC
lcd_ui_api.c 的平台数据里 .spi_cfg = TCFG_TFT_LCD_DEV_SPI_HW_NUM。
六、编译与烧录
bash
make -j20 # 期望:0 error / 0 undefined reference / 0 macro redefined
烧录直接运行 cpu/br27/tools/download.bat,它会自动把 JL_OLED 同步到 JL 再打包。
验证启动日志的关键行
spi pin rest:1, cs:2, rs:4, spi:1 ← 引脚与 SPI 口正确
spi open succ ← SPI1 打开成功
ui_platform_init :: [0,0,128,64] ← OLED 分辨率正确
open success: 0x419a4c ← 资源文件打开成功(不是 open faild!)
dc->width : 128, dc->lines : 64
dc->data_format: 4 ← 4 = DC_DATA_FORMAT_MONO 单色
页面对应关系 (ui_style.h,SOUNDBOX 风格)
| 页面 | 用途 | 页面 | 用途 |
|---|---|---|---|
| PAGE_0 | 主页 | PAGE_6 | 关机/待机 |
| PAGE_1 | 蓝牙 | PAGE_7 | 系统设置 |
| PAGE_2 | FM | PAGE_8 | PC |
| PAGE_3 | 时钟 | PAGE_9 | LINEIN |
| PAGE_4 | 音乐 | PAGE_10 | 录音 |
| PAGE_5 | 开机 | --- | --- |
七、注意事项
sdk_config.h不要手改 ------ JLStudio 工具会覆盖。配置改动统一写在app_config.h里#undef+#define。- 两套 UI 框架必须二选一 ------ 同时链接会导致
lcd_get_hdl()取到哪一套不确定。 build/fileList.c是死代码 ------ 改文件列表请改build/genFileList.c。- 字库
.PIX/.TAB必须成对 ------ 缺.TAB时文字静默不渲染且无任何报错。 - 资源目录保持干净 ------ 文件名 ≤15 字符,不要放备份等无关文件,否则打包报错。
- 改 UI 界面 ------ 用
LCD_UI工程/ui_128_64_JL02/模式界面/下的工具,导出后需同步更新
style_jl02.h的控件 ID 表(工程导出的ename.h,记得保留风格条件包裹)。 font.a的调试打印 ------ 运行时会持续打印language_id == 1/comming in Chinese_Simplified,
这是库内部裸log_print(无 TAG 开关),属正常现象,量产时关TCFG_DEBUG_UART_ENABLE即可。
八、已知限制
-
PC 模式界面不完整 :
ui_128_64_JL02工程里 PAGE_8 只有 7 个控件(同类的 LINEIN 页有 43 个),
左右两侧无内容、电量图标无格数,属资源未画全,代码无法弥补。补全方法:SDK/cpu/br27/tools/LCD_UI工程/ui_128_64_JL02/模式界面/ step1-打开UI绘图工具.bat ← 打开 PAGE_8,参考 PAGE_9(LINEIN) 布局补画 step2-打开UI资源生成工具.bat ← 导出新的 JL.res/JL.str/JL.sty project/ename.h ← 导出后控件ID表会更新导出后把三个资源文件放回
cpu/br27/tools/JL_OLED/,用新ename.h更新style_jl02.h
(保留外层#if (CONFIG_UI_STYLE == STYLE_JL_SOUNDBOX)包裹);新增控件若需代码驱动,
再往pc_action.c里加对应的REGISTER_UI_EVENT_HANDLER。 -
SPDIF / SINK 模式无 UI 页面 :
ui_128_64_JL02工程只画到PAGE_10,二者的ID_WINDOW_*已降级为(-1)。
需要时用 UI 绘图工具补页面,并同步更新style_jl02.h。 -
卡片滑动翻页功能不可用 :老 UI 库
ui_dot.a不提供ui_page_*接口,点阵屏无触摸屏,不影响使用。 -
表盘功能不可用 :点阵屏已关闭
UI_WATCH_RES_ENABLE。
九、移植到其它 SDK 版本
以 JL703N_le_audio_2.0.0_patch_01_03_offline 为例(已完成并编译通过)。
不同 SDK 版本的构建系统可能完全不同,移植点要跟着变。
9.1 先确认构建系统类型
| 本 SDK | offline 版 | |
|---|---|---|
| 源文件列表 | build/genFileList.c 预处理生成,支持 #if 条件 |
硬编码在顶层 Makefile 的 c_SRC_FILES,make 语法无法条件编译 |
| UI 库 / include 路径 | build/Makefile.mk、build/include_dir.txt |
都在顶层 Makefile |
build/fileList.mk |
实际生效 | 没被 include,是死文件 |
判断方法:grep -n "^include\|c_SRC_FILES" Makefile,看列表从哪来。
9.2 offline 版的移植要点
顶层 Makefile 三处
- include 路径
-Iinterface/ui/jl_ui→-Iinterface/utils/ui(连同/ui/cpu/br27) - UI 库 →
res.aui_draw.afont.aui_dot.aui_cpu.a c_SRC_FILES:加入点阵屏框架 7 个文件 +pc_action.c;删除彩屏 IMD 框架 5 个文件
为什么彩屏框架必须从列表删除,不能靠 C 宏
c
#include "asm/imb.h" // ← 第11行,属新版UI库
...
#if (...) && !defined(EXPORT_DOT_UI_ENABLE) // ← 第19行,太晚了
#include 在条件之前就被处理,切到老库后直接 fatal error: 'asm/imb.h' file not found。
C 宏只能挡住代码体,挡不住 #include。
编辑 c_SRC_FILES 的坑 :不要在列表中间插空行或注释,会打断续行符 \,
导致后面以 Tab 开头的行被当成 recipe,报 recipe commences before first target。
说明文字要写在 c_SRC_FILES := \ 之前。
靠 C 宏排除的文件(Makefile 无法条件编译,只能改源码条件)
| 文件 | 原条件 | 改为 |
|---|---|---|
spdif_action.c |
#if (TCFG_UI_ENABLE&&(CONFIG_UI_STYLE == STYLE_JL_SOUNDBOX)) |
追加 && TCFG_APP_SPDIF_EN |
sink_action.c |
同上 | 追加 && TCFG_LOCAL_TWS_ENABLE |
ui_touch_demo.c |
同上 | 追加 && !TCFG_LCD_OLED_ENABLE |
这三个文件原本只判断 UI 风格,切到 SOUNDBOX 后会被编译,但它们引用的
SPDIF_*/SINK_*/PNG_PIC 控件不在 128x64 工程里。改完后 .o 为空文件。
9.3 可直接复制的文件
两版内容一致,可直接覆盖:
res_config.h、ui_style.h、style_jl02.h、lcd_ui_api.c、ui_pushScreen_manager.c、
ui_platform.c、pc_action.c,以及资源(JL_OLED/*)、字库(font/F_GB2312.*)、UI工程目录。
不能直接覆盖 的:app_config.h(两版有 41 行配置差异,需插入式修改)。
可能不用改 的:device_config.c ------ patch 版官方已修好 #if TCFG_HW_SPI2_ENABLE && SUPPORT_SPI2。
9.4 板级差异要单独核对
offline 版的屏挂在 SPI2 而非 SPI1:
| 本 SDK | offline 版 | |
|---|---|---|
TCFG_TFT_LCD_DEV_SPI_HW_NUM |
1 (HW_SPI1) | 2 (HW_SPI2) |
| 屏 CLK / DO | SPI1 = PA07 / PA08 | SPI2 = PA07 / PA08(物理引脚相同) |
| SPI1 用途 | 屏 | 其它外设(PB14/PB13/PB12) |
物理接线一样,只是挂在不同 SPI 控制器上。因此 app_config.h 的覆盖块里不要 强制
TCFG_HW_SPI1_ENABLE,屏用哪个口应由工具端 TCFG_TFT_LCD_DEV_SPI_HW_NUM 决定,
只需保证对应的 TCFG_HW_SPIx_ENABLE 为 1。移植到新板子时务必先核对这一项。