Community project

ESP32 LTE Smartphone

ESP32
Photo of ESP32 LTE Smartphone
Generated with AI

Gigum Rajaguru

Published September 13, 2026

Build a functional LTE smartphone powered by an ESP32 microcontroller. This project combines a 3.3-inch touchscreen display, SIM7600 LTE modem, microphone, and speaker into a handheld device capable of cellular connectivity and voice communication. The guide includes a complete wiring diagram, detailed parts list, and step-by-step assembly instructions to integrate all components into a working prototype.

The firmware provided handles touchscreen input, modem communication, and UI rendering, giving builders a foundation to expand with SMS, calling, and custom applications. A rechargeable power system with charging module keeps the device running, while the home button provides hardware control. This project demonstrates how to combine industrial modules into a compact, battery-powered communication device.

Wiring diagram

Wiring diagram for ESP32 LTE Smartphone

Gather all the parts

QtyComponent
1

ILI9341 TFT Touchscreen

2.8 in / 240×320

240x320 SPI TFT display using the ILI9341 LCD controller with an XPT2046 resistive touch controller sharing the SPI bus

1

SIM7600 LTE CAT-4 Module

SIM7600E breakout + LTE antenna

SIMCom SIM7600-series LTE CAT-4 cellular module or breakout. It is typically controlled over UART with AT commands and needs a stable high-current cellular supply; many maker boards accept 5V input but the bare module uses a lower VBAT rail.

1

HiLetgo INMP441 I²S Microphone Module

INMP441

Omnidirectional 24-bit I²S MEMS microphone module based on the TDK InvenSense INMP441 IC. Outputs digital audio over a 3-wire I²S bus (SCK/BCLK, WS/LRCLK, SD/DOUT). Supply 1.8–3.3 V; native 3.3 V operation with no level shifting required. L/R channel select pin: tie to GND for left-channel mono output or VDD for right-channel mono output. Use the ESP32 Arduino core or ESP-IDF I2S peripheral API; no separate PlatformIO library is required.

1

MAX98357A I2S Class-D Mono Amplifier Breakout

MAX98357A

I2S-input Class-D mono audio amplifier IC on a compact breakout board. Accepts I2S digital audio input (BCLK, LRC, DIN) and drives a small speaker or transducer directly. No I2C/SPI control bus is needed. The amplifier supply range is 2.5V-5.5V, and the I2S input pins are compatible with 3.3V logic. SD/MODE controls shutdown and channel selection; GAIN selects 3 dB, 6 dB, 9 dB, 12 dB, or 15 dB gain.

1

8Ω Speaker

8 Ω / 1 W

Generic small 8Ω 0.5-3W loudspeaker (~28mm typical). Pair with an I2S amp (MAX98357A) or class-D amp (TPA3116D2) for usable volume; do not drive directly from a GPIO pin. Audio output for music/voice playback.

1

Push Button

momentary

Momentary push button switch

1

Lithium Ion Battery - 3.7V 2000mAh

3.7 V / 2000 mAh

3.7V 2000mAh lithium-ion polymer battery with JST-PH connector and protection circuitry. Output ranges from 4.2 V fully charged to 3.0 V cutoff.

1

TP4056 Li-Ion/LiPo charger module with protection

TP4056 with protection

TP4056 single-cell Li-Ion/LiPo linear charger module, 5V USB input, 1A charge current (programmable). Common variants ship with DW01 protection. Pair with battery_lipo_storage for the cell.

1

Boost Converter

5 V high-current

Small adjustable MT3608-style DC-DC boost converter module for stepping a lower DC input up to a higher rail such as 5V, 9V, or 12V. It is a power-path module with VIN/VOUT terminals, not a GPIO peripheral.

Assemble it in 6 steps

1. Prepare the screen and controller

Place the ESP32-S3 board and the 2.8-inch screen on a non-metallic work surface. Connect the screen: VCC → 3V3 (power), GND → GND (ground), MOSI → GPIO11 (screen data), MISO → GPIO13 (touch data), SCK → GPIO12 (clock), TFT_CS → GPIO10 (screen select), TFT_DC → GPIO14 (screen command/data), TFT_RST → GPIO15 (screen reset), and TOUCH_CS → GPIO16 (touch select).

  • Keep the screen wires short and label them before fitting a case.
  • The screen and touch controller share the three MOSI, MISO, and SCK wires; that is normal.
  • Make sure VCC and GND are not swapped — swapped power can damage the screen.

2. Connect the cellular modem and antenna

Attach the LTE antenna to the SIM7600E antenna socket before powering it. Insert an active SLT-Mobitel SIM in the modem. Connect modem VCC → 5V (power), GND → GND (ground), modem TXD → GPIO18 (messages from the modem), modem RXD → GPIO17 (messages to the modem), and PWRKEY → GPIO21 (modem on/off control).

  • Keep the antenna away from the screen, battery, and long bundles of wires.
  • Use a SIM7600E breakout that explicitly accepts 5 V input and 3.3 V UART logic.
  • Never power the SIM7600E without its antenna fitted; cellular transmissions can stress the radio without a proper antenna.
  • Do not try to draw modem power from the ESP32-S3 3V3 pin — cellular bursts need the separate 5 V supply.

