Table of Contents
- FSESC 4.20 Plus — Hardware Reference
- Overview
- Role in SaltyLab
- STM32F405 Pin Mapping (from hw_410.h)
- UART (USART6)
- I2C (I2C2) — External IMU
- Hall Sensor / Encoder
- SPI (SPI1)
- PPM / Servo Input (ICU)
- LEDs
- Control Signals
- ADC Channels
- Voltage / Current Sensing
- NTC Temperature Sensing
- Operating Limits (firmware-enforced)
- Physical Connectors (Flipsky FSESC 4.20 Plus)
- BMI160 IMU Wiring
- ❌ What DOESN'T Work
- ✅ What's Needed
- BMI160 I2C Wiring (once correct pins found)
- Diagnostic: Test BMI160 on Orin First
- VESC Tool Access
- CAN Bus Setup (Orin ↔ VESC)
- VESC Configuration (Current State)
- Pin Conflict / Multiplexing Reference
- Lessons Learned
- References
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
FSESC 4.20 Plus — Hardware Reference
Overview
| Parameter | Value |
|---|---|
| Model | Flipsky Dual FSESC 4.20 Plus |
| Hardware Version | HW 410 (VESC 4.20) |
| Firmware | VESC FW 6.6 (vedderb/bldc) |
| MCU | STM32F405RGT6 (×2, one per ESC) |
| Voltage Range | 8V–60V (3–13S LiPo) |
| Current (per ESC) | 50A continuous, 150A burst |
| Current (dual total) | 100A continuous, 300A burst |
| BEC Output | 5V @ 1.5A |
| CAN Bus | Between both ESCs (internal), external header |
| Our CAN IDs | 61 (USB-connected ESC), 79 (secondary) |
| USB | STM32 Virtual COM Port → /dev/ttyACM1 on Orin |
| Firmware source | hwconf/other/vesc4/hw_410.h in vedderb/bldc |
Role in SaltyLab
As of 2026-03-12, the VESC replaced the MAMBA F722S flight controller + hoverboard ESC entirely. The VESC now handles:
- Motor control — FOC for both hub motors
- Balance PID — via VESC balance app (internal)
- CAN communication — with Orin via CANable 2.0
Architecture: Orin ↔ CAN ↔ VESC (balance + motors)
STM32F405 Pin Mapping (from hw_410.h)
UART (USART6)
| Pin | GPIO | Function |
|---|---|---|
| TX | PC6 | USART6 TX |
| RX | PC7 | USART6 RX |
Header: "UART" / "Header 6" on PCB — the JST header labeled TX/RX.
⚠️ This is NOT I2C. UART and I2C are on completely different pins.
I2C (I2C2) — External IMU
| Pin | GPIO | Function |
|---|---|---|
| SCL | PB10 | I2C2 SCL |
| SDA | PB11 | I2C2 SDA |
⚠️ CRITICAL: PB10/PB11 are NOT on the UART header. They share GPIO port B with hall sensor pins but are DIFFERENT pins (PB10/PB11 vs PB6/PB7).
Note: PB10/PB11 are also USART3 TX/RX (alternate function). On the original VESC 4.12 design, these go to the "COMM" header. On the Flipsky 4.20 Plus, their physical location needs to be traced on the PCB — they may be on the COMM port, an unpopulated header, or not broken out at all.
Hall Sensor / Encoder
| Pin | GPIO | Function |
|---|---|---|
| H1 | PB6 | Hall sensor 1 / Encoder A |
| H2 | PB7 | Hall sensor 2 / Encoder B |
| H3 | PC11 | Hall sensor 3 / Encoder Z |
Header: 6-pin JST "HALL" / "SENSOR" connector (H1, H2, H3, 5V, Temp, GND).
Note: These are NOT the I2C pins despite being in port B.
SPI (SPI1)
| Pin | GPIO | Function |
|---|---|---|
| NSS | PA4 | SPI1 NSS (chip select) |
| SCK | PA5 | SPI1 SCK |
| MISO | PA6 | SPI1 MISO |
| MOSI | PA7 | SPI1 MOSI |
Used for DRV8302/DRV8301 gate driver communication (internal, not user-accessible).
PPM / Servo Input (ICU)
| Pin | GPIO | Function |
|---|---|---|
| PPM | PB5 | TIM3_CH2 — servo/PPM input capture |
Header: Combined with UART header on "Header 6" (typically: VCC, GND, PPM, RX, TX).
LEDs
| Pin | GPIO | Function |
|---|---|---|
| Green | PC4 | Status LED (active high) |
| Red | PC5 | Fault LED (active high) |
Control Signals
| Pin | GPIO | Function |
|---|---|---|
| Gate Enable | PC10 | DRV gate driver enable (active high) |
| DC Cal | PB12 | DC offset calibration |
| DRV Fault | PC12 | DRV fault detect (active low) |
ADC Channels
| ADC Index | Channel | GPIO | Function |
|---|---|---|---|
| 0 | IN0 | PA0 | Phase C sense (SENS3) |
| 1 | IN1 | PA1 | Phase B sense (SENS2) |
| 2 | IN2 | PA2 | Phase A sense (SENS1) |
| 3 | IN8 | PB0 | Motor current 2 |
| 4 | IN9 | PB1 | Motor current 1 |
| 5 | IN3 | PA3 | MOSFET temperature (NTC) |
| 7 | IN6 | PA6 | ADC_EXT2 |
| 8 | IN12 | PC2 | Input voltage (Vin) |
| 10 | IN5 | PA5 | ADC_EXT |
| 11 | IN3 | PA3 | Motor temperature (NTC) |
Voltage / Current Sensing
| Parameter | Value |
|---|---|
| Vref | 3.3V |
| Vin divider R1 | 39kΩ |
| Vin divider R2 | 2.2kΩ |
| Vin ratio | 18.73:1 |
| Current shunt | 0.001Ω |
| Current amp gain | 10× |
| Max measurable Vin | ~57V |
Formula: Vin = (ADC_raw / 4095) × 3.3V × (39000 + 2200) / 2200
NTC Temperature Sensing
- FET thermistor: 10kΩ NTC, β=3434, pullup to 3.3V
- Motor thermistor: 10kΩ NTC (low-side), β configurable
- Formula:
R = (4095 × 10000) / ADC_val - 10000→T = 1 / (ln(R/10000)/3434 + 1/298.15) - 273.15
Operating Limits (firmware-enforced)
| Limit | Min | Max |
|---|---|---|
| Motor current | -100A | 100A |
| Battery current | -100A | 100A |
| Absolute current | 0A | 150A |
| Input voltage | 6V | 57V |
| ERPM | -200,000 | 200,000 |
| Duty min | 0% | 10% |
| Duty max | 0% | 95% |
| FET temp | -40°C | 110°C |
Physical Connectors (Flipsky FSESC 4.20 Plus)
┌─────────────────────────────────────────────┐
│ FSESC 4.20 Plus (Top View) │
│ │
│ ┌──────┐ ┌──────┐ │
│ │ ESC 1│ │ ESC 2│ (each has own STM32) │
│ │CAN 61│ │CAN 79│ │
│ └──┬───┘ └──┬───┘ │
│ │ CAN bus │ │
│ └────┬─────┘ │
│ │ │
│ Headers (edge of board): │
│ ┌─────┐ ┌─────┐ ┌──────┐ ┌─────┐ ┌──────┐ │
│ │MOTOR│ │MOTOR│ │HALL×2│ │UART │ │BATT │ │
│ │ 1 │ │ 2 │ │ │ │+PPM │ │ XT60 │ │
│ └─────┘ └─────┘ └──────┘ └─────┘ └──────┘ │
│ │
│ Also: USB-C, CAN header, anti-spark switch │
└─────────────────────────────────────────────┘
Connector List
| Connector | Type | Pins | Notes |
|---|---|---|---|
| Motor 1 | 3-phase | A, B, C | Thick gauge wires to hub motor |
| Motor 2 | 3-phase | A, B, C | Thick gauge wires to hub motor |
| Battery | XT60 | +, − | Main power input (with anti-spark) |
| USB | USB-C or Micro-B | Data + 5V | Config via VESC Tool |
| HALL 1 | 6-pin JST | H1(PB6), H2(PB7), H3(PC11), 5V, Temp, GND | Motor 1 hall/encoder |
| HALL 2 | 6-pin JST | Same pinout | Motor 2 hall/encoder |
| UART/PPM | JST | PPM(PB5), TX(PC6), RX(PC7), 5V, GND | NOT I2C! |
| CAN | 2-pin JST | CANH, CANL | External CAN bus (to CANable 2.0) |
| COMM | 4-pin JST (if present) | Possibly PB10/PB11 | Needs PCB tracing — see I2C section |
BMI160 IMU Wiring
❌ What DOESN'T Work
Wiring BMI160 to the UART header (TX=PC6, RX=PC7). These are USART6 pins — completely different GPIOs from the I2C2 peripheral (PB10/PB11). No amount of firmware config will make UART pins do I2C on this chip.
✅ What's Needed
BMI160 must connect to PB10 (SCL) and PB11 (SDA) — the I2C2 bus. Options:
-
COMM header — On original VESC 4.12, PB10/PB11 are brought out to a COMM connector. Flipsky may or may not have this. We tried "Header 11" which might be COMM — got zeros, but BMI160 chip may be dead or wrong orientation.
-
Solder directly to STM32 — PB10 = pin 69, PB11 = pin 70 on LQFP64 package. Tiny but doable with fine solder and a magnifier.
-
Run IMU from Orin instead — Wire BMI160 to Orin GPIO I2C (Pin 3=SDA, Pin 5=SCL on J12 header), read IMU data on Orin, feed orientation to VESC over CAN. VESC balance app can accept external IMU data over CAN.
BMI160 I2C Wiring (once correct pins found)
| BMI160 Pin | VESC Pin | Notes |
|---|---|---|
| VCC/VIN | 3.3V or 5V | Breakout has onboard 3.3V regulator |
| GND | GND | Common ground |
| SCL | PB10 (I2C2 SCL) | NOT PC6! |
| SDA | PB11 (I2C2 SDA) | NOT PC7! |
| SA0/AD0 | GND | Sets I2C address to 0x68 (VESC default) |
Diagnostic: Test BMI160 on Orin First
Before fighting with VESC pins, verify the chip is alive:
# Wire BMI160 to Orin J12: Pin 3 (SDA), Pin 5 (SCL), Pin 1 (3.3V), Pin 6 (GND)
sudo i2cdetect -y -r 1
# Should show 0x68 (or 0x69 if SA0 is high)
VESC Tool Access
| Method | Details |
|---|---|
| Direct USB | Plug USB into laptop, open VESC Tool |
| VNC on Orin | ssh seb@192.168.86.158, VNC at :5901 (pw: vesc) |
| vesc-cli.py | /home/seb/vesc-cli.py — status, scan, spin, stop, term, imu, balance |
| VESC Tool path | /usr/local/bin/vesc_tool (built from source, arm64 Qt5) |
vesc-cli.py Quick Reference
# Status of USB-connected VESC
python3 vesc-cli.py status
# Scan CAN bus for all VESCs
python3 vesc-cli.py scan
# Spin motor at 5% duty for 2 seconds
python3 vesc-cli.py spin 5 -t 2
# Spin CAN-connected motor (ID 79)
python3 vesc-cli.py -c 79 spin 5 -t 2
# Stop motor
python3 vesc-cli.py stop
# Send terminal command
python3 vesc-cli.py term faults
# IMU info
python3 vesc-cli.py imu
CAN Bus Setup (Orin ↔ VESC)
| Component | Details |
|---|---|
| Adapter | CANable 2.0 (USB-to-CAN) |
| Orin device | /dev/ttyACM0 |
| Mode | slcan (via python-can — kernel lacks gs_usb/slcan modules on Tegra) |
| Bitrate | 500kbps (VESC default) |
| CAN IDs | ESC 1 = 61, ESC 2 = 79 |
python-can Usage
import can
bus = can.Bus(interface='slcan', channel='/dev/ttyACM0', bitrate=500000)
for msg in bus:
print(f"ID: {msg.arbitration_id:#x} Data: {msg.data.hex()}")
VESC Configuration (Current State)
| Setting | Value | Notes |
|---|---|---|
| app_to_use | 1 (PPM) | Changed from 3 (PPM_UART) to free UART pins |
| IMU type | 4 (BMI160) | Set but not working — wrong wiring (see above) |
| permanent_uart | 1 | Stubbornly stays enabled — GUI change doesn't persist |
| Motor detection | Done | Via VESC Tool GUI (2026-03-12) |
| Battery voltage | 32.8V | Measured 2026-03-12 |
Pin Conflict / Multiplexing Reference
This table clarifies which STM32F405 pins serve which function — the #1 source of wiring confusion:
| GPIO | Primary (HW 410) | Alternate Functions | Header |
|---|---|---|---|
| PA0 | Phase C sense (ADC) | USART2_CTS, TIM2_CH1 | Internal |
| PA1 | Phase B sense (ADC) | USART2_RTS, TIM2_CH2 | Internal |
| PA2 | Phase A sense (ADC) | USART2_TX, TIM2_CH3 | Internal |
| PA3 | FET temp (ADC) | USART2_RX, TIM2_CH4 | Internal |
| PA4 | SPI1 NSS (DRV) | — | Internal |
| PA5 | SPI1 SCK (DRV) | ADC_EXT | Internal |
| PA6 | SPI1 MISO (DRV) | ADC_EXT2 | Internal |
| PA7 | SPI1 MOSI (DRV) | — | Internal |
| PB0 | Motor current 2 (ADC) | — | Internal |
| PB1 | Motor current 1 (ADC) | — | Internal |
| PB5 | PPM input (TIM3_CH2) | — | UART/PPM header |
| PB6 | Hall 1 | USART1_TX, TIM4_CH1 | HALL header |
| PB7 | Hall 2 | USART1_RX, TIM4_CH2 | HALL header |
| PB10 | I2C2 SCL | USART3_TX, TIM2_CH3 | COMM header? |
| PB11 | I2C2 SDA | USART3_RX, TIM2_CH4 | COMM header? |
| PB12 | DC calibration | — | Internal |
| PC2 | Vin sense (ADC) | — | Internal |
| PC4 | LED green | — | On-board |
| PC5 | LED red | — | On-board |
| PC6 | USART6 TX | TIM3_CH1 | UART header |
| PC7 | USART6 RX | TIM3_CH2 | UART header |
| PC10 | Gate enable | — | Internal |
| PC11 | Hall 3 | EXTI | HALL header |
| PC12 | DRV fault | — | Internal |
Key takeaway: PB10/PB11 (I2C/COMM) and PC6/PC7 (UART) are on completely different pins and headers. Connecting an I2C device to the UART header will never work on HW 410.
Lessons Learned
-
UART ≠ I2C on HW 410. The UART header (PC6/PC7) and I2C bus (PB10/PB11) use completely different GPIO pins. Always check
hw_xxx.hbefore wiring. -
VESC 4.x vs VESC 6+ differences. On VESC 6+ boards, the COMM header often multiplexes TX/SCL and RX/SDA on the same pins. On VESC 4.x (HW 410), UART and I2C are physically separate peripherals on separate pins.
-
Verify pin accessibility before buying peripherals. We ordered the BMI160 for VESC use without confirming that PB10/PB11 are broken out on the Flipsky board.
-
permanent_uart_enabledis persistent. Changing it in VESC Tool GUI doesn't stick — may need terminal command or direct config binary write. -
Each ESC has its own STM32. The dual board is two independent VESCs connected by CAN. Config changes to one don't affect the other.
References
- VESC firmware source: vedderb/bldc —
hwconf/other/vesc4/hw_410.h - External IMU wiring (VESC 6): pev.dev/t/external-imu-wiring/294
- BMI160 for VESC balance: spintend.com
- VESC project: vesc-project.com