Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Table of Contents
=======================

* **Wiki:** please check the wiki pages for [Getting Started](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki#getting-started) and for [Troubleshooting](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki#troubleshooting)
* **⚠️ Flashing Issues?** See [BOOT0 Recovery Guide](docs/BOOT0_RECOVERY.md) if you cannot connect to the board
* [Hardware](#hardware)
* [FOC Firmware](#foc-firmware)
* [Example Variants](#example-variants)
Expand Down
7 changes: 7 additions & 0 deletions Src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@ static uint16_t rate = RATE; // Adjustable rate to support multiple drive modes
int main(void) {

HAL_Init();

// Startup delay to allow debugger connection (prevents debug lockout)
// This gives ST-Link time to connect before firmware fully initializes
for(volatile uint32_t i = 0; i < 2000000; i++) {
__NOP(); // 2 second delay at 72MHz
}

Comment on lines +176 to +182
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The delay loop is placed before SystemClock_Config() (called at line 201), so the CPU is still running on the default HSI at 8 MHz — not at 72 MHz as the comment states. At 8 MHz, the loop body executes roughly 9x faster, meaning the actual delay is on the order of ~200 ms rather than ~2 seconds. The comment "2 second delay at 72MHz" is therefore incorrect, and the delay will fail to serve its intended purpose of giving the ST-Link debugger adequate time to connect.

Consider moving the delay after SystemClock_Config() and replacing it with HAL_Delay(2000), which is clock-agnostic, readable, and guaranteed to delay for exactly 2 seconds once the clocks are properly configured.

Suggested change
// Startup delay to allow debugger connection (prevents debug lockout)
// This gives ST-Link time to connect before firmware fully initializes
for(volatile uint32_t i = 0; i < 2000000; i++) {
__NOP(); // 2 second delay at 72MHz
}
// Startup delay to allow debugger connection (prevents debug lockout)
// Use HAL_Delay for a clock-agnostic 2 second delay
HAL_Delay(2000);

Copilot uses AI. Check for mistakes.
__HAL_RCC_AFIO_CLK_ENABLE();
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* System interrupt init*/
Expand Down
150 changes: 150 additions & 0 deletions docs/BOOT0_RECOVERY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# BOOT0 Pin Recovery Guide

## When to Use This Method

If you cannot flash the board via ST-Link because:
- The firmware is blocking debug access
- ST-Link shows "unable to connect to target" or "init mode failed"
- You previously flashed firmware that prevents reprogramming
- You need to recover from a bad flash

## What is BOOT0?

BOOT0 is a special pin on the STM32F103RC microcontroller that determines boot source:
- **BOOT0 = LOW (GND)**: Normal operation - runs firmware from flash memory
- **BOOT0 = HIGH (3.3V)**: Bootloader mode - STM32 enters DFU/programming mode
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states that when BOOT0 is HIGH, the STM32 enters "DFU/programming mode." However, DFU (Device Firmware Upgrade over USB) is not available on the STM32F103RC — that family only supports a UART/SWD bootloader via the system memory boot mode. Referring to this as "DFU mode" is inaccurate and may cause users to expect USB DFU flashing to work, which it will not. The label should be corrected to "System Memory Bootloader" or "UART bootloader" mode.

Suggested change
- **BOOT0 = HIGH (3.3V)**: Bootloader mode - STM32 enters DFU/programming mode
- **BOOT0 = HIGH (3.3V)**: System memory bootloader mode - STM32 enters the factory UART bootloader (not USB DFU)

Copilot uses AI. Check for mistakes.

## Locating BOOT0 Pin

### STM32F103RC Pin Location
- **Pin 60** on the 64-pin LQFP package
- Located on the top edge, 5 pins away from Pin 1 (corner with dot marker)

### Finding BOOT0 on Your Board
Look for:
1. A test pad labeled "BOOT0", "B0", or "BOOT"
2. A solder jumper near the STM32 chip
3. A small resistor (usually 10kΩ) connected from pin 60 to GND

## Step-by-Step Recovery Process

### Method 1: Using BOOT0 Pin (Recommended)

1. **Power OFF the main board**
- Disconnect battery/power source

2. **Connect BOOT0 to 3.3V**
- Use a jumper wire to connect BOOT0 pin/pad to a 3.3V source
- Sources: ST-Link 3.3V pin, board's 3.3V rail, or any 3.3V test pad
- ⚠️ **IMPORTANT**: Use 3.3V, NOT 5V!

3. **Power ON the board**
- With BOOT0 still connected to 3.3V, power on the board
- The STM32 will now enter bootloader mode
- You can release/disconnect BOOT0 after power-on (it only matters during startup)

4. **Flash the firmware**
```bash
pio run --target upload
```
Or use the flash script:
```bash
./flash_board.ps1
```
Comment on lines +50 to +53
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation references ./flash_board.ps1 as a flashing script, but no such file exists anywhere in the repository. This will confuse users who follow this guide. Either remove this reference or add the missing script to the repository.

Suggested change
Or use the flash script:
```bash
./flash_board.ps1
```

Copilot uses AI. Check for mistakes.

5. **Restore normal operation**
- Power OFF the board
- Disconnect BOOT0 from 3.3V (let it return to GND via pull-down resistor)
- Power ON the board - it will now run your new firmware

### Method 2: Using ST-Link Utility (Alternative)

If you have ST-Link Utility software:

1. Open ST-Link Utility
2. Go to **Target** → **Settings**
3. Enable **"Connect Under Reset"** mode
4. Click OK
5. Power cycle the board and immediately click **Target** → **Connect**
6. Once connected, go to **Target** → **Erase Chip**
7. After erasing, flash your new firmware normally

### Method 3: Power Cycle Timing

This method requires precise timing:

1. In ST-Link Utility, enable "Connect Under Reset"
2. Disconnect board power
3. Click Connect in ST-Link Utility (it will wait for connection)
4. Immediately reconnect power to the board
5. ST-Link should catch the chip during the brief boot window

## Prevention: Firmware Startup Delay

As of the latest firmware update, all variants include a 2-second startup delay. This gives debuggers time to connect before the firmware fully initializes, preventing debug lockout.

If you're using older firmware, you can add this delay manually in `Src/main.c`:

```c
int main(void) {
HAL_Init();

// Startup delay to allow debugger connection
for(volatile uint32_t i = 0; i < 2000000; i++) {
__NOP(); // 2 second delay
}

// Rest of initialization...
}
```
Comment on lines +88 to +99
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline code snippet in the "Prevention: Firmware Startup Delay" section has the same bug as the actual code: it presents the loop with the magic count 2000000 alongside the comment // 2 second delay, without accounting for the fact that this runs at 8 MHz HSI (before SystemClock_Config()). Documentation users copying this snippet will face the same timing issue. The example should be updated to use HAL_Delay(2000) placed after SystemClock_Config(), or at minimum note that the loop count needs to be calibrated against the actual clock speed when placed before clock configuration.

Copilot uses AI. Check for mistakes.

## Common Pin Labels

- **BOOT0**: Most common label
- **B0**: Abbreviated version
- **BOOT**: Generic boot pin
- May be unlabeled - look for a 10kΩ resistor to ground from pin 60

## Important Notes

⚠️ **Safety Warnings:**
- Always use **3.3V** for BOOT0, never 5V
- Do not confuse BOOT0 with other pins:
- PF0/PF1 are crystal oscillator pins - do not touch!
- PC12 is a GPIO pin, not BOOT0
- BOOT0 only needs to be HIGH during power-on/reset

💡 **Tips:**
- BOOT0 only matters during chip startup/reset
- Once in bootloader mode, you can release BOOT0
- The pull-down resistor automatically returns BOOT0 to LOW when disconnected
- If your board has a BOOT0 button, just hold it while powering on

## Troubleshooting

**ST-Link still can't connect in bootloader mode:**
- Verify BOOT0 is actually at 3.3V (use multimeter)
- Check ST-Link connections (SWDIO, SWCLK, GND)
- Ensure board is powered
- Try different USB port or ST-Link cable

**Board won't run firmware after flashing:**
- Make sure BOOT0 is disconnected from 3.3V
- Power cycle the board
- Check that BOOT0 has returned to GND (via pull-down resistor)

**Can't find BOOT0 pin:**
- Search for STM32F103RC datasheet for pin 60 location
- Trace from pin 60 on the chip to find test pad
- Look for resistors near the STM32 chip going to ground

## Additional Resources

- [STM32F103RC Datasheet](https://www.st.com/resource/en/datasheet/stm32f103rc.pdf)
- [AN2606: STM32 Bootloader Documentation](https://www.st.com/resource/en/application_note/cd00167594.pdf)
- [Project Wiki](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki)

---

**Last Updated:** March 2026
**Applies to:** All firmware variants (ADC, USART, NUNCHUK, PPM, PWM, IBUS, HOVERCAR, HOVERBOARD, TRANSPOTTER, SKATEBOARD)
Loading