WEEK #04

EMBEDDED PROGRAMMING

Awakening the Machine: Logic, Datasheets & Silicon

01. GROUP ASSIGNMENT

COMPARED!
MISSION LOG: ARCHITECTURE COMPARISON AND EMBEDDED PROGRAMMING

Read the full group report here:

📂 OPEN GROUP ASSIGNMENT

02. DATASHEET RECONNAISSANCE

VS BATTLE!
MISSION LOG: SELECTING THE CHAMPION
I compared the classic ESP32-WROOM against my choice, the ESP32-S3. I needed more pins and native USB support.

Why did I selected the S3? It has more GPIOs, better ADC channels, native USB and the crown jewel, it has acceleration for AI. The WROOM is a solid chip but felt limited for my project goals.
FEATURE ESP32-WROOM-32 ESP32-S3 (My Choice)
🧠 SRAM 520 KB 512 KB + Ext. PSRAM
🔌 GPIO Pins ~34 Pines 45 Pines (More sensors!)
🎛️ ADC (Analog) 12 Channels (Old) 20 Channels (New)
📡 Connectivity BT 4.2 / No USB BT 5.0 / Native USB
💻 Languages C++, MicroPython C++, CircuitPython, Rust
MAP FIGHT!
MISSION LOG: VISUAL PINOUT COMPARISON
Looking at the diagrams, the S3 exposes more GPIOs directly. Note specifically the USB D+/D- pins on the S3 (GPIO 19/20) which allow direct PC connection.
ESP32 WROOM Pinout

VS 1. The Classic ESP32-WROOM

ESP32 S3 Pinout

VS 2. The Modern ESP32-S3 (Winner)

⬇️ DOWNLOAD S3 DATASHEET (PDF)

03. PROGRAMMING WORKFLOW

MISSION LOG: THE LOGIC STRATEGY
To program the board, I used **Visual Studio Code (VS Code)**. It offers superior IntelliSense, Git integration, and a better workflow than the standard Arduino IDE.
  • 1. ENVIRONMENT (IDE):
    I set up the project in VS Code using the PlatformIO extension. This manages the toolchain and dependencies for the ESP32-S3 automatically.
  • 2. INITIALIZATION:
    I initialized Serial Communication at 115200 baud. I configured the Button Pin as INPUT_PULLUP to use the internal resistor, ensuring a stable HIGH signal when idle.
  • 3. THE ALGORITHM:
    The code constantly monitors the GPIO state.
    IF Sensor == LOW (Active) 👉 Turn LED ON (Output) + Print "GOAL DETECTED" to Serial Monitor (Comm).
WOKWI!
PHASE A: VIRTUAL PROTOTYPE
Before flashing the real chip, I validated the C++ logic using Wokwi Simulator.

Video 1. SIMULATING THE CIRCUIT

PHASE B: THE SOURCE CODE (C++)
This is the main.cpp file deployed to the board.

             
#include 

const int ALERT_PIN = 5;   
const int SENSOR_PIN = 4;   

void setup() {
  Serial.begin(115200);
  
  pinMode(SENSOR_PIN, INPUT_PULLUP); 
  pinMode(ALERT_PIN, OUTPUT);
  
  Serial.println(">>> HARDWARE READY: push the button to simmulate a goal");
}

void loop() {

  if (digitalRead(SENSOR_PIN) == LOW) {
    
    digitalWrite(ALERT_PIN, HIGH); 
    Serial.println("Goal detected");
    
    delay(1000); 
    
    digitalWrite(ALERT_PIN, LOW);  
  }
}
   
IT WORKS!
PHASE C: PHYSICAL DEPLOYMENT

I assembled the circuit on a breadboard. The button simulates the ball hitting the goal, the serial monitor shows the system's response, and the LED represents the alarm system activating. The ESP32-S3 is the brain of this operation, running the code we just saw.

I connected the ESP32-S3 via USB-C. Using the PlatformIO Upload task in VS Code, I flashed the firmware. The physical LED responds exactly as programmed.

Video 2. PHYSICAL DEPLOYMENT OF THE CIRCUIT

04. THE DATA LINK

LIVE!
MISSION LOG: ESTABLISHING CONTACT
I programmed a simulation: The Button acts as a goal sensor. When pressed, the ESP32 generates random "Ball Speed" data and sends it to the PC.

System Response:
1. 🔴 Input: Physical Button (GPIO 4).
2. 🟢 Output: Physical LED (GPIO 5)

Video 3. Testing the Input/Output loop. The Serial Monitor displays the "Goal" data in real-time.

MISSION LOG: INTELLIGENT FEEDBACK
I didn't just send data; I made the board listen. If I type a number (e.g., "5") in the Serial Monitor, the board calculates the average speed of the last 5 shots.
#include 

const int PIN_BOTON = 4;    
const int PIN_LED   = 5;    

const int MAX_HISTORIAL = 50;
float historialVelocidades[MAX_HISTORIAL];
int indiceActual = 0;      
int totalTiros = 0;        

bool botonPresionado = false;

void setup() {
  Serial.begin(115200);
  
  pinMode(PIN_BOTON, INPUT_PULLUP);
  pinMode(PIN_LED, OUTPUT);

  randomSeed(analogRead(0));

  Serial.println(">>> READY <<<");
  Serial.println("1. PRESS BUTTON TO SIMULATE A SHOOT.");
  Serial.println("2. WRITE A NUMBER (example: '5') to check the average of the last 5 shots");
  Serial.println("----------------------------------------------------------------");
}

void loop() {

  if (digitalRead(PIN_BOTON) == LOW) {
    if (!botonPresionado) { 
      botonPresionado = true;      
    
      digitalWrite(PIN_LED, HIGH);

      float velocidad = random(400, 950) / 10.0;       

      float posX = random(-350, 350) / 100.0;
    
      float posY = random(10, 240) / 100.0;

      historialVelocidades[indiceActual] = velocidad;  

      indiceActual = (indiceActual + 1) % MAX_HISTORIAL;
      totalTiros++;

      Serial.print("(!) GOAL #" + String(totalTiros) + " | ");
      Serial.print("Speed: " + String(velocidad, 1) + " km/h | ");
      Serial.println("Pos: (" + String(posX) + "m, " + String(posY) + "m)");

      delay(200);
    }
  } else {
    botonPresionado = false;
    digitalWrite(PIN_LED, LOW);
  }

  if (Serial.available() > 0) {

    String texto = Serial.readStringUntil('\n');
    int cantidad = texto.toInt(); 

    if (cantidad > 0 && cantidad <= 50) {
      if (cantidad > totalTiros) {
        Serial.println(">> ERROR: " + String(totalTiros) + " shots registered.");
      } else {

        float suma = 0;
        int contados = 0;

        int idx = indiceActual - 1; 
        
        while (contados < cantidad) {
          if (idx < 0) idx = MAX_HISTORIAL - 1; 
          suma += historialVelocidades[idx];
          idx--;
          contados++;
        }
        
        float promedio = suma / cantidad;
        
        Serial.println("--------------------------------");
        Serial.println(">> AVERAGE:");
        Serial.println("   LAST " + String(cantidad) + " SHOTS.");
        Serial.println("   AVERAGE SPEED: " + String(promedio, 1) + " km/h");
        Serial.println("--------------------------------");
      }
    } else {
      Serial.println(">> Please write a number between 2 and 50.");
    }
  }
}

The Serial Monitor shows real-time data of each "goal". When I input a number, it calculates the average speed of the last shots, demonstrating a two-way communication link. Even if the number exceeds the total shots, it handles the error gracefully.