Skip to content

diy: waveshare lcd touch 2 improvements #230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
1 change: 0 additions & 1 deletion configs/sdkconfig_display_waveshares3_touch_lcd2.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ CONFIG_NEWLIB_NANO_FORMAT=y
CONFIG_NEWLIB_STDIN_LINE_ENDING_LF=y
CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF=y
CONFIG_NT99141_SUPPORT=n
CONFIG_OV2640_SUPPORT=n
CONFIG_OV3660_SUPPORT=n
CONFIG_OV7670_SUPPORT=n
CONFIG_OV7725_SUPPORT=n
Expand Down
6 changes: 5 additions & 1 deletion diy/waveshare/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

## S3 Touch LCD 2

The device uses touchscreen navigation and the BOOT button for sleep/wake.
Bluetooth is enabled by default but can be turned off with the NORADIO config
script.

## Flashing

To prepare the board for flashing, hold down the `boot` button and plug in the
To prepare the board for flashing, hold down the `BOOT` button and plug in the
USB at the same time.

### Enclosure
Expand Down
2 changes: 1 addition & 1 deletion main/display_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static void esp_lcd_init(void* _ignored)
#ifdef ESP_PLATFORM
esp_lcd_panel_io_handle_t io_handle = NULL;

#if CONFIG_DISPLAY_PIN_BL != -1
#if CONFIG_DISPLAY_PIN_BL != -1 && !defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
gpio_config_t bk_gpio_config = { .mode = GPIO_MODE_OUTPUT, .pin_bit_mask = 1ULL << CONFIG_DISPLAY_PIN_BL };
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
ESP_ERROR_CHECK(gpio_set_level(CONFIG_DISPLAY_PIN_BL, 0));
Expand Down
2 changes: 2 additions & 0 deletions main/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include "power/twatchs3.inc"
#elif defined(CONFIG_HAS_IP5306)
#include "power/ip5306.inc"
#elif defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
#include "power/wslcdtouch2.inc"
#else
// Stubs for other hw boards (ie. no power management)
#include "power/minimal.inc"
Expand Down
209 changes: 209 additions & 0 deletions main/power/wslcdtouch2.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// Waveshare LCD Touch 2 implmentation
//
#include <esp_sleep.h>
#include <driver/gpio.h>
#include <driver/ledc.h>
#include <esp_adc/adc_cali.h>
#include <esp_adc/adc_cali_scheme.h>
#include <esp_adc/adc_oneshot.h>
#include <freertos/idf_additions.h>

#include "soc/gpio_num.h"
#include "hal/gpio_types.h"
#include "hal/adc_types.h"
#include "button_gpio.h"
#include "iot_button.h"
#include "power.h"

#define BATTERY_ADC_CHANNEL ADC_CHANNEL_4
#define BATTERY_ADC_ATTEN ADC_ATTEN_DB_12
#define BATTERY_EMA_ALPHA 0.3 // estimated moving average smoothing factor

#define LCD_BL_LEDC_TIMER LEDC_TIMER_0
#define LCD_BL_LEDC_MODE LEDC_LOW_SPEED_MODE

#define LCD_BL_LEDC_CHANNEL LEDC_CHANNEL_0
#define LCD_BL_LEDC_DUTY_RES LEDC_TIMER_10_BIT
#define LCD_BL_LEDC_DUTY (1024)
#define LCD_BL_LEDC_FREQUENCY (10000)

static adc_oneshot_unit_handle_t adc1_handle = NULL;
static adc_cali_handle_t adc1_cali_chan0_handle = NULL;

static int ema_voltage = 0;

static void button_shutdown(void* arg, void* ctx)
{
power_backlight_off();
while (gpio_get_level(GPIO_NUM_0) == 0) {
vTaskDelay(pdMS_TO_TICKS(10));
}
power_shutdown();
}

static esp_err_t boot_button_init(void)
{
const button_config_t btn_cfg = {
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
};

const button_gpio_config_t btn_gpio_cfg = {
.gpio_num = 0,
.active_level = 0,
};

button_handle_t btn_handle = NULL;
ESP_ERROR_CHECK(iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &btn_handle));
ESP_ERROR_CHECK(iot_button_register_cb(btn_handle, BUTTON_LONG_PRESS_HOLD, NULL, button_shutdown, NULL));

esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
gpio_hold_en(GPIO_NUM_0);
gpio_deep_sleep_hold_en();
esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0);

return ESP_OK;
}

static esp_err_t brightness_init(void)
{
gpio_reset_pin(CONFIG_DISPLAY_PIN_BL);
gpio_set_direction(CONFIG_DISPLAY_PIN_BL, GPIO_MODE_OUTPUT);
gpio_set_level(CONFIG_DISPLAY_PIN_BL, 1);

ledc_timer_config_t ledc_timer = { .speed_mode = LCD_BL_LEDC_MODE,
.timer_num = LCD_BL_LEDC_TIMER,
.duty_resolution = LCD_BL_LEDC_DUTY_RES,
.freq_hz = LCD_BL_LEDC_FREQUENCY, // Set output frequency at 5 kHz
.clk_cfg = LEDC_AUTO_CLK };
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

ledc_channel_config_t ledc_channel = { .speed_mode = LCD_BL_LEDC_MODE,
.channel = LCD_BL_LEDC_CHANNEL,
.timer_sel = LCD_BL_LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = CONFIG_DISPLAY_PIN_BL,
.duty = 0, // Set duty to 0%
.hpoint = 0 };
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));

return ESP_OK;
}

esp_err_t power_init(void)
{
// Use the BOOT button as a sleep/wakeup button
ESP_ERROR_CHECK(boot_button_init());

// Initialise backlight brightness
ESP_ERROR_CHECK(brightness_init());

// Initialise the ADC to measure battery level
adc_oneshot_unit_init_cfg_t init_config1 = {
.unit_id = ADC_UNIT_1,
};
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
JADE_ASSERT(adc1_handle);

adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = BATTERY_ADC_ATTEN,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, BATTERY_ADC_CHANNEL, &config));

// Use voltage calibration
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = ADC_UNIT_1,
.atten = BATTERY_ADC_ATTEN,
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
if (adc_cali_create_scheme_curve_fitting(&cali_config, &adc1_cali_chan0_handle) != ESP_OK) {
JADE_LOGW("ADC calibration not available, continuing without it");
adc1_cali_chan0_handle = NULL;
}

return ESP_OK;
}

esp_err_t power_shutdown(void) { esp_deep_sleep_start(); }

esp_err_t power_screen_on(void) { return ESP_OK; }
esp_err_t power_screen_off(void) { return ESP_OK; }

esp_err_t power_backlight_on(uint8_t brightness)
{
if (brightness < BACKLIGHT_MIN) {
brightness = BACKLIGHT_MIN;
} else if (brightness > BACKLIGHT_MAX) {
brightness = BACKLIGHT_MAX;
}

uint32_t duty = (brightness * (LCD_BL_LEDC_DUTY - 1)) / 5;
ESP_ERROR_CHECK(ledc_set_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL, duty));
ESP_ERROR_CHECK(ledc_update_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL));

return ESP_OK;
}

esp_err_t power_backlight_off(void)
{
ESP_ERROR_CHECK(ledc_set_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL, 0));
ESP_ERROR_CHECK(ledc_update_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL));

return ESP_OK;
}

esp_err_t power_camera_on(void) { return ESP_OK; }
esp_err_t power_camera_off(void) { return ESP_OK; }

uint16_t power_get_vbat(void)
{
JADE_ASSERT(adc1_handle);

int raw_adc, voltage;
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, BATTERY_ADC_CHANNEL, &raw_adc));

if (adc1_cali_chan0_handle) {
adc_cali_raw_to_voltage(adc1_cali_chan0_handle, raw_adc, &voltage);
} else {
voltage = (raw_adc * 3300) / 4095; // mV
}

// apply Estimated Moving Average since the ADC seems to have a lot of noise
ema_voltage = BATTERY_EMA_ALPHA * voltage + (1 - BATTERY_EMA_ALPHA) * (ema_voltage == 0 ? voltage : ema_voltage);
/* JADE_LOGI("Raw: %.2dmV, Smoothed: %.2d mV", voltage, ema_voltage); */
return (uint16_t)ema_voltage;
}