3. Wire the speaker and microphone

Connect the amplifier: VIN → 5V (power), GND → GND (ground), BCLK → GPIO38 (sound clock), LRC → GPIO39 (sound timing), and DIN → GPIO41 (sound data). Connect amplifier SPK+ to the speaker POS terminal and SPK- to the speaker NEG terminal. Connect the microphone: VDD → 3V3 (power), GND → GND (ground), SD → GPIO40 (microphone data), SCK → GPIO47 (microphone clock), WS → GPIO48 (microphone timing), and L/R → GND (left-channel selection).

  • Use a small 8-ohm speaker and mount it so its cone is not blocked.
  • The amplifier speaker terminals are a pair; neither speaker wire goes to GND.
  • Do not connect either SPK terminal to ground — it can damage the amplifier.

4. Add the home button

Connect one leg of the momentary push button to GPIO42 (button signal) and the other leg to GND (ground). A quick press returns the display to its home screen.

  • On a four-leg tactile switch, use two legs on opposite sides, not the two legs on the same connected side.
  • Do not connect the button to 5 V; the ESP32-S3 pins use 3.3 V signals.

5. Build the rechargeable power section

Connect battery BAT+ → charger B+ and battery BAT- → charger B-. Connect charger OUT+ → boost converter VIN+ and charger OUT- → boost converter VIN-. Set the boost converter to a steady 5.0 V with a multimeter before connecting it. Then connect boost VOUT+ → the project 5V rail and VOUT- → GND. The 5V rail powers the SIM7600E and amplifier; all grounds join together.

  • Use a protected 3.7 V lithium battery pack with its correct two-wire connector.
  • Charge through the TP4056 input only, using its USB input.
  • Set and measure the boost output before attaching the ESP32-S3 or modem — a setting above 5 V can damage them.
  • Never short, crush, puncture, or charge an unprotected lithium cell; a damaged battery can overheat or catch fire.

6. Power up and fit the handheld case

With power off, inspect every power and ground wire once more. Place the antenna where it has clear space, then secure the boards, battery, speaker, microphone, and screen in a non-metal case. Plug the ESP32-S3 into USB for programming while leaving the cellular power wiring connected. The home screen should appear after deployment.

  • Leave access to the TP4056 charging connector and the ESP32-S3 USB-C connector.
  • Test the screen, then the modem response, before permanently closing the case.
  • Do not enclose the LTE antenna inside metal or directly against the battery; signal strength will be poor.

Review all connections

1. Connections between "tft_touch_1" and "ESP32"

Functiontft_touch_1ESP32
powerVCC3V3
groundGNDGND
spiMOSIGPIO 11
spiMISOGPIO 13
spiSCKGPIO 12
digitalTFT_CSGPIO 10
digitalTFT_DCGPIO 14
digitalTFT_RSTGPIO 15
digitalTOUCH_CSGPIO 16

2. Connections between "lte_modem_1" and "ESP32"

Functionlte_modem_1ESP32
powerVCC5V
groundGNDGND
uartTXDGPIO 18
uartRXDGPIO 17
digitalPWRKEYGPIO 21

3. Connections between "mic_1" and "ESP32"

Functionmic_1ESP32
powerVDD3V3
groundGNDGND
dataSDGPIO 40
groundL/RGND
digitalSCKGPIO 47
digitalWSGPIO 48

4. Connections between "audio_amp_1" and "ESP32"

Functionaudio_amp_1ESP32
powerVIN5V
groundGNDGND
dataBCLKGPIO 38
dataLRCGPIO 39
dataDINGPIO 41
dataSPK+8Ω Speaker POSEXT
dataSPK-8Ω Speaker NEGEXT

5. Connections between "power_button_1" and "ESP32"

Functionpower_button_1ESP32
groundGNDGND
digitalSIGNALGPIO 42

6. Connections between "battery_1" and "ESP32"

Functionbattery_1ESP32
powerBAT+TP4056 Li-Ion/LiPo charger module with protection B+EXT
groundBAT-TP4056 Li-Ion/LiPo charger module with protection B-EXT

7. Connections between "charger_1" and "ESP32"

Functioncharger_1ESP32
powerIN+5 V USB charging inputEXT
groundIN-USB charging input groundEXT
powerOUT+Boost Converter VIN+EXT
groundOUT-Boost Converter VIN-EXT

8. Connections between "boost_5v_1" and "ESP32"

Functionboost_5v_1ESP32
powerVOUT+5V
groundVOUT-GND

Deploy the firmware

#include <Arduino.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <XPT2046_Touchscreen.h>


