Feature/dmg volume potentiometer#283
Conversation
|
邮件已收到,谢谢!——来自QQ邮箱客户端
|
|
Hi Very exciting, its been something I added to my recent device without even knowing if it would ever work! My device is a ESP32-P4 and IDF have stopped it from using what they now call legacy drivers (although older devices can still use them) so I couldnt initially use your code due to errors compiling however AI was able to adjust your code to work with the new ADC driver. I then added some ifdefs so it uses the new driver for P4 devices and the legacy driver for S3 and below, same as the original code. Chances are the new driver will work on older devices anyway! Its all working fine, volume control works fine, So I'll paste my amended code below, but just note my code is based on the latest dev, not master which brings me to the next point with this pull request, but theres likely to be a few issues if the dev is happy to accept. 1) ideally you want to be pushing to the dev build, not master since theres been a lot of changes since master and likely cant be merged and 2) theres other changes to esp32-s3-devkit/config.h (I assume its to match your device) but you will want to remove that, its probably an idea to leave the additional volume related defines as they need to be seen somewhere. So enough rambling, heres the code. I'm not sure if AI has changed other stuff too, sometimes its hard to stop it needlessly re-writing stuff! I have tested it on my ESP32-P4 device and also built for a ESP32-S3 without any volume defines and also with them (my other ESP32 devices dont have any volume pots so cant actually test it works but it builds without error) EDIT: Adjusted the below code to allow better adjustability on my device, it does require different defines in config.h but feels like its easier for the end user to understand & adjust to suit their setup. Example config.h: Updated code: |
|
Hi, I’m glad to hear the code was adapted for the ESP32-P4 and that it worked! Here on my ESP32-S3 it’s working perfectly :-) Your suggestion about submitting PRs to the development branch instead of master makes total sense. I agree it will make merging easier — thanks for the tip. I only read your message after I had already submitted another contribution to the master branch. From now on, my next contributions will go to the development branch as you suggested. I also adapted the volume control code (potentiometer-based) so that a second potentiometer can be used to control the LCD backlight brightness. I tested it extensively and it follows the same logic as the volume control. I’m even using a second potentiometer identical to the original DMG-01 volume potentiometer. After reviewing your ESP32-P4 adaptation, I can see the structure remains essentially the same, and it looks well optimized. Great job on the port! I don’t have an ESP32-P4 board in stock yet, but I ordered one today. It should arrive in about two weeks — I’m aiming to run 16-bit emulators (Mega Drive / Genesis and Super NES). At this point, I’ve finished tuning the Retro-Go firmware for my needs: using the original Game Boy DMG-01 shell in a way that stays as close to the original as possible (pure nerd nostalgia). My current challenge is fitting the prototype inside the original shell, and I think I’ll need to design a custom PCB for this. To avoid cluttering config.h, it may be better for me to document my hardware setup and propose a dedicated target, e.g. "Retro-Go-DMG-01". I had to modify config.h due to the new features (volume and LCD brightness potentiometers), and because my D-PAD wiring also consumes a few additional GPIOs. Thanks again! |
|
Hi Yes saw the brightness wheel too, sounds like it could be a handy addition as well. As for your "Retro-Go-DMG-01" target, that probably wouldnt be something the developer would accept as an official target unless its something that others can make (with a guide) or buy. One off builds are generally not accepted, but that doesnt mean you obviously cant keep it on your own fork. The only targets that are not that are the devkit ones, which are there to serve as a base for people to build from. The GB build sounds cool, I have been tempted to build one too! Thanks |
A suggestion for the Retro Go firmware:
Integrated Software
Technical Characteristics
Volume Control via Potentiometer - Technical Documentation
Overview
This document describes the implementation of analog volume control through a potentiometer connected to the ESP32-S3, based on the existing Retro-Go battery reading architecture.
Hardware
Physical Connections
Characteristics
Implementation
1. Configuration File (config.h)
The file components/retro-go/targets/esp32-s3-devkit/config.h contains the following definitions:
c
// Volume Control Potentiometer (GPIO 7 / ADC1_CH6)
#define RG_POTENTIOMETER_ENABLED 1
#define RG_POTENTIOMETER_ADC_UNIT ADC_UNIT_1
#define RG_POTENTIOMETER_ADC_CHANNEL ADC_CHANNEL_6
#define RG_POTENTIOMETER_ADC_ATTEN ADC_ATTEN_DB_11
// Converts raw ADC value (0-4095) to volume percentage (0-100%)
#define RG_POTENTIOMETER_CALC_VOLUME(raw) ((int32_t)((raw) * 100 / 4095))
// Hysteresis threshold to prevent volume changes from small ADC fluctuations
#define RG_POTENTIOMETER_UPDATE_THRESHOLD 5
// Update interval in microseconds (update every 100ms)
#define RG_POTENTIOMETER_UPDATE_INTERVAL (100 * 1000)
2. Reading Functions (rg_input.c)
rg_input_read_potentiometer_raw(int *out)
Function that reads the raw ADC value from the potentiometer. Similar to the battery reading function:
c
bool rg_input_read_potentiometer_raw(int *out)
{
int raw_value = 0;
#ifdef ESP_PLATFORM
// Read the potentiometer multiple times and average for stability
for (int i = 0; i < 4; ++i)
{
int value = adc_get_raw(RG_POTENTIOMETER_ADC_UNIT, RG_POTENTIOMETER_ADC_CHANNEL);
if (value < 0)
return false;
raw_value += value;
}
raw_value /= 4;
#else
return false;
#endif
}
Characteristics:
3. Input Task (input_task)
The input task was modified to include:
c
static void input_task(void *arg)
{
// ... other variables ...
#ifdef RG_POTENTIOMETER_ENABLED
int64_t next_potentiometer_update = 0;
int last_potentiometer_volume = -1000; // Initialize impossibly low
#endif
#ifdef RG_POTENTIOMETER_ENABLED
if (rg_system_timer() >= next_potentiometer_update)
{
int potentiometer_volume = 0;
if (rg_input_read_potentiometer_raw(&potentiometer_volume))
{
// Hysteresis: only update if change >= RG_POTENTIOMETER_UPDATE_THRESHOLD
if (abs(potentiometer_volume - last_potentiometer_volume) >= RG_POTENTIOMETER_UPDATE_THRESHOLD)
{
int volume = RG_MAX(0, RG_MIN(100, potentiometer_volume));
// Critical check: only call if audio has been initialized
if (rg_audio_get_driver() != NULL)
{
rg_audio_set_volume(volume);
last_potentiometer_volume = volume;
RG_LOGD("Potentiometer adjusted volume to %d%%\n", volume);
}
}
}
next_potentiometer_update = rg_system_timer() + RG_POTENTIOMETER_UPDATE_INTERVAL;
}
#endif
}
Important Characteristics:
4. ADC Initialization
In the function rg_input_init(), the potentiometer ADC is configured:
c
#ifdef RG_POTENTIOMETER_ENABLED
RG_LOGI("Initializing ADC potentiometer driver...");
if (RG_POTENTIOMETER_ADC_UNIT == ADC_UNIT_1)
{
adc1_config_width(ADC_WIDTH_MAX - 1);
adc1_config_channel_atten(RG_POTENTIOMETER_ADC_CHANNEL, RG_POTENTIOMETER_ADC_ATTEN);
}
else if (RG_POTENTIOMETER_ADC_UNIT == ADC_UNIT_2)
{
adc2_config_channel_atten(RG_POTENTIOMETER_ADC_CHANNEL, RG_POTENTIOMETER_ADC_ATTEN);
}
else
{
RG_LOGE("Only ADC1 and ADC2 are supported for potentiometer driver!");
}
#endif
Functional Flow
┌─────────────────────────────────────────────────────────────┐
│ Potentiometer (0-3.3V) ──→ GPIO 7 (ADC1_CH6) │
└────────────────────────────────┬──────────────────────────────┘
│
▼
┌──────────────────────────┐
│ ADC Reads Value (0-4095) │
└────────────┬─────────────┘
│
▼ (Average 4 samples)
┌──────────────────────────┐
│ Calc Volume % (0-100) │
└────────────┬─────────────┘
│
┌─────────┴─────────┐
│ Every 100ms │
└────────┬──────────┘
│
┌────────▼────────┐
│ Check Hysteresis│
│ Δ >= 5% ? │
└────────┬────────┘
│
┌────────────┴────────────┐
│ Audio Initialized? │
│ (driver != NULL) │
└────────────┬────────────┘
│
▼
┌──────────────────────────┐
│ rg_audio_set_volume() │
│ Update UI (if applicable)│
└──────────────────────────┘
Quick Disable
If you need to disable the potentiometer control quickly, modify in config.h:
c
#define RG_POTENTIOMETER_ENABLED 0 // Change to 0
Recompile and reflash. All related code will be removed by the preprocessor.
Testing and Validation
Log Verification
On startup, you will see:
[info] rg_input_init: Initializing ADC potentiometer driver...
When moving the potentiometer:
[debug] Potentiometer adjusted volume to 35%
[debug] Potentiometer adjusted volume to 42%
Troubleshooting
Comparison with Previous Solution
This solution follows the pattern established in Retro-Go for battery reading:
Next Improvements (Optional)
References
Author: Tadeu Botelho
E-mail: tadeubotelho@hotmail.com
GitHub: https://github.com/TadeuBotelho
Date: February 11, 2026
Version: 1.0
Tested Target: esp32-s3-devkit