1- // tdisplays3 and devices with no power-management but it can measure voltage level of the battery and
2- // detect charging status when a battery is connected through an analog input
1+ // T-Display S3 implementation without PMIC (ADC-based)
32//
3+
44#include < driver/gpio.h>
55#include < esp_adc/adc_cali.h>
6+ #include < esp_adc/adc_cali_scheme.h>
67#include < esp_adc/adc_oneshot.h>
8+ #include < esp_sleep.h>
9+
10+ #include " tusb.h"
711
812#define BATTERY_ADC_CHANNEL ADC_CHANNEL_3
13+ #define BATTERY_ADC_ATTEN ADC_ATTEN_DB_12
14+ #define BATTERY_EMA_ALPHA 0 .3f // estimated moving average smoothing factor
915
1016static adc_oneshot_unit_handle_t adc1_handle = NULL ;
11- static adc_cali_handle_t adc1_cali_handle = NULL ;
17+ static adc_cali_handle_t adc1_cali_chan0_handle = NULL ;
18+ static int ema_voltage = 0 ;
1219
1320esp_err_t power_init (void )
1421{
@@ -20,22 +27,30 @@ esp_err_t power_init(void)
2027 JADE_ASSERT (adc1_handle);
2128 // ADC Config
2229 adc_oneshot_chan_cfg_t config = {
23- .atten = ADC_ATTEN_DB_12 ,
30+ .atten = BATTERY_ADC_ATTEN ,
2431 .bitwidth = ADC_BITWIDTH_DEFAULT,
2532 };
2633 ESP_ERROR_CHECK (adc_oneshot_config_channel (adc1_handle, BATTERY_ADC_CHANNEL, &config));
27- // Curve fitting calibration
34+ // Use voltage calibration
2835 adc_cali_curve_fitting_config_t cali_config = {
2936 .unit_id = ADC_UNIT_1,
30- .atten = ADC_ATTEN_DB_12 ,
37+ .atten = BATTERY_ADC_ATTEN ,
3138 .bitwidth = ADC_BITWIDTH_DEFAULT,
3239 };
33- ESP_ERROR_CHECK (adc_cali_create_scheme_curve_fitting (&cali_config, &adc1_cali_handle));
40+ if (adc_cali_create_scheme_curve_fitting (&cali_config, &adc1_cali_chan0_handle) != ESP_OK) {
41+ JADE_LOGW (" ADC calibration not available, continuing without it" );
42+ adc1_cali_chan0_handle = NULL ;
43+ }
3444 return ESP_OK;
3545}
3646
37- esp_err_t power_shutdown (void ) { return ESP_OK; }
47+ esp_err_t power_shutdown (void )
48+ {
49+ esp_deep_sleep_start ();
50+ return ESP_OK;
51+ }
3852esp_err_t power_screen_on (void ) { return ESP_OK; }
53+ esp_err_t power_screen_off (void ) { return ESP_OK; }
3954esp_err_t power_backlight_on (const uint8_t brightness) { return ESP_OK; }
4055esp_err_t power_backlight_off (void ) { return ESP_OK; }
4156esp_err_t power_camera_on (void ) { return ESP_OK; }
@@ -44,12 +59,20 @@ esp_err_t power_camera_off(void) { return ESP_OK; }
4459uint16_t power_get_vbat (void )
4560{
4661 JADE_ASSERT (adc1_handle);
47- int cal_vbat = 0 ;
48- int raw_vbat = 0 ;
49- ESP_ERROR_CHECK (adc_oneshot_read (adc1_handle, BATTERY_ADC_CHANNEL, &raw_vbat));
50- ESP_ERROR_CHECK (adc_cali_raw_to_voltage (adc1_cali_handle, raw_vbat, &cal_vbat));
51- return (uint16_t )(cal_vbat * 2 );
62+ int raw_adc, voltage;
63+ ESP_ERROR_CHECK (adc_oneshot_read (adc1_handle, BATTERY_ADC_CHANNEL, &raw_adc));
64+ if (adc1_cali_chan0_handle) {
65+ ESP_ERROR_CHECK (adc_cali_raw_to_voltage (adc1_cali_chan0_handle, raw_adc, &voltage));
66+ } else {
67+ voltage = (raw_adc * 3300 ) / 4095 ;
68+ }
69+ // Apply Estimated Moving Average (EMA)
70+ const int ema_v = ema_voltage ? ema_voltage : voltage;
71+ ema_voltage = (BATTERY_EMA_ALPHA * voltage) + ((1 - BATTERY_EMA_ALPHA) * ema_v);
72+ // T-Display S3 voltage divider is 2 (100k/100k)
73+ return (uint16_t )(ema_voltage * 2 );
5274}
75+
5376uint8_t power_get_battery_status (void )
5477{
5578 const uint16_t vbat = power_get_vbat ();
@@ -70,11 +93,8 @@ uint8_t power_get_battery_status(void)
7093
7194bool power_get_battery_charging (void )
7295{
73- uint16_t vbat = power_get_vbat ();
74- // If the voltage is greater than 4500 mV and less than 4750 it means its charging
75- if (vbat > 4500 && vbat < 4750 ) {
76- return true ;
77- }
96+ // The charging IC STAT pin is not connected to GPIO, so we can't know for sure.
97+ // Return false to avoid showing "Charging" icon permanently when on USB.
7898 return false ;
7999}
80100
@@ -84,12 +104,19 @@ uint16_t power_get_vusb(void) { return 0; }
84104uint16_t power_get_iusb (void ) { return 0 ; }
85105uint16_t power_get_temp (void ) { return 0 ; }
86106
107+ void disable_usb_host (void ) {}
108+ void enable_usb_host (void ) {}
109+
87110bool usb_is_powered (void )
88111{
89- // If the voltage is greater than 4500 mV it means USB is connected
90- uint16_t vbat = power_get_vbat ();
91- if (vbat > 4500 ) {
112+ // Check if USB is mounted and not suspended (active connection)
113+ if (tud_mounted () && !tud_suspended ()) {
114+ return true ;
115+ }
116+ // Fallback: If voltage is near zero (<1V) but chip is on,
117+ // we must be running on USB power without a battery.
118+ if (power_get_vbat () < 1000 ) {
92119 return true ;
93120 }
94121 return false ;
95- }
122+ }
0 commit comments