// Forward declarations
void drawHome();
void drawModemPage();
void queryModem();
void showModemPage();
void handleTouch();
void handleButton();

constexpr int TFT_CS_PIN = 10;
constexpr int TFT_DC_PIN = 14;
constexpr int TFT_RST_PIN = 15;
constexpr int TOUCH_CS_PIN = 16;
constexpr int MODEM_RX_PIN = 18;
constexpr int MODEM_TX_PIN = 17;
constexpr int MODEM_PWRKEY_PIN = 21;
constexpr int BUTTON_PIN = 42;

Adafruit_ILI9341 tft(TFT_CS_PIN, TFT_DC_PIN, TFT_RST_PIN);
XPT2046_Touchscreen touch(TOUCH_CS_PIN);
HardwareSerial modem(1);

const uint16_t BACKGROUND = ILI9341_BLACK;
const uint16_t PANEL = ILI9341_DARKCYAN;
const uint16_t ACCENT = ILI9341_CYAN;
const uint16_t TEXT = ILI9341_WHITE;

bool modemPage = false;
bool lastButton = HIGH;
uint32_t lastButtonChange = 0;
uint32_t lastTouch = 0;
String modemLine = "Starting modem...";

void drawHome() {
  tft.fillScreen(BACKGROUND);
  tft.fillRect(0, 0, 320, 38, PANEL);
  tft.setTextColor(TEXT, PANEL);
  tft.setTextSize(2);
  tft.setCursor(10, 11);
  tft.print("Sri Lanka Phone");

  tft.drawRoundRect(12, 58, 296, 70, 8, ACCENT);
  tft.setTextColor(TEXT, BACKGROUND);
  tft.setTextSize(2);
  tft.setCursor(28, 78);
  tft.print("Messages");
  tft.setTextSize(1);
  tft.setCursor(28, 105);
  tft.print("SMS modem link ready");

  tft.drawRoundRect(12, 145, 296, 70, 8, ACCENT);
  tft.setTextSize(2);
  tft.setCursor(28, 165);
  tft.print("Mobile network");
  tft.setTextSize(1);
  tft.setCursor(28, 192);
  tft.print("Tap for modem status");

  tft.setTextColor(ILI9341_LIGHTGREY, BACKGROUND);
  tft.setCursor(14, 224);
  tft.print("Side button returns here");
}

void drawModemPage() {
  tft.fillScreen(BACKGROUND);
  tft.fillRect(0, 0, 320, 38, PANEL);
  tft.setTextColor(TEXT, PANEL);
  tft.setTextSize(2);
  tft.setCursor(10, 11);
  tft.print("Network status");
  tft.setTextColor(TEXT, BACKGROUND);
  tft.setTextSize(1);
  tft.setCursor(14, 62);
  tft.print("SIM7600 AT response:");
  tft.fillRoundRect(14, 80, 292, 88, 6, ILI9341_NAVY);
  tft.setCursor(22, 94);
  tft.print(modemLine);
  tft.setCursor(14, 198);
  tft.setTextColor(ILI9341_YELLOW, BACKGROUND);
  tft.print("Voice calls require SLT-Mobitel VoLTE");
  tft.setCursor(14, 215);
  tft.print("provisioning on your SIM.");
}

void queryModem() {
  modemLine = "No reply yet";
  while (modem.available()) modem.read();
  modem.println("AT");
  uint32_t started = millis();
  String reply;
  while (millis() - started < 1200) {
    while (modem.available()) {
      char c = static_cast<char>(modem.read());
      if (c != '\r' && c != '\n') reply += c;
    }
  }
  if (reply.length() > 0) modemLine = reply.substring(0, 34);
  if (modemPage) drawModemPage();
}

void showModemPage() {
  modemPage = true;
  drawModemPage();
  queryModem();
}

void handleTouch() {
  if (!touch.touched() || millis() - lastTouch < 250) return;
  TS_Point p = touch.getPoint();
  lastTouch = millis();
  int screenY = map(p.x, 200, 3800, 0, 320);
  if (!modemPage && screenY > 135) showModemPage();
  else if (modemPage) {
    modemPage = false;
    drawHome();
  }
}

void handleButton() {
  bool state = digitalRead(BUTTON_PIN);
  if (state != lastButton && millis() - lastButtonChange > 35) {
    lastButtonChange = millis();
    lastButton = state;
    if (state == LOW) {
      modemPage = false;
      drawHome();
    }
  }
}

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(MODEM_PWRKEY_PIN, OUTPUT);
  digitalWrite(MODEM_PWRKEY_PIN, HIGH);

  SPI.begin(12, 13, 11, TFT_CS_PIN);
  tft.begin();
  tft.setRotation(1);
  touch.begin();
  touch.setRotation(1);
  drawHome();

  modem.begin(115200, SERIAL_8N1, MODEM_RX_PIN, MODEM_TX_PIN);
  delay(100);
  queryModem();
}

void loop() {
  handleTouch();
  handleButton();
}

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik