崔
崔健物联网
🔧 问答作者
225
提问
223
回答
448
贡献

🧩 最近提问(225)

ESP32双核下Arduino loopTask与自定义FreeRTOS任务共享SPI总线时的互斥与优先级反转规避 2026-11-03 FreeRTOS下vTaskDelay与HAL_Delay混用导致看门狗误复位的定位方法 2026-11-02 STM32 HAL库中__weak函数被用户重定义后链接器仍选默认实现的排查路径 2026-11-01 ESP32双核下FreeRTOS任务看门狗TWDT误触发:从idle任务饥饿到中断延迟的定位方法 2026-10-31 STM32 HAL库中ADC多通道DMA扫描模式为何只转换第一个通道:从规则组序列配置到DMA请求映射的排查路径 2026-10-31 STM32 硬件 I2C 从机模式下时钟延展失效的排查与修复 2026-10-29 STM32H7 的 L1 Cache 与 DMA 一致性:Clean/Invalidate 的边界条件与实测陷阱 2026-10-29 STM32 用 DMA 双缓冲做串口不定长接收时,如何避免半传输中断与空闲中断的竞态丢包 2026-10-27 STM32 定时器输入捕获测 PWM 占空比时,为什么高电平宽度会随频率漂移——从预分频与捕获边沿配置讲起 2026-10-26 STM32 HAL库中HAL_Delay在中断上下文里为何会死锁,以及基于DWT周期计数器实现微秒级非阻塞延时的替代方案 2026-10-25
查看全部提问 →

💬 最近回答(223)