uint8_t power_get_battery_status(void)
{
const uint16_t vbat = power_get_vbat() * 3; // apply voltage divider
if (vbat > 3800) {
return 5;
} else if (vbat > 3600) {
return 4;
} else if (vbat > 3400) {
return 3;
} else if (vbat > 3200) {
return 2;
} else if (vbat > 3000) {
return 1;
}
return 0;
}

// The STAT pin on the charging IC isn't exposed to a GPIO so we cannot read it
// and can't easily tap it with a wire. There is a charging LED though so you
// can see if the battery is being charged.
bool power_get_battery_charging(void) { return 0; }
uint16_t power_get_ibat_charge(void) { return 0; }
uint16_t power_get_ibat_discharge(void) { return 0; }
uint16_t power_get_vusb(void) { return 0; }
uint16_t power_get_iusb(void) { return 0; }
uint16_t power_get_temp(void) { return 0; }

void disable_usb_host(void) {}
void enable_usb_host(void) {}

// This is only a guess by the ADC voltage when the USB is plugged in
bool usb_connected(void) { return power_get_vbat() > 1350; }
12 changes: 10 additions & 2 deletions main/process/dashboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -1708,7 +1708,8 @@ static void handle_view_otps(void)
}

// NOTE: Only Jade v1.1's and v2's have brightness controls
#if defined(CONFIG_BOARD_TYPE_JADE_V1_1) || defined(CONFIG_BOARD_TYPE_JADE_V2)
#if defined(CONFIG_BOARD_TYPE_JADE_V1_1) || defined(CONFIG_BOARD_TYPE_JADE_V2) \
|| defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
static void handle_screen_brightness(void)
{
static const char* LABELS[] = { "Min(1)", "Low(2)", "Medium(3)", "High(4)", "Max(5)" };
Expand Down Expand Up @@ -2053,6 +2054,12 @@ static void handle_display_battery_volts(void)
const int ret = snprintf(power_status, sizeof(power_status), "%umv", vbat);
JADE_ASSERT(ret > 0 && ret < sizeof(power_status));
}
#elif defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
const uint16_t vbat = power_get_vbat() * 3; // applying voltage divider
if (vbat > 0) {
const int ret = snprintf(power_status, sizeof(power_status), "%umv", vbat);
JADE_ASSERT(ret > 0 && ret < sizeof(power_status));
}
#elif defined(CONFIG_HAS_IP5306)
const float approx_voltage = power_get_vbat() / 1000.0;
const int ret = snprintf(power_status, sizeof(power_status), "Approx %.1fv", approx_voltage);
Expand Down Expand Up @@ -2277,7 +2284,8 @@ static void handle_settings(const bool startup_menu)
break;

// NOTE: Only Jade v1.1's and v2's have brightness controls
#if defined(CONFIG_BOARD_TYPE_JADE_V1_1) || defined(CONFIG_BOARD_TYPE_JADE_V2)
#if defined(CONFIG_BOARD_TYPE_JADE_V1_1) || defined(CONFIG_BOARD_TYPE_JADE_V2) \
|| defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
case BTN_SETTINGS_DISPLAY_BRIGHTNESS:
handle_screen_brightness();
break;
Expand Down
2 changes: 1 addition & 1 deletion main/ui/dashboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ gui_activity_t* make_display_settings_activity(void)

// NOTE: Only Jade v1.1's and v2's have brightness controls
// NOTE: Jade v1.1's do not support Flip Orientation because of issues with screen offsets
#if defined(CONFIG_BOARD_TYPE_JADE_V2)
#if defined(CONFIG_BOARD_TYPE_JADE_V2) || defined(CONFIG_BOARD_TYPE_WS_TOUCH_LCD2)
btn_data_t menubtns[]
= { { .txt = "Display Brightness", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_BRIGHTNESS },
{ .txt = "Flip Orientation", .font = GUI_DEFAULT_FONT, .ev_id = BTN_SETTINGS_DISPLAY_ORIENTATION },
Expand Down