Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions components/retro-go/rg_input.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "rg_system.h"
#include "rg_input.h"
#include "rg_audio.h"
#include "rg_display.h"

#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -103,6 +105,58 @@ bool rg_input_read_battery_raw(rg_battery_t *out)
return true;
}

#ifdef RG_POTENTIOMETER_ENABLED
bool rg_input_read_potentiometer_raw(int *out)
{
int raw_value = 0;

#ifdef ESP_PLATFORM
// Read the potentiometer multiple times and average for stability
// This is similar to how battery voltage is read
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

if (out)
*out = RG_POTENTIOMETER_CALC_VOLUME(raw_value);
return true;
}
#endif

#ifdef RG_BRIGHTNESS_POTENTIOMETER_ENABLED
bool rg_input_read_brightness_potentiometer_raw(int *out)
{
int raw_value = 0;

#ifdef ESP_PLATFORM
// Read the potentiometer multiple times and average for stability
// This is similar to how battery voltage is read
for (int i = 0; i < 4; ++i)
{
int value = adc_get_raw(RG_BRIGHTNESS_POTENTIOMETER_ADC_UNIT, RG_BRIGHTNESS_POTENTIOMETER_ADC_CHANNEL);
if (value < 0)
return false;
raw_value += value;
}
raw_value /= 4;
#else
return false;
#endif

if (out)
*out = RG_BRIGHTNESS_POTENTIOMETER_CALC_BRIGHTNESS(raw_value);
return true;
}
#endif

bool rg_input_read_gamepad_raw(uint32_t *out)
{
uint32_t state = 0;
Expand Down Expand Up @@ -218,6 +272,14 @@ static void input_task(void *arg)
uint32_t local_gamepad_state = 0;
uint32_t state;
int64_t next_battery_update = 0;
#ifdef RG_POTENTIOMETER_ENABLED
int64_t next_potentiometer_update = 0;
int last_potentiometer_volume = -1000; // Initialize with value that won't match any real volume
#endif
#ifdef RG_BRIGHTNESS_POTENTIOMETER_ENABLED
int64_t next_brightness_potentiometer_update = 0;
int last_brightness_potentiometer_level = -1000; // Initialize with value that won't match any real brightness
#endif

// Start the task with debounce history full to allow a button held during boot to be detected
memset(debounce, 0xFF, sizeof(debounce));
Expand Down Expand Up @@ -258,6 +320,58 @@ static void input_task(void *arg)
next_battery_update = rg_system_timer() + 2 * 1000000; // update every 2 seconds
}

