From b9be8cbebca233c14fe2f17f152400e8b0f8ed6e Mon Sep 17 00:00:00 2001 From: Salty Date: Fri, 13 Mar 2026 17:20:09 -0400 Subject: [PATCH] Add FSESC 4.20 Plus hardware reference wiki page Complete documentation of Flipsky Dual FSESC 4.20 Plus: - Full STM32F405 pin mapping from hw_410.h - All connectors and headers identified - ADC, voltage/current sensing, NTC formulas - Operating limits (firmware-enforced) - BMI160 IMU wiring problem documented (UART != I2C) - Pin conflict/multiplexing reference table - CAN bus setup (CANable 2.0, python-can) - VESC Tool access (VNC, vesc-cli.py) - Current config state and lessons learned --- FSESC-4.20-Plus.md | 314 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 FSESC-4.20-Plus.md diff --git a/FSESC-4.20-Plus.md b/FSESC-4.20-Plus.md new file mode 100644 index 0000000..a2d8bd9 --- /dev/null +++ b/FSESC-4.20-Plus.md @@ -0,0 +1,314 @@ +# 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: + +1. **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. + +2. **Solder directly to STM32** — PB10 = pin 69, PB11 = pin 70 on LQFP64 package. Tiny but doable with fine solder and a magnifier. + +3. **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: +```bash +# 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 +```bash +# 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 +```python +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 + +1. **UART ≠ I2C on HW 410.** The UART header (PC6/PC7) and I2C bus (PB10/PB11) use completely different GPIO pins. Always check `hw_xxx.h` before wiring. + +2. **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. + +3. **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. + +4. **`permanent_uart_enabled` is persistent.** Changing it in VESC Tool GUI doesn't stick — may need terminal command or direct config binary write. + +5. **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](https://github.com/vedderb/bldc) — `hwconf/other/vesc4/hw_410.h` +- **External IMU wiring (VESC 6):** [pev.dev/t/external-imu-wiring/294](https://pev.dev/t/external-imu-wiring/294) +- **BMI160 for VESC balance:** [spintend.com](https://spintend.com/products/bmi-160-module-for-diy-balanced-board-with-vesc) +- **VESC project:** [vesc-project.com](https://vesc-project.com)