写在最前面
感谢原作者ducalex的辛勤付出,
一,项目概况
简介
C19开源掌机是一款基于ESP32-S3开发的复古游戏设备,使用Retro-Go开源系统,可运行GB、GBC、FC、SFC、GG、SMS等复古主机/掌机模拟器。
硬件基础
1.蕉色幻想的基于 立创·ESP32S3R8N8开发板 的 复古掌上游戏机
2.morinaka的基于ESP32-S3的C19掌机(适配GBC外壳)
软件基础
1.Retro-Go源GIT项目地址:retro-go
2.蕉色幻想开源的C19项目源码:见群文件
软硬件设计方案
1.硬件项目:Retro-Go开源掌机(适配GBC外壳)
*注本项目硬件与morinaka的“基于ESP32-S3的C19掌机(适配GBC外壳)”的相同,仅作少量丝印修改
2.软件源码:https://github.com/yyhhdr/retro-go.git
交流群:971882968
宗旨
最近复刻的过程中,编译固件时遇到一些问题,正好群友提到有编译教程的需求。
故此做一个编译步骤简介,一来方便后来者,二来写一笔备忘。
二,环境搭建
参考资料
本文选择windows作为编译平台。
C19项目基于ESP32-S3,这是一款乐鑫的WiFi/BLE SOC,因此编译环境的搭建现需要参考官方文件:
Windows 平台工具链的标准设置 - ESP32 - — ESP-IDF 编程指南 v5.4.1 文档
另外Retro-Go作者的编译指导文件也是一个重要参考:
retro-go/BUILDING.md at master · ducalex/retro-go
搭建步骤
ESP-IDF
第一步需要下载ESP-IDF,下载地址:dl.espressif.cn/dl/esp-idf/?idf=4.4
根据Retro-Go作者的描述“Versions 4.4 to 5.3 are supported.”我们选择4.4到5.3之间的安装包都可以.
我选择的是ESP-IDE v3.0.0-with-esp-idf-5.2.2,安装只需要一路下一步即可。
PYTHON
接着安装PYTHON,官网下载:Download Python | Python.org
下载最新版即可,安装同样一路下一步。
GIT
接着安装GIT,官网:Git - Downloading Package
按电脑实际情况选择安装即可。
一点备注
根据乐鑫的手册,安装ESP-IDF时,会自动安装内置的python,按理不需要额外安装一次python,但是我在编译的时候,有一台电脑 遇到了"py不是内部命令"这样的报错,单独下载python后报错解除,遇到同样问题的朋友可以参考解决。这也导致了ESP-IDF CMD命令窗口和 window的CMD窗口查询到的版本号不同,一个是ESP-IDF内嵌的,一个是我后装的。
安装完毕后,打开ESP-IDF CMD命令窗口,可以按如下命令查看安装版本
python --version
git --version
或者在window的CMD窗口中,按如下命令查询版本
py --version
git --version
三,克隆代码
在硬盘上指定一个文件夹作为克隆代码的防止区域,比如D:\retro-go
打开ESP-IDF CMD命令窗口,切换到文件夹所在为位置,
输入git clone的 命令如下:
git clone -b master https://github.com/ducalex/retro-go/
如果遇到网络问题可以使用加速节点,命令为:
git clone -b master https://github.moeyy.xyz/https://github.com/ducalex/retro-go/
文件不大,使用加速节点下载还是挺快的。
四,编译固件
参考资料
我们看一下retro-go作者的编译指南
Build everything and generate a firmware image:
- Generate a .fw file to be installed with odroid-go-firmware or odroid-go-multi-firmware from SD Card:
python rg_tool.py build-fw
orpython rg_tool.py release
(clean build)- Generate a .img to be flashed with esptool.py (Serial):
python rg_tool.py build-img
orpython rg_tool.py release
(clean build)
For a smaller build you can also specify which apps you want, for example the launcher + DOOM only:
python rg_tool.py build-fw launcher prboom-go
Note that the app named
retro-core
contains the following emulators: NES, PCE, G&W, Lynx, and SMS/GG/COL. As such, these emulators cannot be selected individually. The reason for the bundling is simply size, together they account for a mere 700KB instead of almost 3MB when they were built separately.
固件格式
按作者的介绍,我们有两种烧录的方式,对应的编译命令也略有区别
第一种是编译成.fw文件 ,放置在SD卡内,按住B键开机,选择对应固件安装,安装完毕重启即可进入系统。
第二种是编译成.img文件,通过串口下载工具下载。
可以看出我们是通过rg_tool.py这个脚本编译固件,作者在文中已经讲解的比较清晰,有不清楚的也可以输入
帮助命令来查看详细说明
python rg_tool.py --help
编译举例
在正式编译C19前 ,我们先举一个简单的例子
立创开源平台有一款比较热门的ESP32游戏机ESPlay:开源掌机 ESPLAY V0.3 游戏机
这款机器源自Github开源项目,原名叫,esplay-micro,
项目地址:pebri86/esplay_micro_hardware: Micro version of esplay hardware, ESP32 based gaming console
在上文的帮助文件中可以看到--target可选esplay-micro,这说明retro-go作者已经针对ESPlay作好了官方移植,由于ESPlay项目本身有bootloader,所以我选择编译成.fw,这样可以在Retro-Go固件和ESPlay原生固件之间切换。
编译指令如下:
python rg_tool.py --target esplay-micro build-fw
由于我们并未修改Retro-Go的任何代码,所以只要编译环境适配正确,编译就会正常执行。
编译完成后,将生成的固件放入SD卡内,按住menu键并开机,选择Retro-Go固件,烧录完成后重启即可。
为ESPlay编译Retro-Go固件的过程,不涉及代码修改。且其编译过程与C19项目非常相似,所以可以将其作为验证编译环境配置无误的方法。
一点备注
额外说一点,直接编译esplay的Retro-Go固件可能会报一个格式错误,错误提示定位在\retro-go\retro-core\components\snes9x\src\memmap.c文件的612行
这是一个常规的格式符错误,跟运行的系统有关,解决方法发是将612行的%d改为%lu,。
这是SFC模拟器的相关文件,后面咱们编译C19也需要用到,所以如果出现了这个错误,建议现在就予以修改。
修改前
printf("Rom loaded: name: %s, id: %s, company: %s, size: %dKB\n", Memory.ROMName, Memory.ROMId, Memory.CompanyId, Memory.CalculatedSize / 1024);
修改后
printf("Rom loaded: name: %s, id: %s, company: %s, size: %luKB\n", Memory.ROMName, Memory.ROMId, Memory.CompanyId, Memory.CalculatedSize / 1024);
编译C19
接着我们回到主线
我打算使用串口下载完整的固件,移植的目标机器是C19开源掌机,因此编译指令如下:
(C19代码移植后面细说,此时姑且认为代码已经OK)
python rg_tool.py --target c19 build-img
首次编译时会编译launcher之类的app,还会编译各个模拟器,所以耗时略长
编译完成后我们会在根目录下得到一个.img文件
如果编译 指令末尾是build-fw则得到.fw文件,如果release则得到.img和.fw
烧录固件
我们下载乐鑫的lash_download_tool,Flash 下载工具用户指南 - ESP32 - — ESP 测试工具 latest 文档
打开下载器,由于我是照搬morinaka的板子,所以跟他一样,使用USB下载,
选择刚刚生成的img,点击start开始烧录。
烧录完成后重启即可进入Retro-Go系统。
五,移植
参考资料
移植的方法可以参考官方给出的指南:retro-go/PORTING.md at master · ducalex/retro-go
Retro-Go的作者将硬件封装的比较完善,移植的时候 主要关注3个文件,config.h、env.py、sdkconfig,如下:
Targets
A target in retro-go is a set of files that describes a hardware device (drivers to use, GPIOs, button mapping, etc). Targets are folders located in components/retro-go/targets/
and usually contain the following files:
Name | Description |
---|---|
config.h | This is the retro-go configuration file, it describes your hardware to retro-go |
env.py | This is imported by rg_tool.py, it is used to set environment variables required by tooling, such as the esp32 chip type or baudrates or binary formats |
sdkconfig | This is the esp-idf configuration file for your board/device |
正如前文所述,Retro-Go官方并未适配C19项目,但是官方移植中,有采用相同主控的方案,我们可以参考他的代码结构,比如esp32s3-devkit-c。
移植文件中最重要的是config.h,其中描述了目标机器的硬件参数。
如果目标机器使用的硬件方案已经有驱动 ,则只需要配置即可 ,如果官方没有可用的驱动则需要自行编写驱动。
C19项目的硬件 均已有驱动。
新增target
首先我们打开\retro-go\components\retro-go\config.h,在开头的预编译分支中加上我们的项目C19
#elif defined(RG_TARGET_C19)
#include "targets/c19/config.h"
复制C19源码
蕉大的源码是一个名为C19的文件夹,内含config.h、env.py、sdkconfig。
将C19源码放置在\retro-go\components\retro-go\targets\目录下。
修改config.h
蕉大使用的应该是Retro-Go V1.42版本,如果我们也是用1.42版本应该可以直接编译通过。
但是我是通过git clone来的最新分支,版本是1.44,我尝试直接使用,但是出现了系统崩溃的情况。
后来查看源码,这两个版本之间原作者做了一些改动,我们也需要相应微调代码。
且蕉大的源码屏蔽了屏幕背光调节与WIFI,我想启用他们,所以需要稍微修改代码。
修改Storage
打开config.h
可以参考esp32s3-devkit-c的配置,存储的配置我们修改为
// Storage
#define RG_STORAGE_SDSPI_HOST SPI3_HOST
#define RG_STORAGE_SDSPI_SPEED SDMMC_FREQ_DEFAULT
#define RG_STORAGE_ROOT "/sd"
开启背光调节
需要开启背光调节,我们需要在//video增加一条语句
#define RG_SCREEN_BACKLIGHT 1
修改电池配置
// Battery
#define RG_BATTERY_DRIVER 1
#define RG_BATTERY_ADC_UNIT ADC_UNIT_1
#define RG_BATTERY_ADC_CHANNEL ADC_CHANNEL_0
#define RG_BATTERY_CALC_PERCENT(raw) (((raw) * 2.f - 3500.f) / (4200.f - 3500.f) * 100.f)
#define RG_BATTERY_CALC_VOLTAGE(raw) ((raw) * 2.f * 0.001f)
小结
仔细对比可以发现原作者对这些定义做了一定的修改,编译遇到报错就去找哪里错了。
找到了错误点不知道怎么改就参考其他的target,总的来说也不难。
修改源码
此时编译烧录后会发现背光的变化和设置值正好相反,你按亮度加,屏幕反而会变暗。
我是修改了一下\retro-go\components\retro-go\rg_display.c。
其中的rg_display_set_backlight函数修改为:
void rg_display_set_backlight(display_backlight_t percent)
{
config.backlight = RG_MIN(RG_MAX(percent, RG_DISPLAY_BACKLIGHT_MIN), RG_DISPLAY_BACKLIGHT_MAX);
rg_settings_set_number(NS_GLOBAL, SETTING_BACKLIGHT, config.backlight);
//lcd_set_backlight(config.backlight); //retro-go原文件
lcd_set_backlight(RG_DISPLAY_BACKLIGHT_MAX-config.backlight); //背光异常,比如增加背光,实际变暗,则启用在这条
}
此时编译发现背光调节正常,但是每次开关机设定的背光参数不存。
于是我又修改了rg_display_init函数,在lcd_init();之后重新设置一下背光值。
void rg_display_init(void)
{
RG_LOGI("Initialization...\n");
// TO DO: We probably should call the setters to ensure valid values...
config = (rg_display_config_t){
.backlight = rg_settings_get_number(NS_GLOBAL, SETTING_BACKLIGHT, 80),
.scaling = rg_settings_get_number(NS_APP, SETTING_SCALING, RG_DISPLAY_SCALING_FIT),
.filter = rg_settings_get_number(NS_APP, SETTING_FILTER, RG_DISPLAY_FILTER_BOTH),
.rotation = rg_settings_get_number(NS_APP, SETTING_ROTATION, RG_DISPLAY_ROTATION_AUTO),
.border_file = rg_settings_get_string(NS_APP, SETTING_BORDER, NULL),
.custom_zoom = rg_settings_get_number(NS_APP, SETTING_CUSTOM_ZOOM, 1.0),
};
display = (rg_display_t){
.screen.real_width = RG_SCREEN_WIDTH,
.screen.real_height = RG_SCREEN_HEIGHT,
.screen.margin_top = RG_SCREEN_MARGIN_TOP,
.screen.margin_bottom = RG_SCREEN_MARGIN_BOTTOM,
.screen.margin_left = RG_SCREEN_MARGIN_LEFT,
.screen.margin_right = RG_SCREEN_MARGIN_RIGHT,
.screen.width = RG_SCREEN_WIDTH - RG_SCREEN_MARGIN_LEFT - RG_SCREEN_MARGIN_RIGHT,
.screen.height = RG_SCREEN_HEIGHT - RG_SCREEN_MARGIN_TOP - RG_SCREEN_MARGIN_BOTTOM,
.changed = true,
};
lcd_init();
lcd_set_backlight(RG_DISPLAY_BACKLIGHT_MAX - config.backlight); //新增代码
display_task_queue = rg_task_create("rg_display", &display_task, NULL, 4 * 1024, RG_TASK_PRIORITY_6, 1);
if (config.border_file)
load_border_file(config.border_file);
RG_LOGI("Display ready.\n");
}
至此功能全部调通,背光正常,WiFi可开启。
六,一点补充
启用wifi
联网需要新建一个/retro-go/config/wifi.json,在其中添加ssid和密码,如下:
{
"ssid0": "my-network",
"password0": "my-password",
"ssid1": "my-other-network",
"password1": "my-password",
"ssid2": "my-third-network",
"password2": "my-password",
"ssid3": "my-last-network",
"password3": "my-password"
}
NTP授时
原作者设定是联网后立刻向NTP服务器请求时间,默认使用的是pool.ntp.org。
有的时候会连不上 ,ping一下会发现延迟过高,这时可以换成国内服务器,比如阿里的ntp.aliyun.com。
位置是在\retro-go\components\retro-go\rg_network.c。
系统崩溃的情概况
有的时候会出现,烧录完新固件后,可以开机进系统,但是一进模拟器就系统崩溃的情况。 有可能是/retro-go/config/global.json中的配置导致的。 比如当前固件支持WiFi和背光调节,此时切换回不支持WiFi的固件,就有可能触发。 解决方式:删除global.json即可。
七,汉化
详见此文档
C19开源掌机添加中文的方法_基于Retro-Go_V1.44