Skip to content

Firmware Overview

Firmware Overview

The ESP32 firmware handles input capture, debouncing, and BLE communication for each child module.

Architecture

┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ ESP32 CONTROLLER FIRMWARE │
│ │
│ ┌───────────────────────────────────────────────────────────────────────────────────┐ │
│ │ FreeRTOS Tasks │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ Controller Task (Priority 5, 10ms loop) │ │ │
│ │ │ │ │ │
│ │ │ GPIO Read ──► Debounce ──► Aggregate ──► BLE Notify │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │
│ │ │ NimBLE Host (P6) │ │ Battery Task (P4) │ │ │
│ │ │ BLE stack │ │ ADC read (2s) │ │ │
│ │ └─────────────────────┘ └─────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Hardware Layer │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 8 Action │ │ 4-Way │ │ System │ │ OLED │ │ Battery │ │ │
│ │ │ Buttons │ │ Joystick │ │ Buttons │ │ Display │ │ ADC │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └───────────────────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────────────────┘

Project Structure

  • Directoryfirmware/esp32/
    • Directorymain/
      • main.c Entry point, task creation
      • Directorysrc/
        • controller_input.c GPIO config, state aggregation
        • debounce.c Button debounce state machine
        • gatt_svc.c BLE GATT service
        • gap.c BLE advertising, connection
        • display.c SSD1306 OLED driver
        • battery.c ADC battery monitoring
      • Directoryinclude/ Header files
    • CMakeLists.txt
    • sdkconfig.defaults

Components

Controller Input

Handles GPIO configuration and state aggregation:

GPIOFunction
15, 4, 16, 17, 5, 18, 19, 23Action buttons (1-8)
25, 32, 33, 26Joystick (L, R, U, D)
27, 14, 12Select, Start, Pair
21, 22I2C (Display)
34Battery ADC

Debounce Module

Software debouncing with configurable timing:

  • Debounce delay: 20-50ms
  • Algorithm: State machine with counter
  • Purpose: Filter electrical noise and bounce

GATT Service

BLE GATT server for input state notifications:

Service UUID: 666f7065-6e41-7263-6164-65000000000
├── Characteristic: Input State
│ ├── UUID: 666f7065-6e41-7263-6164-65000000001
│ ├── Properties: Read, Notify
│ └── Value: 4-byte state packet

GAP (Generic Access Profile)

Handles BLE advertising and connection management:

  • Device name: “NimBLE_GATT” (or configured name)
  • Advertising interval: 20-40ms
  • Connection parameters: 7.5-15ms interval for low latency

Button State Packet

4-byte packet sent via BLE notification:

Byte 0: [b1][b2][b3][b4][b5][b6][b7][b8] Action buttons
Byte 1: [jL][jR][jU][jD][--][--][--][--] Joystick
Byte 2: [SE][ST][PA][--][--][--][--][--] System buttons
Byte 3: [reserved]

Building and Flashing

Terminal window
cd firmware/esp32
idf.py set-target esp32
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor

Configuration

Key settings in sdkconfig.defaults:

# BLE Configuration
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
# FreeRTOS
CONFIG_FREERTOS_HZ=1000

Next Steps