#ifdef RG_POTENTIOMETER_ENABLED
if (rg_system_timer() >= next_potentiometer_update)
{
int potentiometer_volume = 0;
if (rg_input_read_potentiometer_raw(&potentiometer_volume))
{
// Only update volume if change is significant enough (hysteresis)
// This prevents minor ADC fluctuations from constantly updating the volume
if (abs(potentiometer_volume - last_potentiometer_volume) >= RG_POTENTIOMETER_UPDATE_THRESHOLD)
{
// Clamp volume to 0-100% range
int volume = RG_MAX(0, RG_MIN(100, potentiometer_volume));
// Only call rg_audio_set_volume if audio driver is ready (non-null)
// This prevents panic during early boot before audio initialization
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

#ifdef RG_BRIGHTNESS_POTENTIOMETER_ENABLED
if (rg_system_timer() >= next_brightness_potentiometer_update)
{
int brightness_level = 0;
if (rg_input_read_brightness_potentiometer_raw(&brightness_level))
{
// Only update brightness if change is significant enough (hysteresis)
// This prevents minor ADC fluctuations from constantly updating the brightness
if (abs(brightness_level - last_brightness_potentiometer_level) >= RG_BRIGHTNESS_POTENTIOMETER_UPDATE_THRESHOLD)
{
// Clamp brightness to valid range (1-100, display module has min/max internally)
int brightness = RG_MAX(1, RG_MIN(100, brightness_level));
// Only call rg_display_set_backlight if display driver is ready
// This prevents issues during early boot before display initialization
if (rg_display_get_backlight() >= 0)
{
rg_display_set_backlight(brightness);
last_brightness_potentiometer_level = brightness;
RG_LOGD("Brightness potentiometer adjusted backlight to %d%%\n", brightness);
}
}
}
next_brightness_potentiometer_update = rg_system_timer() + RG_BRIGHTNESS_POTENTIOMETER_UPDATE_INTERVAL;
}
#endif

rg_task_delay(10);
}

Expand Down Expand Up @@ -354,6 +468,40 @@ void rg_input_init(void)
}
#endif

#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

#ifdef RG_BRIGHTNESS_POTENTIOMETER_ENABLED
RG_LOGI("Initializing ADC brightness potentiometer driver...");
if (RG_BRIGHTNESS_POTENTIOMETER_ADC_UNIT == ADC_UNIT_1)
{
adc1_config_width(ADC_WIDTH_MAX - 1);
adc1_config_channel_atten(RG_BRIGHTNESS_POTENTIOMETER_ADC_CHANNEL, RG_BRIGHTNESS_POTENTIOMETER_ADC_ATTEN);
}
else if (RG_BRIGHTNESS_POTENTIOMETER_ADC_UNIT == ADC_UNIT_2)
{
adc2_config_channel_atten(RG_BRIGHTNESS_POTENTIOMETER_ADC_CHANNEL, RG_BRIGHTNESS_POTENTIOMETER_ADC_ATTEN);
}
else
{
RG_LOGE("Only ADC1 and ADC2 are supported for brightness potentiometer driver!");
}
#endif

// The first read returns bogus data in some drivers, waste it.
rg_input_read_gamepad_raw(NULL);

Expand Down
73 changes: 64 additions & 9 deletions components/retro-go/targets/esp32-s3-devkit/config.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
// #define RG_STORAGE_FLASH_PARTITION "vfs"

// Audio
#define RG_AUDIO_USE_INT_DAC 0 // 0 = Disable, 1 = GPIO25, 2 = GPIO26, 3 = Both
#define RG_AUDIO_USE_INT_DAC 0 // 0 = Disable, 1 = GPIO25, 2 = GPIO26, 3 = Both (Atenção: Apenas ESP32 pussui as portas 25 e 26 podendo ser usadas com o módulo analógico PAM8302 que possuo em estoque. O ESP32S3 é 100% digital.
#define RG_AUDIO_USE_EXT_DAC 1 // 0 = Disable, 1 = Enable


// Video
#define RG_SCREEN_DRIVER 0 // 0 = ILI9341/ST7789
#define RG_SCREEN_HOST SPI2_HOST
Expand Down Expand Up @@ -44,6 +45,8 @@
ILI9341_CMD(0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F);



/* Backup Default Code:
// Input
// Refer to rg_input.h to see all available RG_KEY_* and RG_GAMEPAD_*_MAP types
#define RG_GAMEPAD_ADC_MAP {\
Expand All @@ -52,6 +55,8 @@
{RG_KEY_DOWN, ADC_UNIT_1, ADC_CHANNEL_5, ADC_ATTEN_DB_11, 1024, 3071},\
{RG_KEY_LEFT, ADC_UNIT_1, ADC_CHANNEL_6, ADC_ATTEN_DB_11, 3072, 4096},\
}
*/
/*
#define RG_GAMEPAD_GPIO_MAP {\
{RG_KEY_SELECT, .num = GPIO_NUM_16, .pullup = 1, .level = 0},\
{RG_KEY_START, .num = GPIO_NUM_17, .pullup = 1, .level = 0},\
Expand All @@ -60,27 +65,77 @@
{RG_KEY_A, .num = GPIO_NUM_15, .pullup = 1, .level = 0},\
{RG_KEY_B, .num = GPIO_NUM_5, .pullup = 1, .level = 0},\
}
*/

// D-PAD Map
#define RG_GAMEPAD_GPIO_MAP {\
{RG_KEY_SELECT, .num = GPIO_NUM_16, .pullup = 1, .level = 0},\
{RG_KEY_START, .num = GPIO_NUM_17, .pullup = 1, .level = 0},\
{RG_KEY_MENU, .num = GPIO_NUM_18, .pullup = 1, .level = 0},\
{RG_KEY_OPTION, .num = GPIO_NUM_8, .pullup = 1, .level = 0},\
{RG_KEY_A, .num = GPIO_NUM_15, .pullup = 1, .level = 0},\
{RG_KEY_B, .num = GPIO_NUM_5, .pullup = 1, .level = 0},\
{RG_KEY_UP, .num = GPIO_NUM_2, .pullup = 1, .level = 0},\
{RG_KEY_RIGHT, .num = GPIO_NUM_14, .pullup = 1, .level = 0},\
{RG_KEY_DOWN, .num = GPIO_NUM_45, .pullup = 1, .level = 0},\
{RG_KEY_LEFT, .num = GPIO_NUM_46, .pullup = 1, .level = 0},\
}

