Skip to content
1achy edited this page May 16, 2024 · 3 revisions

ESP32 Touchscreen Gamepad with BLE Integration

Welcome to the ESP32 Touchscreen Gamepad with BLE Integration project! This project utilizes an ESP32 microcontroller, a touchscreen display, and BLE Gamepad functionality to create a customizable gamepad interface.

Overview

This project includes the following components:

  • ESP32 Microcontroller: Handles the processing and BLE communication.
  • Touchscreen Display: Displays the gamepad interface and captures touch inputs.
  • BLE Gamepad Library: Enables the ESP32 to function as a Bluetooth gamepad.

Sections

  1. Hardware Requirements
  2. Software Requirements
  3. Project Structure
  4. Setting Up the Project
  5. Usage

Hardware Requirements

  • ESP32 Development Board
  • 320x240 Touchscreen Display
  • USB Cable
  • Computer with PlatformIO installed

Software Requirements

  • PlatformIO IDE or VSCode with PlatformIO extension
  • Arduino framework for ESP32
  • Libraries: LovyanGFX, BLE Gamepad, and other dependencies listed in platformio.ini

Project Structure

ESP32_TouchGamepad/

├── include/

│ ├── LGFX_ESP32_esp32-2432s028.hpp

│ └── SHCustomProtocol.h

├── src/

│ └── main.ino

├── platformio.ini

└── README.md

Setting Up the Project

PlatformIO Configuration

Create a platformio.ini file with the following content to manage library dependencies and board configuration.

[common]
lib_deps =
    adafruit/Adafruit GFX Library@^1.11.5
    adafruit/Adafruit LED Backpack Library@^1.1
    adafruit/Adafruit NeoPixel@^1.10.5
    adafruit/Adafruit PCD8544 Nokia 5110 LCD library@^2.0.1
    adafruit/Adafruit [email protected]
    adafruit/Adafruit WS2801 [email protected]
    lemmingdev/ESP32-BLE-Gamepad@^0.5.2
    h2zero/NimBLE-Arduino@^1.4.0

    https://github.com/9khil/LedControl#913cbcebb8ceea6783bb271d385d18b99c2d5e79
    marcoschwartz/[email protected]
    smougenot/[email protected]+sha.9486982048
    https://github.com/paulo-raca/ArduinoBufferedStreams.git#5e3a1a3d140955384a07878c64808e77fa2a7521
    noah1510/LedController @ ^1.7.0
    locoduino/RingBuffer@^1.0.4
    https://github.com/maxint-rd/TM16xx#95a1bdd959bf6fce75d0059f129386155f49f984
    https://github.com/khoih-prog/ESPAsync_WiFiManager
    makuna/NeoPixelBus

[env:esp32]
platform = espressif32@^6.2
board = esp32doit-devkit-v1
framework = arduino
lib_deps = 
    moononournation/GFX Library for Arduino@^1.4.0
    locoduino/RingBuffer@^1.0.4
    https://github.com/paulo-raca/ArduinoBufferedStreams.git#5e3a1a3d140955384a07878c64808e77fa2a7521
    https://github.com/khoih-prog/ESPAsync_WiFiManager

build_flags = 
    -w -DESP32=true
monitor_speed = 115200
Main Code (main.ino)
Create a main.ino file in the src directory with the following content:

cpp
Copy code
#include "SHCustomProtocol.h"

SHCustomProtocol shCustomProtocol;

void setup() {
    shCustomProtocol.setup();
}

void loop() {
    shCustomProtocol.loop();
}
Display Configuration (LGFX_ESP32_esp32-2432s028.hpp)
Create the LGFX_ESP32_esp32-2432s028.hpp file in the include directory to configure the touchscreen display.

cpp
Copy code
#ifndef LGFX_ESP32_ESP32_2432S028_HPP
#define LGFX_ESP32_ESP32_2432S028_HPP

#include <LovyanGFX.hpp>

