基于SipeedM1sDock的GBA模拟器实现
本项目是基于BL808实现可以通过PC按键进行游戏操作的简易GBA(44VBA)模拟游戏机。
标签
嵌入式系统
显示
GBA
BL808
maskmoo
更新2023-03-28
747

项目介绍

44VBA模拟器

44vba是一个基于VBA-M(VisualBoyAdvance-M)项目的GBA模拟器。与VBA-M不同的是,44vba使用了新的是在vba-next核心,并支持多种平台,如ESP32-S3、嵌入式linux和wasm等。

44vba是一个开源项目,可以在GitHub上找到该项目的代码和相关文档。

需求:

目标:实现简易GBA模拟游戏机功能,熟悉BL808的工程编译,屏幕驱动

具体要求:

  • 完成屏幕的基础驱动
  • 完成GBA模拟器软件 44VBA 的基础移植
  • 通过串口进行游戏操作

设计思路

了解和熟悉BL808工程编译和屏幕驱动是实现GBA模拟器的基础。所以首先需要了解BL808的基础知识,包括它的编译工具链、开发环境和支持库等。

其次,需要了解GBA模拟器软件的基础知识,包括它的架构、运行原理和操作系统要求等。可以先熟悉它的基础移植流程,并根据需要进行修改和优化。

在实现GBA模拟器的过程中,由于M1S的物理按键只有两个,所以就采用串口进行游戏操作。因为Demo部分已经实现了CLI功能,所以串口控制这部分也是基于此的。

环境搭建

软件的开发是需要在Linux平台进行,在M1s_BL808_example: M1s_BL808_example 的仓库上有详细的说明文档以及上手指南M1s DOCK 上手 - Sipeed Wiki,一些常见的问题在上面都能找到答案。

可以正常编译说明环境没有问题

屏幕驱动

M1S使用的是ST7789V芯片。ST7789V是一款TFT-LCD显示驱动芯片,由STMicroelectronics公司推出,主要用于智能手表、便携式电子设备、家庭娱乐和汽车电子等领域。

它支持18位色深、320x480像素的分辨率,可以实现清晰、生动的图像显示。ST7789V采用SPI接口标准。

ST7789V的特点:

  1. 低功耗:ST7789V采用了低功耗设计,可以在长时间使用时减少能耗,延长电池寿命。
  2. 高对比度:ST7789V具有高达1000:1的对比度,可以在不同的光照条件下显示更清晰、更生动的图像。
  3. 支持多种显示模式:ST7789V支持全屏显示和局部显示两种模式,可以根据应用需求进行选择。
  4. 兼容性强:ST7789V具有广泛的兼容性,可以与多种硬件和软件平台配合使用。
  5. 显示速度快:ST7789V的显示速度快,可以在不同的应用场景下满足快速响应的要求。

在BL808的SDK中已经实现ST7789V显示驱动,所以这里就直接调用即可。

添加UART控制命令解析

采用用串口通讯的方式来进行控制,按键对应关系如下表:

| PC按键 | 游戏按键 | 控制命令符 | | :------: | :------: | :--------: | | “A” | "a" | "ctrl -b" | | “S" | "b" | "ctrl -c" | | "Tab" | "select" | "ctrl -d" | | "Space" | "start" | "ctrl -e" | | "Right": | "right" | "ctrl -f" | | "Left" | "left" | "ctrl -g" | | "Up" | "up" | "ctrl -h" | | "Down" | "down" | "ctrl -i" |

static void cmd_c906_gba_ctrl(char *buf, int len, int argc, char **argv)
{
    // static TaskHandle_t task_handle = NULL;
    // bool to_be_exit = false;
    // char *gba_path = NULL;
    gba_ctrl_value = 0;
    int opt;
    getopt_env_t getopt_env;
    utils_getopt_init(&getopt_env, 0);
    // put ':' in the starting of the string so that program can distinguish
    // between '?' and ':'
    while ((opt = utils_getopt(&getopt_env, argc, argv, ":abcdefghijklm:")) != -1) {
        switch (opt) {
            case 'a':
                printf("ctrl test\r\n");
                break;
            case 'b':
                gba_ctrl_value |= 1 << 0;
                break;
            case 'c':
                gba_ctrl_value |= 1 << 1;
                break;
            case 'd':
                gba_ctrl_value |= 1 << 2;
                break;
            case 'e':
                gba_ctrl_value |= 1 << 3;
                break;
            case 'f':
                gba_ctrl_value |= 1 << 4;
                break;
            case 'g':
                gba_ctrl_value |= 1 << 5;
                break;
            case 'h':
                gba_ctrl_value |= 1 << 6;
                break; 
            case 'i':
                gba_ctrl_value |= 1 << 7;
                break;    
            case 'j':
                gba_ctrl_value |= 1 << 8;
                break;    
            case 'k':
                gba_ctrl_value |= 1 << 9;
                break;    
            case 'l':
                gba_ctrl_value |= 1 << 10;
                break;      
            case 'm':
                gba_ctrl_value |= 1 << 11;
                break;                                                                                                              
            case ':':
                // printf("%s: %c requires an argument\r\n", *argv, getopt_env.optopt);
                break;
            case '?':
                // printf("unknow option: %c\r\n", getopt_env.optopt);
                break;
        }
    }
    // optind is for the extra arguments which are not parsed
    // for (; getopt_env.optind < argc; getopt_env.optind++) {
    //     printf("extra arguments: %s\r\n", argv[getopt_env.optind]);
    // }
    printf("gba_ctrl_value:%d \r\n", gba_ctrl_value);
}

const static struct cli_command cmds_user[] STATIC_CLI_CMD_ATTRIBUTE = {
    {"gba", "c906 gba command", cmd_c906_gba},
    {"ctrl", "c906 gba ctrl command", cmd_c906_gba_ctrl},
};  

模拟器是通过void UpdateJoypad(void)函数去更新获取控制信息,这里通过串口的CLi传入控制信息,然后在模拟器主函数中进行更新。


static void emuMain(void *arg)
{
    printf("Emuinit \r\n");
    CPUSetupBuffers();
    CPUInit(NULL, false);
    CPUReset();

    while (1) {
        if(joy == 0){
            joy = gba_ctrl_value;
        }
        UpdateJoypad();
        emuRunFrame();
    }
}

GBA游戏控制Python脚本

gba_ctrl.py脚本是由Python编写,通过keyboard来监听和发送键盘事件、serial库来实现串口的数据通信,进而实现的GBA游戏启动和控制功能。

import keyboard
import serial
import time 

serialPort="COM58"   #串口号

baudRate=2000000       #波特率

ser=serial.Serial(serialPort,baudRate,timeout=0.5) 

print("参数设置:串口=%s ,波特率=%d"%(serialPort,baudRate))#输出串口号和波特率

#启动游戏

# "a", "b", "select", "start", "right", "left", "up", "down", "r", "l",
ctrl_str = ""
def callback(x):
    print(x)
    print()
    if x.name == "a":
        ctrl_str = "ctrl -b"
    elif x.name == "s":
        ctrl_str = "ctrl -c"
    elif x.name == "tab":
        ctrl_str = "ctrl -d"
    elif x.name == "space":
        ctrl_str = "ctrl -e"
    elif x.name == "right":
        ctrl_str = "ctrl -f"
    elif x.name == "left":
        ctrl_str = "ctrl -g"
    elif x.name == "up":
        ctrl_str = "ctrl -h"
    elif x.name == "down":
        ctrl_str = "ctrl -i"                                                
    else:
        ctrl_str = ""
    print("ctrl-cmd:", ctrl_str)

    ser.write(("ctrl -a"+'\n').encode())
    ser.write((ctrl_str+'\n').encode())

#启动游戏
time.sleep(1)
ser.write(("gba -l /flash/MarioBreak.gba"+"\n").encode())

keyboard.on_press(callback)
# 按下任何按键时(包括长按),都会调用callback,其中一定会传一个值,就是键盘事件
keyboard.wait()

游戏添加启动

1 GBA游戏文件下载

Gameboy Advance Development (gbadev.org)

GbaDownload

选择要下载的游戏下载完成后将GBA文件拷贝进M1S在电脑映射的U盘里面。

2 启动脚本

可以在gba_ctrl.py脚本启动游戏处更改对应启动游戏的名称。

#启动游戏
time.sleep(1)
ser.write(("gba -l /flash/MarioBreak.gba"+"\n").encode())

然后运行

python .\gba_ctrl.py

后续计划

玩游戏没有声音总觉得缺点什么,后面计划增加一个基于IIS的音频输出功能。

参考

1 M1s DOCK 上手 - Sipeed Wiki

2 Gameboy Advance Development (gbadev.org)

3 44vba (github.com)

4 Home · libretro/vba-next Wiki (github.com)

5 M1s DOCK 开发板 - Sipeed Wiki

附件下载
44vba_demo.zip
源代码
Other.zip
编译固件+游戏文件+控制脚本
团队介绍
勇往直前
团队成员
maskmoo
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号