// Battery
#define RG_BATTERY_DRIVER 1
#define RG_BATTERY_ADC_UNIT ADC_UNIT_1
#define RG_BATTERY_ADC_CHANNEL ADC_CHANNEL_3
#define RG_BATTERY_ADC_CHANNEL ADC_CHANNEL_3
#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)

// Volume Control Potentiometer (GPIO 7 / ADC1_CH6)
// This potentiometer is connected to GPIO 7 and will be read periodically to control audio volume
// The ADC raw value (0-4095) is mapped to volume percentage (0-100%)
#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%)
// The formula maps 0V to 0% and 3.3V to 100%
// raw_voltage = (adc_raw * 3.3) / 4095
// volume = (raw_voltage / 3.3) * 100 = (adc_raw / 4095) * 100
#define RG_POTENTIOMETER_CALC_VOLUME(raw) ((int32_t)((raw) * 100 / 4095))
// Hysteresis threshold to prevent volume changes from small ADC fluctuations (in percentage points)
#define RG_POTENTIOMETER_UPDATE_THRESHOLD 5
// Update interval in microseconds (update every 100ms)
#define RG_POTENTIOMETER_UPDATE_INTERVAL (100 * 1000)

// LCD Brightness Control Potentiometer (GPIO 6 / ADC1_CH5)
// This potentiometer is connected to GPIO 6 and will be read periodically to control LCD brightness
// The ADC raw value (0-4095) is mapped to brightness percentage (0-100%)
#define RG_BRIGHTNESS_POTENTIOMETER_ENABLED 1
#define RG_BRIGHTNESS_POTENTIOMETER_ADC_UNIT ADC_UNIT_1
#define RG_BRIGHTNESS_POTENTIOMETER_ADC_CHANNEL ADC_CHANNEL_5
#define RG_BRIGHTNESS_POTENTIOMETER_ADC_ATTEN ADC_ATTEN_DB_11
// Converts raw ADC value (0-4095) to brightness percentage (0-100%)
// The formula maps 0V to 0% and 3.3V to 100%
// raw_voltage = (adc_raw * 3.3) / 4095
// brightness = (raw_voltage / 3.3) * 100 = (adc_raw / 4095) * 100
#define RG_BRIGHTNESS_POTENTIOMETER_CALC_BRIGHTNESS(raw) ((int32_t)((raw) * 100 / 4095))
// Hysteresis threshold to prevent brightness changes from small ADC fluctuations (in percentage points)
#define RG_BRIGHTNESS_POTENTIOMETER_UPDATE_THRESHOLD 5
// Update interval in microseconds (update every 100ms)
#define RG_BRIGHTNESS_POTENTIOMETER_UPDATE_INTERVAL (100 * 1000)


// Status LED
#define RG_GPIO_LED GPIO_NUM_38

// SPI Display (back up working)
#define RG_GPIO_LCD_MISO GPIO_NUM_NC
#define RG_GPIO_LCD_MOSI GPIO_NUM_12
#define RG_GPIO_LCD_CLK GPIO_NUM_48
#define RG_GPIO_LCD_CS GPIO_NUM_NC
#define RG_GPIO_LCD_DC GPIO_NUM_47
#define RG_GPIO_LCD_BCKL GPIO_NUM_39
#define RG_GPIO_LCD_RST GPIO_NUM_3
#define RG_GPIO_LCD_MISO GPIO_NUM_NC // MISO (SDO) ---> Not Connection Where <---
#define RG_GPIO_LCD_MOSI GPIO_NUM_12 // MOSI (SDI / DIN)
#define RG_GPIO_LCD_CLK GPIO_NUM_48 // SCK (CLK)
#define RG_GPIO_LCD_CS GPIO_NUM_NC // GND
#define RG_GPIO_LCD_DC GPIO_NUM_47 // DC (D/C)
#define RG_GPIO_LCD_BCKL GPIO_NUM_39 // LED / BL (BackLight)
#define RG_GPIO_LCD_RST GPIO_NUM_3 // RST (RESET)

// SD Card
#define RG_GPIO_SDSPI_MISO GPIO_NUM_9
#define RG_GPIO_SDSPI_MOSI GPIO_NUM_11
#define RG_GPIO_SDSPI_CLK GPIO_NUM_13
Expand Down
Loading