书接上文

《单片机开发—ESP32-S3模块上手》
《单片机开发—ESP32S3移植lvgl+触摸屏》
《单片机开发—ESP32S3移植NES模拟器(一)》

暖场视频,小时候称这个为—超级曲线射门!!!!!!!!!!

ESP32上天使之翼游戏

继续优化

看门狗

源码中有两处看门狗的喂狗操作,前期都被注释掉了。

因为开始经常出现看门狗报警的重启。然后我将看门狗都关闭之后就不再重启了

问题如果不再出现,那它还是问题吗

分区表

前面如果需要使用分区存储rom数据的时候,需要使用定制的分区表
在(Top) → Partition Table → Partition Table 配置下,选择第四项

根目录下放置文件,内容如下

如果直接用内存,就不需要修改这些。
如果有多个应用的话,可以在这里选择配置,从不同位置启动程序。

I2S声音输出

有了声音,才能更好的玩游戏

所以又斥资购买的外置模块,接线图如下


I2S有3个主要信号,各种叫法,反正就这个意思

各种昵称 说明
SCLK 、BCLK 串行时钟SCLK,也叫位时钟(BCLK),即对应数字音频的每一位数据,SCLK都有1个脉冲。SCLK的频率=2×采样频率×采样位数。
LRCK、LRC、WS 帧时钟LRCK,(也称WS),用于切换左右声道的数据。LRCK为“1”表示正在传输的是右声道的数据,为“0”则表示正在传输的是左声道的数据。LRCK的频率等于采样频率。
SDATA、DIN 串行数据SDATA,就是用二进制补码表示的音频数据。

