ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

如何把拓麻歌子装进 Flipper Zero:ROM 加载、fbt 构建与 4 位机模拟全解

如何把拓麻歌子装进 Flipper Zero:ROM 加载、fbt 构建与 4 位机模拟全解 如何把拓麻歌子装进 Flipper ZeroROM 加载、fbt 构建与 4 位机模拟全解【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper想在 Flipper Zero 上养一只 1996 年的电子鸡Tama P1 Emulator 做到了它基于 TamaLIB 模拟拓麻歌子 P1 的 4 位机 CPU、32×16 像素 LCD 和蜂鸣器能按键操作、能存档、能随系统 64 kHz 节拍活着。这篇讲清四件事ROM 怎么放、fbt怎么把它编成.fap插件跑起来、按键怎么映射含两个隐藏操作以及 4 位机模拟与save.bin存档在源码层面到底是怎么回事。这个项目是什么源码怎么分层一句话定位一个应用外壳 模拟内核结构的 Flipper Zero 外部EXTERNAL插件外壳负责 ROM、事件循环与渲染内核是跨平台的 TamaLIB。源码只有 4 个关键角色看表就够文件职责tama_p1.c应用外壳ROM 加载、30 FPS 刷新、输入分发、存档读写tama.h常量与状态结构ROM/存档路径、2 倍缩放、TamaApp结构体hal.cTamaLIB 的硬件适配层不到 150 行tamalib/自底向上写的 4 位机模拟核心cpu.c、hw.c、tamalib.c构建元数据在 application.fam入口函数tama_p1_app依赖gui与storage两个系统服务堆栈 1 KB归类Games_Extra。从零到开玩ROM、按键与两个隐藏操作ROM 放进 SD 卡的 3 步在 microSD 卡根目录建tama_p1文件夹从网上找 Tamagotchi P1 的 ROM 文件README 提到流传版本里有个叫a的文件重命名为rom.bin确认最终路径是/ext/tama_p1/rom.bin——这是tama.h里TAMA_ROM_PATH写死的。为什么 ROM 放对了还要重排字节序这是整个项目最容易被忽略的一步。TamaLIB 的 README 交代了背景网上流传的 P1 ROM 是从芯片裸片的高清照片上光学识读出来的而 P1 用的是 Epson E0C6S46 4 位 MCU整块内存空间 4096 个单元、每单元只存 4 bit。ROM 文件里一个字节装的是两条相邻指令两个半字节CPU 却按半字节顺序逐条读指令——所以加载时必须把每对字节按半页重新排序前字节换成后字节、后字节取前字节的低 4 位。代码就 4 行tama_p1.c的tama_p1_init// Reorder endianess of ROM for(size_t i 0; i fi.size; i 2) { uint8_t b ctx-rom[i]; ctx-rom[i] ctx-rom[i 1]; ctx-rom[i 1] b 0xF; }重排完才调tamalib_init()以 64000 Hz 初始化模拟时钟源同时把 STM32 的 TIM2 配成 64 kHz 计数器LL_TIM_InitTypeDef tim_init { .Prescaler 999, .CounterMode LL_TIM_COUNTERMODE_UP, .Autoreload 0xFFFFFFFF, }; LL_TIM_Init(TIM2, tim_init);模拟世界的秒从这块硬件计数器里读节拍才和真实世界对齐。按键映射三键主玩 两个隐藏操作Flipper 按键动作左键 / OK / 右键A / B / C长按返回保存并退出上键静音模拟 A C 同时按下下键短按 或 返回短按立即保存状态后两行 README 只字未提是源码输入处理里白送的上键松手前会把BTN_LEFT和BTN_RIGHT一起报给 TamaLIBP1 原机的静音手势两个短按各自触发一次tama_p1_save_state()。关于存档先说一个矛盾点README 前文写着 There is currently no saving同页 Implemented 却列着 Saving/Loading emulator state (stored in /ext/tama_p1/save.bin)源码里读写函数也完整存在。结论存档是真的文档过时了——文档和代码打架时以代码为准。编译部署fbt 一条命令出.fap流程三步把tama_p1整个文件夹移到固件源码树的applications/plugins/tama_p1编译图标资源——8 个 14×14 状态图标 PNG 要变成 C 头文件应用直接引用符号而非加载 PNGscripts/assets.py icons applications/tama_p1/icons applications/tama_p1/compiled编译、部署、启动一条命令搞定./fbt launch_app APPSRCapplications/plugins/tama_p1README 原文用的是 Windows 反斜杠Linux/macOS 下请照上面用正斜杠。排错按症状对号入座屏幕写着 No ROMstorage_common_stat没找到rom.bin逐字检查文件夹名下划线不能少和文件名屏幕写着 Halted模拟 CPU 执行到了 haltg_ctx-halted被 HAL 回调置位通常意味着 ROM 不完整或重排逻辑被改动过编译报 unused parameterTamaLIB 的cpu.c/hw.c会触发未使用参数告警严格告警配置下直接变错误——在site_cons/cc.scons的CCFLAGS里加-Wno-unused-parameter按键行为不对劲挂串口日志看事件流python .\serial_logger.py来自 FlipperScripts监听后每次按键都会以sequence/key/type三元组打印Tag 分别为TamaP1与TamaLIB对照上表即可定位映射问题。拆开看它到底怎么模拟一台 4 位机被模拟的目标与内存布局目标机画像Epson E0C6S46 4 位 MCU32,768 Hz32×16 黑白 LCD 加 8 个状态图标。cpu.h 把 4096 个半字节切成四块区域地址大小RAM0x000~0x27F640 个半字节LCD 缓冲 ×20xE00/0xE80各 80 个半字节I/O 寄存器0xF00~0xF7F128 个半字节注意 STM32WB 内存紧张代码默认开启LOW_FOOTPRINT只把上述有效区域打包进约 464 字节的紧凑缓冲每个u8_t装两个半字节读写全靠GET/SET_RAM_MEMORY宏做移位与掩码——相当于两个人拼一张桌子、各占半格。HAL模拟器和平台之间的转接头TamaLIB 本身不认识任何硬件它只认hal_t结构体里的一排函数指针内存分配、时钟get_timestamp/sleep_until、屏幕set_lcd_matrix/set_lcd_icon、蜂鸣器set_frequency/play_frequency、日志与 halt 回调。hal.c 逐个填上 Flipper 的实现时间戳直接读LL_TIM_GetCounter(TIM2)像素写入转存到 16 个uint32_t帧缓冲一行 32 像素各占 1 bit频率上报后除以 10 换算成真实频率再喂给furi_hal_speaker。节奏控制的诀窍在sleep_until发现模拟时间落后目标时先释放互斥锁、furi_delay_tick(1)让出 CPU再重新拿锁继续步进——否则模拟线程会越追越落后。另外 hal_types.h 特意注明timestamp_t必须是无符号类型按微秒计时时 32 位无符号数约 1 小时 11 分自然回绕有符号会让时间比较出错。线程模型与渲染模拟跑在独立线程栈 1 KB里循环调tamalib_step()而不是用 TamaLIB 自带的tamalib_mainloop()——这样 Flipper 的 GUI 事件循环完全掌握节奏。GUI 侧用周期定时器按 30 FPS 触发刷新抢一把 25 tick 超时的互斥锁把 32×16 像素按 2 倍缩放居中画成 64×32再在矩阵上下各排 4 个 14×14 的状态图标间距按宽度均分。输入与 tick 事件走 8 深度的FuriMessageQueue两线程用同一把递归互斥锁保护帧缓冲。save.bin 里装了什么存档写在/ext/tama_p1/save.bin布局是定长二进制片段字段大小说明魔数 版本4 1 字节TLST与版本 2用于合法性校验CPU 寄存器数字节PC高字节掩码 0x1F、X/Y掩码 0xF、A/B/Flags 各取低 4 位、NP低 5 位、SP计时器4×4 3 字节tick 计数器、时钟/可编程定时器时间戳、使能与数据/重装载中断16×3 字节每槽 factor/mask/triggeredRAM I/O640 128 字节每个半字节占 1 字节整块搬运加载时先验魔数与版本不符就记 FATAL 日志并放弃恢复恢复完 RAM 与 I/O 后调tamalib_refresh_hw()模拟硬件重新同步显示和蜂鸣器——宠物不会因为退出应用就断粮。当前边界哪些事它还做不了README 的 To-do 清单照单全收多存档槽只有一个save.bin、游戏内软复位、测试模式入口、音量调节一个都没落地。快进功能源码里fast_forward_done已被置位、注释明写TODO: implement fast forwarding所以倍速养宠目前不存在。TamaLIB 本身导出了cpu_add_bp()断点接口想给它配个断点调试面板是顺理成章的下一步音量与存档槽则属于纯应用层改动。延伸阅读TamaLIB 是 GPLv2 的跨平台库桌面、Arduino、STM32 小板上都有移植先例tamalib/README.md 的移植清单值得一读仓库Applications/目录里还有小行星、掷骰子、Coleco 手柄等游戏类插件对照本项目的外壳 内核分层去看移植思路会清楚很多。【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进