I'm starting a new tutorial where I make a fully homemade ebike from scratch. Homemade motor from a car alterantor, homemade battery and homemade ESC with regenerative braking. That's what we will make today!
by: ELECTRONOOBS on 2026-08-30

To solder the buck converter we first need to fill the exposed tracks below with solder because we can't do it later. I will eventually fill all exposed tracks with solder.
Then add the current sensor. I’m using the ACS758 bidirectional 50A sensor. Also solder the fuse clips and the input connectors. I’ve also added the first input capacitor of 1000uF and 50V together with the TVS diode. This diode will protect the circuit from voltage peaks, because we have a lot of those.
Add the voltage regulators for 12 and 3.3V. Once power is ready we add the MOSFETs, drivers, small pins, ESP32 and the rest. Check schematic for the values!

/*
* BLDC Static Commutation - Serial Buffer Patch (Core v3.x Fix)
* Target: Electronoobs Custom ESC v1.0 (IRFZ44N check)
* Purpose: Safe logic verification with pure digital writes via direct polling loop.
* Clears GPIO 15 hardware conflicts for flawless serial telemetry output.
*/
#include "soc/io_mux_reg.h"
// --- PIN DEFINITIONS FROM PHYSICAL LAYOUT ---
const int PIN_HIN_A = 12;
const int PIN_LIN_A = 13;
const int PIN_HIN_B = 14;
const int PIN_LIN_B = 27;
const int PIN_HIN_C = 25;
const int PIN_LIN_C = 26;
const int PIN_DRIVER_SD = 32;
// Motor Internal Hall Sensors Pins (Patched order to GPIO 15)
const int PIN_HALL_1 = 4;
const int PIN_HALL_2 = 3; // Patched to GPIO 15 (MTDO pin)
const int PIN_HALL_3 = 39;
// Analog Inputs for Control
const int PIN_THROTTLE_POT = 36;
// Global variables
byte hallState = 0;
void setup() {
// Initialize Serial Monitor at 115200 baud
Serial.begin(115200);
delay(1000); // Critical delay to allow the USB bridge to clear garbage bytes
Serial.println("\n=============================================");
Serial.println("--- SYSTEM BOOT: Electronoobs Buffer Patch ---");
Serial.println("=============================================");
// CRITICAL REGULATORY FIX FOR GPIO 15: Overrides MTDO/JTAG internal function
// Forces Pin 15 register to act purely as a standard GPIO line using Core v3.x macros
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_MTDO_GPIO15);
// Set all driver control pins as standard digital outputs
pinMode(PIN_HIN_A, OUTPUT); pinMode(PIN_LIN_A, OUTPUT);
pinMode(PIN_HIN_B, OUTPUT); pinMode(PIN_LIN_B, OUTPUT);
pinMode(PIN_HIN_C, OUTPUT); pinMode(PIN_LIN_C, OUTPUT);
// Force clean safe state
allPhasesOff();
// Configure SD Pin and force LOW to enable driver hardware
pinMode(PIN_DRIVER_SD, OUTPUT);
digitalWrite(PIN_DRIVER_SD, LOW);
// Configure Motor Hall inputs
pinMode(PIN_HALL_1, INPUT);
pinMode(PIN_HALL_2, INPUT);
pinMode(PIN_HALL_3, INPUT);
Serial.println("[INFO] Setup complete. Buffer cleared. Entering Loop.");
}
void loop() {
// Read physical Hall sensors via direct polling loop
byte h1 = digitalRead(PIN_HALL_1);
byte h2 = digitalRead(PIN_HALL_2);
byte h3 = digitalRead(PIN_HALL_3);
// Pack bits into standard 3-bit pattern
hallState = (h1 << 2) | (h2 << 1) | h3;
// Execute static digital commutation directly based on the polished status
commuteMotorStatic(hallState);
// Read Potentiometer safely
int potValue = analogRead(PIN_THROTTLE_POT);
// Throttled Telemetry output loop to ensure zero buffer overloading
static unsigned long lastLog = 0;
if (millis() - lastLog > 300) {
Serial.print("[ALIVE] Pot: "); Serial.print(potValue);
Serial.print(" | Hall Binary Pattern: 0b");
if (hallState < 0b100) Serial.print("0");
if (hallState < 0b010) Serial.print("0");
Serial.println(hallState, BIN);
lastLog = millis();
}
}
// 6-Step Pure Digital Commutation Table (Static execution for easy multimeter tracking)
void commuteMotorStatic(byte state) {
switch (state) {
case 0b101: // Step 1
digitalWrite(PIN_HIN_A, HIGH); digitalWrite(PIN_LIN_A, LOW);
digitalWrite(PIN_HIN_B, LOW); digitalWrite(PIN_LIN_B, HIGH);
digitalWrite(PIN_HIN_C, LOW); digitalWrite(PIN_LIN_C, LOW);
break;
case 0b001: // Step 2
digitalWrite(PIN_HIN_A, HIGH); digitalWrite(PIN_LIN_A, LOW);
digitalWrite(PIN_HIN_B, LOW); digitalWrite(PIN_LIN_B, LOW);
digitalWrite(PIN_HIN_C, LOW); digitalWrite(PIN_LIN_C, HIGH);
break;
case 0b011: // Step 3
digitalWrite(PIN_HIN_A, LOW); digitalWrite(PIN_LIN_A, LOW);
digitalWrite(PIN_HIN_B, HIGH); digitalWrite(PIN_LIN_B, LOW);
digitalWrite(PIN_HIN_C, LOW); digitalWrite(PIN_LIN_C, HIGH);
break;
case 0b010: // Step 4
digitalWrite(PIN_HIN_A, LOW); digitalWrite(PIN_LIN_A, HIGH);
digitalWrite(PIN_HIN_B, HIGH); digitalWrite(PIN_LIN_B, LOW);
digitalWrite(PIN_HIN_C, LOW); digitalWrite(PIN_LIN_C, LOW);
break;
case 0b110: // Step 5
digitalWrite(PIN_HIN_A, LOW); digitalWrite(PIN_LIN_A, HIGH);
digitalWrite(PIN_HIN_B, LOW); digitalWrite(PIN_LIN_B, LOW);
digitalWrite(PIN_HIN_C, HIGH); digitalWrite(PIN_LIN_C, LOW);
break;
case 0b100: // Step 6
digitalWrite(PIN_HIN_A, LOW); digitalWrite(PIN_LIN_A, LOW);
digitalWrite(PIN_HIN_B, LOW); digitalWrite(PIN_LIN_B, HIGH);
digitalWrite(PIN_HIN_C, HIGH); digitalWrite(PIN_LIN_C, LOW);
break;
default: // Fault state (0b000 or 0b111) -> Complete isolation
allPhasesOff();
break;
}
}
void allPhasesOff() {
digitalWrite(PIN_HIN_A, LOW); digitalWrite(PIN_LIN_A, LOW);
digitalWrite(PIN_HIN_B, LOW); digitalWrite(PIN_LIN_B, LOW);
digitalWrite(PIN_HIN_C, LOW); digitalWrite(PIN_LIN_C, LOW);
}
Leave a comment
Please login in order to comment.