增加了声音的驱动,将原来写在一起的部分分离开,方便以后移植。

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "esp_log.h"
#include <math.h>
#include "drv_pin.h"
#include "drv_sound.h"#if CONFIG_SOUND_ENABLEDvoid sound_init(void)
{i2s_config_t i2s_config = {.mode = I2S_MODE_MASTER | I2S_MODE_TX ,.sample_rate = AUDIO_SAMPLERATE,.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,.communication_format = I2S_COMM_FORMAT_I2S_MSB,.dma_buf_count = 8,.dma_buf_len = 64,.use_apll = false,.intr_alloc_flags = ESP_INTR_FLAG_INTRDISABLED   //Interrupt level 1};i2s_pin_config_t pin_config = {.mck_io_num = I2S_PIN_NO_CHANGE,.bck_io_num = I2S_BCK_IO,.ws_io_num = I2S_WS_IO,.data_out_num = I2S_DO_IO,.data_in_num = I2S_DI_IO    //Not used};i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);i2s_set_pin(I2S_NUM, &pin_config);
}void sound_send(const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait)
{i2s_write(I2S_NUM, src, size, bytes_written, ticks_to_wait);
}
void sound_stop(void)
{i2s_stop(I2S_NUM);
}
void sound_clear(void)
{i2s_zero_dma_buffer(I2S_NUM);
}
#endif

用这些函数代替之前的操作。
不过为什么波特率配置为这个44.1k的一半,还不太清楚,后续可以研究一下。

按照这样配置的时候,会有很大的杂音。需要修改一下声道。

 .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,

这里也要注意,模块电压是5V,等我回去试试电压5V是不是更好一些。

手柄适配

声音有了,还是需要用手柄玩,更贴心。

常用的九孔插头,里面有5根线有用。

七孔插头

还有一种

引脚 含义
VCC 5V供电
GND 地线
LATCH 锁存信号,由主机发送
CLOCK 时钟信号,有些文档会叫PULSE,由主机发送
DATA 串行数据线 低电平有效。

时序图

先普及个基础知识。日版美版FC主机均为NTSC制式,画面为60Hz。欧版以及中国的仿制机为PAL-D制式,50Hz。港版正规机以及某些地区是PAL-60制式,60Hz。下面的说明都是基于60Hz来解释,50Hz和60Hz时间参数有点差异。

当游戏机启动后,游戏机会每16.67ms(60Hz,1/60秒)读取一次手柄的状态。这个过程通过两个步骤来实现。

首先主机发送一个LATCH锁存信号脉冲,这个脉冲的宽度为12us。告诉手柄开始检查按键状态。

在LATCH的脉冲发送后间隔6us,CLOCK(PULSE)线开始发送周期为12us,占空比50%的脉冲信号,一共发8次。每次的脉冲的上升沿对DATA线采样,检查DATA线是否在该位置被拉低。按键被检查的顺序是固定的(游戏机设计时候设计人员固定的),按键顺序为A,B,SEL,START,上下左右。上图DATA线上标注的就是每个按键时序所在位置。如果按键被按下,那么对于位置的DATA是低电平。

这里找到了一个原理图,感觉可以自己做一个了。

引脚初始化,一定要注意上拉和下拉的使用

读取代码如下,时间可以严格按照时序图中的要求来定义,记住在上升沿的时候,读取data值。

    int b2b1 = 65535;gpio_set_level(INPUT_HW_JS1_LATCH_PIN, 1);ets_delay_us(12);gpio_set_level(INPUT_HW_JS1_LATCH_PIN, 0);for(int i = 0; i < 8; i++){ets_delay_us(6);if(gpio_get_level(INPUT_HW_JS1_DATA_PIN) == 0){b2b1 -= sfc_ps_button_info[i];//printf("%s ",sfc_ps_button_va[i]);}gpio_set_level(INPUT_HW_JS1_CLOCK_PIN, 1);ets_delay_us(6);gpio_set_level(INPUT_HW_JS1_CLOCK_PIN, 0);}

一定要注意,这种手柄的电压,至少要达到4.8V,否则可能出现如下问题
1.延迟必须增大才能读取按键
2.在读取按键的时候,一次如果按下超过两个按键,就会识别为全部按下。

这也是我灵光一现,才破解了这个问题。

双手柄支持

这里需要重新增加一个手柄

void osd_getinput2(void)
{// Note: These are in the order of PSX controller bitmasks (see psxcontroller.c)const int ev[16] = {event_joypad2_select, 0, 0, event_joypad2_start, event_joypad2_up, event_joypad2_right, event_joypad2_down, event_joypad2_left,0, 0, 0, 0, 0, event_joypad2_a, event_joypad2_b, 0};static int oldb = 0xffff;int b = input2_read();int chg = b ^ oldb;int x;oldb = b;event_t evh;//    printf("Input: %x\n", b);for (x = 0; x < 16; x++){if (chg & 1){evh = event_get(ev[x]);if (evh)evh((b & 1) ? INP_STATE_BREAK : INP_STATE_MAKE);}chg >>= 1;b >>= 1;}
}

主要就是注意选择事件。不过改归改,还么测试

游戏名称

注意复制到SD卡中的游戏,名字不能过长,否则会出现死机的问题,导致重启。
另外可以增加如下判断,只显示rom名称,屏蔽其他文件

这个后续可以替换成其他界面,毕竟连汉字都不支持,低端

游戏兼容性

测试了一些过关游戏,基本都可以,不过在测试一些智能卡的游戏的时候,会出现重启现象,打印输出

GUI: Mapper 74 not yet implemented

因为本身模拟器支持的mapper有限,并没有支持到74号,这个游戏就是《天使之翼》,
还有164号mapper,游戏是《三国志2》。

后续一定要解决这个问题,加上mapper。
至于这个mapper是什么

mapper,这个概念来源于 memory mapping,又叫做 Memory Management Chip,它是解决地址映射的一种电路,简单来说就是决定物理内存如何映射到 CPU 或者 PPU 的地址空间。
mapper 可以用来支持增加卡带的 RAM 甚至支持额外的音频通道,但更一般的目的就是控制物理内存到地址空间的映射,突破游戏 40KB 的限制。
为什么说是 40KB 的限制,因为早期一般的游戏最大就是 的 PRG,以及 的 CHR,加起来就是 40KB,而更复杂的 mapper 硬件可以使得游戏突破这个限制。

软件重启

增加了手柄远端重启机器,其实就是在按键的时候判断一下,如果同时按下select和start,重启设备

这样测试就比较方便了。

效果展示

冒险岛系列

赤色要塞

热血系列,这么激烈打斗的游戏,非常流畅。
快打旋风

激龟忍者传视频

ESP32S3-nes上的《激龟忍者传3》

参考资料

《FC游戏机手柄工作原理 》
《小霸王游戏机手柄(一)——硬件破解》
《NES 模拟器开发教程》
《童年神机小霸王(七) Mapper》
这篇文章的作者写了几篇相关的介绍,感兴趣的可以学习一下。

结束语

这个83年推出的产品,到现在快四十年了,承载了无数80后的儿童时光,几年玩的游戏加起来,估计也没有几十兆的空间,里面的技术可想而知,把硬件软件的性能压榨到了极点了。

最近这chatGPT很火,国内外各种模仿争相出现,国内的还是老样子,不该问的别问。救媳妇还是救妈妈,豆腐脑吃甜的还是辣的,是吧

反正豆腐脑我吃咸的。

单片机开发---ESP32S3移植NES模拟器(二)相关推荐

  1. 单片机开发---ESP32S3移植NES模拟器(一)

    书接上文 <单片机开发-ESP32-S3模块上手> <单片机开发-ESP32S3移植lvgl+触摸屏> 参考内容 依旧是参考韦东山老师的作品来移植的 <ESP32|爷青回 ...

  2. 构建一个轻量级的嵌入式虚拟平台,开发工程用板stm32 picoc解释器,大量自定义函数,sarm拓展,lwip移植,nes模拟器移植,系统优化,等等技术的融合

    让嵌入式想java一样一处编写到处运行 第一次写博客,其实接触嵌入式已经快两年了,从开始学51单片机的时候,怀着满腔的热情.写出了点亮第一个流水灯代码的时候那个无比的激动,到后面自己做许多有趣的东西( ...

  3. 使用vscode + gcc进行 STM32 单片机开发(三)DMA读写SD卡,移植FATFS文件系统

    背景 在本系列的前两篇文章( 使用vscode + gcc进行 STM32 单片机开发(一)编译及调试 使用vscode + gcc进行 STM32 单片机开发(二)gcc环境 移植rtthread) ...

  4. iMX6ULL应用移植 | 移植 infoNES 模拟器(重玩经典NES游戏)

    没玩过NES游戏的童年,可能不是80后的童年.我们小时候是从玩FC开始接触游戏机的,那时真的是红极一时啊,我上初中时还省吃俭用买了一台小霸王,暑假里把电视机都给打爆了!那时任天堂单是FC机的主机的发售 ...

  5. [2021]Linux下C语言qrencode二维码生成库的基本使用和ARM开发板移植

    文章目录 一.前言 二.准备所用到的环境以及版本信息 1.Ubuntu和内核版本 2.gcc和g++版本 3.交叉编译gcc和g++版本 4.开发板信息 三.开发环境编译&安装qrencode ...

  6. V3S移植nes游戏模拟器(附带游戏合集)

    V3S移植nes游戏模拟器(附带游戏合集) 1.资源准备: nes源码 alsa源码(本文采用buildroot已编译好的alsa库 编译该库可参考mplayer那篇文章,也可自行编译) 可以使用音频 ...

  7. arm linux 内核配置,嵌入式 Linux开发Kernel移植(二)——kernel内核配置和编译

    嵌入式 Linux开发Kernel移植(二)--kernel内核配置和编译 本文选择linux 2.6.35.7版本kernel进行实践. 一.linux kernel源码目录分析 Kbuild,Ke ...

  8. 开源夏令营《基于HackRF开发GPS信号仿真模拟器》工作总结(二)

    2014.07.14--2014.07.20,开源夏令营的第二周. 这周主要解决的问题: 坐标系转换: WGS-84是地心地固坐标系的一种(地心直角坐标系),也是GPS系统定位结果输出中所采用的坐标系 ...

  9. ubuntu 串口调试工具推荐_谈一谈单片机开发的几种调试方案

    单片机开发过程中,有一个好的调试系统可以极大地提高开发效率. 举个例子,做平衡系统时调节PID参数,你会选择 修改参数–>编译–>烧录–>运行–>修改-,还是做一个功能可以一边 ...

最新文章

  1. Oracle 11G RAC:生产环境下架构
  2. linux移走一年前的文件,Shell脚本实现删除一年前文件功能分享
  3. horizon client长时间不操作不断开_动挡操作禁忌,伤车只在一瞬间!否则变速箱会提前...
  4. 划船训练常见错误:含胸驼背肩胛骨活动不足
  5. html pc端万年历插件,# pc端个性化日历实现
  6. 【CSS】学习笔记1 使用CSS样式表
  7. svn拉取文件合并_svn - SVN - 大象笔记
  8. 注释为基础的SpringMVC
  9. Android通过第三方软件打开Word、Excel、PPT、PDF等文档
  10. latex插入参考文献--BibTex格式
  11. [note] 电磁场和微波理论课组(一)——电磁学(磁学部分)
  12. 树莓派远程桌面连接-使用Windows自带远程桌面连接工具
  13. 强叔侃墙 NAT篇 NAT Server 三十二字真言(上篇)_实验一正一反,出入自如去反存正,自断出路
  14. 常规网站改版是否对搜索引擎友好?
  15. NFC手机识别身份证的技术实现思路
  16. 带搜索功能的GridView控件
  17. Waves启动Explorer 2.0
  18. 华清远见-重庆中心-前端技术阶段
  19. 内存超频会损坏内存吗 内存超频开不了机如何解决
  20. 基于python的移动物体检测_树莓派+摄像头实现对移动物体的检测

热门文章

  1. 特斯拉无人驾驶最核心的人工智能算法,竟是强化学习
  2. 采集CSDN博客中的RSS订阅小功能
  3. 读书笔记——《Python编程从入门到实践》第二章
  4. 网络图片转换为文件类型(File)
  5. 我真没想写图书管理系统啊
  6. 实用技巧,分享五个不为人知的PS隐藏技巧
  7. springboot集成mongoDB高级聚合查询,关联查询
  8. 有道云笔记Markdown(一)
  9. 千名德国基尔居民测试疫情警报手环
  10. 如何映射网络驱动器?