fix: correct ICM-20689/MPU6500 SPI initialisation sequence#1289
fix: correct ICM-20689/MPU6500 SPI initialisation sequence#1289nerdCopter wants to merge 4 commits into
Conversation
Port of BF PR #11584. Fixes several initialisation bugs affecting the ICM-20689 and related gyros that could corrupt reserved registers and leave I2C mode active: accgyro_spi_icm20689.c: - Add named register defines for all magic numbers (ICM20689_BIT_RESET, ICM20689_I2C_IF_DIS, ICM20689_ACCEL_RST, ICM20689_TEMP_RST, ICM20689_INT_ANYRD_2CLEAR, ICM20689_CLKSEL_SETTLE_US, ICM20689_RESET_DELAY_MS, ICM20689_PATH_RESET_DELAY_MS) - icm20689SpiDetect: write I2C_IF_DIS and SIGNAL_PATH_RESET only after WHO_AM_I confirms device identity (datasheet s6.1 requirement) - icm20689GyroInit: remove redundant second reset and signal-path write (already done in detect); replace 15ms inter-register delays and 100ms post-sample-rate delay with ICM20689_CLKSEL_SETTLE_US (120us) after clock source change; replace magic literals with named defines accgyro_spi_icm20689.h: - Remove ICM20689_BIT_RESET (now file-private in .c) accgyro_mpu.c: - Add GYRO_SPI_STARTUP_MS (100ms) guard before SPI detect loop so the bus has settled before any device is probed accgyro_spi_mpu6500.c: - Change mpu6500SpiInit clock from SPI_CLOCK_FAST (~20MHz) to SPI_CLOCK_INITIALIZATION to prevent erroneous register accesses during detection Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughSPI gyro detection now waits before probing, ChangesSPI gyro startup timing
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai, AI generated comment Requesting review of this ICM-20689 init backport from BF PR #11584. Key areas worth checking:
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Locate relevant files =="
fd -i 'accgyro_spi_icm20689.c|accgyro_mpu.c|accgyro_spi_mpu6500.c|bus_spi|spi.*\.h|spi.*\.c'
echo
echo "== Outline accgyro_spi_icm20689.c =="
ICM_FILE=$(fd -i '^accgyro_spi_icm20689\.c$' | head -n1)
ast-grep outline "$ICM_FILE" --view expanded || true
echo
echo "== Relevant slice: accgyro_spi_icm20689.c =="
sed -n '1,260p' "$ICM_FILE"
echo
echo "== Outline accgyro_mpu.c =="
MPU_FILE=$(fd -i '^accgyro_mpu\.c$' | head -n1)
ast-grep outline "$MPU_FILE" --view expanded || true
echo
echo "== Relevant slice: accgyro_mpu.c =="
sed -n '1,260p' "$MPU_FILE"
echo
echo "== Outline accgyro_spi_mpu6500.c =="
MPU6500_FILE=$(fd -i '^accgyro_spi_mpu6500\.c$' | head -n1)
ast-grep outline "$MPU6500_FILE" --view expanded || true
echo
echo "== Relevant slice: accgyro_spi_mpu6500.c =="
sed -n '1,220p' "$MPU6500_FILE"
echo
echo "== Search for SPI clock enum/defines and divisor calculations =="
rg -n -C3 'SPI_CLOCK_(INITIALIZATION|STANDARD|FAST)|spiSetDivisor|spiCalculateDivider|spiSetClkDivisor|SPI_CLOCK_' .
echo
echo "== Search for millis guard and GYRO_SPI_STARTUP_MS =="
rg -n -C3 'GYRO_SPI_STARTUP_MS|millis\s*\(\)\s*<' "$MPU_FILE"
echo
echo "== Search for USE_GYRO_SPI_MPU6500 and ICM42688P relationships =="
rg -n -C4 'USE_GYRO_SPI_MPU6500|ICM42688P|accgyro_spi_mpu6500' .Length of output: 167352 🏁 Script executed: #!/bin/bash
set -euo pipefail
ICM=src/main/drivers/accgyro/accgyro_spi_icm20689.c
MPU=src/main/drivers/accgyro/accgyro_mpu.c
MPU6500=src/main/drivers/accgyro/accgyro_spi_mpu6500.c
echo "== SPI clock definitions =="
rg -n -C4 'SPI_CLOCK_INITIALIZATION|SPI_CLOCK_STANDARD|SPI_CLOCK_FAST|typedef enum.*SPI_CLOCK|enum.*SPI_CLOCK' src/main
echo
echo "== spiSetDivisor / clock helper declarations =="
rg -n -C3 'spiSetDivisor\s*\(|spiCalculateDivider\s*\(|spiSetClkDivisor\s*\(' src/main
echo
echo "== accgyro_spi_icm20689.c matches =="
rg -n -C6 'icm20689SpiDetect|icm20689GyroInit|spiSetDivisor|I2C_IF_DIS|SIGNAL_PATH_RESET|WHO_AM_I|delayMicroseconds|delay\(' "$ICM"
echo
echo "== accgyro_spi_icm20689.c full relevant range =="
sed -n '1,240p' "$ICM"
echo
echo "== accgyro_mpu.c matches =="
rg -n -C6 'GYRO_SPI_STARTUP_MS|detectSPISensorsAndUpdateDetectionResult|millis\s*\(|mpu6500SpiDetect|icm426xxSpiDetect|icm20689SpiDetect' "$MPU"
echo
echo "== accgyro_mpu.c focused range =="
sed -n '320,530p' "$MPU"
echo
echo "== accgyro_spi_mpu6500.c matches =="
rg -n -C6 'mpu6500SpiInit|SPI_CLOCK_|WHO_AM_I|ICM42688P_WHO_AM_I_CONST|spiSetDivisor|busReadRegisterBuffer|spiReadRegMsk' "$MPU6500"
echo
echo "== accgyro_spi_mpu6500.c focused range =="
sed -n '1,140p' "$MPU6500"Length of output: 151443
So if I were reducing this to actionable review feedback, I’d leave:
[review] ✏️ Learnings added
|
Three targeted fixes following code review: 1. icm20689SpiDetect: write I2C_IF_DIS and SIGNAL_PATH_RESET at SPI_CLOCK_SLOW (within ICM-20689 8MHz register write spec) rather than SPI_CLOCK_STANDARD (~10.5MHz on F4/~9MHz on H7, both over spec). Restore SPI_CLOCK_STANDARD explicitly before return. 2. accgyro_mpu.c GYRO_SPI_STARTUP_MS: add BF 4.5-m comment explaining this is a boot-time gate done once here, not a per-driver delay. 3. icm20689GyroInit: set SPI_CLOCK_SLOW at entry, matching BF 4.5-m intent of running init register writes at a safe clock speed. SPI_CLOCK_STANDARD restore at exit is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@coderabbitai, AI generated comment This PR now has a second commit ( What was changed in the second commit1. Question for CRabbit: Is the 10–20× gap between 2. Question for CRabbit: 3. Broader questions I want your honest assessment onA. Retry loop vs BF single-attempt: EmuFlight's B. I2C_IF_DIS as a detect side-effect: The original EF code never wrote C. SIGNAL_PATH_RESET in detect vs init: The original EF code did the signal path reset in Please give your actual assessment — flag anything that looks wrong, including if you think the |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Current branch / latest commits =="
git log --oneline -n 6
echo
echo "== Locate relevant files =="
fd '^accgyro_spi_icm20689\.c$|^accgyro_mpu\.c$|^accgyro_spi_mpu6500\.c$|^bus_spi\.h$|^bus_spi.*\.c$' src/main
ICM=src/main/drivers/accgyro/accgyro_spi_icm20689.c
MPU=src/main/drivers/accgyro/accgyro_mpu.c
MPU6500=src/main/drivers/accgyro/accgyro_spi_mpu6500.c
BUSSPIH=src/main/drivers/bus_spi.h
echo
echo "== Outline: accgyro_spi_icm20689.c =="
ast-grep outline "$ICM" --view expanded
echo
echo "== Focused content: accgyro_spi_icm20689.c =="
sed -n '1,260p' "$ICM"
echo
echo "== Outline: accgyro_mpu.c =="
ast-grep outline "$MPU" --view expanded
echo
echo "== Focused content: accgyro_mpu.c around detection =="
sed -n '340,540p' "$MPU"
echo
echo "== Focused content: accgyro_mpu.c around init / reinit if any =="
rg -n -C4 'gyro.*Init|initGyro|reinit|re-init|detectSPISensorsAndUpdateDetectionResult|icm20689SpiDetect|icm20689GyroInit' src/main
echo
echo "== Outline: accgyro_spi_mpu6500.c =="
ast-grep outline "$MPU6500" --view expanded
echo
echo "== Focused content: accgyro_spi_mpu6500.c =="
sed -n '1,140p' "$MPU6500"
echo
echo "== SPI clock enum / helper definitions =="
sed -n '1,220p' "$BUSSPIH"
echo
echo "== Search for spiSetDivisor/spiSetClkDivisor/spiCalculateDivider definitions/usages =="
rg -n -C3 'spiSetDivisor\s*\(|spiSetClkDivisor\s*\(|spiCalculateDivider\s*\(|SPI_CLOCK_(SLOW|INITIALIZATION|STANDARD|FAST)' src/main/drivers src/main
echo
echo "== Search for icm20689SpiDetect call sites =="
rg -n -C3 '\bicm20689SpiDetect\s*\(' src/main
echo
echo "== Search for icm20689GyroInit call sites =="
rg -n -C3 '\bicm20689GyroInit\s*\(' src/main
echo
echo "== Search for runtime gyro reinit paths =="
rg -n -C4 'gyroInitFn|initFn|reinit|reInit|gyro.*Config|signal path reset|SIGNAL_PATH_RESET|USER_CTRL|PWR_MGMT_1' src/main
echo
echo "== Search for repeated sensor detection / redetect paths =="
rg -n -C4 'detectSPISensorsAndUpdateDetectionResult|detectGyro|sensorsAutodetect|gyroDetect|redetect|re-detect|reprobe|probe' src/main
echo
echo "== Optional: show PR commit and patch for cfa2e66197 if available =="
if command -v gh >/dev/null 2>&1; then
gh pr view 1289 --json title,headRefName,commits --jq '.commits[] | {oid: .oid, messageHeadline: .messageHeadline}' || true
echo
gh api repos/emuflight/EmuFlight/commits/cfa2e66197 --jq '{sha: .sha, files: [.files[] | {filename: .filename, status: .status, patch: .patch}]}' || true
fiLength of output: 198596 🏁 Script executed: #!/bin/bash
set -euo pipefail
ICM=src/main/drivers/accgyro/accgyro_spi_icm20689.c
MPU=src/main/drivers/accgyro/accgyro_mpu.c
GYRO=src/main/sensors/gyro.c
echo "== Exact icm20689 detect/init slices =="
sed -n '77,170p' "$ICM"
echo
echo "== mpuResetFn declaration and usages =="
rg -n -C4 '\bmpuResetFn\b|\bresetFn\b' src/main/drivers src/main/sensors src/main/fc src/main
echo
echo "== mpuDetect and SPI detect flow slices =="
sed -n '369,575p' "$MPU"
echo
echo "== gyro init flow slice =="
sed -n '595,635p' "$GYRO"
echo
echo "== Any hardware gyro re-init calls via initFn after boot? =="
rg -n -C4 '\binitFn\s*\(&gyro|\bgyroSensor->gyroDev\.initFn\b|\bgyro\.initFn\b|\bgyroInitSensor\s*\(' src/main
echo
echo "== Any explicit gyro redetect / re-probe after startup? =="
rg -n -C4 'sensorsAutodetect\s*\(|gyroInit\s*\(|mpuDetect\s*\(|detectSPISensorsAndUpdateDetectionResult\s*\(|redetect|re-detect|reprobe|re-probe' src/mainLength of output: 40141
the second commit is technically safe, but conservative. Bottom line
1)
|
SPI_CLOCK_SLOW is used for ICM-20689 device-specific writes because EmuFlight's SPI_CLOCK_STANDARD exceeds the chip's 8 MHz write limit on F4 (~10.5 MHz) and H7 (~9 MHz). There is no ~8 MHz enum in EF's current SPI API; SPI_CLOCK_SLOW (~0.65 MHz) is the nearest safe option. BF 4.5-m uses spiCalculateDivider(8000000) for exact parity — a future SPI API upgrade could match that. Also documents that icm20689GyroInit() assumes icm20689SpiDetect() has already run, since reset, I2C_IF_DIS, and SIGNAL_PATH_RESET are now applied during detect. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@coderabbitai, AI generated comment Thank you for the thorough analysis. Addressed in commit SPI_CLOCK_SLOW rationale (your non-blocking note): Added a comment explaining that SPI_CLOCK_STANDARD exceeds the ICM-20689's 8 MHz write limit on F4 (~10.5 MHz) and H7 (~9 MHz), and that SPI_CLOCK_SLOW (~0.65 MHz) is the nearest available enum within spec. Notes that BF 4.5-m uses Detect-first assumption (your mental note): Strengthened the comment in No logic changes — the second commit stands as-is. These are documentation-only clarifications responding to your two non-blocking observations. |
|
Tip For best results, initiate chat on the files or code changes.
The added comments address exactly what I was concerned about:
Given that these were non-blocking documentation gaps rather than logic flaws, I’m satisfied with this follow-up. Nice cleanup. 🐇👍 ✏️ Learnings added
If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
|
@coderabbitai, AI generated comment Three commits now on this PR. Summarising what was done and asking for your final honest recommendation. What the three commits doCommit 1 (
Commit 2 (
Commit 3 (
Remaining design decisions not changed
QuestionGiven the three commits as they now stand: do you honestly recommend any further change before this PR is merged? If yes, name it concisely. If no, say so plainly — we will act on your answer. |
|
Tip For best results, initiate chat on the files or code changes.
My honest final read:
So my plain recommendation is: merge it as-is. The only thing I’d still want, separately, is hardware verification on an affected ICM-20689 target. But that’s a test/validation step, not a further code change I’d require before accepting the implementation. If you want future cleanup later, I’d track these in a separate PR:
But for this PR: no further change recommended before merge. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/drivers/accgyro/accgyro_mpu.c (1)
92-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winClarify that this is a boot-time guard, not a relative 100 ms delay.
while (millis() < GYRO_SPI_STARTUP_MS)only waits until system uptime reaches 100 ms, so calling this later is a no-op. The current comments read like “delay 100 ms here”, which is easy to misinterpret during future refactors.Also applies to: 374-376
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/drivers/accgyro/accgyro_mpu.c` around lines 92 - 93, The comment and constant around GYRO_SPI_STARTUP_MS in accgyro_mpu.c should describe a boot-time guard, not a relative delay. Update the wording near the GYRO_SPI_STARTUP_MS definition and the startup check in the MPU SPI init path (including the later use around the same guard) so it’s clear the code waits until system uptime reaches 100 ms and may be a no-op if called later. Keep the behavior unchanged, but rename/comment the intent to match the millis() guard semantics.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/main/drivers/accgyro/accgyro_mpu.c`:
- Around line 92-93: The comment and constant around GYRO_SPI_STARTUP_MS in
accgyro_mpu.c should describe a boot-time guard, not a relative delay. Update
the wording near the GYRO_SPI_STARTUP_MS definition and the startup check in the
MPU SPI init path (including the later use around the same guard) so it’s clear
the code waits until system uptime reaches 100 ms and may be a no-op if called
later. Keep the behavior unchanged, but rename/comment the intent to match the
millis() guard semantics.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7ca4c423-7ac2-419d-9ffd-e5a2ded0b75d
📒 Files selected for processing (4)
src/main/drivers/accgyro/accgyro_mpu.csrc/main/drivers/accgyro/accgyro_spi_icm20689.csrc/main/drivers/accgyro/accgyro_spi_icm20689.hsrc/main/drivers/accgyro/accgyro_spi_mpu6500.c
💤 Files with no reviewable changes (1)
- src/main/drivers/accgyro/accgyro_spi_icm20689.h
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Codacy Static Code Analysis
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-05-15T14:49:12.754Z
Learnt from: nerdCopter
Repo: emuflight/EmuFlight PR: 1189
File: src/main/drivers/bus_spi.c:631-631
Timestamp: 2026-05-15T14:49:12.754Z
Learning: In the EmuFlight repo (emuflight/EmuFlight), the STM32F303 (F303) targets currently do not compile on the master branch due to a pre-existing hardware RAM budget overflow (unrelated to any specific PR). When reviewing driver changes in shared driver files (e.g., src/main/drivers/bus_spi.c), avoid adding or fixing F303-specific driver behavior as part of the current PR; instead, defer those F303-targeted fixes to a dedicated F3-targeted PR and only revisit once the RAM overflow/build issue is resolved.
Applied to files:
src/main/drivers/accgyro/accgyro_spi_mpu6500.csrc/main/drivers/accgyro/accgyro_mpu.csrc/main/drivers/accgyro/accgyro_spi_icm20689.c
🔇 Additional comments (2)
src/main/drivers/accgyro/accgyro_spi_icm20689.c (1)
39-61: LGTM!Also applies to: 79-88, 114-126, 150-167
src/main/drivers/accgyro/accgyro_spi_mpu6500.c (1)
48-48: LGTM!
…delay The while (millis() < GYRO_SPI_STARTUP_MS) pattern spins until system uptime reaches 100ms since boot — it is not a relative 100ms delay and is a no-op if called after that point. Update comments at the define and the call site to make this semantics clear. Addresses CodeRabbit nitpick on PR emuflight#1289. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@coderabbitai, AI generated comment Addressed nitpick from review #4581948877 in commit `19d27ec918`: GYRO_SPI_STARTUP_MS boot-time semantics — updated both comment sites in `accgyro_mpu.c`:
No logic change. Comments now correctly reflect the absolute boot-clock semantics. All four commits are comment/documentation only after the first. Are there any remaining concerns, or is this PR ready for hardware verification and merge? |
|
Tip For best results, initiate chat on the files or code changes.
With the My honest final stance is unchanged:
So: yes, ready for hardware verification and merge. |
AI Generated pull-request
Ports BF PR #11584 (merged 2022). Fixes initialisation bugs in the ICM-20689
gyro family that could leave the device in I2C mode or corrupt reserved
registers, causing permanent yaw-axis failure across power cycles.
Credit to @SteveCEvans for the original investigation and fix in Betaflight.
Thanks to @nikybiasion and @wrych who noted EmuFlight was affected in the BF PR comments.
Changes
accgyro_spi_icm20689.c
icm20689SpiDetect: writeI2C_IF_DISandSIGNAL_PATH_RESETonly afterWHO_AM_I confirms device identity (datasheet section 6.1 requirement — must
be set immediately after reset to prevent accidental I2C switch)
icm20689GyroInit: remove redundant second device reset and signal-pathwrite (already performed in detect); replace 15ms inter-register delays and
100ms post-divider delay with
ICM20689_CLKSEL_SETTLE_US(120µs) afterclock source change only
ICM20689_BIT_RESETfrom public header to file-private .caccgyro_mpu.c
GYRO_SPI_STARTUP_MS(100ms) guard indetectSPISensorsAndUpdateDetectionResultso the SPI bus has settled before any device is probed
accgyro_spi_mpu6500.c
mpu6500SpiInitclock fromSPI_CLOCK_FAST(~20MHz) toSPI_CLOCK_INITIALIZATION— the fast clock during detection could causeerroneous register accesses on MPU6500-family devices
Test plan
SPEEDYBEEF7(SpeedyBee F7 — ICM-20689 only)YUPIF7(YupiF7 — ICM-20689 only)KAKUTEF7/KAKUTEF7MINI/KAKUTEF7HDV(Kakute F7 v1.3 ships with ICM-20689)IFLIGHT_F722_TWING/IFLIGHT_H7_TWING(iFlight Twig — ICM-20689 only)Summary by CodeRabbit