Retro-Go compiling notes

写在最前面

感谢原作者ducalex的辛勤付出,

感谢国内大佬蕉色幻想morinaka对开源社区的贡献及对本项目的软硬件支持。 本文转载自作者 WIGWAG的飞书文档

一,项目概况

简介

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 or python rg_tool.py release (clean build)
  • Generate a .img to be flashed with esptool.py (Serial):
    python rg_tool.py build-img or python rg_tool.py release (clean build)

For a smaller build you can also specify which apps you want, for example the launcher + DOOM only:

  1. 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