-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Fix ESC spinup during settings save using circular DMA #11260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: maintenance-9.x
Are you sure you want to change the base?
Changes from all commits
a6ba116
d32cf25
4249b55
ebcd802
9c2c1f4
eda9f22
c7b342d
e7075c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -33,6 +33,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "drivers/system.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "drivers/flash.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "drivers/pwm_output.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "fc/config.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -321,6 +322,18 @@ static bool writeSettingsToEEPROM(void) | |||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| void writeConfigToEEPROM(void) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #if !defined(SITL_BUILD) && defined(USE_DSHOT) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // Prevent ESC spinup during settings save using circular DMA | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pwmSetMotorDMACircular(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Force motor updates to latch current (zero) throttle into circular DMA buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pwmCompleteMotorUpdate(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| delayMicroseconds(200); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pwmCompleteMotorUpdate(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| delayMicroseconds(200); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pwmCompleteMotorUpdate(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+325
to
+335
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Gate the DMA mode switch on the runtime motor protocol (e.g.,
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| bool success = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // write it | ||||||||||||||||||||||||||||||||||||||||||||||||||
| for (int attempt = 0; attempt < 3 && !success; attempt++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -333,6 +346,11 @@ void writeConfigToEEPROM(void) | |||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| #if !defined(SITL_BUILD) && defined(USE_DSHOT) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // Restore normal DMA mode | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pwmSetMotorDMACircular(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (success && isEEPROMContentValid()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -226,6 +226,20 @@ void pwmEnableMotors(void) | |||||||||||||||||||||
| pwmMotorsEnabled = true; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| void pwmSetMotorDMACircular(bool circular) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| #ifdef USE_DSHOT | ||||||||||||||||||||||
| // Set DMA circular mode for all motor outputs | ||||||||||||||||||||||
| for (int i = 0; i < getMotorCount(); i++) { | ||||||||||||||||||||||
| if (motors[i].pwmPort && motors[i].pwmPort->tch) { | ||||||||||||||||||||||
| impl_timerPWMSetDMACircular(motors[i].pwmPort->tch, circular); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
Comment on lines
+233
to
+237
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Add a check for
Suggested change
|
||||||||||||||||||||||
| #else | ||||||||||||||||||||||
| UNUSED(circular); | ||||||||||||||||||||||
| #endif | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| bool isMotorBrushed(uint16_t motorPwmRateHz) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| return (motorPwmRateHz > 500); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -580,3 +580,61 @@ void impl_timerPWMStopDMA(TCH_t * tch) | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| HAL_TIM_Base_Start(tch->timCtx->timHandle); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| void impl_timerPWMSetDMACircular(TCH_t * tch, bool circular) | ||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (!tch->dma || !tch->dma->dma) { | ||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const uint32_t streamLL = lookupDMALLStreamTable[DMATAG_GET_STREAM(tch->timHw->dmaTag)]; | ||||||||||||||||||||||||||||||||||||||||||||||
| DMA_TypeDef *dmaBase = tch->dma->dma; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Save the current transfer count before disabling | ||||||||||||||||||||||||||||||||||||||||||||||
| uint32_t dataLength = LL_DMA_GetDataLength(dmaBase, streamLL); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Protect DMA reconfiguration from interrupt interference | ||||||||||||||||||||||||||||||||||||||||||||||
| ATOMIC_BLOCK(NVIC_PRIO_MAX) { | ||||||||||||||||||||||||||||||||||||||||||||||
| // Disable timer DMA request first to stop new transfer triggers | ||||||||||||||||||||||||||||||||||||||||||||||
| LL_TIM_DisableDMAReq_CCx(tch->timHw->tim, lookupDMASourceTable[tch->timHw->channelIndex]); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Disable the DMA stream | ||||||||||||||||||||||||||||||||||||||||||||||
| LL_DMA_DisableStream(dmaBase, streamLL); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // CRITICAL: Wait for stream to actually become disabled | ||||||||||||||||||||||||||||||||||||||||||||||
| // The EN bit doesn't clear immediately, especially if transfer is in progress | ||||||||||||||||||||||||||||||||||||||||||||||
| uint32_t timeout = 10000; | ||||||||||||||||||||||||||||||||||||||||||||||
| while (LL_DMA_IsEnabledStream(dmaBase, streamLL) && timeout--) { | ||||||||||||||||||||||||||||||||||||||||||||||
| __NOP(); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // If timeout occurred, DMA stream is still enabled - abort reconfiguration | ||||||||||||||||||||||||||||||||||||||||||||||
| if (timeout == 0 && LL_DMA_IsEnabledStream(dmaBase, streamLL)) { | ||||||||||||||||||||||||||||||||||||||||||||||
| // Re-enable timer DMA request and return to avoid unstable state | ||||||||||||||||||||||||||||||||||||||||||||||
| LL_TIM_EnableDMAReq_CCx(tch->timHw->tim, lookupDMASourceTable[tch->timHw->channelIndex]); | ||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+606
to
+616
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Fix the incorrect DMA timeout check by re-evaluating the stream status after the loop instead of checking if
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Clear any pending transfer complete flags | ||||||||||||||||||||||||||||||||||||||||||||||
| DMA_CLEAR_FLAG(tch->dma, DMA_IT_TCIF); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Modify the DMA mode | ||||||||||||||||||||||||||||||||||||||||||||||
| if (circular) { | ||||||||||||||||||||||||||||||||||||||||||||||
| LL_DMA_SetMode(dmaBase, streamLL, LL_DMA_MODE_CIRCULAR); | ||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||
| LL_DMA_SetMode(dmaBase, streamLL, LL_DMA_MODE_NORMAL); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Reload the transfer count (required after mode change) | ||||||||||||||||||||||||||||||||||||||||||||||
| // If dataLength was 0 (transfer completed), keep it at 0 - the next motor update will reload it | ||||||||||||||||||||||||||||||||||||||||||||||
| if (dataLength > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||
| LL_DMA_SetDataLength(dmaBase, streamLL, dataLength); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Re-enable DMA stream | ||||||||||||||||||||||||||||||||||||||||||||||
| LL_DMA_EnableStream(dmaBase, streamLL); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Re-enable timer DMA requests | ||||||||||||||||||||||||||||||||||||||||||||||
| LL_TIM_EnableDMAReq_CCx(tch->timHw->tim, lookupDMASourceTable[tch->timHw->channelIndex]); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
sensei-hacker marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -519,3 +519,39 @@ void impl_timerPWMStopDMA(TCH_t * tch) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tch->dmaState = TCH_DMA_IDLE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TIM_Cmd(tch->timHw->tim, ENABLE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void impl_timerPWMSetDMACircular(TCH_t * tch, bool circular) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!tch->dma || !tch->dma->ref) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Protect DMA reconfiguration from interrupt interference | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ATOMIC_BLOCK(NVIC_PRIO_MAX) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Temporarily disable DMA while modifying configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DMA_Cmd(tch->dma->ref, DISABLE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Wait for DMA stream to actually be disabled | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The EN bit doesn't clear immediately, especially if transfer is in progress | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uint32_t timeout = 10000; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while ((tch->dma->ref->CR & DMA_SxCR_EN) && timeout--) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| __NOP(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If timeout occurred, DMA stream is still enabled - abort reconfiguration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (timeout == 0 && (tch->dma->ref->CR & DMA_SxCR_EN)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DMA_Cmd(tch->dma->ref, ENABLE); // Re-enable and return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Modify the DMA mode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (circular) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tch->dma->ref->CR |= DMA_SxCR_CIRC; // Set circular bit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tch->dma->ref->CR &= ~DMA_SxCR_CIRC; // Clear circular bit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Re-enable DMA | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DMA_Cmd(tch->dma->ref, ENABLE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+530
to
+556
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Match the HAL implementation by disabling the timer’s DMA request source before disabling/reconfiguring the DMA stream, then re-enable it afterward to prevent mid-transition DMA triggers. [Learned best practice, importance: 5]
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sensei-hacker marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.