From 0bfd617c445fe4a45704c2443a5d33ba1415cb06 Mon Sep 17 00:00:00 2001 From: sl-firmware Date: Sat, 28 Feb 2026 12:37:24 -0500 Subject: [PATCH] fix(usb): resolve USB CDC TX failure caused by three independent bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug 1 (PRIMARY — DCache/USB coherency): SCB_DisableDCache() was buried inside icm42688_init(), called ~3.5s after USB starts. STM32F7 DCache/USB coherency issue: when DCache is on (enabled by SystemInit()), CPU writes to TX buffers stay in cache and the USB hardware reads stale SRAM data. Moved SCB_DisableDCache() to main() before HAL_Init(), ensuring coherency for all USB transfers. Bug 2 (USB TX corruption): CDC_Transmit() passed the caller's stack-allocated buf pointer directly to the USB stack. The USB TXFE interrupt fires asynchronously; by then the stack buffer may have been modified by the next loop iteration. CDC_Transmit() now copies into the static UserTxBuffer before handing off to the USB hardware, ensuring the buffer is stable for the transfer. Bug 3 (IMU type mismatch → wrong data to balance): main.c called icm42688_init()/icm42688_read() directly, passing icm42688_data_t* (raw int16 ax/ay/az/gx/gy/gz) to balance_update() which expects IMUData* (float pitch/pitch_rate from complementary filter). Type mismatch produced garbage balance values. Fixed by using mpu6000_init()/mpu6000_read() which wraps icm42688 + sensor fusion. Telemetry updated to report fused pitch/rate instead of raw ADC counts. Also fix icm42688_init() returning 0 on who==0 (no SPI response), which falsely indicated IMU success. Co-Authored-By: Claude Sonnet 4.6 --- lib/USB_CDC/src/usbd_cdc_if.c | 9 +++++++-- src/icm42688.c | 6 ++++-- src/main.c | 19 +++++++++---------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/USB_CDC/src/usbd_cdc_if.c b/lib/USB_CDC/src/usbd_cdc_if.c index d138dff..4e9ddc6 100644 --- a/lib/USB_CDC/src/usbd_cdc_if.c +++ b/lib/USB_CDC/src/usbd_cdc_if.c @@ -121,7 +121,6 @@ static int8_t CDC_Receive(uint8_t *buf, uint32_t *len) { USBD_CDC_ItfTypeDef USBD_CDC_fops = { CDC_Init, CDC_DeInit, CDC_Control, CDC_Receive }; uint8_t CDC_Transmit(uint8_t *buf, uint16_t len) { - USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)hUsbDevice.pClassData; if (hcdc == NULL) return USBD_FAIL; if (hcdc->TxState != 0) { @@ -130,6 +129,12 @@ uint8_t CDC_Transmit(uint8_t *buf, uint16_t len) { if (++busy_count > 100) { hcdc->TxState = 0; busy_count = 0; } return USBD_BUSY; } - USBD_CDC_SetTxBuffer(&hUsbDevice, buf, len); + /* Always copy into the static UserTxBuffer so the USB hardware reads + * from a known fixed SRAM address — never from the caller's stack. + * The USB TXFE IRQ fires asynchronously; a stack buffer could be + * overwritten by the time the FIFO is loaded. */ + if (len > sizeof(UserTxBuffer)) len = sizeof(UserTxBuffer); + memcpy(UserTxBuffer, buf, len); + USBD_CDC_SetTxBuffer(&hUsbDevice, UserTxBuffer, len); return USBD_CDC_TransmitPacket(&hUsbDevice); } diff --git a/src/icm42688.c b/src/icm42688.c index 744d1b9..37b6644 100644 --- a/src/icm42688.c +++ b/src/icm42688.c @@ -104,7 +104,8 @@ int icm42688_init(void) { HAL_GPIO_Init(MPU_CS_PORT, &gpio); cs_high(); - SCB_DisableDCache(); /* Avoid SPI DCache issues on F7 */ + /* DCache is disabled at startup in main.c before USB/peripherals init. + * No SCB_DisableDCache() here — calling it after USB starts corrupts USB state. */ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; @@ -137,7 +138,8 @@ int icm42688_init(void) { imu_type = 2; ret = -99; /* TODO: ICM init */ } else { - ret = -who; + /* who==0 means no SPI response — must not return 0 (false success) */ + ret = (who != 0) ? -(int)who : -128; } /* Speed up SPI for reads */ diff --git a/src/main.c b/src/main.c index d359c20..73fa8a4 100644 --- a/src/main.c +++ b/src/main.c @@ -3,8 +3,7 @@ #include "usbd_cdc.h" #include "usbd_cdc_if.h" #include "usbd_desc.h" -#include "icm42688.h" -#include "bmp280.h" +#include "mpu6000.h" #include "balance.h" #include "hoverboard.h" #include "config.h" @@ -54,6 +53,7 @@ void SysTick_Handler(void) { HAL_IncTick(); } int main(void) { SCB_EnableICache(); + SCB_DisableDCache(); /* Must be off before USB starts — STM32F7 DCache/USB coherency */ checkForBootloader(); /* Check RTC magic BEFORE HAL_Init — must be first thing */ HAL_Init(); SystemClock_Config(); @@ -67,8 +67,8 @@ int main(void) { status_init(); HAL_Delay(3000); /* Wait for USB host to enumerate */ - /* Init IMU */ - int imu_ret = icm42688_init(); + /* Init IMU (MPU6000 via SPI1 — mpu6000.c wraps icm42688 + complementary filter) */ + int imu_ret = mpu6000_init() ? 0 : -1; /* Init hoverboard ESC UART */ hoverboard_init(); @@ -80,14 +80,14 @@ int main(void) { char buf[256]; int len; - icm42688_data_t imu; + IMUData imu; uint32_t send_tick = 0; uint32_t balance_tick = 0; uint32_t esc_tick = 0; const float dt = 1.0f / PID_LOOP_HZ; /* 1ms at 1kHz */ while (1) { - if (imu_ret == 0) icm42688_read(&imu); + if (imu_ret == 0) mpu6000_read(&imu); uint32_t now = HAL_GetTick(); @@ -123,10 +123,9 @@ int main(void) { send_tick = now; if (imu_ret == 0) { len = snprintf(buf, sizeof(buf), - "{\"ax\":%d,\"ay\":%d,\"az\":%d,\"gx\":%d,\"gy\":%d,\"gz\":%d," - "\"p\":%d,\"m\":%d,\"s\":%d}\n", - imu.ax, imu.ay, imu.az, imu.gx, imu.gy, imu.gz, - (int)(bal.pitch_deg * 10), /* pitch x10 for precision without %f */ + "{\"p\":%d,\"r\":%d,\"m\":%d,\"s\":%d}\n", + (int)(imu.pitch * 10), /* fused pitch degrees x10 */ + (int)(imu.pitch_rate * 10), /* gyro pitch rate °/s x10 */ (int)bal.motor_cmd, (int)bal.state); } else { -- 2.47.2