class LGFX : public lgfx::LGFX_Device
{
    lgfx::Panel_ILI9341 _panel_instance;
    lgfx::Bus_SPI _bus_instance;

public:
    LGFX(void)
    {
        {
            auto cfg = _bus_instance.config();
            cfg.spi_host = VSPI_HOST;
            cfg.spi_mode = 0;
            cfg.freq_write = 40000000;
            cfg.freq_read = 16000000;
            cfg.spi_3wire = false;
            cfg.use_lock = true;
            cfg.dma_channel = 1;
            cfg.pin_sclk = 18;
            cfg.pin_mosi = 23;
            cfg.pin_miso = -1;
            cfg.pin_dc = 2;
            _bus_instance.config(cfg);
            _panel_instance.setBus(&_bus_instance);
        }

        {
            auto cfg = _panel_instance.config();
            cfg.pin_cs = 15;
            cfg.pin_rst = 4;
            cfg.pin_busy = -1;
            cfg.panel_width = 320;
            cfg.panel_height = 240;
            cfg.offset_x = 0;
            cfg.offset_y = 0;
            cfg.offset_rotation = 0;
            cfg.dummy_read_pixel = 8;
            cfg.dummy_read_bits = 1;
            cfg.readable = true;
            cfg.invert = false;
            cfg.rgb_order = false;
            cfg.dlen_16bit = false;
            cfg.bus_shared = false;
            _panel_instance.config(cfg);
        }
        setPanel(&_panel_instance);
    }
};

#endif // LGFX_ESP32_ESP32_2432S028_HPP
Custom Protocol (SHCustomProtocol.h)
Create the SHCustomProtocol.h file in the include directory to define the custom protocol for handling touchscreen inputs and BLE gamepad functionality.

cpp
Copy code
#ifndef __SHCUSTOMPROTOCOL_H__
#define __SHCUSTOMPROTOCOL_H__

#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <lgfx_user/LGFX_ESP32_esp32-2432s028.hpp>
#include <Arduino.h>
#include <map>
#include <BleGamepad.h>

static LGFX tft;

static const int SCREEN_WIDTH = 320;
static const int SCREEN_HEIGHT = 240;
static const int X_CENTER = SCREEN_WIDTH / 2;
static const int Y_CENTER = SCREEN_HEIGHT / 2;
static const int ROWS = 5;
static const int COLS = 5;
static const int CELL_WIDTH = SCREEN_WIDTH / COLS;
static const int HALF_CELL_WIDTH = CELL_WIDTH / 2;
static const int CELL_HIGHT = SCREEN_HEIGHT / ROWS;
static const int HALF_CELL_HIGHT = CELL_HIGHT / 2;
static const int COL[] = {0, CELL_WIDTH, CELL_WIDTH * 2, CELL_WIDTH * 3, CELL_WIDTH * 4, CELL_WIDTH * 6, CELL_WIDTH * 7};
static const int ROW[] = {0, CELL_HIGHT, CELL_HIGHT * 2, CELL_HIGHT * 3, CELL_HIGHT * 4, CELL_HIGHT * 6, CELL_HIGHT * 7};

std::map<String, String> prevData;
std::map<String, int32_t> prevColor;

BleGamepad bleGamepad("ESP32 Touch Gamepad", "YourCompany", 100);
BleGamepadConfiguration bleGamepadConfig;

int currentPage = 1;

class SHCustomProtocol
{
private:
    int rpmPercent = 50;
    int prev_rpmPercent = 50;
    int rpmRedLineSetting = 90;
    String gear = "N";
    String prev_gear;
    String speed = "0";
    String currentLapTime = "00:00.00";
    String lastLapTime = "00:00.00";
    String bestLapTime = "00:00.00";
    String sessionBestLiveDeltaSeconds = "0.000";
    String sessionBestLiveDeltaProgressSeconds = "0.00";
    String tyrePressureFrontLeft = "00.0";
    String tyrePressureFrontRight = "00.0";
    String tyrePressureRearLeft = "00.0";
    String tyrePressureRearRight = "00.0";
    String tcLevel = "0";