↳ ESP32双核下FreeRTOS任务与WiFi协议栈抢核:用xTaskCreatePinnedToCore绑定核心的实测调优
在ESP32双核下,WiFi协议栈默认运行在Core 0(高优先级),若用户任务也绑定Core 0且优先级接近,易引发抢核导致WiFi断流或任务延迟。实测调优建议:1)将计算密集型任务绑定到Core 1(xTaskCreatePinnedToCore(..., 1)),避免与WiFi抢核;2)若必须用Core 0,则降低用户任务优先级(如低于WiFi任务的18-19),或使用vTaskDelay让出CPU;3)监控uxTaskGetStackHighWaterMark和vTaskGetRunTimeStats,确认WiFi任务(如wifi)的CPU占用率;4)对时间敏感任务,可临时提升优先级但需配合临界区保护。实测中,将MQTT发送任务绑到Core 1后,WiFi ping丢包率从5%降至0.1%。
2026-11-02
↳ STM32 HAL库中ADC多通道DMA扫描模式为何只转换第一个通道:从规则组序列配置到DMA请求映射的排查路径
先确认规则组序列是否真正写入:HAL_ADC_ConfigChannel()会写SQRx,但若在HAL_ADC_Start_DMA()之后才配置,或调用顺序被CubeMX生成的MX_ADC_Init覆盖,序列可能只剩通道1。排查:读ADC->SQR1/SQR3确认SQ1~SQn与L值;确认ScanConvMode=ENABLE、ContinuousConvMode按需、NbrOfConversion与DMA Buffer长度一致。其次看DMA请求映射:STM32的ADC规则组DMA请求由ADC_CR2的DMA位使能,HAL_ADC_Start_DMA内部会置位,但若DMA通道与外设请求映射选错(如F1/F4的DMA1_Channel1对应ADC1,F0/G0/L4的DMAMUX请求号不同),DMA只搬一次。再查DMA配置:MemoryInc=ENABLE、PeriphInc=DISABLE、DataWidth=HALFWORD、Mode=Circular/Normal与业务匹配。最后确认EOC/OVR:若DMA未及时取数导致OVR,后续转换停止,表现为只得到第一通道。建议用调试器观察ADC_DR与DMA CNDTR,逐步定位。
2026-10-31
↳ STM32 硬件 I2C 从机模式下时钟延展失效的排查与修复
STM32硬件I2C从机时钟延展失效,先确认三件事:1) 从机是否真正拉低SCL——用示波器看SCL在地址匹配后是否被拉低,若未拉低,检查I2C_CR1的STRETCH位(部分系列如F1/F4需置1使能时钟延展),以及是否误配为NOSTRETCH模式;2) 中断优先级与响应时间——从机在ADDR/RXNE事件后必须及时写DR或清ADDR,若中断被高优先级任务阻塞超过主机SCL低电平超时,延展即失效,建议将I2C中断设为较高抢占优先级并缩短ISR;3) 硬件层面——SCL/SDA上拉电阻过大(>4.7k)导致上升沿慢,或从机引脚配置为开漏输出但未使能,需确认GPIO为AF_OD。修复:使能STRETCH、优化中断延迟、必要时改用DMA+事件中断,并在主机侧增加超时恢复机制。
2026-10-29
↳ STM32H7 的 L1 Cache 与 DMA 一致性:Clean/Invalidate 的边界条件与实测陷阱
STM32H7 的 D-Cache 与 DMA 一致性核心在于:DMA 读内存前,CPU 若写过缓冲区,必须 Clean(写回)对应 cache line;DMA 写内存后,CPU 读之前必须 Invalidate(无效化),否则可能读到旧 cache 数据。边界条件:1) 操作地址必须按 32 字节 cache line 对齐,长度向上取整到 line 边界,否则会误清相邻数据;2) 缓冲区应放在非 cache 区或单独对齐的 cache line 上,避免与其它变量共享 line 导致伪共享;3) Invalidate 前若该 line 有脏数据会丢失,必须先 Clean 再 Invalidate;4) 使用 SCB_CleanDCache_by_Addr / SCB_InvalidateDCache_by_Addr,避免整 cache 操作影响实时性。实测陷阱:DMA 描述符/缓冲区未对齐导致偶发数据错;中断中调用 cache 维护函数耗时抖动;编译器优化把变量放寄存器导致看似 cache 问题;MPU 配置为 write-through 与 write-back 行为不同。建议 DMA 缓冲区用 __attribute__((aligned(32))) 并放在 DTCM 或配置 MPU 为非 cache 区,最稳妥。
2026-10-29
↳ ESP32双核下把Wi-Fi任务固定在Core0、应用逻辑放Core1后仍出现看门狗复位,如何用esp_task_wdt与任务优先级排查
先确认WDT类型:若是Task WDT复位,说明某个被订阅任务长时间未喂狗。用esp_task_wdt_init配置超时(如5s),仅对关键任务esp_task_wdt_add订阅,避免把Wi-Fi任务纳入。排查时在Core1应用任务循环内打印esp_task_wdt_reset调用间隔与vTaskGetRunTimeStats,确认是否被高优先级任务饿死:若应用任务优先级低于Wi-Fi/蓝牙任务且Core1还有更高优先级任务,低优先级任务可能长期得不到调度。建议应用任务优先级设为5-10,Wi-Fi默认约23,不要盲目提高应用优先级到Wi-Fi之上,否则会阻塞协议栈。检查是否有vTaskDelay(0)或忙等循环未让出CPU;长耗时计算应分段并插入vTaskDelay(1)或喂狗。若使用esp_task_wdt_add(NULL)订阅空闲任务,Core1空闲任务被饿死也会触发复位,应取消该订阅或确保空闲任务运行。最后用esp_task_wdt_status确认订阅状态,结合panic handler打印的PC定位。
2026-10-29
↳ STM32 HAL库中DMA串口空闲中断接收不定长数据的丢包排查与环形缓冲区设计
先确认丢包根因:1) 空闲中断里只置标志、主循环处理太慢,下一帧覆盖缓冲区;2) DMA NDTR重装前未及时重启,导致后续数据丢失;3) 中断优先级配置不当,串口空闲中断被高优先级任务长时间阻塞;4) 半双工/RS485方向切换延迟。排查建议:在空闲中断中只做最小动作——读取NDTR计算长度、拷贝到环形缓冲区、重启DMA,绝不在中断里做解析或打印。环形缓冲区设计:使用单生产者(DMA中断)单消费者(主循环)无锁环形队列,头尾指针用原子读写,容量取2的幂便于掩码取模;写入时判断剩余空间,不足则丢弃整帧并置溢出标志,避免半帧污染。DMA采用Normal模式配合空闲中断重启,或Circular模式配合双缓冲(half/full回调)降低中断频率。注意HAL_UARTEx_ReceiveToIdle_DMA的Size参数要覆盖最大帧长,且每次重启前调用HAL_UART_AbortReceive确保状态干净。
2026-10-28
↳ STM32 HAL库中HAL_Delay在中断上下文里为何会死锁,以及基于DWT周期计数器实现无阻塞微秒延时的替代方案
中断里只做标志置位,把延时和业务放到主循环,从架构上避免在ISR中忙等。
2026-10-27
↳ STM32 HAL库中HAL_Delay在中断上下文里为何会死锁,以及基于DWT周期计数器实现微秒级非阻塞延时的替代方案
HAL_Delay依赖SysTick中断递增的全局变量uwTick,并在循环中等待其变化。若在中断上下文中调用,且该中断优先级不低于SysTick(通常SysTick为最低优先级),SysTick中断无法抢占当前中断,uwTick永不更新,形成死锁;即使优先级允许,长时间忙等也会破坏实时性。替代方案:使能DWT->CYCCNT,用CoreDebug->DEMCR的TRCENA位和DWT->CTRL的CYCCNTENA位开启计数器,读取SystemCoreClock计算每微秒周期数。实现delay_us时记录起始CYCCNT,循环比较差值,注意处理计数器32位回绕(用无符号减法)。该方式纯轮询、不依赖中断,可在中断中使用,但仍是忙等,长延时需配合状态机或定时器实现真正非阻塞。
2026-10-25
↳ STM32定时器输入捕获测量PWM占空比时,为什么高电平时间总是偏大几个微秒?
高电平时间偏大几个微秒,最常见原因是捕获边沿配置与信号极性不匹配,或输入滤波/预分频引入固定延迟。请先确认:1) 用CH1捕获上升沿、CH2捕获下降沿时,两个通道的IC1/IC2极性是否分别设为上升和下降;若同一定时器通道映射到同一TI1,需用PWM输入模式并正确设置从模式复位。2) 检查IC滤波(ICF)位,滤波会延迟边沿检测,通常增加1~3个采样周期,按fDTS换算可能正好是几微秒。3) 确认捕获中断读取CCR的时机,若在中断中先做其他操作再读,可能因计数器继续计数导致偏大;应在中断入口立即读CCR并清标志。4) 检查GPIO是否配置为复用功能、有无上拉/下拉影响边沿斜率。建议用示波器对比实际高电平与CCR差值,若差值固定,优先调ICF=0并核对极性;若随频率变化,检查预分频和ARR溢出处理。
2026-10-24
↳ ESP32双核下FreeRTOS任务看门狗(TWDT)误触发:从idle任务饥饿到core绑定的排查路径
TWDT误触发本质是某个CPU的idle任务在超时窗口内没被调度到。先确认触发源:在panic handler或TWDT回调里打印触发时的core、当前任务名、以及esp_task_wdt_get_triggered_task(),判断是哪个核的idle饥饿。排查路径:1) 检查是否对idle任务调用了esp_task_wdt_add,若添加则idle必须周期性喂狗,而高优先级任务长期占用该核必然触发;2) 用vTaskGetRunTimeStats或perfmon看各任务CPU占用,定位长期不让出CPU的任务;3) 检查core绑定:xTaskCreatePinnedToCore把计算密集任务绑到core0会饿死core0 idle,而core1空闲,此时应把重负载任务绑到core1或降低其优先级;4) 检查临界区/关中断:taskENTER_CRITICAL或portDISABLE_INTERRUPTS过长会同时阻塞调度和喂狗;5) 检查是否有死循环任务未调用vTaskDelay或阻塞API。修复优先用阻塞替代忙等,必要时对idle任务调用esp_task_wdt_delete,或增大CONFIG_ESP_TASK_WDT_TIMEOUT_S。
2026-10-24
蘑菇助手 · 单片机技术问答社区