collapse detector with gdb support
This commit is contained in:
parent
858ba81923
commit
735b786b65
|
|
@ -0,0 +1,239 @@
|
||||||
|
# ESP32-C5 WiFi Monitor GDB Configuration
|
||||||
|
# Auto-loaded for WiFi frame analysis with PHY rate and duration
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# THRESHOLD TUNING COMMANDS
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
define show_thresholds
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
printf "WiFi Monitor Thresholds (GDB-tunable)\n"
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
printf "High NAV threshold: %u us\n", threshold_high_nav_us
|
||||||
|
printf "Duration mismatch log: %u us\n", threshold_duration_mismatch_us
|
||||||
|
printf "PHY rate fallback: %u Mbps\n", threshold_phy_rate_fallback_mbps
|
||||||
|
printf "Duration multiplier: %ux expected\n", threshold_duration_multiplier
|
||||||
|
printf "\n"
|
||||||
|
printf "Collapse Detection:\n"
|
||||||
|
printf " Retry rate threshold: %.1f%%\n", threshold_retry_rate_percent
|
||||||
|
printf " Avg NAV collapse: %u us\n", threshold_avg_nav_collapse_us
|
||||||
|
printf " Collision percentage: %.1f%%\n", threshold_collision_percent
|
||||||
|
printf " Mismatch percentage: %.1f%%\n", threshold_mismatch_percent
|
||||||
|
printf "\n"
|
||||||
|
printf "Logging Control:\n"
|
||||||
|
printf " Log every N mismatches: %u (1=all, 10=every 10th)\n", log_every_n_mismatches
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
define set_high_nav
|
||||||
|
if $argc != 1
|
||||||
|
printf "Usage: set_high_nav <microseconds>\n"
|
||||||
|
printf "Example: set_high_nav 8000 (set to 8ms)\n"
|
||||||
|
else
|
||||||
|
set threshold_high_nav_us = $arg0
|
||||||
|
printf "High NAV threshold set to %u us\n", threshold_high_nav_us
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define set_mismatch_log
|
||||||
|
if $argc != 1
|
||||||
|
printf "Usage: set_mismatch_log <microseconds>\n"
|
||||||
|
printf "Example: set_mismatch_log 15000 (log when NAV > 15ms)\n"
|
||||||
|
else
|
||||||
|
set threshold_duration_mismatch_us = $arg0
|
||||||
|
printf "Duration mismatch logging threshold set to %u us\n", threshold_duration_mismatch_us
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define set_rate_fallback
|
||||||
|
if $argc != 1
|
||||||
|
printf "Usage: set_rate_fallback <mbps>\n"
|
||||||
|
printf "Example: set_rate_fallback 50 (fallback if < 50 Mbps)\n"
|
||||||
|
else
|
||||||
|
set threshold_phy_rate_fallback_mbps = $arg0
|
||||||
|
printf "PHY rate fallback threshold set to %u Mbps\n", threshold_phy_rate_fallback_mbps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define set_multiplier
|
||||||
|
if $argc != 1
|
||||||
|
printf "Usage: set_multiplier <factor>\n"
|
||||||
|
printf "Example: set_multiplier 3 (NAV > 3x expected = mismatch)\n"
|
||||||
|
else
|
||||||
|
set threshold_duration_multiplier = $arg0
|
||||||
|
printf "Duration multiplier set to %ux expected\n", threshold_duration_multiplier
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define set_log_rate
|
||||||
|
if $argc != 1
|
||||||
|
printf "Usage: set_log_rate <n>\n"
|
||||||
|
printf "Example: set_log_rate 10 (log every 10th mismatch)\n"
|
||||||
|
printf " set_log_rate 1 (log all mismatches)\n"
|
||||||
|
else
|
||||||
|
set log_every_n_mismatches = $arg0
|
||||||
|
printf "Logging every %u mismatch(es)\n", log_every_n_mismatches
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define tune_sensitive
|
||||||
|
set threshold_high_nav_us = 3000
|
||||||
|
set threshold_duration_mismatch_us = 5000
|
||||||
|
set threshold_phy_rate_fallback_mbps = 150
|
||||||
|
set threshold_duration_multiplier = 1.5
|
||||||
|
set threshold_retry_rate_percent = 15.0
|
||||||
|
set threshold_avg_nav_collapse_us = 5000
|
||||||
|
set threshold_collision_percent = 5.0
|
||||||
|
set threshold_mismatch_percent = 3.0
|
||||||
|
printf "Thresholds set to SENSITIVE (catch more issues)\n"
|
||||||
|
show_thresholds
|
||||||
|
end
|
||||||
|
|
||||||
|
define tune_normal
|
||||||
|
set threshold_high_nav_us = 5000
|
||||||
|
set threshold_duration_mismatch_us = 10000
|
||||||
|
set threshold_phy_rate_fallback_mbps = 100
|
||||||
|
set threshold_duration_multiplier = 2
|
||||||
|
set threshold_retry_rate_percent = 20.0
|
||||||
|
set threshold_avg_nav_collapse_us = 10000
|
||||||
|
set threshold_collision_percent = 10.0
|
||||||
|
set threshold_mismatch_percent = 5.0
|
||||||
|
printf "Thresholds set to NORMAL (default)\n"
|
||||||
|
show_thresholds
|
||||||
|
end
|
||||||
|
|
||||||
|
define tune_relaxed
|
||||||
|
set threshold_high_nav_us = 10000
|
||||||
|
set threshold_duration_mismatch_us = 20000
|
||||||
|
set threshold_phy_rate_fallback_mbps = 50
|
||||||
|
set threshold_duration_multiplier = 3
|
||||||
|
set threshold_retry_rate_percent = 30.0
|
||||||
|
set threshold_avg_nav_collapse_us = 15000
|
||||||
|
set threshold_collision_percent = 15.0
|
||||||
|
set threshold_mismatch_percent = 10.0
|
||||||
|
printf "Thresholds set to RELAXED (fewer false positives)\n"
|
||||||
|
show_thresholds
|
||||||
|
end
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# FRAME ANALYSIS COMMANDS
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
define show_frame_full
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
printf "Frame: %s\n", wifi_frame_type_str(frame->type, frame->subtype)
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
printf "RSSI: %d dBm\n", frame->rssi
|
||||||
|
printf "Channel: %d\n", frame->channel
|
||||||
|
printf "Retry: %s\n", frame->retry ? "YES" : "no"
|
||||||
|
printf "\n"
|
||||||
|
set $bw_str = "20MHz"
|
||||||
|
if frame->bandwidth == 1
|
||||||
|
set $bw_str = "40MHz"
|
||||||
|
end
|
||||||
|
if frame->bandwidth == 2
|
||||||
|
set $bw_str = "80MHz"
|
||||||
|
end
|
||||||
|
printf "PHY Rate: %u Kbps (%.1f Mbps)\n", frame->phy_rate_kbps, frame->phy_rate_kbps / 1000.0
|
||||||
|
printf "Mode: MCS %d, BW %s, SGI %s\n", frame->mcs, $bw_str, frame->sgi ? "Yes" : "No"
|
||||||
|
printf "\n"
|
||||||
|
printf "Byte Count: %u bytes\n", frame->frame_len
|
||||||
|
if frame->phy_rate_kbps > 0
|
||||||
|
set $tx_us = (frame->frame_len * 8000) / frame->phy_rate_kbps
|
||||||
|
set $overhead = 44
|
||||||
|
set $expected = $tx_us + $overhead
|
||||||
|
printf "Expected Duration: %u us (%u tx + %u overhead)\n", $expected, $tx_us, $overhead
|
||||||
|
printf "Actual Duration (NAV): %u us\n", frame->duration_id
|
||||||
|
set $diff = frame->duration_id - $expected
|
||||||
|
if $diff > 0
|
||||||
|
printf "Difference: +%d us LONGER than expected", $diff
|
||||||
|
if $diff > 5000
|
||||||
|
printf " ⚠⚠⚠ HIGH!\n"
|
||||||
|
else
|
||||||
|
printf "\n"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
set $diff = -$diff
|
||||||
|
printf "Difference: -%d us shorter\n", $diff
|
||||||
|
end
|
||||||
|
else
|
||||||
|
printf "Actual Duration (NAV): %u us\n", frame->duration_id
|
||||||
|
end
|
||||||
|
printf "\n"
|
||||||
|
printf "Dest: %02x:%02x:%02x:%02x:%02x:%02x\n", frame->addr1[0], frame->addr1[1], frame->addr1[2], frame->addr1[3], frame->addr1[4], frame->addr1[5]
|
||||||
|
printf "Source: %02x:%02x:%02x:%02x:%02x:%02x\n", frame->addr2[0], frame->addr2[1], frame->addr2[2], frame->addr2[3], frame->addr2[4], frame->addr2[5]
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
define show_duration
|
||||||
|
set $tx_us = 0
|
||||||
|
if frame->phy_rate_kbps > 0
|
||||||
|
set $tx_us = (frame->frame_len * 8000) / frame->phy_rate_kbps
|
||||||
|
set $expected = $tx_us + 44
|
||||||
|
printf "%s: %u bytes @ %.1f Mbps → Expected %u us, NAV %u us", wifi_frame_type_str(frame->type, frame->subtype), frame->frame_len, frame->phy_rate_kbps/1000.0, $expected, frame->duration_id
|
||||||
|
set $diff = frame->duration_id - $expected
|
||||||
|
if $diff > 0
|
||||||
|
printf " (+%d)\n", $diff
|
||||||
|
else
|
||||||
|
set $diff = -$diff
|
||||||
|
printf " (-%d)\n", $diff
|
||||||
|
end
|
||||||
|
else
|
||||||
|
printf "%s: %u bytes, NAV %u us\n", wifi_frame_type_str(frame->type, frame->subtype), frame->frame_len, frame->duration_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define find_high_nav
|
||||||
|
break monitor_frame_callback if frame->duration_id > 10000
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "⚠ HIGH NAV: "
|
||||||
|
show_duration
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
printf "Watching for NAV > 10000 us\n"
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
define find_mismatch
|
||||||
|
break monitor_frame_callback if frame->phy_rate_kbps > 0 && frame->duration_id > ((frame->frame_len * 8000) / frame->phy_rate_kbps + 44) * 2
|
||||||
|
printf "Watching for NAV 2x+ expected duration\n"
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
define watch_data
|
||||||
|
break monitor_frame_callback if frame->type == 2
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
show_duration
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
printf "Watching DATA frames\n"
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
printf "WiFi Monitor GDB Commands Loaded\n"
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
printf "Frame Analysis:\n"
|
||||||
|
printf " show_frame_full - Complete frame analysis\n"
|
||||||
|
printf " show_duration - Quick duration comparison\n"
|
||||||
|
printf " find_high_nav - Auto-break on high NAV\n"
|
||||||
|
printf " find_mismatch - Auto-break on NAV mismatch\n"
|
||||||
|
printf " watch_data - Monitor DATA frames\n"
|
||||||
|
printf "\n"
|
||||||
|
printf "Threshold Tuning:\n"
|
||||||
|
printf " show_thresholds - Display current thresholds\n"
|
||||||
|
printf " set_high_nav <us> - Set high NAV threshold\n"
|
||||||
|
printf " set_mismatch_log <us> - Set mismatch log threshold\n"
|
||||||
|
printf " set_rate_fallback <mbps> - Set rate fallback threshold\n"
|
||||||
|
printf " set_multiplier <n> - Set duration multiplier\n"
|
||||||
|
printf " set_log_rate <n> - Log every Nth mismatch\n"
|
||||||
|
printf "\n"
|
||||||
|
printf "Preset Profiles:\n"
|
||||||
|
printf " tune_sensitive - Catch more issues (stricter)\n"
|
||||||
|
printf " tune_normal - Default settings (balanced)\n"
|
||||||
|
printf " tune_relaxed - Fewer false positives (lenient)\n"
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
printf "Type 'show_thresholds' to see current settings\n"
|
||||||
|
printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
# ESP32 Mass Deployment Scripts
|
|
||||||
|
|
||||||
Scripts for deploying, configuring, and testing multiple ESP32 devices in parallel.
|
|
||||||
|
|
||||||
## Scripts
|
|
||||||
|
|
||||||
### 1. `mass_deploy.sh` - Basic Deployment
|
|
||||||
Simple parallel flashing and configuration.
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```bash
|
|
||||||
chmod +x mass_deploy.sh
|
|
||||||
PASSWORD='your_wifi_password' ./mass_deploy.sh ~/Code/esp32/esp32-iperf
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. `mass_deploy_enhanced.sh` - Production Deployment (RECOMMENDED)
|
|
||||||
Enhanced version with retry logic and verification.
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```bash
|
|
||||||
chmod +x mass_deploy_enhanced.sh
|
|
||||||
|
|
||||||
# Basic usage
|
|
||||||
PASSWORD='your_wifi_password' ./mass_deploy_enhanced.sh ~/Code/esp32/esp32-iperf
|
|
||||||
|
|
||||||
# With custom settings
|
|
||||||
PASSWORD='mypass' \
|
|
||||||
SSID='MyNetwork' \
|
|
||||||
START_IP='192.168.1.100' \
|
|
||||||
./mass_deploy_enhanced.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**Environment Variables:**
|
|
||||||
- `PASSWORD` - WiFi password (required)
|
|
||||||
- `SSID` - WiFi SSID (default: ClubHouse2G)
|
|
||||||
- `START_IP` - Starting IP (default: 192.168.1.51)
|
|
||||||
- `MAX_RETRIES` - Retry attempts (default: 2)
|
|
||||||
- `VERIFY_PING` - Test after config (default: true)
|
|
||||||
|
|
||||||
### 3. `test_devices.sh` - Device Testing
|
|
||||||
Tests all deployed devices with iperf.
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```bash
|
|
||||||
chmod +x test_devices.sh
|
|
||||||
NUM_DEVICES=32 ./test_devices.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Connect all ESP32 devices via USB
|
|
||||||
|
|
||||||
# 2. Deploy with one command
|
|
||||||
PASSWORD='your_wifi_pass' ./mass_deploy_enhanced.sh ~/Code/esp32/esp32-iperf
|
|
||||||
|
|
||||||
# 3. Test all devices
|
|
||||||
NUM_DEVICES=32 ./test_devices.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
**Before:** 60-90 minutes (sequential)
|
|
||||||
**After:** 15-20 minutes (parallel) ⚡
|
|
||||||
|
|
||||||
See DEPLOYMENT_GUIDE.md for full documentation.
|
|
||||||
|
|
@ -1,951 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>ESP32-C5 GDB Debugging Guide</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--primary-color: #0e7490;
|
|
||||||
--secondary-color: #357edd;
|
|
||||||
--bg-color: #f9f9f9;
|
|
||||||
--code-bg: #f0f0f0;
|
|
||||||
--border-color: #e0e0e0;
|
|
||||||
--text-color: #1a1a1a;
|
|
||||||
--success-color: #19a974;
|
|
||||||
--warning-color: #ff6300;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
||||||
line-height: 1.6;
|
|
||||||
color: var(--text-color);
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
|
||||||
background: var(--bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
background: linear-gradient(135deg, #0891b2, var(--secondary-color));
|
|
||||||
color: white;
|
|
||||||
padding: 40px 30px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1 {
|
|
||||||
margin: 0 0 10px 0;
|
|
||||||
font-size: 2.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
header p {
|
|
||||||
margin: 5px 0;
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav {
|
|
||||||
background: white;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav h2 {
|
|
||||||
margin-top: 0;
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
column-count: 2;
|
|
||||||
column-gap: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav li {
|
|
||||||
margin: 8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav a {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
text-decoration: none;
|
|
||||||
transition: color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav a:hover {
|
|
||||||
color: #0e7490;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
background: white;
|
|
||||||
padding: 40px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
color: var(--primary-color);
|
|
||||||
border-bottom: 2px solid var(--border-color);
|
|
||||||
padding-bottom: 10px;
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
background: var(--code-bg);
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background: var(--code-bg);
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
border-left: 4px solid var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
pre code {
|
|
||||||
background: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin: 20px 0;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
background: var(--secondary-color);
|
|
||||||
color: white;
|
|
||||||
padding: 12px;
|
|
||||||
text-align: left;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding: 12px;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:hover {
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert {
|
|
||||||
padding: 15px 20px;
|
|
||||||
border-radius: 6px;
|
|
||||||
margin: 20px 0;
|
|
||||||
border-left: 4px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-info {
|
|
||||||
background: #e7f5ff;
|
|
||||||
border-color: var(--secondary-color);
|
|
||||||
color: #004085;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-success {
|
|
||||||
background: #e7f9f0;
|
|
||||||
border-color: var(--success-color);
|
|
||||||
color: #155724;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-warning {
|
|
||||||
background: #fff4e5;
|
|
||||||
border-color: var(--warning-color);
|
|
||||||
color: #856404;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkmark::before {
|
|
||||||
content: '✅ ';
|
|
||||||
}
|
|
||||||
|
|
||||||
.crossmark::before {
|
|
||||||
content: '❌ ';
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning::before {
|
|
||||||
content: '⚠️ ';
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 50px;
|
|
||||||
padding: 30px;
|
|
||||||
color: #666;
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
display: inline-block;
|
|
||||||
background: var(--secondary-color);
|
|
||||||
color: white;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border-radius: 5px;
|
|
||||||
text-decoration: none;
|
|
||||||
margin: 5px;
|
|
||||||
transition: background 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:hover {
|
|
||||||
background: #0e7490;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
body {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
padding: 30px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul {
|
|
||||||
column-count: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<h1>ESP32-C5 GDB Debugging Guide</h1>
|
|
||||||
<p><strong>Author:</strong> Bob McMahon</p>
|
|
||||||
<p><strong>Hardware:</strong> ESP32-C5 DevKit (RISC-V)</p>
|
|
||||||
<p><strong>ESP-IDF:</strong> v6.0 or later</p>
|
|
||||||
<p><strong>Last Updated:</strong> December 2025</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<nav>
|
|
||||||
<h2>Table of Contents</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="#introduction">Introduction</a></li>
|
|
||||||
<li><a href="#why-gdb">Why GDB Debugging?</a></li>
|
|
||||||
<li><a href="#capabilities">ESP32-C5 Debug Capabilities</a></li>
|
|
||||||
<li><a href="#prerequisites">Prerequisites</a></li>
|
|
||||||
<li><a href="#building">Building with Debug Symbols</a></li>
|
|
||||||
<li><a href="#starting">Starting a Debug Session</a></li>
|
|
||||||
<li><a href="#commands">Essential GDB Commands</a></li>
|
|
||||||
<li><a href="#strategies">Debugging Strategies</a></li>
|
|
||||||
<li><a href="#examples">Real-World Examples</a></li>
|
|
||||||
<li><a href="#troubleshooting">Troubleshooting</a></li>
|
|
||||||
<li><a href="#advanced">Advanced Techniques</a></li>
|
|
||||||
<li><a href="#resources">Resources</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<section id="introduction">
|
|
||||||
<h2>Introduction</h2>
|
|
||||||
<p>The ESP32-C5 is Espressif's first RISC-V microcontroller with dual-band WiFi 6 (802.11ax) support. Unlike its Xtensa predecessors (ESP32, ESP32-S3), the ESP32-C5's RISC-V architecture and built-in USB-JTAG interface make debugging significantly easier.</p>
|
|
||||||
|
|
||||||
<p>This guide demonstrates how to use GDB (GNU Debugger) to debug ESP32-C5 firmware, focusing on real-world scenarios like troubleshooting WiFi driver issues, CSI configuration problems, and memory corruption.</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="why-gdb">
|
|
||||||
<h2>Why GDB Debugging?</h2>
|
|
||||||
|
|
||||||
<p>Traditional debugging with <code>ESP_LOGI()</code> statements has limitations:</p>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Method</th>
|
|
||||||
<th>Limitations</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><strong>Printf Debugging</strong></td>
|
|
||||||
<td>
|
|
||||||
• Alters timing and behavior<br>
|
|
||||||
• Cannot inspect internal driver state<br>
|
|
||||||
• Requires recompilation for each change<br>
|
|
||||||
• Output floods serial console
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><strong>LED Blink Debugging</strong></td>
|
|
||||||
<td>
|
|
||||||
• Very limited information<br>
|
|
||||||
• Time-consuming iteration<br>
|
|
||||||
• Cannot show complex state
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="alert alert-success">
|
|
||||||
<strong>GDB debugging solves these problems:</strong>
|
|
||||||
<ul>
|
|
||||||
<li class="checkmark"><strong>Set breakpoints</strong> without modifying code</li>
|
|
||||||
<li class="checkmark"><strong>Inspect variables</strong> at any point in execution</li>
|
|
||||||
<li class="checkmark"><strong>Step through code</strong> line by line</li>
|
|
||||||
<li class="checkmark"><strong>Examine memory</strong> and registers</li>
|
|
||||||
<li class="checkmark"><strong>Watch variables</strong> for changes</li>
|
|
||||||
<li class="checkmark"><strong>View call stacks</strong> to understand program flow</li>
|
|
||||||
<li class="checkmark"><strong>Debug ESP-IDF internals</strong> (WiFi driver, FreeRTOS, etc.)</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="capabilities">
|
|
||||||
<h2>ESP32-C5 Debug Capabilities</h2>
|
|
||||||
|
|
||||||
<p>The ESP32-C5 has <strong>built-in USB-JTAG</strong> support, eliminating the need for external debug adapters:</p>
|
|
||||||
|
|
||||||
<h3>Hardware Features</h3>
|
|
||||||
<ul>
|
|
||||||
<li><strong>Built-in USB-JTAG</strong>: Debug over the same USB cable used for flashing</li>
|
|
||||||
<li><strong>4 Hardware Breakpoints</strong>: No speed penalty</li>
|
|
||||||
<li><strong>Unlimited Software Breakpoints</strong>: Via flash patching</li>
|
|
||||||
<li><strong>2 Watchpoints</strong>: Trigger on memory read/write</li>
|
|
||||||
<li><strong>Real-time Debugging</strong>: Debug live, running firmware</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Comparison with Other ESP32 Chips</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Feature</th>
|
|
||||||
<th>ESP32 (Xtensa)</th>
|
|
||||||
<th>ESP32-S3 (Xtensa)</th>
|
|
||||||
<th>ESP32-C5 (RISC-V)</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><strong>Debug Interface</strong></td>
|
|
||||||
<td>External JTAG required</td>
|
|
||||||
<td>Built-in USB-JTAG</td>
|
|
||||||
<td>Built-in USB-JTAG</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><strong>Debugger</strong></td>
|
|
||||||
<td>xt-gdb (Xtensa)</td>
|
|
||||||
<td>xt-gdb (Xtensa)</td>
|
|
||||||
<td>riscv32-esp-elf-gdb</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><strong>Setup Complexity</strong></td>
|
|
||||||
<td>High (extra hardware)</td>
|
|
||||||
<td>Medium</td>
|
|
||||||
<td><strong>Low</strong> (just USB)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><strong>OpenOCD Support</strong></td>
|
|
||||||
<td>Mature</td>
|
|
||||||
<td>Mature</td>
|
|
||||||
<td>Good (ESP-IDF v6.0+)</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="prerequisites">
|
|
||||||
<h2>Prerequisites</h2>
|
|
||||||
|
|
||||||
<h3>Hardware</h3>
|
|
||||||
<ul>
|
|
||||||
<li><strong>ESP32-C5 DevKit</strong> with USB-C cable</li>
|
|
||||||
<li><strong>Host Computer</strong> running Linux, macOS, or Windows (WSL2)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Software</h3>
|
|
||||||
<ul>
|
|
||||||
<li><strong>ESP-IDF v6.0 or later</strong> (ESP32-C5 support)</li>
|
|
||||||
<li><strong>OpenOCD</strong> (included with ESP-IDF)</li>
|
|
||||||
<li><strong>GDB for RISC-V</strong> (riscv32-esp-elf-gdb, included with ESP-IDF)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Verify Installation</h3>
|
|
||||||
<pre><code># Check ESP-IDF version
|
|
||||||
idf.py --version
|
|
||||||
# Should show: ESP-IDF v6.0 or later
|
|
||||||
|
|
||||||
# Check GDB
|
|
||||||
riscv32-esp-elf-gdb --version
|
|
||||||
# Should show: GNU gdb (esp-gdb) 12.1 or later
|
|
||||||
|
|
||||||
# Check OpenOCD
|
|
||||||
openocd --version
|
|
||||||
# Should show: Open On-Chip Debugger 0.12.0-esp32 or later</code></pre>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="building">
|
|
||||||
<h2>Building with Debug Symbols</h2>
|
|
||||||
|
|
||||||
<p>Debug symbols allow GDB to map machine code back to source code, showing variable names, function names, and line numbers.</p>
|
|
||||||
|
|
||||||
<h3>Method 1: Using menuconfig (Recommended)</h3>
|
|
||||||
<pre><code>cd ~/your-project
|
|
||||||
idf.py menuconfig</code></pre>
|
|
||||||
|
|
||||||
<p>Navigate to and configure:</p>
|
|
||||||
<pre><code>Component config
|
|
||||||
→ Compiler options
|
|
||||||
→ Optimization Level → Debug (-Og) ← Select this
|
|
||||||
→ [*] Generate debug symbols (-g) ← Enable
|
|
||||||
→ Debug information format → DWARF-4 ← Select</code></pre>
|
|
||||||
|
|
||||||
<p>Additional recommended settings:</p>
|
|
||||||
<pre><code>Component config
|
|
||||||
→ Compiler options
|
|
||||||
→ [*] Enable assertions (assert) ← Enable
|
|
||||||
→ [ ] Strip function/variable names ← DISABLE
|
|
||||||
|
|
||||||
Component config
|
|
||||||
→ FreeRTOS
|
|
||||||
→ [*] Enable stack overflow checks ← Enable
|
|
||||||
→ Check method → Canary bytes ← Select</code></pre>
|
|
||||||
|
|
||||||
<h3>Optimization Levels Explained</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Level</th>
|
|
||||||
<th>GCC Flag</th>
|
|
||||||
<th>Code Speed</th>
|
|
||||||
<th>Debug Quality</th>
|
|
||||||
<th>Use Case</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr style="background-color: #e7f9f0;">
|
|
||||||
<td><strong>Debug</strong></td>
|
|
||||||
<td><code>-Og</code></td>
|
|
||||||
<td>Medium</td>
|
|
||||||
<td><strong>Excellent</strong></td>
|
|
||||||
<td><strong>GDB debugging</strong> ✅</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>None</td>
|
|
||||||
<td><code>-O0</code></td>
|
|
||||||
<td>Slow</td>
|
|
||||||
<td>Excellent</td>
|
|
||||||
<td>Extreme debugging</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Size</td>
|
|
||||||
<td><code>-Os</code></td>
|
|
||||||
<td>Medium</td>
|
|
||||||
<td>Poor</td>
|
|
||||||
<td>Production</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Performance</td>
|
|
||||||
<td><code>-O2</code></td>
|
|
||||||
<td>Fast</td>
|
|
||||||
<td>Poor</td>
|
|
||||||
<td>Production</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<strong>For debugging, always use <code>-Og</code> (Debug level).</strong> It provides good performance while preserving all variable information for GDB.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Build Process</h3>
|
|
||||||
<pre><code>cd ~/your-project
|
|
||||||
|
|
||||||
# Clean previous build
|
|
||||||
idf.py fullclean
|
|
||||||
|
|
||||||
# Build with debug symbols
|
|
||||||
idf.py build
|
|
||||||
|
|
||||||
# Flash to device
|
|
||||||
idf.py -p /dev/ttyUSB0 flash</code></pre>
|
|
||||||
|
|
||||||
<h3>Verify Debug Symbols</h3>
|
|
||||||
<pre><code># Check if ELF file contains debug sections
|
|
||||||
riscv32-esp-elf-readelf -S build/your-project.elf | grep debug
|
|
||||||
|
|
||||||
# Expected output (debug sections present):
|
|
||||||
# [27] .debug_aranges PROGBITS 00000000 0f8a2c 004638 00 0 0 8
|
|
||||||
# [28] .debug_info PROGBITS 00000000 0fd064 19d4f4 00 0 0 1
|
|
||||||
# [29] .debug_abbrev PROGBITS 00000000 29a558 02b8f9 00 0 0 1
|
|
||||||
# [30] .debug_line PROGBITS 00000000 2c5e51 0e7a3c 00 0 0 1</code></pre>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="starting">
|
|
||||||
<h2>Starting a Debug Session</h2>
|
|
||||||
|
|
||||||
<h3>Three-Step Debug Process</h3>
|
|
||||||
<ol>
|
|
||||||
<li><strong>Flash the firmware</strong> to the device</li>
|
|
||||||
<li><strong>Start OpenOCD</strong> to connect to the device</li>
|
|
||||||
<li><strong>Start GDB</strong> to control debugging</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<h3>Step 1: Flash Firmware</h3>
|
|
||||||
<pre><code>cd ~/your-project
|
|
||||||
idf.py -p /dev/ttyUSB0 flash</code></pre>
|
|
||||||
|
|
||||||
<h3>Step 2: Start OpenOCD (Terminal 1)</h3>
|
|
||||||
<pre><code>cd ~/your-project
|
|
||||||
idf.py openocd</code></pre>
|
|
||||||
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<strong>Leave this terminal running.</strong> OpenOCD acts as a bridge between GDB and the ESP32-C5.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Step 3: Start GDB (Terminal 2)</h3>
|
|
||||||
<pre><code>cd ~/your-project
|
|
||||||
idf.py gdb</code></pre>
|
|
||||||
|
|
||||||
<p>You're now in the GDB prompt and ready to debug!</p>
|
|
||||||
|
|
||||||
<h3>Quick Start Commands</h3>
|
|
||||||
<pre><code>(gdb) target remote :3333
|
|
||||||
(gdb) file build/your-project.elf
|
|
||||||
(gdb) monitor reset halt
|
|
||||||
(gdb) thbreak app_main
|
|
||||||
(gdb) continue</code></pre>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="commands">
|
|
||||||
<h2>Essential GDB Commands</h2>
|
|
||||||
|
|
||||||
<h3>Navigation and Execution</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Command</th>
|
|
||||||
<th>Shortcut</th>
|
|
||||||
<th>Description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><code>break <location></code></td>
|
|
||||||
<td><code>b</code></td>
|
|
||||||
<td>Set breakpoint</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>continue</code></td>
|
|
||||||
<td><code>c</code></td>
|
|
||||||
<td>Resume execution</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>next</code></td>
|
|
||||||
<td><code>n</code></td>
|
|
||||||
<td>Step over (skip function calls)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>step</code></td>
|
|
||||||
<td><code>s</code></td>
|
|
||||||
<td>Step into (enter functions)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>finish</code></td>
|
|
||||||
<td><code>fin</code></td>
|
|
||||||
<td>Run until function returns</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3>Inspection</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Command</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Example</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><code>print <var></code></td>
|
|
||||||
<td>Print variable value</td>
|
|
||||||
<td><code>p my_variable</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>print *<ptr></code></td>
|
|
||||||
<td>Dereference pointer</td>
|
|
||||||
<td><code>p *config</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>x/<fmt> <addr></code></td>
|
|
||||||
<td>Examine memory</td>
|
|
||||||
<td><code>x/32xb 0x40000000</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>info locals</code></td>
|
|
||||||
<td>Show local variables</td>
|
|
||||||
<td><code>i lo</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>backtrace</code></td>
|
|
||||||
<td>Show call stack</td>
|
|
||||||
<td><code>bt</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>list</code></td>
|
|
||||||
<td>Show source code</td>
|
|
||||||
<td><code>l</code></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3>Breakpoints & Watchpoints</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Command</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Example</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><code>break <func></code></td>
|
|
||||||
<td>Break on function entry</td>
|
|
||||||
<td><code>b esp_wifi_init</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>break <func> if <cond></code></td>
|
|
||||||
<td>Conditional breakpoint</td>
|
|
||||||
<td><code>b send if len > 1000</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>watch <var></code></td>
|
|
||||||
<td>Break when variable changes</td>
|
|
||||||
<td><code>watch my_counter</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>info breakpoints</code></td>
|
|
||||||
<td>List all breakpoints</td>
|
|
||||||
<td><code>i b</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>delete <num></code></td>
|
|
||||||
<td>Delete breakpoint</td>
|
|
||||||
<td><code>d 1</code></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="strategies">
|
|
||||||
<h2>Debugging Strategies</h2>
|
|
||||||
|
|
||||||
<h3>Strategy 1: Breakpoint at Function Entry</h3>
|
|
||||||
<p><strong>Use case:</strong> Understand when and why a function is called.</p>
|
|
||||||
<pre><code>(gdb) break esp_wifi_set_csi_config
|
|
||||||
(gdb) continue
|
|
||||||
# When it breaks...
|
|
||||||
(gdb) info args
|
|
||||||
(gdb) print *config
|
|
||||||
(gdb) backtrace
|
|
||||||
(gdb) continue</code></pre>
|
|
||||||
|
|
||||||
<h3>Strategy 2: Conditional Breakpoints</h3>
|
|
||||||
<p><strong>Use case:</strong> Break only when specific conditions occur.</p>
|
|
||||||
<pre><code># Break only when error occurs
|
|
||||||
(gdb) break esp_wifi_set_csi_config if $a0 != 0
|
|
||||||
|
|
||||||
# Break only for specific SSID
|
|
||||||
(gdb) break wifi_connect if strcmp(ssid, "MyNetwork") == 0
|
|
||||||
|
|
||||||
# Break when buffer is full
|
|
||||||
(gdb) break send_packet if queue_size >= 100</code></pre>
|
|
||||||
|
|
||||||
<h3>Strategy 3: Step Through Algorithm</h3>
|
|
||||||
<p><strong>Use case:</strong> Understand complex logic step by step.</p>
|
|
||||||
<pre><code>(gdb) break process_csi_data
|
|
||||||
(gdb) continue
|
|
||||||
(gdb) next # Execute current line
|
|
||||||
(gdb) next # Next line
|
|
||||||
(gdb) step # Step into function call if any
|
|
||||||
(gdb) finish # Complete current function</code></pre>
|
|
||||||
|
|
||||||
<h3>Strategy 4: Watch for Variable Changes</h3>
|
|
||||||
<p><strong>Use case:</strong> Find where a variable gets corrupted.</p>
|
|
||||||
<pre><code>(gdb) watch connection_state
|
|
||||||
(gdb) continue
|
|
||||||
# GDB will break when variable changes
|
|
||||||
(gdb) backtrace
|
|
||||||
(gdb) print connection_state</code></pre>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="examples">
|
|
||||||
<h2>Real-World Examples</h2>
|
|
||||||
|
|
||||||
<h3>Example 1: Debug CSI Configuration Failure</h3>
|
|
||||||
<p><strong>Problem:</strong> <code>esp_wifi_set_csi_config()</code> returns <code>ESP_FAIL</code> but we don't know why.</p>
|
|
||||||
|
|
||||||
<pre><code>(gdb) break esp_wifi_set_csi_config
|
|
||||||
Breakpoint 1 at 0x42012a4e
|
|
||||||
|
|
||||||
(gdb) continue
|
|
||||||
Breakpoint 1, esp_wifi_set_csi_config (config=0x3ffb0000)
|
|
||||||
|
|
||||||
# Examine the config structure
|
|
||||||
(gdb) print *config
|
|
||||||
$1 = {
|
|
||||||
enable = 1,
|
|
||||||
lltf_en = 1,
|
|
||||||
htltf_en = 1,
|
|
||||||
stbc_htltf2_en = 1,
|
|
||||||
ltf_merge_en = 1,
|
|
||||||
channel_filter_en = 1, ← Suspicious!
|
|
||||||
manu_scale = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Step through to see where it fails
|
|
||||||
(gdb) step
|
|
||||||
(gdb) step
|
|
||||||
...
|
|
||||||
(gdb) print error_code
|
|
||||||
$2 = 259 ← ESP_FAIL (0x103)
|
|
||||||
|
|
||||||
# Found it! channel_filter_en must be 0 on ESP32-C5</code></pre>
|
|
||||||
|
|
||||||
<div class="alert alert-success">
|
|
||||||
<strong>Solution:</strong> Set <code>channel_filter_en = 0</code> in the code.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Example 2: Find Memory Corruption</h3>
|
|
||||||
<p><strong>Problem:</strong> A pointer is getting corrupted, causing crashes.</p>
|
|
||||||
|
|
||||||
<pre><code># Set watchpoint on the pointer
|
|
||||||
(gdb) watch *(void**)&my_buffer_ptr
|
|
||||||
Hardware watchpoint 2: *(void**)&my_buffer_ptr
|
|
||||||
|
|
||||||
# Run until it changes
|
|
||||||
(gdb) continue
|
|
||||||
Hardware watchpoint 2: *(void**)&my_buffer_ptr
|
|
||||||
Old value = (void *) 0x3ffb1000
|
|
||||||
New value = (void *) 0x00000000
|
|
||||||
|
|
||||||
# See what code changed it
|
|
||||||
(gdb) backtrace
|
|
||||||
#0 process_packet (data=0x3ffb0800) at network.c:142
|
|
||||||
#1 0x42008654 in network_task () at network.c:201
|
|
||||||
|
|
||||||
# Look at the source
|
|
||||||
(gdb) list
|
|
||||||
137 void process_packet(uint8_t *data) {
|
|
||||||
138 if (data == NULL) {
|
|
||||||
139 ESP_LOGE(TAG, "Null data!");
|
|
||||||
140 my_buffer_ptr = NULL; ← Found it!
|
|
||||||
141 return;
|
|
||||||
142 }</code></pre>
|
|
||||||
|
|
||||||
<div class="alert alert-success">
|
|
||||||
<strong>Solution:</strong> Fix the null-pointer handling logic.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Example 3: Understand WiFi Connection Failure</h3>
|
|
||||||
<p><strong>Problem:</strong> WiFi connects but immediately disconnects.</p>
|
|
||||||
|
|
||||||
<pre><code>(gdb) break event_handler
|
|
||||||
(gdb) condition 1 event_id == WIFI_EVENT_STA_DISCONNECTED
|
|
||||||
(gdb) continue
|
|
||||||
|
|
||||||
Breakpoint 1, event_handler (event_id=3, event_data=0x3ffb2000)
|
|
||||||
|
|
||||||
# Examine disconnect reason
|
|
||||||
(gdb) print *(wifi_event_sta_disconnected_t*)event_data
|
|
||||||
$1 = {
|
|
||||||
ssid = "ClubHouse",
|
|
||||||
ssid_len = 9,
|
|
||||||
bssid = {0xe0, 0x46, 0xee, 0x07, 0xdf, 0x01},
|
|
||||||
reason = 2, ← WIFI_REASON_AUTH_EXPIRE
|
|
||||||
rssi = -75
|
|
||||||
}
|
|
||||||
|
|
||||||
# Reason 2 = Authentication expired = weak signal or interference</code></pre>
|
|
||||||
|
|
||||||
<div class="alert alert-success">
|
|
||||||
<strong>Solution:</strong> Improve antenna placement or reduce distance to AP.
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="troubleshooting">
|
|
||||||
<h2>Troubleshooting</h2>
|
|
||||||
|
|
||||||
<h3>Problem: "No symbol table is loaded"</h3>
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<strong>Symptom:</strong>
|
|
||||||
<pre><code>(gdb) break app_main
|
|
||||||
Function "app_main" not defined.</code></pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p><strong>Solutions:</strong></p>
|
|
||||||
<pre><code># 1. Rebuild with debug symbols
|
|
||||||
idf.py menuconfig # Set optimization to Debug (-Og)
|
|
||||||
idf.py fullclean build
|
|
||||||
|
|
||||||
# 2. Load correct ELF file in GDB
|
|
||||||
(gdb) file build/your-project.elf
|
|
||||||
|
|
||||||
# 3. Verify symbols exist
|
|
||||||
riscv32-esp-elf-nm build/your-project.elf | grep app_main</code></pre>
|
|
||||||
|
|
||||||
<h3>Problem: "Cannot access memory at address 0x..."</h3>
|
|
||||||
<p><strong>Causes:</strong> Variable optimized out, out of scope, or invalid pointer</p>
|
|
||||||
|
|
||||||
<p><strong>Solutions:</strong></p>
|
|
||||||
<pre><code># Check if variable exists
|
|
||||||
(gdb) info locals
|
|
||||||
(gdb) info args
|
|
||||||
|
|
||||||
# Examine raw memory
|
|
||||||
(gdb) print &my_variable
|
|
||||||
(gdb) x/4xw 0x3ffb0000</code></pre>
|
|
||||||
|
|
||||||
<h3>Problem: Breakpoint Not Hitting</h3>
|
|
||||||
<p><strong>Solutions:</strong></p>
|
|
||||||
<pre><code># Check breakpoint status
|
|
||||||
(gdb) info breakpoints
|
|
||||||
|
|
||||||
# Try software breakpoint
|
|
||||||
(gdb) delete 1
|
|
||||||
(gdb) break my_func</code></pre>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="advanced">
|
|
||||||
<h2>Advanced Techniques</h2>
|
|
||||||
|
|
||||||
<h3>Technique 1: Scripting GDB</h3>
|
|
||||||
<p>Create a <code>.gdbinit</code> file to automate common tasks:</p>
|
|
||||||
|
|
||||||
<pre><code># ~/.gdbinit or project/.gdbinit
|
|
||||||
|
|
||||||
# Connect automatically
|
|
||||||
target remote :3333
|
|
||||||
file build/CSI.elf
|
|
||||||
|
|
||||||
# Define custom commands
|
|
||||||
define reset-and-break
|
|
||||||
monitor reset halt
|
|
||||||
thbreak app_main
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
# Set common breakpoints
|
|
||||||
break esp_wifi_set_csi_config
|
|
||||||
break esp_wifi_connect</code></pre>
|
|
||||||
|
|
||||||
<h3>Technique 2: Debugging FreeRTOS Tasks</h3>
|
|
||||||
<pre><code># Show all tasks
|
|
||||||
(gdb) info threads
|
|
||||||
Id Target Id Frame
|
|
||||||
* 1 Remote target vTaskDelay ()
|
|
||||||
2 Remote target prvIdleTask ()
|
|
||||||
3 Remote target wifi_task ()
|
|
||||||
|
|
||||||
# Switch to different task
|
|
||||||
(gdb) thread 3
|
|
||||||
|
|
||||||
# See that task's stack
|
|
||||||
(gdb) backtrace</code></pre>
|
|
||||||
|
|
||||||
<h3>Technique 3: Live Variable Modification</h3>
|
|
||||||
<p>Change variables on-the-fly without recompiling:</p>
|
|
||||||
|
|
||||||
<pre><code>(gdb) break send_packet
|
|
||||||
(gdb) continue
|
|
||||||
|
|
||||||
# Change packet size before sending
|
|
||||||
(gdb) print packet_size
|
|
||||||
$1 = 1024
|
|
||||||
(gdb) set packet_size = 64
|
|
||||||
|
|
||||||
# Continue with modified value
|
|
||||||
(gdb) continue</code></pre>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="resources">
|
|
||||||
<h2>Resources</h2>
|
|
||||||
|
|
||||||
<h3>Official Documentation</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://docs.espressif.com/projects/esp-idf/en/latest/esp32c5/api-guides/jtag-debugging/">ESP-IDF GDB Guide</a></li>
|
|
||||||
<li><a href="https://www.espressif.com/sites/default/files/documentation/esp32-c5_datasheet_en.pdf">ESP32-C5 Datasheet</a></li>
|
|
||||||
<li><a href="http://openocd.org/doc/html/index.html">OpenOCD Manual</a></li>
|
|
||||||
<li><a href="https://sourceware.org/gdb/current/onlinedocs/gdb/">GDB Manual</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>ESP32 Community</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://esp32.com/">ESP32 Forum</a></li>
|
|
||||||
<li><a href="https://reddit.com/r/esp32">r/esp32 Subreddit</a></li>
|
|
||||||
<li><a href="https://github.com/espressif/esp-idf">Espressif GitHub</a></li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="summary">
|
|
||||||
<h2>Summary</h2>
|
|
||||||
|
|
||||||
<p>GDB debugging on the ESP32-C5 provides powerful insights into firmware behavior:</p>
|
|
||||||
|
|
||||||
<div class="alert alert-success">
|
|
||||||
<ul>
|
|
||||||
<li class="checkmark"><strong>Built-in USB-JTAG</strong> eliminates external hardware requirements</li>
|
|
||||||
<li class="checkmark"><strong>Hardware and software breakpoints</strong> for flexible debugging</li>
|
|
||||||
<li class="checkmark"><strong>Real-time variable inspection</strong> without printf statements</li>
|
|
||||||
<li class="checkmark"><strong>Watchpoints</strong> to catch memory corruption</li>
|
|
||||||
<li class="checkmark"><strong>Call stack analysis</strong> to understand program flow</li>
|
|
||||||
<li class="checkmark"><strong>ESP-IDF driver debugging</strong> to troubleshoot library issues</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p><strong>Key takeaways:</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>Always build with <strong>Debug (-Og)</strong> optimization for best debug experience</li>
|
|
||||||
<li>Use <strong>conditional breakpoints</strong> to break only when needed</li>
|
|
||||||
<li>Combine <strong>watchpoints</strong> with breakpoints to find memory corruption</li>
|
|
||||||
<li><strong>Script common tasks</strong> in <code>.gdbinit</code> for faster debugging</li>
|
|
||||||
<li>The <strong>WiFi driver log</strong> is still the ground truth for connection status</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>GDB debugging significantly reduces debug time compared to printf-based approaches, especially for complex issues like WiFi driver bugs, FreeRTOS task interactions, and memory corruption.</p>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p><strong>About this guide:</strong> Created based on real-world ESP32-C5 development experience, specifically debugging WiFi 6 CSI (Channel State Information) capture issues for the iperf WiFi Analyzer project.</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a href="https://github.com/iperf2/iperf2" class="button">iperf2 GitHub</a>
|
|
||||||
<a href="https://sourceforge.net/projects/iperf2/" class="button">iperf2 SourceForge</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><strong>Hardware:</strong> ESP32-C5 DevKit<br>
|
|
||||||
<strong>Project:</strong> WiFi Collapse Detection using CSI</p>
|
|
||||||
|
|
||||||
<p>© 2025 Bob McMahon. Last updated: December 4, 2025</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,941 +0,0 @@
|
||||||
# GDB Debugging on ESP32-C5: Complete Guide
|
|
||||||
|
|
||||||
A comprehensive guide to debugging ESP32-C5 firmware using GDB and the built-in USB-JTAG interface.
|
|
||||||
|
|
||||||
**Author**: Bob McMahon
|
|
||||||
**Hardware**: ESP32-C5 DevKit (RISC-V)
|
|
||||||
**ESP-IDF**: v6.0 or later
|
|
||||||
**Last Updated**: December 2025
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [Introduction](#introduction)
|
|
||||||
2. [Why GDB Debugging?](#why-gdb-debugging)
|
|
||||||
3. [ESP32-C5 Debug Capabilities](#esp32-c5-debug-capabilities)
|
|
||||||
4. [Prerequisites](#prerequisites)
|
|
||||||
5. [Building with Debug Symbols](#building-with-debug-symbols)
|
|
||||||
6. [Starting a Debug Session](#starting-a-debug-session)
|
|
||||||
7. [Essential GDB Commands](#essential-gdb-commands)
|
|
||||||
8. [Debugging Strategies](#debugging-strategies)
|
|
||||||
9. [Real-World Examples](#real-world-examples)
|
|
||||||
10. [Troubleshooting](#troubleshooting)
|
|
||||||
11. [Advanced Techniques](#advanced-techniques)
|
|
||||||
12. [Resources](#resources)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
The ESP32-C5 is Espressif's first RISC-V microcontroller with dual-band WiFi 6 (802.11ax) support. Unlike its Xtensa predecessors (ESP32, ESP32-S3), the ESP32-C5's RISC-V architecture and built-in USB-JTAG interface make debugging significantly easier.
|
|
||||||
|
|
||||||
This guide demonstrates how to use GDB (GNU Debugger) to debug ESP32-C5 firmware, focusing on real-world scenarios like troubleshooting WiFi driver issues, CSI configuration problems, and memory corruption.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Why GDB Debugging?
|
|
||||||
|
|
||||||
Traditional debugging with `ESP_LOGI()` statements has limitations:
|
|
||||||
|
|
||||||
| Method | Limitations |
|
|
||||||
|--------|-------------|
|
|
||||||
| **Printf Debugging** | - Alters timing and behavior<br>- Cannot inspect internal driver state<br>- Requires recompilation for each change<br>- Output floods serial console |
|
|
||||||
| **LED Blink Debugging** | - Very limited information<br>- Time-consuming iteration<br>- Cannot show complex state |
|
|
||||||
|
|
||||||
**GDB debugging solves these problems:**
|
|
||||||
|
|
||||||
- ✅ **Set breakpoints** without modifying code
|
|
||||||
- ✅ **Inspect variables** at any point in execution
|
|
||||||
- ✅ **Step through code** line by line
|
|
||||||
- ✅ **Examine memory** and registers
|
|
||||||
- ✅ **Watch variables** for changes
|
|
||||||
- ✅ **View call stacks** to understand program flow
|
|
||||||
- ✅ **Debug ESP-IDF internals** (WiFi driver, FreeRTOS, etc.)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ESP32-C5 Debug Capabilities
|
|
||||||
|
|
||||||
The ESP32-C5 has **built-in USB-JTAG** support, eliminating the need for external debug adapters:
|
|
||||||
|
|
||||||
### Hardware Features
|
|
||||||
|
|
||||||
- **Built-in USB-JTAG**: Debug over the same USB cable used for flashing
|
|
||||||
- **4 Hardware Breakpoints**: No speed penalty
|
|
||||||
- **Unlimited Software Breakpoints**: Via flash patching
|
|
||||||
- **2 Watchpoints**: Trigger on memory read/write
|
|
||||||
- **Real-time Debugging**: Debug live, running firmware
|
|
||||||
|
|
||||||
### Comparison with Other ESP32 Chips
|
|
||||||
|
|
||||||
| Feature | ESP32 (Xtensa) | ESP32-S3 (Xtensa) | ESP32-C5 (RISC-V) |
|
|
||||||
|---------|----------------|-------------------|-------------------|
|
|
||||||
| **Debug Interface** | External JTAG required | Built-in USB-JTAG | Built-in USB-JTAG |
|
|
||||||
| **Debugger** | xt-gdb (Xtensa) | xt-gdb (Xtensa) | riscv32-esp-elf-gdb |
|
|
||||||
| **Setup Complexity** | High (extra hardware) | Medium | **Low** (just USB) |
|
|
||||||
| **OpenOCD Support** | Mature | Mature | Good (ESP-IDF v6.0+) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
### Hardware
|
|
||||||
|
|
||||||
- **ESP32-C5 DevKit** with USB-C cable
|
|
||||||
- **Host Computer** running Linux, macOS, or Windows (WSL2)
|
|
||||||
|
|
||||||
### Software
|
|
||||||
|
|
||||||
- **ESP-IDF v6.0 or later** (ESP32-C5 support)
|
|
||||||
- **OpenOCD** (included with ESP-IDF)
|
|
||||||
- **GDB for RISC-V** (riscv32-esp-elf-gdb, included with ESP-IDF)
|
|
||||||
|
|
||||||
### Verify Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check ESP-IDF version
|
|
||||||
idf.py --version
|
|
||||||
# Should show: ESP-IDF v6.0 or later
|
|
||||||
|
|
||||||
# Check GDB
|
|
||||||
riscv32-esp-elf-gdb --version
|
|
||||||
# Should show: GNU gdb (esp-gdb) 12.1 or later
|
|
||||||
|
|
||||||
# Check OpenOCD
|
|
||||||
openocd --version
|
|
||||||
# Should show: Open On-Chip Debugger 0.12.0-esp32 or later
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Building with Debug Symbols
|
|
||||||
|
|
||||||
Debug symbols allow GDB to map machine code back to source code, showing variable names, function names, and line numbers.
|
|
||||||
|
|
||||||
### Method 1: Using menuconfig (Recommended)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/your-project
|
|
||||||
idf.py menuconfig
|
|
||||||
```
|
|
||||||
|
|
||||||
Navigate to and configure:
|
|
||||||
|
|
||||||
```
|
|
||||||
Component config
|
|
||||||
→ Compiler options
|
|
||||||
→ Optimization Level → Debug (-Og) ← Select this
|
|
||||||
→ [*] Generate debug symbols (-g) ← Enable
|
|
||||||
→ Debug information format → DWARF-4 ← Select
|
|
||||||
```
|
|
||||||
|
|
||||||
Additional recommended settings:
|
|
||||||
|
|
||||||
```
|
|
||||||
Component config
|
|
||||||
→ Compiler options
|
|
||||||
→ [*] Enable assertions (assert) ← Enable
|
|
||||||
→ [ ] Strip function/variable names ← DISABLE
|
|
||||||
|
|
||||||
Component config
|
|
||||||
→ FreeRTOS
|
|
||||||
→ [*] Enable stack overflow checks ← Enable
|
|
||||||
→ Check method → Canary bytes ← Select
|
|
||||||
```
|
|
||||||
|
|
||||||
Save and exit (`S` then `Q`).
|
|
||||||
|
|
||||||
### Method 2: Direct sdkconfig Edit
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/your-project
|
|
||||||
|
|
||||||
# Backup current config
|
|
||||||
cp sdkconfig sdkconfig.backup
|
|
||||||
|
|
||||||
# Add debug settings
|
|
||||||
cat >> sdkconfig << 'EOF'
|
|
||||||
# Debug optimization
|
|
||||||
CONFIG_COMPILER_OPTIMIZATION_DEBUG=y
|
|
||||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
|
|
||||||
|
|
||||||
# Enable assertions
|
|
||||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
|
|
||||||
|
|
||||||
# Stack checking
|
|
||||||
CONFIG_COMPILER_STACK_CHECK_MODE_NORM=y
|
|
||||||
CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
|
|
||||||
|
|
||||||
# Debug info
|
|
||||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
### Optimization Levels Explained
|
|
||||||
|
|
||||||
| Level | GCC Flag | Code Speed | Code Size | Debug Quality | Use Case |
|
|
||||||
|-------|----------|------------|-----------|---------------|----------|
|
|
||||||
| **Debug** | `-Og` | Medium | Medium | **Excellent** | **GDB debugging** ✅ |
|
|
||||||
| None | `-O0` | Slow | Large | Excellent | Extreme debugging |
|
|
||||||
| Size | `-Os` | Medium | **Small** | Poor | Production |
|
|
||||||
| Performance | `-O2` | **Fast** | Medium | Poor | Production |
|
|
||||||
| Max Performance | `-O3` | **Fastest** | Large | Very Poor | Benchmarks |
|
|
||||||
|
|
||||||
**For debugging, always use `-Og` (Debug level).** It provides good performance while preserving all variable information for GDB.
|
|
||||||
|
|
||||||
### Build Process
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/your-project
|
|
||||||
|
|
||||||
# Clean previous build
|
|
||||||
idf.py fullclean
|
|
||||||
|
|
||||||
# Build with debug symbols
|
|
||||||
idf.py build
|
|
||||||
|
|
||||||
# Flash to device
|
|
||||||
idf.py -p /dev/ttyUSB0 flash
|
|
||||||
```
|
|
||||||
|
|
||||||
### Verify Debug Symbols
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check if ELF file contains debug sections
|
|
||||||
riscv32-esp-elf-readelf -S build/your-project.elf | grep debug
|
|
||||||
|
|
||||||
# Expected output (debug sections present):
|
|
||||||
# [27] .debug_aranges PROGBITS 00000000 0f8a2c 004638 00 0 0 8
|
|
||||||
# [28] .debug_info PROGBITS 00000000 0fd064 19d4f4 00 0 0 1
|
|
||||||
# [29] .debug_abbrev PROGBITS 00000000 29a558 02b8f9 00 0 0 1
|
|
||||||
# [30] .debug_line PROGBITS 00000000 2c5e51 0e7a3c 00 0 0 1
|
|
||||||
# [31] .debug_str PROGBITS 00000000 3ad88d 036184 01 MS 0 0 1
|
|
||||||
```
|
|
||||||
|
|
||||||
If you don't see `.debug_*` sections, debug symbols are missing. Check your optimization settings.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Starting a Debug Session
|
|
||||||
|
|
||||||
### Three-Step Debug Process
|
|
||||||
|
|
||||||
1. **Flash the firmware** to the device
|
|
||||||
2. **Start OpenOCD** to connect to the device
|
|
||||||
3. **Start GDB** to control debugging
|
|
||||||
|
|
||||||
### Step 1: Flash Firmware
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/your-project
|
|
||||||
idf.py -p /dev/ttyUSB0 flash
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Start OpenOCD (Terminal 1)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/your-project
|
|
||||||
idf.py openocd
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected output:
|
|
||||||
```
|
|
||||||
Open On-Chip Debugger v0.12.0-esp32-20230419 (2023-04-19-13:01)
|
|
||||||
Licensed under GNU GPL v2
|
|
||||||
...
|
|
||||||
Info : [esp32c5] Target halted, PC=0x42008a4e, debug_reason=00000001
|
|
||||||
Info : [esp32c5] Reset cause (3) - (Software core reset)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Leave this terminal running.** OpenOCD acts as a bridge between GDB and the ESP32-C5.
|
|
||||||
|
|
||||||
### Step 3: Start GDB (Terminal 2)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/your-project
|
|
||||||
idf.py gdb
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected output:
|
|
||||||
```
|
|
||||||
GNU gdb (esp-gdb) 12.1_20221002
|
|
||||||
...
|
|
||||||
(gdb)
|
|
||||||
```
|
|
||||||
|
|
||||||
You're now in the GDB prompt and ready to debug!
|
|
||||||
|
|
||||||
### Quick Start Commands
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Connect to OpenOCD (usually done automatically)
|
|
||||||
target remote :3333
|
|
||||||
|
|
||||||
# Load symbols
|
|
||||||
file build/your-project.elf
|
|
||||||
|
|
||||||
# Reset and halt at app_main
|
|
||||||
monitor reset halt
|
|
||||||
thbreak app_main
|
|
||||||
continue
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Essential GDB Commands
|
|
||||||
|
|
||||||
### Navigation and Execution
|
|
||||||
|
|
||||||
| Command | Shortcut | Description | Example |
|
|
||||||
|---------|----------|-------------|---------|
|
|
||||||
| `break <location>` | `b` | Set breakpoint | `b app_main` |
|
|
||||||
| `continue` | `c` | Resume execution | `c` |
|
|
||||||
| `next` | `n` | Step over (skip function calls) | `n` |
|
|
||||||
| `step` | `s` | Step into (enter functions) | `s` |
|
|
||||||
| `finish` | `fin` | Run until function returns | `fin` |
|
|
||||||
| `until <line>` | `u` | Run until line number | `u 100` |
|
|
||||||
| `run` | `r` | Start program | `r` |
|
|
||||||
|
|
||||||
### Inspection
|
|
||||||
|
|
||||||
| Command | Shortcut | Description | Example |
|
|
||||||
|---------|----------|-------------|---------|
|
|
||||||
| `print <var>` | `p` | Print variable value | `p my_variable` |
|
|
||||||
| `print *<ptr>` | `p *` | Dereference pointer | `p *config` |
|
|
||||||
| `x/<fmt> <addr>` | `x` | Examine memory | `x/32xb 0x40000000` |
|
|
||||||
| `info locals` | `i lo` | Show local variables | `i lo` |
|
|
||||||
| `info args` | `i ar` | Show function arguments | `i ar` |
|
|
||||||
| `info registers` | `i r` | Show CPU registers | `i r` |
|
|
||||||
| `backtrace` | `bt` | Show call stack | `bt` |
|
|
||||||
| `list` | `l` | Show source code | `l` |
|
|
||||||
|
|
||||||
### Breakpoints
|
|
||||||
|
|
||||||
| Command | Description | Example |
|
|
||||||
|---------|-------------|---------|
|
|
||||||
| `break <func>` | Break on function entry | `b esp_wifi_init` |
|
|
||||||
| `break <file>:<line>` | Break at specific line | `b main.c:42` |
|
|
||||||
| `break *<addr>` | Break at memory address | `b *0x42008a4e` |
|
|
||||||
| `break <func> if <cond>` | Conditional breakpoint | `b send_data if len > 1000` |
|
|
||||||
| `tbreak <location>` | Temporary breakpoint (one-time) | `tb app_main` |
|
|
||||||
| `info breakpoints` | List all breakpoints | `i b` |
|
|
||||||
| `delete <num>` | Delete breakpoint | `d 1` |
|
|
||||||
| `disable <num>` | Disable breakpoint | `dis 1` |
|
|
||||||
| `enable <num>` | Enable breakpoint | `en 1` |
|
|
||||||
|
|
||||||
### Watchpoints
|
|
||||||
|
|
||||||
| Command | Description | Example |
|
|
||||||
|---------|-------------|---------|
|
|
||||||
| `watch <var>` | Break when variable changes | `watch my_counter` |
|
|
||||||
| `watch *<addr>` | Break when memory changes | `watch *(int*)0x3ff00000` |
|
|
||||||
| `rwatch <var>` | Break on read | `rwatch secret_key` |
|
|
||||||
| `awatch <var>` | Break on read or write | `awatch buffer[0]` |
|
|
||||||
|
|
||||||
### Memory Examination
|
|
||||||
|
|
||||||
| Format | Description | Example |
|
|
||||||
|--------|-------------|---------|
|
|
||||||
| `x/32xb <addr>` | 32 bytes in hex | `x/32xb &config` |
|
|
||||||
| `x/8xw <addr>` | 8 words (32-bit) in hex | `x/8xw 0x40000000` |
|
|
||||||
| `x/s <addr>` | String (null-terminated) | `x/s ssid_buffer` |
|
|
||||||
| `x/i <addr>` | Instruction (disassembly) | `x/10i $pc` |
|
|
||||||
|
|
||||||
### Control Flow
|
|
||||||
|
|
||||||
| Command | Description |
|
|
||||||
|---------|-------------|
|
|
||||||
| `monitor reset halt` | Reset chip and stop at bootloader |
|
|
||||||
| `monitor reset` | Reset chip and run |
|
|
||||||
| `interrupt` | Pause execution (Ctrl+C) |
|
|
||||||
| `quit` | Exit GDB |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Debugging Strategies
|
|
||||||
|
|
||||||
### Strategy 1: Breakpoint at Function Entry
|
|
||||||
|
|
||||||
**Use case**: Understand when and why a function is called.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Break when WiFi CSI configuration is attempted
|
|
||||||
break esp_wifi_set_csi_config
|
|
||||||
|
|
||||||
# Run until breakpoint
|
|
||||||
continue
|
|
||||||
|
|
||||||
# When it breaks, examine arguments
|
|
||||||
info args
|
|
||||||
print *config
|
|
||||||
|
|
||||||
# Check who called this function
|
|
||||||
backtrace
|
|
||||||
|
|
||||||
# Continue execution
|
|
||||||
continue
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategy 2: Conditional Breakpoints
|
|
||||||
|
|
||||||
**Use case**: Break only when specific conditions occur.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Break only when error occurs
|
|
||||||
break esp_wifi_set_csi_config if $a0 != 0
|
|
||||||
|
|
||||||
# Break only for specific SSID
|
|
||||||
break wifi_connect if strcmp(ssid, "MyNetwork") == 0
|
|
||||||
|
|
||||||
# Break when buffer is full
|
|
||||||
break send_packet if queue_size >= 100
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategy 3: Step Through Algorithm
|
|
||||||
|
|
||||||
**Use case**: Understand complex logic step by step.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Break at start of function
|
|
||||||
break process_csi_data
|
|
||||||
|
|
||||||
# Run until breakpoint
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Step through line by line
|
|
||||||
next # Execute current line
|
|
||||||
next # Next line
|
|
||||||
step # Step into function call if any
|
|
||||||
finish # Complete current function
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategy 4: Watch for Variable Changes
|
|
||||||
|
|
||||||
**Use case**: Find where a variable gets corrupted.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Watch a variable
|
|
||||||
watch connection_state
|
|
||||||
|
|
||||||
# Run - GDB will break when variable changes
|
|
||||||
continue
|
|
||||||
|
|
||||||
# When it breaks, see the call stack
|
|
||||||
backtrace
|
|
||||||
|
|
||||||
# See old and new values
|
|
||||||
print connection_state
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategy 5: Post-Mortem Debugging
|
|
||||||
|
|
||||||
**Use case**: Analyze crash dumps.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# After a crash, examine the panic
|
|
||||||
backtrace
|
|
||||||
|
|
||||||
# See register state at crash
|
|
||||||
info registers
|
|
||||||
|
|
||||||
# Examine memory around crash
|
|
||||||
x/32xw $sp # Stack pointer
|
|
||||||
x/10i $pc # Instructions at crash
|
|
||||||
|
|
||||||
# Check for stack overflow
|
|
||||||
info frame
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Real-World Examples
|
|
||||||
|
|
||||||
### Example 1: Debug CSI Configuration Failure
|
|
||||||
|
|
||||||
**Problem**: `esp_wifi_set_csi_config()` returns `ESP_FAIL` but we don't know why.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Start GDB session
|
|
||||||
(gdb) target remote :3333
|
|
||||||
(gdb) file build/CSI.elf
|
|
||||||
(gdb) monitor reset halt
|
|
||||||
|
|
||||||
# Break on CSI configuration
|
|
||||||
(gdb) break esp_wifi_set_csi_config
|
|
||||||
Breakpoint 1 at 0x42012a4e
|
|
||||||
|
|
||||||
# Run until breakpoint
|
|
||||||
(gdb) continue
|
|
||||||
Breakpoint 1, esp_wifi_set_csi_config (config=0x3ffb0000)
|
|
||||||
|
|
||||||
# Examine the config structure being passed
|
|
||||||
(gdb) print *config
|
|
||||||
$1 = {
|
|
||||||
enable = 1,
|
|
||||||
lltf_en = 1,
|
|
||||||
htltf_en = 1,
|
|
||||||
stbc_htltf2_en = 1,
|
|
||||||
ltf_merge_en = 1,
|
|
||||||
channel_filter_en = 1, ← Suspicious!
|
|
||||||
manu_scale = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# channel_filter_en = 1 is known to cause ESP_FAIL on some chips
|
|
||||||
# Let's step through to confirm
|
|
||||||
|
|
||||||
(gdb) step
|
|
||||||
(gdb) step
|
|
||||||
...
|
|
||||||
# Reaches error check for channel_filter_en
|
|
||||||
|
|
||||||
(gdb) print error_code
|
|
||||||
$2 = 259 ← ESP_FAIL (0x103)
|
|
||||||
|
|
||||||
# Found it! channel_filter_en must be 0 on ESP32-C5
|
|
||||||
```
|
|
||||||
|
|
||||||
**Solution**: Set `channel_filter_en = 0` in the code.
|
|
||||||
|
|
||||||
### Example 2: Find Memory Corruption
|
|
||||||
|
|
||||||
**Problem**: A pointer is getting corrupted, causing crashes.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Set watchpoint on the pointer
|
|
||||||
(gdb) watch *(void**)&my_buffer_ptr
|
|
||||||
Hardware watchpoint 2: *(void**)&my_buffer_ptr
|
|
||||||
|
|
||||||
# Run until it changes
|
|
||||||
(gdb) continue
|
|
||||||
Hardware watchpoint 2: *(void**)&my_buffer_ptr
|
|
||||||
Old value = (void *) 0x3ffb1000
|
|
||||||
New value = (void *) 0x00000000
|
|
||||||
|
|
||||||
# See what code changed it
|
|
||||||
(gdb) backtrace
|
|
||||||
#0 process_packet (data=0x3ffb0800) at network.c:142
|
|
||||||
#1 0x42008654 in network_task () at network.c:201
|
|
||||||
#2 0x4200a123 in vTaskDelay () at FreeRTOS.c:1543
|
|
||||||
|
|
||||||
# Look at the source
|
|
||||||
(gdb) list
|
|
||||||
137 void process_packet(uint8_t *data) {
|
|
||||||
138 if (data == NULL) {
|
|
||||||
139 ESP_LOGE(TAG, "Null data!");
|
|
||||||
140 my_buffer_ptr = NULL; ← Found it! Setting to NULL here
|
|
||||||
141 return;
|
|
||||||
142 }
|
|
||||||
```
|
|
||||||
|
|
||||||
**Solution**: Fix the null-pointer handling logic.
|
|
||||||
|
|
||||||
### Example 3: Understand WiFi Connection Failure
|
|
||||||
|
|
||||||
**Problem**: WiFi connects but immediately disconnects.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Break on disconnect event
|
|
||||||
(gdb) break event_handler
|
|
||||||
Breakpoint 1 at 0x42009876
|
|
||||||
|
|
||||||
# Add condition for disconnect events only
|
|
||||||
(gdb) condition 1 event_id == WIFI_EVENT_STA_DISCONNECTED
|
|
||||||
|
|
||||||
(gdb) continue
|
|
||||||
Breakpoint 1, event_handler (event_id=3, event_data=0x3ffb2000)
|
|
||||||
|
|
||||||
# Examine disconnect reason
|
|
||||||
(gdb) print *(wifi_event_sta_disconnected_t*)event_data
|
|
||||||
$1 = {
|
|
||||||
ssid = "ClubHouse",
|
|
||||||
ssid_len = 9,
|
|
||||||
bssid = {0xe0, 0x46, 0xee, 0x07, 0xdf, 0x01},
|
|
||||||
reason = 2, ← WIFI_REASON_AUTH_EXPIRE
|
|
||||||
rssi = -75
|
|
||||||
}
|
|
||||||
|
|
||||||
# Reason 2 = Authentication expired = weak signal or interference
|
|
||||||
```
|
|
||||||
|
|
||||||
**Solution**: Improve antenna placement or reduce distance to AP.
|
|
||||||
|
|
||||||
### Example 4: Profile Function Performance
|
|
||||||
|
|
||||||
**Use case**: Measure time spent in a critical function.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Break at function entry
|
|
||||||
(gdb) break process_csi_data
|
|
||||||
Breakpoint 1 at 0x42010a00
|
|
||||||
|
|
||||||
# Continue to breakpoint
|
|
||||||
(gdb) continue
|
|
||||||
Breakpoint 1, process_csi_data ()
|
|
||||||
|
|
||||||
# Get current cycle count (RISC-V has cycle counter)
|
|
||||||
(gdb) print $cycle
|
|
||||||
$1 = 12456789
|
|
||||||
|
|
||||||
# Step out of function
|
|
||||||
(gdb) finish
|
|
||||||
|
|
||||||
# Check cycles again
|
|
||||||
(gdb) print $cycle
|
|
||||||
$2 = 12501234
|
|
||||||
|
|
||||||
# Calculate time (assuming 240 MHz clock)
|
|
||||||
# (12501234 - 12456789) / 240,000,000 = 0.185 ms
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 5: Debug Stack Overflow
|
|
||||||
|
|
||||||
**Problem**: Task crashes with stack overflow.
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Break after crash
|
|
||||||
(gdb) backtrace
|
|
||||||
#0 0x420089a4 in panic_abort ()
|
|
||||||
#1 0x4200a123 in vTaskStackOverflow ()
|
|
||||||
#2 0x42012456 in my_task ()
|
|
||||||
|
|
||||||
# Check stack usage
|
|
||||||
(gdb) info frame
|
|
||||||
Stack level 2, frame at 0x3ffb0ff8:
|
|
||||||
pc = 0x42012456 in my_task
|
|
||||||
saved pc = 0x4200a123
|
|
||||||
Arglist at 0x3ffb0ff8, args:
|
|
||||||
Locals at 0x3ffb0ff8, Previous frame's sp is 0x3ffb1000
|
|
||||||
|
|
||||||
# Stack grew to 0x3ffb0ff8 but task stack base is 0x3ffb1000
|
|
||||||
# Only 8 bytes left! Stack is too small.
|
|
||||||
|
|
||||||
# Check task stack size in code
|
|
||||||
(gdb) print task_stack_size
|
|
||||||
$1 = 2048 ← Too small!
|
|
||||||
```
|
|
||||||
|
|
||||||
**Solution**: Increase task stack size to 4096 or 6144 bytes.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Problem: "No symbol table is loaded"
|
|
||||||
|
|
||||||
**Symptom**:
|
|
||||||
```gdb
|
|
||||||
(gdb) break app_main
|
|
||||||
Function "app_main" not defined.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Causes**:
|
|
||||||
1. Debug symbols not built
|
|
||||||
2. Wrong ELF file loaded
|
|
||||||
3. Optimization stripped symbols
|
|
||||||
|
|
||||||
**Solutions**:
|
|
||||||
```bash
|
|
||||||
# 1. Rebuild with debug symbols
|
|
||||||
cd ~/your-project
|
|
||||||
idf.py menuconfig # Set optimization to Debug (-Og)
|
|
||||||
idf.py fullclean build
|
|
||||||
|
|
||||||
# 2. Load correct ELF file in GDB
|
|
||||||
(gdb) file build/your-project.elf
|
|
||||||
|
|
||||||
# 3. Verify symbols exist
|
|
||||||
riscv32-esp-elf-nm build/your-project.elf | grep app_main
|
|
||||||
```
|
|
||||||
|
|
||||||
### Problem: "Cannot access memory at address 0x..."
|
|
||||||
|
|
||||||
**Symptom**:
|
|
||||||
```gdb
|
|
||||||
(gdb) print my_variable
|
|
||||||
Cannot access memory at address 0x3ffb0000
|
|
||||||
```
|
|
||||||
|
|
||||||
**Causes**:
|
|
||||||
1. Variable optimized out
|
|
||||||
2. Variable not in scope
|
|
||||||
3. Pointer is invalid
|
|
||||||
|
|
||||||
**Solutions**:
|
|
||||||
```gdb
|
|
||||||
# Check if variable exists
|
|
||||||
(gdb) info locals # Show all local variables
|
|
||||||
(gdb) info args # Show function arguments
|
|
||||||
|
|
||||||
# If optimized out, rebuild with -Og
|
|
||||||
# If out of scope, break where variable is accessible
|
|
||||||
# If pointer invalid, examine pointer value
|
|
||||||
(gdb) print &my_variable # Get address
|
|
||||||
(gdb) x/4xw 0x3ffb0000 # Examine raw memory
|
|
||||||
```
|
|
||||||
|
|
||||||
### Problem: Breakpoint Not Hitting
|
|
||||||
|
|
||||||
**Symptom**: Breakpoint set but never triggers.
|
|
||||||
|
|
||||||
**Causes**:
|
|
||||||
1. Code never executed
|
|
||||||
2. Breakpoint at wrong location
|
|
||||||
3. Out of hardware breakpoints
|
|
||||||
|
|
||||||
**Solutions**:
|
|
||||||
```gdb
|
|
||||||
# Check breakpoint status
|
|
||||||
(gdb) info breakpoints
|
|
||||||
Num Type Disp Enb Address What
|
|
||||||
1 breakpoint keep y 0x42012000 in my_func at main.c:42
|
|
||||||
|
|
||||||
# If address is 0x00000000, function doesn't exist
|
|
||||||
# If "Enb" is "n", breakpoint is disabled
|
|
||||||
(gdb) enable 1
|
|
||||||
|
|
||||||
# Try software breakpoint instead
|
|
||||||
(gdb) delete 1
|
|
||||||
(gdb) break my_func
|
|
||||||
```
|
|
||||||
|
|
||||||
### Problem: GDB Disconnects Randomly
|
|
||||||
|
|
||||||
**Symptom**: "Remote connection closed" during debugging.
|
|
||||||
|
|
||||||
**Causes**:
|
|
||||||
1. Watchdog timeout
|
|
||||||
2. CPU held too long at breakpoint
|
|
||||||
3. OpenOCD crash
|
|
||||||
|
|
||||||
**Solutions**:
|
|
||||||
```gdb
|
|
||||||
# Disable watchdog in menuconfig
|
|
||||||
# Component config → ESP System Settings →
|
|
||||||
# → [*] Interrupt watchdog timeout (ms) → 0 (disabled)
|
|
||||||
|
|
||||||
# In GDB, don't hold breakpoints too long
|
|
||||||
# Continue quickly or disable watchdog:
|
|
||||||
(gdb) monitor esp wdt off
|
|
||||||
```
|
|
||||||
|
|
||||||
### Problem: "Cannot insert breakpoint"
|
|
||||||
|
|
||||||
**Symptom**:
|
|
||||||
```gdb
|
|
||||||
(gdb) break my_func
|
|
||||||
Cannot insert breakpoint 1.
|
|
||||||
Error accessing memory address 0x42012000
|
|
||||||
```
|
|
||||||
|
|
||||||
**Causes**:
|
|
||||||
1. Code in flash, not RAM (need flash breakpoints)
|
|
||||||
2. Out of hardware breakpoints
|
|
||||||
3. Region not writable
|
|
||||||
|
|
||||||
**Solutions**:
|
|
||||||
```gdb
|
|
||||||
# Use hardware breakpoint
|
|
||||||
(gdb) hbreak my_func
|
|
||||||
|
|
||||||
# Check breakpoint count
|
|
||||||
(gdb) info breakpoints
|
|
||||||
# ESP32-C5 has 4 hardware breakpoints max
|
|
||||||
|
|
||||||
# Delete unused breakpoints
|
|
||||||
(gdb) delete 2 3 4
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Advanced Techniques
|
|
||||||
|
|
||||||
### Technique 1: Scripting GDB
|
|
||||||
|
|
||||||
Create a `.gdbinit` file to automate common tasks:
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# ~/.gdbinit or project/.gdbinit
|
|
||||||
|
|
||||||
# Connect automatically
|
|
||||||
target remote :3333
|
|
||||||
|
|
||||||
# Load symbols
|
|
||||||
file build/CSI.elf
|
|
||||||
|
|
||||||
# Define custom commands
|
|
||||||
define reset-and-break
|
|
||||||
monitor reset halt
|
|
||||||
thbreak app_main
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
# Set common breakpoints
|
|
||||||
break esp_wifi_set_csi_config
|
|
||||||
break esp_wifi_connect
|
|
||||||
|
|
||||||
# Custom print for WiFi config
|
|
||||||
define print-wifi-config
|
|
||||||
printf "SSID: %s\n", wifi_config.sta.ssid
|
|
||||||
printf "Password: %s\n", wifi_config.sta.password
|
|
||||||
printf "Channel: %d\n", wifi_config.sta.channel
|
|
||||||
end
|
|
||||||
|
|
||||||
# Display instructions
|
|
||||||
echo \n=== ESP32-C5 Debug Session ===\n
|
|
||||||
echo Commands:\n
|
|
||||||
echo reset-and-break : Reset chip and break at app_main\n
|
|
||||||
echo print-wifi-config: Show WiFi configuration\n
|
|
||||||
echo \n
|
|
||||||
```
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
```bash
|
|
||||||
idf.py gdb
|
|
||||||
# Automatically connects and loads symbols
|
|
||||||
(gdb) reset-and-break # Your custom command
|
|
||||||
```
|
|
||||||
|
|
||||||
### Technique 2: Debugging FreeRTOS Tasks
|
|
||||||
|
|
||||||
List all tasks and their states:
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Show all tasks
|
|
||||||
(gdb) info threads
|
|
||||||
Id Target Id Frame
|
|
||||||
* 1 Remote target vTaskDelay () at FreeRTOS.c:1543
|
|
||||||
2 Remote target prvIdleTask () at FreeRTOS.c:2301
|
|
||||||
3 Remote target wifi_task () at esp_wifi_driver.c:456
|
|
||||||
|
|
||||||
# Switch to different task
|
|
||||||
(gdb) thread 3
|
|
||||||
[Switching to thread 3 (Remote target)]
|
|
||||||
|
|
||||||
# See that task's stack
|
|
||||||
(gdb) backtrace
|
|
||||||
#0 wifi_task () at esp_wifi_driver.c:456
|
|
||||||
#1 0x4200a456 in vPortTaskWrapper ()
|
|
||||||
```
|
|
||||||
|
|
||||||
### Technique 3: Examine WiFi Driver Internals
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Break in WiFi driver
|
|
||||||
(gdb) break esp_wifi_internal.c:esp_wifi_set_bandwidth
|
|
||||||
|
|
||||||
# When it breaks, examine internal state
|
|
||||||
(gdb) print g_wifi_state
|
|
||||||
(gdb) print g_wifi_config
|
|
||||||
(gdb) print g_sta_netif
|
|
||||||
|
|
||||||
# Step through WiFi driver code
|
|
||||||
(gdb) step
|
|
||||||
(gdb) step
|
|
||||||
```
|
|
||||||
|
|
||||||
### Technique 4: Live Variable Modification
|
|
||||||
|
|
||||||
Change variables on-the-fly without recompiling:
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Break at function
|
|
||||||
(gdb) break send_packet
|
|
||||||
(gdb) continue
|
|
||||||
|
|
||||||
# Change packet size before sending
|
|
||||||
(gdb) print packet_size
|
|
||||||
$1 = 1024
|
|
||||||
(gdb) set packet_size = 64
|
|
||||||
(gdb) print packet_size
|
|
||||||
$2 = 64
|
|
||||||
|
|
||||||
# Continue with modified value
|
|
||||||
(gdb) continue
|
|
||||||
```
|
|
||||||
|
|
||||||
### Technique 5: Reverse Debugging (Limited)
|
|
||||||
|
|
||||||
Record execution to step backwards:
|
|
||||||
|
|
||||||
```gdb
|
|
||||||
# Enable recording (only works for short sequences)
|
|
||||||
(gdb) target record-full
|
|
||||||
|
|
||||||
# Run forward
|
|
||||||
(gdb) continue
|
|
||||||
(gdb) next
|
|
||||||
|
|
||||||
# Step backwards!
|
|
||||||
(gdb) reverse-step
|
|
||||||
(gdb) reverse-next
|
|
||||||
|
|
||||||
# Disable recording (uses lots of memory)
|
|
||||||
(gdb) record stop
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Resources
|
|
||||||
|
|
||||||
### Official Documentation
|
|
||||||
|
|
||||||
- **ESP-IDF GDB Guide**: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c5/api-guides/jtag-debugging/
|
|
||||||
- **ESP32-C5 Datasheet**: https://www.espressif.com/sites/default/files/documentation/esp32-c5_datasheet_en.pdf
|
|
||||||
- **OpenOCD Manual**: http://openocd.org/doc/html/index.html
|
|
||||||
- **GDB Manual**: https://sourceware.org/gdb/current/onlinedocs/gdb/
|
|
||||||
|
|
||||||
### GDB Cheat Sheets
|
|
||||||
|
|
||||||
- **GDB Quick Reference**: https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf
|
|
||||||
- **RISC-V GDB Guide**: https://github.com/riscv/riscv-gnu-toolchain
|
|
||||||
|
|
||||||
### ESP32 Community
|
|
||||||
|
|
||||||
- **ESP32 Forum**: https://esp32.com/
|
|
||||||
- **r/esp32 Subreddit**: https://reddit.com/r/esp32
|
|
||||||
- **Espressif GitHub**: https://github.com/espressif/esp-idf
|
|
||||||
|
|
||||||
### GDB Tutorials
|
|
||||||
|
|
||||||
- **Debugging with GDB**: https://sourceware.org/gdb/onlinedocs/gdb/
|
|
||||||
- **RMS's GDB Tutorial**: https://www.gnu.org/software/gdb/documentation/
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
GDB debugging on the ESP32-C5 provides powerful insights into firmware behavior:
|
|
||||||
|
|
||||||
- ✅ **Built-in USB-JTAG** eliminates external hardware requirements
|
|
||||||
- ✅ **Hardware and software breakpoints** for flexible debugging
|
|
||||||
- ✅ **Real-time variable inspection** without printf statements
|
|
||||||
- ✅ **Watchpoints** to catch memory corruption
|
|
||||||
- ✅ **Call stack analysis** to understand program flow
|
|
||||||
- ✅ **ESP-IDF driver debugging** to troubleshoot library issues
|
|
||||||
|
|
||||||
**Key takeaways**:
|
|
||||||
|
|
||||||
1. Always build with **Debug (-Og)** optimization for best debug experience
|
|
||||||
2. Use **conditional breakpoints** to break only when needed
|
|
||||||
3. Combine **watchpoints** with breakpoints to find memory corruption
|
|
||||||
4. **Script common tasks** in `.gdbinit` for faster debugging
|
|
||||||
5. The **WiFi driver log** is still the ground truth for connection status
|
|
||||||
|
|
||||||
GDB debugging significantly reduces debug time compared to printf-based approaches, especially for complex issues like WiFi driver bugs, FreeRTOS task interactions, and memory corruption.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
This guide was created based on real-world ESP32-C5 development experience, specifically debugging WiFi 6 CSI (Channel State Information) capture issues for the iperf WiFi Analyzer project.
|
|
||||||
|
|
||||||
**Hardware**: ESP32-C5 DevKit
|
|
||||||
**Project**: WiFi Collapse Detection using CSI
|
|
||||||
**Repository**: https://github.com/iperf2/iperf2
|
|
||||||
|
|
||||||
For questions or corrections, please open an issue on GitHub.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Last Updated**: December 4, 2025
|
|
||||||
|
|
@ -1,222 +0,0 @@
|
||||||
# ESP32-C5 GDB Debugging Guide - README
|
|
||||||
|
|
||||||
Two versions of the comprehensive GDB debugging guide have been created:
|
|
||||||
|
|
||||||
## Files
|
|
||||||
|
|
||||||
1. **ESP32-C5_GDB_Debugging_Guide.md** - Markdown version
|
|
||||||
- Perfect for GitHub, documentation sites, or conversion to other formats
|
|
||||||
- Clean, portable, works everywhere
|
|
||||||
|
|
||||||
2. **ESP32-C5_GDB_Debugging_Guide.html** - HTML version
|
|
||||||
- Professional web-ready format with styling
|
|
||||||
- Responsive design (mobile-friendly)
|
|
||||||
- Direct upload to website
|
|
||||||
|
|
||||||
## Content Overview
|
|
||||||
|
|
||||||
### Complete Coverage:
|
|
||||||
|
|
||||||
1. **Introduction** - ESP32-C5 overview and debugging benefits
|
|
||||||
2. **Why GDB?** - Comparison with printf debugging
|
|
||||||
3. **Hardware Capabilities** - Built-in USB-JTAG features
|
|
||||||
4. **Prerequisites** - Required software and hardware
|
|
||||||
5. **Building with Debug Symbols** - Step-by-step configuration
|
|
||||||
6. **Starting Debug Session** - Three-step process (flash, OpenOCD, GDB)
|
|
||||||
7. **Essential Commands** - Comprehensive GDB command reference
|
|
||||||
8. **Debugging Strategies** - Five proven strategies
|
|
||||||
9. **Real-World Examples** - Five complete debugging scenarios:
|
|
||||||
- CSI configuration failure (your actual problem!)
|
|
||||||
- Memory corruption detection
|
|
||||||
- WiFi connection troubleshooting
|
|
||||||
- Performance profiling
|
|
||||||
- Stack overflow debugging
|
|
||||||
10. **Troubleshooting** - Common problems and solutions
|
|
||||||
11. **Advanced Techniques** - Scripting, FreeRTOS, live modification
|
|
||||||
12. **Resources** - Links to official docs and community
|
|
||||||
|
|
||||||
## Key Features
|
|
||||||
|
|
||||||
- ✅ **Based on your actual ESP32-C5 experience**
|
|
||||||
- ✅ **Real debugging examples from CSI issues**
|
|
||||||
- ✅ **Complete command reference**
|
|
||||||
- ✅ **Troubleshooting guide**
|
|
||||||
- ✅ **Professional web design** (HTML version)
|
|
||||||
- ✅ **Ready to publish**
|
|
||||||
|
|
||||||
## Publishing Options
|
|
||||||
|
|
||||||
### Option 1: GitHub Pages
|
|
||||||
```bash
|
|
||||||
# Add to your GitHub repo docs/
|
|
||||||
git add ESP32-C5_GDB_Debugging_Guide.md
|
|
||||||
git commit -m "Add GDB debugging guide"
|
|
||||||
git push
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option 2: Direct Website Upload
|
|
||||||
```bash
|
|
||||||
# Upload the HTML file to your web server
|
|
||||||
scp ESP32-C5_GDB_Debugging_Guide.html user@yoursite.com:/var/www/html/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option 3: Static Site Generator
|
|
||||||
```bash
|
|
||||||
# The markdown works with Jekyll, Hugo, MkDocs, etc.
|
|
||||||
cp ESP32-C5_GDB_Debugging_Guide.md docs/
|
|
||||||
# Build your static site
|
|
||||||
```
|
|
||||||
|
|
||||||
## Customization
|
|
||||||
|
|
||||||
### HTML Styling
|
|
||||||
|
|
||||||
The HTML version includes CSS in the `<style>` section. To customize:
|
|
||||||
|
|
||||||
```css
|
|
||||||
:root {
|
|
||||||
--primary-color: #0e7490; /* Teal accent */
|
|
||||||
--secondary-color: #357edd; /* Blue links */
|
|
||||||
--bg-color: #f9f9f9; /* Background */
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Change these colors to match your website theme.
|
|
||||||
|
|
||||||
### Branding
|
|
||||||
|
|
||||||
Update footer section with your info:
|
|
||||||
- Website URL
|
|
||||||
- Contact information
|
|
||||||
- Additional projects
|
|
||||||
- Social media links
|
|
||||||
|
|
||||||
### Content
|
|
||||||
|
|
||||||
Feel free to:
|
|
||||||
- Add your specific hardware setup
|
|
||||||
- Include project-specific examples
|
|
||||||
- Add screenshots/diagrams
|
|
||||||
- Link to your iperf2 documentation
|
|
||||||
|
|
||||||
## SEO Optimization (HTML version)
|
|
||||||
|
|
||||||
Consider adding to `<head>`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<meta name="description" content="Complete guide to GDB debugging on ESP32-C5 with real-world WiFi driver examples">
|
|
||||||
<meta name="keywords" content="ESP32-C5, GDB, debugging, RISC-V, WiFi, CSI, iperf">
|
|
||||||
<meta name="author" content="Bob McMahon">
|
|
||||||
|
|
||||||
<!-- Open Graph for social sharing -->
|
|
||||||
<meta property="og:title" content="ESP32-C5 GDB Debugging Guide">
|
|
||||||
<meta property="og:description" content="Professional guide to debugging ESP32-C5 firmware">
|
|
||||||
<meta property="og:type" content="article">
|
|
||||||
```
|
|
||||||
|
|
||||||
## Analytics (Optional)
|
|
||||||
|
|
||||||
Add Google Analytics to HTML version in `<head>`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- Google Analytics -->
|
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=YOUR-GA-ID"></script>
|
|
||||||
<script>
|
|
||||||
window.dataLayer = window.dataLayer || [];
|
|
||||||
function gtag(){dataLayer.push(arguments);}
|
|
||||||
gtag('js', new Date());
|
|
||||||
gtag('config', 'YOUR-GA-ID');
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Consider adding a license. Suggested Creative Commons:
|
|
||||||
|
|
||||||
```
|
|
||||||
This work is licensed under CC BY 4.0
|
|
||||||
(Attribution 4.0 International)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Maintenance
|
|
||||||
|
|
||||||
### Update Checklist:
|
|
||||||
- [ ] ESP-IDF version updates
|
|
||||||
- [ ] New debugging techniques discovered
|
|
||||||
- [ ] Additional real-world examples
|
|
||||||
- [ ] Community feedback/corrections
|
|
||||||
- [ ] New ESP32-C5 features
|
|
||||||
|
|
||||||
### Version History:
|
|
||||||
- v1.0 (Dec 2025): Initial release
|
|
||||||
- Based on ESP32-C5 CSI debugging experience
|
|
||||||
- Complete command reference
|
|
||||||
- Five real-world examples
|
|
||||||
|
|
||||||
## Feedback
|
|
||||||
|
|
||||||
Encourage readers to:
|
|
||||||
- Report errors or outdated info
|
|
||||||
- Suggest improvements
|
|
||||||
- Share their own debugging experiences
|
|
||||||
- Contribute examples
|
|
||||||
|
|
||||||
## Related Content Ideas
|
|
||||||
|
|
||||||
This guide could be part of a series:
|
|
||||||
1. ✅ **GDB Debugging Guide** (this document)
|
|
||||||
2. ESP32-C5 WiFi 6 Programming Guide
|
|
||||||
3. CSI Data Analysis Tutorial
|
|
||||||
4. iperf WiFi Analyzer Usage Guide
|
|
||||||
5. ESP32-C5 vs ESP32-S3 Comparison
|
|
||||||
|
|
||||||
## Technical Details
|
|
||||||
|
|
||||||
### Markdown Features Used:
|
|
||||||
- Tables
|
|
||||||
- Code blocks with syntax highlighting
|
|
||||||
- Nested lists
|
|
||||||
- Emphasis (bold, italic)
|
|
||||||
- Links
|
|
||||||
- Headers (h1-h3)
|
|
||||||
|
|
||||||
### HTML Features:
|
|
||||||
- Responsive design (mobile-friendly)
|
|
||||||
- CSS Grid/Flexbox layout
|
|
||||||
- Syntax highlighting styles
|
|
||||||
- Alert boxes (info, success, warning)
|
|
||||||
- Jump-to-section navigation
|
|
||||||
- Accessible markup
|
|
||||||
|
|
||||||
### Browser Compatibility:
|
|
||||||
- Chrome/Edge ✅
|
|
||||||
- Firefox ✅
|
|
||||||
- Safari ✅
|
|
||||||
- Mobile browsers ✅
|
|
||||||
|
|
||||||
## File Sizes
|
|
||||||
|
|
||||||
- Markdown: ~50 KB
|
|
||||||
- HTML: ~80 KB (includes embedded CSS)
|
|
||||||
|
|
||||||
Both are lightweight and fast to load.
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
1. **Review** both versions
|
|
||||||
2. **Customize** branding/colors
|
|
||||||
3. **Test** HTML in browser
|
|
||||||
4. **Publish** to your website
|
|
||||||
5. **Share** with ESP32 community
|
|
||||||
6. **Update** based on feedback
|
|
||||||
|
|
||||||
## Questions?
|
|
||||||
|
|
||||||
Both versions are production-ready. The content is comprehensive, accurate, and based on your real debugging experience with the ESP32-C5 CSI issues.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Files created:**
|
|
||||||
- `ESP32-C5_GDB_Debugging_Guide.md` (50 KB)
|
|
||||||
- `ESP32-C5_GDB_Debugging_Guide.html` (80 KB)
|
|
||||||
- `GDB_GUIDE_README.md` (this file)
|
|
||||||
363
MASS_DEPLOY.md
363
MASS_DEPLOY.md
|
|
@ -1,363 +0,0 @@
|
||||||
# Mass ESP32 Deployment Guide
|
|
||||||
|
|
||||||
Complete guide for flashing 32+ ESP32 devices with unique static IPs.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This system allows you to:
|
|
||||||
- Flash multiple ESP32/ESP32-S2/ESP32-S3 devices automatically
|
|
||||||
- Assign unique static IP addresses to each device (192.168.1.50-192.168.1.81)
|
|
||||||
- Configure WiFi credentials during build
|
|
||||||
- Reconfigure WiFi after flashing via console
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Install Python dependencies
|
|
||||||
pip install pyserial
|
|
||||||
|
|
||||||
# Ensure ESP-IDF is installed with all targets
|
|
||||||
cd ~/Code/esp32/esp-idf
|
|
||||||
./install.sh esp32,esp32s2,esp32s3
|
|
||||||
|
|
||||||
# Activate ESP-IDF environment
|
|
||||||
. ~/Code/esp32/esp-idf/export.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Method 1: Automated Mass Flash (Recommended)
|
|
||||||
|
|
||||||
### Prepare Your Devices
|
|
||||||
|
|
||||||
1. Connect all ESP32 devices to USB hubs
|
|
||||||
2. Verify detection:
|
|
||||||
```bash
|
|
||||||
cd ~/Code/esp32/esp32-iperf
|
|
||||||
python3 detect_esp32.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### Flash All Devices
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/Code/esp32/esp32-iperf
|
|
||||||
|
|
||||||
# Dry run to see the plan
|
|
||||||
python3 flash_all.py \
|
|
||||||
--ssid "YourWiFiSSID" \
|
|
||||||
--password "YourPassword" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--gateway 192.168.1.1 \
|
|
||||||
--dry-run
|
|
||||||
|
|
||||||
# Actually flash (this will take a while!)
|
|
||||||
python3 flash_all.py \
|
|
||||||
--ssid "YourWiFiSSID" \
|
|
||||||
--password "YourPassword" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--gateway 192.168.1.1
|
|
||||||
|
|
||||||
# With chip probing (slower but more accurate)
|
|
||||||
python3 flash_all.py \
|
|
||||||
--ssid "YourWiFiSSID" \
|
|
||||||
--password "YourPassword" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--probe
|
|
||||||
```
|
|
||||||
|
|
||||||
### Script Options
|
|
||||||
|
|
||||||
- `--ssid`: WiFi network name (required)
|
|
||||||
- `--password`: WiFi password (required)
|
|
||||||
- `--start-ip`: Starting IP address (default: 192.168.1.50)
|
|
||||||
- `--gateway`: Gateway IP (default: 192.168.1.1)
|
|
||||||
- `--probe`: Probe each device to detect exact chip type (slower)
|
|
||||||
- `--dry-run`: Show plan without flashing
|
|
||||||
- `--project-dir`: Custom project directory
|
|
||||||
|
|
||||||
### What the Script Does
|
|
||||||
|
|
||||||
For each device:
|
|
||||||
1. Detects chip type (ESP32/ESP32-S2/ESP32-S3)
|
|
||||||
2. Calculates unique IP address (increments from start IP)
|
|
||||||
3. Creates custom sdkconfig.defaults with WiFi and IP settings
|
|
||||||
4. Sets the correct target (esp32/esp32s2/esp32s3)
|
|
||||||
5. Builds firmware with custom configuration
|
|
||||||
6. Flashes the device
|
|
||||||
|
|
||||||
## Method 2: Manual Configuration Per Device
|
|
||||||
|
|
||||||
If you want to flash devices one at a time or need custom settings:
|
|
||||||
|
|
||||||
### Create sdkconfig.defaults
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/Code/esp32/esp32-iperf
|
|
||||||
cat > sdkconfig.defaults << EOF
|
|
||||||
# WiFi Configuration
|
|
||||||
CONFIG_WIFI_SSID="YourSSID"
|
|
||||||
CONFIG_WIFI_PASSWORD="YourPassword"
|
|
||||||
CONFIG_WIFI_MAXIMUM_RETRY=5
|
|
||||||
|
|
||||||
# Static IP Configuration
|
|
||||||
CONFIG_USE_STATIC_IP=y
|
|
||||||
CONFIG_STATIC_IP_ADDR="192.168.1.50"
|
|
||||||
CONFIG_STATIC_GATEWAY_ADDR="192.168.1.1"
|
|
||||||
CONFIG_STATIC_NETMASK_ADDR="255.255.255.0"
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build and Flash
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Set target (choose one)
|
|
||||||
idf.py set-target esp32 # for ESP32
|
|
||||||
idf.py set-target esp32s2 # for ESP32-S2
|
|
||||||
idf.py set-target esp32s3 # for ESP32-S3
|
|
||||||
|
|
||||||
# Build
|
|
||||||
idf.py build
|
|
||||||
|
|
||||||
# Flash to specific device
|
|
||||||
idf.py -p /dev/ttyUSB0 flash monitor
|
|
||||||
|
|
||||||
# For next device, edit sdkconfig.defaults with new IP
|
|
||||||
# Then clean and rebuild
|
|
||||||
idf.py fullclean
|
|
||||||
# ... edit sdkconfig.defaults ...
|
|
||||||
idf.py build
|
|
||||||
idf.py -p /dev/ttyUSB1 flash
|
|
||||||
```
|
|
||||||
|
|
||||||
## Method 3: Reconfigure After Flashing
|
|
||||||
|
|
||||||
If devices are already flashed but need different WiFi credentials:
|
|
||||||
|
|
||||||
### Via Console
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Connect to device
|
|
||||||
idf.py -p /dev/ttyUSB0 monitor
|
|
||||||
|
|
||||||
# At the prompt
|
|
||||||
iperf> wifi -s "NewSSID" -p "NewPassword"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Via Script (Multiple Devices)
|
|
||||||
|
|
||||||
Create a script to update all devices:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
for port in /dev/ttyUSB{0..31}; do
|
|
||||||
echo "Updating $port..."
|
|
||||||
# Send commands via screen or minicom
|
|
||||||
screen -S esp_config $port 115200 -X stuff "wifi -s \"NewSSID\" -p \"NewPassword\"\n"
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
## IP Address Assignment
|
|
||||||
|
|
||||||
Based on your 32 detected devices:
|
|
||||||
|
|
||||||
```
|
|
||||||
Device 1 -> /dev/ttyUSB0 -> 192.168.1.50
|
|
||||||
Device 2 -> /dev/ttyUSB1 -> 192.168.1.51
|
|
||||||
Device 3 -> /dev/ttyUSB2 -> 192.168.1.52
|
|
||||||
...
|
|
||||||
Device 32 -> /dev/ttyUSB31 -> 192.168.1.81
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing Your Deployment
|
|
||||||
|
|
||||||
### Check Device Connectivity
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Ping all devices
|
|
||||||
for i in {50..81}; do
|
|
||||||
ping -c 1 -W 1 192.168.1.$i && echo "192.168.1.$i is UP" || echo "192.168.1.$i is DOWN"
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run iperf Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Start all devices as iperf servers
|
|
||||||
# (via console on each device)
|
|
||||||
iperf> iperf -s
|
|
||||||
|
|
||||||
# From your PC, test each device
|
|
||||||
for i in {50..81}; do
|
|
||||||
echo "Testing 192.168.1.$i"
|
|
||||||
iperf -c 192.168.1.$i -t 5
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
### Batch iperf Test Script
|
|
||||||
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
start_ip = "192.168.1.50"
|
|
||||||
end_ip = "192.168.1.81"
|
|
||||||
|
|
||||||
base = start_ip.rsplit('.', 1)[0]
|
|
||||||
start = int(start_ip.rsplit('.', 1)[1])
|
|
||||||
end = int(end_ip.rsplit('.', 1)[1])
|
|
||||||
|
|
||||||
results = []
|
|
||||||
for i in range(start, end + 1):
|
|
||||||
ip = f"{base}.{i}"
|
|
||||||
print(f"Testing {ip}...", end=' ', flush=True)
|
|
||||||
|
|
||||||
result = subprocess.run(
|
|
||||||
['iperf', '-c', ip, '-t', '5', '-f', 'm'],
|
|
||||||
capture_output=True,
|
|
||||||
text=True,
|
|
||||||
timeout=10
|
|
||||||
)
|
|
||||||
|
|
||||||
if result.returncode == 0:
|
|
||||||
# Parse bandwidth from output
|
|
||||||
for line in result.stdout.split('\n'):
|
|
||||||
if 'Mbits/sec' in line:
|
|
||||||
bandwidth = line.split()[-2]
|
|
||||||
print(f"✓ {bandwidth} Mbits/sec")
|
|
||||||
results.append((ip, bandwidth))
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("✗ FAILED")
|
|
||||||
|
|
||||||
print(f"\nTested {len(results)}/{end-start+1} devices successfully")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Device Not Detected
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check USB connection
|
|
||||||
lsusb
|
|
||||||
|
|
||||||
# Check permissions
|
|
||||||
sudo usermod -a -G dialout $USER
|
|
||||||
# Log out and back in
|
|
||||||
|
|
||||||
# Check if port exists
|
|
||||||
ls -la /dev/ttyUSB*
|
|
||||||
```
|
|
||||||
|
|
||||||
### Flash Failed
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Try holding BOOT button during flash
|
|
||||||
idf.py -p /dev/ttyUSB0 flash
|
|
||||||
|
|
||||||
# Lower baud rate
|
|
||||||
idf.py -p /dev/ttyUSB0 -b 115200 flash
|
|
||||||
|
|
||||||
# Erase flash first
|
|
||||||
idf.py -p /dev/ttyUSB0 erase-flash
|
|
||||||
idf.py -p /dev/ttyUSB0 flash
|
|
||||||
```
|
|
||||||
|
|
||||||
### WiFi Not Connecting
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Monitor the device
|
|
||||||
idf.py -p /dev/ttyUSB0 monitor
|
|
||||||
|
|
||||||
# Check logs for WiFi errors
|
|
||||||
# Try reconfiguring via console:
|
|
||||||
iperf> wifi -s "YourSSID" -p "YourPassword"
|
|
||||||
```
|
|
||||||
|
|
||||||
### IP Address Conflict
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check what's using the IP
|
|
||||||
ping 192.168.1.50
|
|
||||||
arp -a | grep 192.168.1.50
|
|
||||||
|
|
||||||
# Reflash with different IP range
|
|
||||||
python3 flash_all.py \
|
|
||||||
--ssid "YourSSID" \
|
|
||||||
--password "YourPassword" \
|
|
||||||
--start-ip 192.168.1.100
|
|
||||||
```
|
|
||||||
|
|
||||||
## Console Commands Reference
|
|
||||||
|
|
||||||
### WiFi Configuration
|
|
||||||
```
|
|
||||||
wifi -s <ssid> -p <password>
|
|
||||||
```
|
|
||||||
|
|
||||||
### iperf Commands
|
|
||||||
```bash
|
|
||||||
# TCP server
|
|
||||||
iperf -s
|
|
||||||
|
|
||||||
# TCP client
|
|
||||||
iperf -c <ip>
|
|
||||||
|
|
||||||
# UDP server
|
|
||||||
iperf -s -u
|
|
||||||
|
|
||||||
# UDP client
|
|
||||||
iperf -c <ip> -u
|
|
||||||
|
|
||||||
# Custom port
|
|
||||||
iperf -s -p 5002
|
|
||||||
|
|
||||||
# Custom duration
|
|
||||||
iperf -c <ip> -t 30
|
|
||||||
|
|
||||||
# Stop running test
|
|
||||||
iperf -a
|
|
||||||
```
|
|
||||||
|
|
||||||
## Advanced: Parallel Flashing
|
|
||||||
|
|
||||||
To flash multiple devices simultaneously:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
# flash_parallel.sh
|
|
||||||
|
|
||||||
# Flash 4 devices at once
|
|
||||||
idf.py -p /dev/ttyUSB0 flash &
|
|
||||||
idf.py -p /dev/ttyUSB1 flash &
|
|
||||||
idf.py -p /dev/ttyUSB2 flash &
|
|
||||||
idf.py -p /dev/ttyUSB3 flash &
|
|
||||||
|
|
||||||
wait
|
|
||||||
echo "Batch complete"
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: Each device still needs its own build with unique IP.
|
|
||||||
|
|
||||||
## Production Deployment Workflow
|
|
||||||
|
|
||||||
1. **Prepare**: Connect all devices, verify detection
|
|
||||||
2. **Flash**: Run mass flash script with dry-run first
|
|
||||||
3. **Verify**: Ping all IPs to confirm connectivity
|
|
||||||
4. **Test**: Run iperf from PC to each device
|
|
||||||
5. **Deploy**: Mount devices in test locations
|
|
||||||
6. **Monitor**: Use iperf console to run tests
|
|
||||||
|
|
||||||
## File Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
esp32-iperf/
|
|
||||||
├── main/
|
|
||||||
│ ├── main.c # Main app with WiFi
|
|
||||||
│ ├── iperf.c # iperf implementation
|
|
||||||
│ ├── iperf.h # iperf header
|
|
||||||
│ └── Kconfig.projbuild # Configuration options
|
|
||||||
├── CMakeLists.txt
|
|
||||||
├── README.md
|
|
||||||
├── flash_all.py # Mass flash script
|
|
||||||
├── detect_esp32.py # Device detection
|
|
||||||
└── sdkconfig.defaults # Auto-generated config
|
|
||||||
```
|
|
||||||
|
|
@ -1,249 +0,0 @@
|
||||||
# Parallel Mass Flash Guide
|
|
||||||
|
|
||||||
Speed up your 32-device deployment from **60-90 minutes** to **15-20 minutes**!
|
|
||||||
|
|
||||||
## Quick Comparison
|
|
||||||
|
|
||||||
| Method | Time for 32 Devices | Command |
|
|
||||||
|--------|---------------------|---------|
|
|
||||||
| **Sequential** | 60-90 minutes | `flash_all.py` |
|
|
||||||
| **Parallel (build-and-flash)** | 20-25 minutes | `flash_all_parallel.py --build-parallel 4` |
|
|
||||||
| **Parallel (build-then-flash)** | 15-20 minutes | `flash_all_parallel.py --strategy build-then-flash` |
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Method 1: Build-and-Flash (Recommended for Most Users)
|
|
||||||
|
|
||||||
Builds and flashes devices in batches. Lower memory usage, good balance.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/Code/esp32/esp32-iperf
|
|
||||||
git checkout mass_deployment
|
|
||||||
|
|
||||||
# Use default settings (CPU cores - 1 for parallelism)
|
|
||||||
python3 flash_all_parallel.py \
|
|
||||||
--ssid "YourWiFi" \
|
|
||||||
--password "YourPassword" \
|
|
||||||
--start-ip 192.168.1.50
|
|
||||||
|
|
||||||
# Or specify parallel operations
|
|
||||||
python3 flash_all_parallel.py \
|
|
||||||
--ssid "YourWiFi" \
|
|
||||||
--password "YourPassword" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--build-parallel 4
|
|
||||||
```
|
|
||||||
|
|
||||||
**How it works:** Builds 4 devices at once, flashes them as they complete, then moves to the next batch.
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- Lower memory usage
|
|
||||||
- Good parallelism
|
|
||||||
- Fails are isolated per device
|
|
||||||
|
|
||||||
**Time:** ~20-25 minutes for 32 devices
|
|
||||||
|
|
||||||
### Method 2: Build-Then-Flash (Fastest)
|
|
||||||
|
|
||||||
Builds all configurations first, then flashes everything in parallel.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 flash_all_parallel.py \
|
|
||||||
--ssid "YourWiFi" \
|
|
||||||
--password "YourPassword" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--strategy build-then-flash \
|
|
||||||
--build-parallel 4 \
|
|
||||||
--flash-parallel 16
|
|
||||||
```
|
|
||||||
|
|
||||||
**How it works:**
|
|
||||||
1. Phase 1: Builds all 32 configurations (4 at a time)
|
|
||||||
2. Phase 2: Flashes all 32 devices (16 at a time)
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- Fastest method
|
|
||||||
- Maximizes flash parallelism
|
|
||||||
- Clear phases
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- Uses more disk space temporarily (~2GB during Phase 1)
|
|
||||||
- Higher memory usage
|
|
||||||
|
|
||||||
**Time:** ~15-20 minutes for 32 devices
|
|
||||||
|
|
||||||
## Options
|
|
||||||
|
|
||||||
```
|
|
||||||
--ssid "SSID" WiFi network name (required)
|
|
||||||
--password "PASSWORD" WiFi password (required)
|
|
||||||
--start-ip 192.168.1.50 Starting IP address
|
|
||||||
--gateway 192.168.1.1 Gateway IP
|
|
||||||
--strategy build-and-flash | build-then-flash
|
|
||||||
--build-parallel N Parallel builds (default: CPU cores - 1)
|
|
||||||
--flash-parallel N Parallel flash ops (default: 8)
|
|
||||||
--probe Probe chip types with esptool
|
|
||||||
--dry-run Show plan without executing
|
|
||||||
```
|
|
||||||
|
|
||||||
## Hardware Considerations
|
|
||||||
|
|
||||||
### CPU/Memory Requirements
|
|
||||||
|
|
||||||
**For build-parallel 4:**
|
|
||||||
- CPU: 4+ cores recommended
|
|
||||||
- RAM: 8GB minimum, 16GB recommended
|
|
||||||
- Disk space: 10GB free
|
|
||||||
|
|
||||||
**For build-parallel 8:**
|
|
||||||
- CPU: 8+ cores
|
|
||||||
- RAM: 16GB minimum
|
|
||||||
- Disk space: 20GB free
|
|
||||||
|
|
||||||
### USB Hub Requirements
|
|
||||||
|
|
||||||
- **Use powered USB hubs** - Each ESP32 draws 200-500mA
|
|
||||||
- **USB bandwidth:** USB 2.0 is sufficient (12 Mbps per device for flashing)
|
|
||||||
- **Recommended:** Distribute devices across multiple USB controllers
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Conservative (4-core system)
|
|
||||||
```bash
|
|
||||||
python3 flash_all_parallel.py \
|
|
||||||
--ssid "TestNet" \
|
|
||||||
--password "password123" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--build-parallel 2 \
|
|
||||||
--flash-parallel 8
|
|
||||||
```
|
|
||||||
|
|
||||||
### Balanced (8-core system)
|
|
||||||
```bash
|
|
||||||
python3 flash_all_parallel.py \
|
|
||||||
--ssid "TestNet" \
|
|
||||||
--password "password123" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--build-parallel 4 \
|
|
||||||
--flash-parallel 12
|
|
||||||
```
|
|
||||||
|
|
||||||
### Aggressive (16+ core system)
|
|
||||||
```bash
|
|
||||||
python3 flash_all_parallel.py \
|
|
||||||
--ssid "TestNet" \
|
|
||||||
--password "password123" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--strategy build-then-flash \
|
|
||||||
--build-parallel 8 \
|
|
||||||
--flash-parallel 16
|
|
||||||
```
|
|
||||||
|
|
||||||
## Monitoring Progress
|
|
||||||
|
|
||||||
The script shows real-time progress:
|
|
||||||
|
|
||||||
```
|
|
||||||
Phase 1: Building 32 configurations with 4 parallel builds...
|
|
||||||
[Device 1] Building for esp32 with IP 192.168.1.50
|
|
||||||
[Device 2] Building for esp32 with IP 192.168.1.51
|
|
||||||
[Device 3] Building for esp32 with IP 192.168.1.52
|
|
||||||
[Device 4] Building for esp32 with IP 192.168.1.53
|
|
||||||
[Device 1] ✓ Build complete
|
|
||||||
[Device 5] Building for esp32 with IP 192.168.1.54
|
|
||||||
[Device 2] ✓ Build complete
|
|
||||||
...
|
|
||||||
|
|
||||||
Phase 2: Flashing 32 devices with 16 parallel operations...
|
|
||||||
[Device 1] Flashing /dev/ttyUSB0 -> 192.168.1.50
|
|
||||||
[Device 2] Flashing /dev/ttyUSB1 -> 192.168.1.51
|
|
||||||
...
|
|
||||||
[Device 1] ✓ Flash complete at 192.168.1.50
|
|
||||||
[Device 2] ✓ Flash complete at 192.168.1.51
|
|
||||||
...
|
|
||||||
|
|
||||||
DEPLOYMENT SUMMARY
|
|
||||||
Successfully deployed: 32/32 devices
|
|
||||||
Total time: 892.3 seconds (14.9 minutes)
|
|
||||||
Average time per device: 27.9 seconds
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### "Out of memory" during build
|
|
||||||
**Solution:** Reduce `--build-parallel`:
|
|
||||||
```bash
|
|
||||||
python3 flash_all_parallel.py ... --build-parallel 2
|
|
||||||
```
|
|
||||||
|
|
||||||
### Flash timeouts
|
|
||||||
**Solution:** Reduce `--flash-parallel`:
|
|
||||||
```bash
|
|
||||||
python3 flash_all_parallel.py ... --flash-parallel 4
|
|
||||||
```
|
|
||||||
|
|
||||||
### USB hub overload
|
|
||||||
**Symptoms:** Devices disconnecting, flash failures
|
|
||||||
|
|
||||||
**Solution:**
|
|
||||||
1. Use powered USB hubs
|
|
||||||
2. Distribute devices across multiple hubs
|
|
||||||
3. Reduce flash parallelism
|
|
||||||
|
|
||||||
### Mixed chip types
|
|
||||||
**Solution:** Use `--probe` to auto-detect:
|
|
||||||
```bash
|
|
||||||
python3 flash_all_parallel.py ... --probe
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Comparison
|
|
||||||
|
|
||||||
Testing on a typical 8-core system with 32 devices:
|
|
||||||
|
|
||||||
| Method | Build Time | Flash Time | Total Time |
|
|
||||||
|--------|-----------|------------|------------|
|
|
||||||
| Sequential (original) | 48 min | 16 min | 64 min |
|
|
||||||
| Parallel (build-parallel 4, build-and-flash) | 15 min | 7 min | 22 min |
|
|
||||||
| Parallel (build-parallel 4, build-then-flash) | 12 min | 4 min | 16 min |
|
|
||||||
| Parallel (build-parallel 8, build-then-flash) | 8 min | 4 min | 12 min |
|
|
||||||
|
|
||||||
**Speedup:** 3-5x faster than sequential!
|
|
||||||
|
|
||||||
## When to Use Each Script
|
|
||||||
|
|
||||||
### Use `flash_all.py` (Sequential) when:
|
|
||||||
- First time setup to verify everything works
|
|
||||||
- Limited CPU/memory (< 4GB RAM)
|
|
||||||
- Debugging individual device issues
|
|
||||||
- Only flashing a few devices (< 5)
|
|
||||||
|
|
||||||
### Use `flash_all_parallel.py` when:
|
|
||||||
- Flashing many devices (10+)
|
|
||||||
- You have sufficient resources (8GB+ RAM, 4+ cores)
|
|
||||||
- Time is important
|
|
||||||
- Production deployment
|
|
||||||
|
|
||||||
## Best Practices
|
|
||||||
|
|
||||||
1. **Test first:** Run with `--dry-run` to verify configuration
|
|
||||||
2. **Start conservative:** Begin with lower parallelism, increase if stable
|
|
||||||
3. **Monitor resources:** Use `htop` to watch CPU/memory during builds
|
|
||||||
4. **Staged deployment:** Flash in batches (e.g., 16 at a time) if you have issues
|
|
||||||
5. **Verify connectivity:** Ping all devices after flashing
|
|
||||||
|
|
||||||
## Advanced: Maximum Speed Setup
|
|
||||||
|
|
||||||
For the absolute fastest deployment on a high-end system:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 16-core system, 32GB RAM, multiple USB controllers
|
|
||||||
python3 flash_all_parallel.py \
|
|
||||||
--ssid "TestNet" \
|
|
||||||
--password "password123" \
|
|
||||||
--start-ip 192.168.1.50 \
|
|
||||||
--strategy build-then-flash \
|
|
||||||
--build-parallel 12 \
|
|
||||||
--flash-parallel 32
|
|
||||||
```
|
|
||||||
|
|
||||||
With this setup, you could potentially flash all 32 devices in **10-12 minutes**!
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
# ESP32 Mass Deployment - Quick Reference
|
|
||||||
|
|
||||||
## Files You Need
|
|
||||||
|
|
||||||
1. **mass_deploy_enhanced.sh** - Main deployment script (RECOMMENDED)
|
|
||||||
2. **test_devices.sh** - Testing script
|
|
||||||
3. **DEPLOYMENT_GUIDE.md** - Full documentation
|
|
||||||
|
|
||||||
## One-Line Deployment
|
|
||||||
|
|
||||||
```bash
|
|
||||||
PASSWORD='your_wifi_pass' ./mass_deploy_enhanced.sh ~/Code/esp32/esp32-iperf
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Commands
|
|
||||||
|
|
||||||
### Deploy 32 devices
|
|
||||||
```bash
|
|
||||||
PASSWORD='mypass' ./mass_deploy_enhanced.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test all devices
|
|
||||||
```bash
|
|
||||||
NUM_DEVICES=32 ./test_devices.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Custom IP range
|
|
||||||
```bash
|
|
||||||
PASSWORD='mypass' START_IP='192.168.1.100' ./mass_deploy_enhanced.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Different WiFi network
|
|
||||||
```bash
|
|
||||||
PASSWORD='newpass' SSID='NewNetwork' GATEWAY='192.168.2.1' START_IP='192.168.2.50' ./mass_deploy_enhanced.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## IP Address Scheme
|
|
||||||
|
|
||||||
Default: `192.168.1.51 + device_index`
|
|
||||||
- Device 0 → 192.168.1.51
|
|
||||||
- Device 1 → 192.168.1.52
|
|
||||||
- Device 31 → 192.168.1.82
|
|
||||||
|
|
||||||
## Time Savings
|
|
||||||
|
|
||||||
- **Old way:** 60-90 minutes for 32 devices
|
|
||||||
- **New way:** 15-20 minutes for 32 devices
|
|
||||||
- **Speedup:** 4-5x faster! ⚡
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
**No devices found?**
|
|
||||||
```bash
|
|
||||||
ls /dev/ttyUSB* /dev/ttyACM*
|
|
||||||
sudo usermod -a -G dialout $USER # then logout/login
|
|
||||||
```
|
|
||||||
|
|
||||||
**Flash failed?**
|
|
||||||
```bash
|
|
||||||
BAUD_RATE=115200 PASSWORD='pass' ./mass_deploy_enhanced.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**Can't ping devices?**
|
|
||||||
- Check WiFi password
|
|
||||||
- Wait 30 seconds after deployment
|
|
||||||
- Verify network supports static IPs
|
|
||||||
|
|
||||||
**iperf connection refused?**
|
|
||||||
- Device still booting (wait 30s)
|
|
||||||
- Check logs: `cat /tmp/esp32_deploy_*.log`
|
|
||||||
60
README.md
60
README.md
|
|
@ -1,60 +0,0 @@
|
||||||
# esp32-iperf (ESP-IDF 6.x)
|
|
||||||
|
|
||||||
Minimal ESP32/ESP32-S3 iPerf firmware with **station mode** and optional **static IP**.
|
|
||||||
Tested on **ESP-IDF 6.0** (dev snapshot).
|
|
||||||
|
|
||||||
## Repo layout
|
|
||||||
|
|
||||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | Linux |
|
|
||||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | ----- |
|
|
||||||
|
|
||||||
# Hello World Example
|
|
||||||
|
|
||||||
Starts a FreeRTOS task to print "Hello World".
|
|
||||||
|
|
||||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
|
||||||
|
|
||||||
## How to use example
|
|
||||||
|
|
||||||
Follow detailed instructions provided specifically for this example.
|
|
||||||
|
|
||||||
Select the instructions depending on Espressif chip installed on your development board:
|
|
||||||
|
|
||||||
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
|
|
||||||
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
|
|
||||||
|
|
||||||
|
|
||||||
## Example folder contents
|
|
||||||
|
|
||||||
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
|
|
||||||
|
|
||||||
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
|
|
||||||
|
|
||||||
Below is short explanation of remaining files in the project folder.
|
|
||||||
|
|
||||||
```
|
|
||||||
├── CMakeLists.txt
|
|
||||||
├── pytest_hello_world.py Python script used for automated testing
|
|
||||||
├── main
|
|
||||||
│ ├── CMakeLists.txt
|
|
||||||
│ └── hello_world_main.c
|
|
||||||
└── README.md This is the file you are currently reading
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
* Program upload failure
|
|
||||||
|
|
||||||
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
|
|
||||||
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
|
|
||||||
|
|
||||||
## Technical support and feedback
|
|
||||||
|
|
||||||
Please use the following feedback channels:
|
|
||||||
|
|
||||||
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
|
|
||||||
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
|
|
||||||
|
|
||||||
We will get back to you as soon as possible.
|
|
||||||
|
|
@ -0,0 +1,488 @@
|
||||||
|
# GDB Runtime Threshold Tuning Guide
|
||||||
|
|
||||||
|
Adjust WiFi monitor thresholds **on-the-fly** using GDB - no rebuild required!
|
||||||
|
|
||||||
|
## Best of Both Worlds
|
||||||
|
|
||||||
|
✅ **C code performance** - 10,000+ frames/sec
|
||||||
|
✅ **GDB tunability** - Adjust thresholds in real-time
|
||||||
|
✅ **No rebuild needed** - Change settings instantly
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Code/esp32/esp32-iperf
|
||||||
|
|
||||||
|
# Update components
|
||||||
|
cp wifi_monitor.c components/wifi_monitor/
|
||||||
|
cp .gdbinit .
|
||||||
|
|
||||||
|
# Rebuild once
|
||||||
|
idf.py build
|
||||||
|
idf.py -p /dev/ttyACM0 flash
|
||||||
|
|
||||||
|
# Enable GDB auto-load
|
||||||
|
mkdir -p ~/.config/gdb
|
||||||
|
echo "set auto-load safe-path /" >> ~/.config/gdb/gdbinit
|
||||||
|
```
|
||||||
|
|
||||||
|
## Start GDB Session
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Terminal 1: OpenOCD
|
||||||
|
idf.py openocd
|
||||||
|
|
||||||
|
# Terminal 2: GDB
|
||||||
|
idf.py gdb
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### View Current Thresholds
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
(gdb) show_thresholds
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
WiFi Monitor Thresholds (GDB-tunable)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
High NAV threshold: 5000 us
|
||||||
|
Duration mismatch log: 10000 us
|
||||||
|
PHY rate fallback: 100 Mbps
|
||||||
|
Duration multiplier: 2x expected
|
||||||
|
|
||||||
|
Collapse Detection:
|
||||||
|
Retry rate threshold: 20.0%
|
||||||
|
Avg NAV collapse: 10000 us
|
||||||
|
Collision percentage: 10.0%
|
||||||
|
Mismatch percentage: 5.0%
|
||||||
|
|
||||||
|
Logging Control:
|
||||||
|
Log every N mismatches: 1 (1=all, 10=every 10th)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Preset Profiles
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Sensitive - catch more issues (stricter thresholds)
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
Thresholds set to SENSITIVE (catch more issues)
|
||||||
|
High NAV: 3000 us
|
||||||
|
Rate fallback: 150 Mbps
|
||||||
|
Retry rate: 15.0%
|
||||||
|
|
||||||
|
# Normal - balanced (default)
|
||||||
|
(gdb) tune_normal
|
||||||
|
Thresholds set to NORMAL (default)
|
||||||
|
|
||||||
|
# Relaxed - fewer false positives (lenient)
|
||||||
|
(gdb) tune_relaxed
|
||||||
|
Thresholds set to RELAXED (fewer false positives)
|
||||||
|
High NAV: 10000 us
|
||||||
|
Rate fallback: 50 Mbps
|
||||||
|
Retry rate: 30.0%
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adjust Individual Thresholds
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Set high NAV threshold to 8000 us (8ms)
|
||||||
|
(gdb) set_high_nav 8000
|
||||||
|
High NAV threshold set to 8000 us
|
||||||
|
|
||||||
|
# Set mismatch logging threshold to 15000 us
|
||||||
|
(gdb) set_mismatch_log 15000
|
||||||
|
Duration mismatch logging threshold set to 15000 us
|
||||||
|
|
||||||
|
# Set rate fallback to 50 Mbps
|
||||||
|
(gdb) set_rate_fallback 50
|
||||||
|
PHY rate fallback threshold set to 50 Mbps
|
||||||
|
|
||||||
|
# Set duration multiplier (NAV > 3x expected = mismatch)
|
||||||
|
(gdb) set_multiplier 3
|
||||||
|
Duration multiplier set to 3x expected
|
||||||
|
|
||||||
|
# Log every 10th mismatch (reduce verbosity)
|
||||||
|
(gdb) set_log_rate 10
|
||||||
|
Logging every 10 mismatch(es)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available Thresholds
|
||||||
|
|
||||||
|
### Detection Thresholds
|
||||||
|
|
||||||
|
| Threshold | Default | What It Does |
|
||||||
|
|-----------|---------|--------------|
|
||||||
|
| `threshold_high_nav_us` | 5000 | NAV above this = "high" |
|
||||||
|
| `threshold_duration_mismatch_us` | 10000 | Log mismatches when NAV exceeds this |
|
||||||
|
| `threshold_phy_rate_fallback_mbps` | 100 | PHY rate below this = fallback |
|
||||||
|
| `threshold_duration_multiplier` | 2 | NAV > expected × this = mismatch |
|
||||||
|
|
||||||
|
### Collapse Detection Thresholds
|
||||||
|
|
||||||
|
| Threshold | Default | What It Does |
|
||||||
|
|-----------|---------|--------------|
|
||||||
|
| `threshold_retry_rate_percent` | 20.0 | Retry rate for collapse |
|
||||||
|
| `threshold_avg_nav_collapse_us` | 10000 | Avg NAV for collapse |
|
||||||
|
| `threshold_collision_percent` | 10.0 | Collision % for collapse |
|
||||||
|
| `threshold_mismatch_percent` | 5.0 | Duration mismatch % for collapse |
|
||||||
|
|
||||||
|
### Logging Control
|
||||||
|
|
||||||
|
| Threshold | Default | What It Does |
|
||||||
|
|-----------|---------|--------------|
|
||||||
|
| `log_every_n_mismatches` | 1 | Log every Nth mismatch (1=all) |
|
||||||
|
|
||||||
|
## Tuning Examples
|
||||||
|
|
||||||
|
### Example 1: Noisy 2.4GHz Environment
|
||||||
|
|
||||||
|
Problem: Too many false positives on 2.4GHz
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Use relaxed profile
|
||||||
|
(gdb) tune_relaxed
|
||||||
|
|
||||||
|
# Or manually adjust
|
||||||
|
(gdb) set_high_nav 10000 # 10ms threshold
|
||||||
|
(gdb) set_rate_fallback 24 # 2.4GHz rates lower
|
||||||
|
(gdb) set_multiplier 3 # Allow 3x mismatch
|
||||||
|
(gdb) set_log_rate 10 # Log every 10th
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
Now only severe issues trigger alerts.
|
||||||
|
|
||||||
|
### Example 2: Clean 5GHz Network
|
||||||
|
|
||||||
|
Problem: Want to catch subtle issues
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Use sensitive profile
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
|
||||||
|
# Or manually adjust
|
||||||
|
(gdb) set_high_nav 3000 # 3ms threshold
|
||||||
|
(gdb) set_rate_fallback 200 # Should stay >200 Mbps
|
||||||
|
(gdb) set_multiplier 1.5 # Catch 1.5x mismatches
|
||||||
|
(gdb) set_log_rate 1 # Log everything
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
Catches issues early before collapse.
|
||||||
|
|
||||||
|
### Example 3: Production Monitoring
|
||||||
|
|
||||||
|
Problem: Need to reduce log spam
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Keep normal thresholds but reduce logging
|
||||||
|
(gdb) tune_normal
|
||||||
|
(gdb) set_log_rate 100 # Log every 100th mismatch
|
||||||
|
(gdb) set_mismatch_log 20000 # Only log severe (>20ms)
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
Statistics still track everything, but logs are cleaner.
|
||||||
|
|
||||||
|
### Example 4: Debugging Specific Issue
|
||||||
|
|
||||||
|
Problem: Investigating NAV spikes around 7-8ms
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Fine-tune for specific range
|
||||||
|
(gdb) set_high_nav 6000 # Start counting at 6ms
|
||||||
|
(gdb) set_mismatch_log 7000 # Log anything >7ms
|
||||||
|
(gdb) set_multiplier 1 # Catch all mismatches
|
||||||
|
(gdb) set_log_rate 1 # Log everything
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Now watch for those specific spikes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 5: Live WiFi Load Test
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Start with normal
|
||||||
|
(gdb) tune_normal
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Run iperf from another machine
|
||||||
|
# Watch serial output...
|
||||||
|
|
||||||
|
# If too noisy, relax on the fly
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) set_log_rate 20
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# If not catching issues, make sensitive
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tune while testing - no rebuild!**
|
||||||
|
|
||||||
|
## Direct Variable Access
|
||||||
|
|
||||||
|
You can also set variables directly:
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Set variables directly
|
||||||
|
(gdb) set threshold_high_nav_us = 7500
|
||||||
|
(gdb) set threshold_phy_rate_fallback_mbps = 75
|
||||||
|
(gdb) set log_every_n_mismatches = 5
|
||||||
|
|
||||||
|
# Or use C-style
|
||||||
|
(gdb) print threshold_high_nav_us = 7500
|
||||||
|
$1 = 7500
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitor Effects in Real-Time
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Set thresholds
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Watch serial monitor in other terminal
|
||||||
|
# See immediate effect on logging
|
||||||
|
|
||||||
|
# If too verbose
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) set_log_rate 10
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Logs immediately reduced by 10x!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Preset Profile Comparison
|
||||||
|
|
||||||
|
### Sensitive Profile
|
||||||
|
|
||||||
|
```
|
||||||
|
High NAV: 3000 us (stricter)
|
||||||
|
Mismatch log: 5000 us
|
||||||
|
Rate fallback: 150 Mbps (higher)
|
||||||
|
Multiplier: 1.5x (catches more)
|
||||||
|
Retry rate: 15.0% (lower)
|
||||||
|
Avg NAV collapse: 5000 us
|
||||||
|
Collision %: 5.0%
|
||||||
|
Mismatch %: 3.0%
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use for**: Clean networks, early issue detection, debugging
|
||||||
|
|
||||||
|
### Normal Profile (Default)
|
||||||
|
|
||||||
|
```
|
||||||
|
High NAV: 5000 us (balanced)
|
||||||
|
Mismatch log: 10000 us
|
||||||
|
Rate fallback: 100 Mbps
|
||||||
|
Multiplier: 2x
|
||||||
|
Retry rate: 20.0%
|
||||||
|
Avg NAV collapse: 10000 us
|
||||||
|
Collision %: 10.0%
|
||||||
|
Mismatch %: 5.0%
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use for**: General monitoring, production
|
||||||
|
|
||||||
|
### Relaxed Profile
|
||||||
|
|
||||||
|
```
|
||||||
|
High NAV: 10000 us (lenient)
|
||||||
|
Mismatch log: 20000 us
|
||||||
|
Rate fallback: 50 Mbps (lower)
|
||||||
|
Multiplier: 3x (allows more)
|
||||||
|
Retry rate: 30.0% (higher)
|
||||||
|
Avg NAV collapse: 15000 us
|
||||||
|
Collision %: 15.0%
|
||||||
|
Mismatch %: 10.0%
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use for**: Noisy environments, 2.4GHz, reduce false positives
|
||||||
|
|
||||||
|
## Tips & Best Practices
|
||||||
|
|
||||||
|
### 1. Start Conservative, Tune Down
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Start sensitive to see what's happening
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# If too noisy, relax specific thresholds
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) set_log_rate 10
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Still too noisy? Adjust threshold
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) set_high_nav 8000
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Use Logging Rate Control
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Keep all detection active but reduce log spam
|
||||||
|
(gdb) tune_normal
|
||||||
|
(gdb) set_log_rate 20 # Log every 20th
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Statistics still count everything!
|
||||||
|
# Periodic stats show full picture
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Match Band Characteristics
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# 2.4GHz - lower rates, more interference
|
||||||
|
(gdb) set_rate_fallback 24
|
||||||
|
(gdb) set_high_nav 8000
|
||||||
|
|
||||||
|
# 5GHz - higher rates, cleaner
|
||||||
|
(gdb) set_rate_fallback 100
|
||||||
|
(gdb) set_high_nav 5000
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Experiment Live
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Change settings while monitoring
|
||||||
|
(gdb) continue
|
||||||
|
# ... let it run ...
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) set_mismatch_log 15000
|
||||||
|
(gdb) continue
|
||||||
|
# ... see effect immediately ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Save Custom Profiles
|
||||||
|
|
||||||
|
Create your own `.gdbinit` commands:
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Add to .gdbinit
|
||||||
|
define tune_my_network
|
||||||
|
set threshold_high_nav_us = 6500
|
||||||
|
set threshold_phy_rate_fallback_mbps = 120
|
||||||
|
set log_every_n_mismatches = 5
|
||||||
|
printf "Custom profile loaded\n"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Then use:
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
(gdb) tune_my_network
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Impact
|
||||||
|
|
||||||
|
**Zero!** Threshold changes have no performance impact:
|
||||||
|
|
||||||
|
- ✅ Variables are checked per frame (already happening)
|
||||||
|
- ✅ No function calls added
|
||||||
|
- ✅ No memory allocation
|
||||||
|
- ✅ Still processes 10,000+ frames/sec
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Thresholds Not Taking Effect
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Verify threshold was set
|
||||||
|
(gdb) print threshold_high_nav_us
|
||||||
|
$1 = 8000
|
||||||
|
|
||||||
|
# Check spelling
|
||||||
|
(gdb) show_thresholds
|
||||||
|
```
|
||||||
|
|
||||||
|
### Too Much Logging
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Reduce log rate
|
||||||
|
(gdb) set_log_rate 50 # Log every 50th
|
||||||
|
|
||||||
|
# Or increase mismatch threshold
|
||||||
|
(gdb) set_mismatch_log 20000 # Only log >20ms
|
||||||
|
```
|
||||||
|
|
||||||
|
### Not Catching Issues
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Make more sensitive
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
|
||||||
|
# Or lower specific threshold
|
||||||
|
(gdb) set_high_nav 3000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Session
|
||||||
|
|
||||||
|
Complete workflow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start debugging
|
||||||
|
$ idf.py gdb
|
||||||
|
|
||||||
|
# Check current settings
|
||||||
|
(gdb) show_thresholds
|
||||||
|
|
||||||
|
# Start monitoring
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Run iperf from another machine
|
||||||
|
# Watch serial output...
|
||||||
|
|
||||||
|
# Too many logs? Adjust
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) set_log_rate 10
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Not catching subtle issues? Make sensitive
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Perfect! Check final settings
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) show_thresholds
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
WiFi Monitor Thresholds (GDB-tunable)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
High NAV threshold: 3000 us
|
||||||
|
Duration mismatch log: 5000 us
|
||||||
|
PHY rate fallback: 150 Mbps
|
||||||
|
Duration multiplier: 1.5x expected
|
||||||
|
...
|
||||||
|
Log every N mismatches: 10
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
# Document these settings for your network!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
| Feature | Benefit |
|
||||||
|
|---------|---------|
|
||||||
|
| **Runtime tuning** | No rebuild needed |
|
||||||
|
| **GDB commands** | Easy to use |
|
||||||
|
| **Preset profiles** | Quick adjustment |
|
||||||
|
| **Zero overhead** | Full C code speed |
|
||||||
|
| **Live testing** | Tune while running |
|
||||||
|
| **Experiment freely** | Try different settings |
|
||||||
|
|
||||||
|
**Perfect combination of speed and flexibility!** 🎯
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Key Commands**:
|
||||||
|
- `show_thresholds` - See current settings
|
||||||
|
- `tune_sensitive` / `tune_normal` / `tune_relaxed` - Preset profiles
|
||||||
|
- `set_high_nav <us>` - Adjust high NAV threshold
|
||||||
|
- `set_log_rate <n>` - Control logging verbosity
|
||||||
|
- `continue` - Resume monitoring with new settings
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
# WiFi Monitor Threshold Tuning - Quick Reference
|
||||||
|
|
||||||
|
## GDB Commands
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# View current thresholds
|
||||||
|
show_thresholds
|
||||||
|
|
||||||
|
# Preset profiles
|
||||||
|
tune_sensitive # Catch more issues (stricter)
|
||||||
|
tune_normal # Default settings
|
||||||
|
tune_relaxed # Fewer false positives
|
||||||
|
|
||||||
|
# Individual thresholds
|
||||||
|
set_high_nav <us> # High NAV threshold (default: 5000)
|
||||||
|
set_mismatch_log <us> # Log when NAV exceeds (default: 10000)
|
||||||
|
set_rate_fallback <mbps> # Rate fallback threshold (default: 100)
|
||||||
|
set_multiplier <n> # Duration multiplier (default: 2)
|
||||||
|
set_log_rate <n> # Log every Nth mismatch (default: 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tunable Variables
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| `threshold_high_nav_us` | 5000 | NAV above this = "high" |
|
||||||
|
| `threshold_duration_mismatch_us` | 10000 | Log mismatches above this NAV |
|
||||||
|
| `threshold_phy_rate_fallback_mbps` | 100 | PHY rate below this = fallback |
|
||||||
|
| `threshold_duration_multiplier` | 2 | NAV > expected × this = mismatch |
|
||||||
|
| `threshold_retry_rate_percent` | 20.0 | Retry % for collapse |
|
||||||
|
| `threshold_avg_nav_collapse_us` | 10000 | Avg NAV for collapse |
|
||||||
|
| `threshold_collision_percent` | 10.0 | Collision % for collapse |
|
||||||
|
| `threshold_mismatch_percent` | 5.0 | Mismatch % for collapse |
|
||||||
|
| `log_every_n_mismatches` | 1 | Log every Nth (1=all, 10=every 10th) |
|
||||||
|
|
||||||
|
## Quick Examples
|
||||||
|
|
||||||
|
### Too Much Logging
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
(gdb) set_log_rate 10 # Log every 10th mismatch
|
||||||
|
(gdb) set_mismatch_log 20000 # Only log >20ms NAV
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
### Not Catching Issues
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
(gdb) tune_sensitive # Use stricter thresholds
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4GHz Network
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
(gdb) tune_relaxed # More lenient
|
||||||
|
(gdb) set_rate_fallback 24 # 2.4GHz rates lower
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5GHz High Performance
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
(gdb) set_rate_fallback 200 # Expect >200 Mbps
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
## Preset Profile Settings
|
||||||
|
|
||||||
|
| Threshold | Sensitive | Normal | Relaxed |
|
||||||
|
|-----------|-----------|--------|---------|
|
||||||
|
| High NAV | 3000 us | 5000 us | 10000 us |
|
||||||
|
| Mismatch log | 5000 us | 10000 us | 20000 us |
|
||||||
|
| Rate fallback | 150 Mbps | 100 Mbps | 50 Mbps |
|
||||||
|
| Multiplier | 1.5x | 2x | 3x |
|
||||||
|
| Retry rate | 15% | 20% | 30% |
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Code/esp32/esp32-iperf
|
||||||
|
|
||||||
|
# Update files
|
||||||
|
cp wifi_monitor.c components/wifi_monitor/
|
||||||
|
cp .gdbinit .
|
||||||
|
|
||||||
|
# Build once
|
||||||
|
idf.py build
|
||||||
|
idf.py -p /dev/ttyACM0 flash
|
||||||
|
|
||||||
|
# Enable GDB auto-load (one-time)
|
||||||
|
mkdir -p ~/.config/gdb
|
||||||
|
echo "set auto-load safe-path /" >> ~/.config/gdb/gdbinit
|
||||||
|
```
|
||||||
|
|
||||||
|
## Typical Workflow
|
||||||
|
|
||||||
|
```gdb
|
||||||
|
# Start GDB
|
||||||
|
$ idf.py gdb
|
||||||
|
|
||||||
|
# Check defaults
|
||||||
|
(gdb) show_thresholds
|
||||||
|
|
||||||
|
# Start monitoring
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Adjust on the fly (Ctrl-C to pause)
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) set_log_rate 20
|
||||||
|
(gdb) continue
|
||||||
|
|
||||||
|
# Check effect, adjust again if needed
|
||||||
|
(gdb) Ctrl-C
|
||||||
|
(gdb) tune_sensitive
|
||||||
|
(gdb) continue
|
||||||
|
```
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
✅ **No rebuild** - Adjust thresholds instantly
|
||||||
|
✅ **Zero overhead** - Full C code performance
|
||||||
|
✅ **Live tuning** - Change while running
|
||||||
|
✅ **Experiment** - Try different settings easily
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**For complete guide**: See GDB_THRESHOLD_TUNING_GUIDE.md
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
idf_component_register(SRCS "main.c"
|
idf_component_register(
|
||||||
|
SRCS
|
||||||
|
"main.c"
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
REQUIRES led_strip driver wifi_cfg csi_log esp_wifi esp_netif nvs_flash)
|
PRIV_REQUIRES
|
||||||
|
csi_log
|
||||||
|
wifi_cfg
|
||||||
|
wifi_monitor
|
||||||
|
)
|
||||||
|
|
|
||||||
114
main/main.c
114
main/main.c
|
|
@ -20,6 +20,7 @@
|
||||||
#include "iperf.h"
|
#include "iperf.h"
|
||||||
#include "wifi_cfg.h"
|
#include "wifi_cfg.h"
|
||||||
#include "csi_log.h"
|
#include "csi_log.h"
|
||||||
|
#include "wifi_monitor.h"
|
||||||
|
|
||||||
|
|
||||||
static const char *TAG = "main";
|
static const char *TAG = "main";
|
||||||
|
|
@ -48,7 +49,8 @@ typedef enum {
|
||||||
LED_STATE_NO_CONFIG,
|
LED_STATE_NO_CONFIG,
|
||||||
LED_STATE_WAITING,
|
LED_STATE_WAITING,
|
||||||
LED_STATE_CONNECTED,
|
LED_STATE_CONNECTED,
|
||||||
LED_STATE_FAILED
|
LED_STATE_FAILED,
|
||||||
|
LED_STATE_MONITORING
|
||||||
} led_state_t;
|
} led_state_t;
|
||||||
|
|
||||||
static led_state_t current_led_state = LED_STATE_NO_CONFIG;
|
static led_state_t current_led_state = LED_STATE_NO_CONFIG;
|
||||||
|
|
@ -102,6 +104,11 @@ static void led_task(void *arg)
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LED_STATE_MONITORING:
|
||||||
|
set_led_color(0, 0, 255); // Solid BLUE
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
break;
|
||||||
|
|
||||||
case LED_STATE_FAILED:
|
case LED_STATE_FAILED:
|
||||||
if (blink_state) {
|
if (blink_state) {
|
||||||
set_led_color(255, 0, 0);
|
set_led_color(255, 0, 0);
|
||||||
|
|
@ -196,6 +203,103 @@ static void csi_init_task(void *arg) {
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- WiFi Monitor Mode support ---------------------------------------------------
|
||||||
|
static bool s_monitor_enabled = false;
|
||||||
|
static uint32_t s_monitor_frame_count = 0;
|
||||||
|
|
||||||
|
static void monitor_frame_callback(const wifi_frame_info_t *frame,
|
||||||
|
const uint8_t *payload,
|
||||||
|
uint16_t len) {
|
||||||
|
s_monitor_frame_count++;
|
||||||
|
|
||||||
|
// Log first 10 frames in detail
|
||||||
|
if (s_monitor_frame_count <= 10) {
|
||||||
|
const char *type_str = wifi_frame_type_str(frame->type, frame->subtype);
|
||||||
|
ESP_LOGI("MONITOR", "Frame #%lu: %s, NAV: %u us, RSSI: %d dBm, Retry: %d",
|
||||||
|
s_monitor_frame_count, type_str, frame->duration_id,
|
||||||
|
frame->rssi, frame->retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn on collision indicators
|
||||||
|
if (frame->retry && frame->duration_id > 5000) {
|
||||||
|
ESP_LOGW("MONITOR", "⚠ COLLISION: Retry frame with high NAV (%u us)", frame->duration_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->duration_id > 30000) {
|
||||||
|
ESP_LOGW("MONITOR", "⚠ VERY HIGH NAV: %u us - possible collapse!", frame->duration_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void monitor_stats_task(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10000)); // Every 10 seconds
|
||||||
|
|
||||||
|
wifi_collapse_stats_t stats;
|
||||||
|
if (wifi_monitor_get_stats(&stats) == ESP_OK) {
|
||||||
|
ESP_LOGI("MONITOR", "========================================");
|
||||||
|
ESP_LOGI("MONITOR", "WiFi Monitor Statistics:");
|
||||||
|
ESP_LOGI("MONITOR", " Total frames: %lu", stats.total_frames);
|
||||||
|
ESP_LOGI("MONITOR", " Retry frames: %lu (%.2f%%)",
|
||||||
|
stats.retry_frames, stats.retry_rate);
|
||||||
|
ESP_LOGI("MONITOR", " High NAV frames: %lu", stats.high_nav_frames);
|
||||||
|
ESP_LOGI("MONITOR", " Average NAV: %u us", stats.avg_nav);
|
||||||
|
ESP_LOGI("MONITOR", " Max NAV: %u us", stats.max_nav);
|
||||||
|
ESP_LOGI("MONITOR", " Collision events: %lu", stats.collision_events);
|
||||||
|
|
||||||
|
// Check for collapse
|
||||||
|
if (wifi_monitor_is_collapsed()) {
|
||||||
|
ESP_LOGW("MONITOR", "⚠⚠⚠ WiFi COLLAPSE DETECTED! ⚠⚠⚠");
|
||||||
|
ESP_LOGW("MONITOR", " High retry rate: %.2f%%", stats.retry_rate);
|
||||||
|
ESP_LOGW("MONITOR", " High avg NAV: %u us", stats.avg_nav);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI("MONITOR", "✓ WiFi operating normally");
|
||||||
|
}
|
||||||
|
ESP_LOGI("MONITOR", "========================================");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_enable_monitor_mode(uint8_t channel) {
|
||||||
|
if (s_monitor_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI("MONITOR", "Starting WiFi monitor mode on channel %d", channel);
|
||||||
|
|
||||||
|
esp_err_t err = wifi_monitor_init(channel, monitor_frame_callback);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE("MONITOR", "WiFi monitor init failed: %s", esp_err_to_name(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = wifi_monitor_start();
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE("MONITOR", "WiFi monitor start failed: %s", esp_err_to_name(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_monitor_enabled = true;
|
||||||
|
current_led_state = LED_STATE_MONITORING;
|
||||||
|
|
||||||
|
ESP_LOGI("MONITOR", "WiFi monitor started - BLUE LED solid");
|
||||||
|
ESP_LOGI("MONITOR", "Capturing 802.11 frames for collapse detection");
|
||||||
|
|
||||||
|
// Start statistics task
|
||||||
|
xTaskCreate(monitor_stats_task, "monitor_stats", 4096, NULL, 5, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void monitor_init_task(void *arg) {
|
||||||
|
// Get the channel from the connected AP
|
||||||
|
wifi_ap_record_t ap_info;
|
||||||
|
if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
|
||||||
|
wifi_enable_monitor_mode(ap_info.primary);
|
||||||
|
} else {
|
||||||
|
// Default to channel 6 if we can't get AP info
|
||||||
|
wifi_enable_monitor_mode(6);
|
||||||
|
}
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||||
int32_t event_id, void* event_data)
|
int32_t event_id, void* event_data)
|
||||||
{
|
{
|
||||||
|
|
@ -386,8 +490,13 @@ static void event_handler(void* arg, esp_event_base_t event_base,
|
||||||
ESP_LOGI(TAG, "WiFi CONNECTED - BLUE LED solid");
|
ESP_LOGI(TAG, "WiFi CONNECTED - BLUE LED solid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try CSI first (might fail on ESP32-C5)
|
||||||
xTaskCreate(csi_init_task, "csi_init", 4096, NULL, 5, NULL);
|
xTaskCreate(csi_init_task, "csi_init", 4096, NULL, 5, NULL);
|
||||||
|
|
||||||
|
// Start WiFi monitor mode (works reliably)
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||||
|
xTaskCreate(monitor_init_task, "monitor_init", 4096, NULL, 5, NULL);
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
|
||||||
iperf_cfg_t cfg;
|
iperf_cfg_t cfg;
|
||||||
|
|
@ -431,7 +540,8 @@ void app_main(void) {
|
||||||
ESP_LOGI(TAG, "LED Status:");
|
ESP_LOGI(TAG, "LED Status:");
|
||||||
ESP_LOGI(TAG, " YELLOW solid = NO CONFIG (send CFG/END)");
|
ESP_LOGI(TAG, " YELLOW solid = NO CONFIG (send CFG/END)");
|
||||||
ESP_LOGI(TAG, " BLUE slow blink = Connecting");
|
ESP_LOGI(TAG, " BLUE slow blink = Connecting");
|
||||||
ESP_LOGI(TAG, " BLUE solid = Connected ✓");
|
ESP_LOGI(TAG, " GREEN solid = Connected ✓");
|
||||||
|
ESP_LOGI(TAG, " BLUE solid = Monitor Mode (capturing 802.11 frames)");
|
||||||
ESP_LOGI(TAG, " RED fast blink = Failed ✗");
|
ESP_LOGI(TAG, " RED fast blink = Failed ✗");
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue