[STM32F4] 在中断服务程序 里面调用 osEventFlagsSet /osEventFlagsGet 无效

[复制链接]
27|10
SocialButterfly 发表于 2026-9-16 08:46 | 显示全部楼层 |阅读模式
在STM32F407VET6里将触摸液晶屏中断接到 PC5。
已经开启 EXTI [9:5] 中断,用cubeMX生成代码,并且勾选了调用 HAL 中断处理函数。
已经定义事件标志;动态内存分配与静态内存分配两种方式测试均失败。
FreeRTOS 配置项:`xEventGroupSetBitFromISR`已启用。

我的目的是触摸中断触发时置位一个事件标志。
随后唤醒正在使用`osEventFlagsWait()`等待的处理线程。
从返回值上看,中断里面的函数调用本身是执行成功的。

调试跟踪显示 touchEventHandle 指向的堆地址和 FreeRTOS 所分配的位置是一致的。
这一组 Set / Get 例程在线程内部调用时工作正常。我已经做了单步调试跟踪,但仍然找不出为什么运行出错。Set 函数会深入执行跟队列相关的底层代码。难道事件标志位底层是使用队列实现的吗?而 Get 例程看起来逻辑更简单,并没有用到队列。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == Touch_INT_Pin)
{
uint32_t flags = 0x00;
extern osEventFlagsId_t touchEventHandle;

flags = osEventFlagsSet(touchEventHandle, 0x01);
// ^ returns 0x01, as expected.

flags = osEventFlagsGet(touchEventHandle);
// ^ returns 0x00, but should be 0x01

  }
}


公羊子丹 发表于 2026-9-16 12:17 | 显示全部楼层
你这个现象其实有个经典坑:FreeRTOS 的事件组在 ISR 里用 FromISR 版本置位时,置位动作是延迟到 PendSV 才真正生效的,不是立即写。所以你在 HAL_GPIO_EXTI_Callback 里 Set 完紧跟着 Get,读到 0x00 是正常的,线程能被 Wait 唤醒就说明位最终确实置上了。
周半梅 发表于 2026-9-16 12:18 | 显示全部楼层
我赌你怀疑'事件标志底层用队列实现'那个直觉方向是对的。但更可能的问题在调用上下文:CMSIS-RTOS v2 的 osEventFlagsSet 内部靠 xPortIsInsideInterrupt() 判断是否走 FromISR。只要它正确识别你在 ISR 里,就该走安全的延迟置位路径,Get 读到旧值不矛盾。
帛灿灿 发表于 2026-9-16 12:19 | 显示全部楼层
想问下你 osEventFlagsWait 那个线程最终能正常唤醒吗?如果能,说明 Set 是成功的,只是 ISR 内 Get 时序问题;如果不能唤醒,那才是真没置上,得查 touchEventHandle 是不是在 ISR 和线程里是同一个句柄、有没有被意外重建。
童雨竹 发表于 2026-9-16 12:20 | 显示全部楼层
补充个排查动作:别在 ISR 里调 osEventFlagsGet 去验证,这本身就不该在中断里做。正确做法是线程里 Wait 返回后读一次确认。你贴的调试线索说 Set 返回 0x01(成功),其实已经说明 API 认为置位请求已提交。
万图 发表于 2026-9-16 12:21 | 显示全部楼层
注意一个前提:要在中断里用事件标志,FreeRTOSConfig.h 里 configUSE_TIMERS 得开,因为 xEventGroupSetBitsFromISR 依赖定时器服务任务(Timer Daemon)去真正置位。如果定时器任务优先级太低或被饿死,置位会迟迟不生效,线程唤醒就拖很久。
Wordsworth 发表于 2026-9-16 12:22 | 显示全部楼层
我之前也踩过类似的。后来干脆不在 ISR 里折腾事件标志,ISR 里只给一个队列发个 1 字节 token(xQueueSendFromISR),线程里收 token 再处理。简单粗暴还避开了事件组延迟置位的认知负担,小系统里挺好用。
Bblythe 发表于 2026-9-16 12:22 | 显示全部楼层
从 CMSIS-RTOS2 源码看,osEventFlagsSet 内部已经是 ISR 安全的,会自动选 FromISR 版本,所以你不用自己换函数。问题更可能出在:你确认 HAL_GPIO_EXTI_Callback 里读到的 touchEventHandle 和线程创建的是同一个变量?变量作用域问题很常见。
Pulitzer 发表于 2026-9-16 12:23 | 显示全部楼层
测试建议:临时在 EXTI 回调里把 osEventFlagsSet 换成直接置一个全局 volatile 标志,线程里轮询这个标志,验证中断本身和线程切换是通的。如果这样能跑通,就反证是事件组 ISR 语义的问题,不是你板子或配置坏了。
Uriah 发表于 2026-9-16 12:24 | 显示全部楼层
补充:你说试了动态和静态两种创建事件标志都失败,这反而说明不是内存分配的问题,而是 ISR 语义。建议翻一下你用的 CMSIS-RTOS 版本,老版本的 osEventFlags 对 FromISR 支持有差异,升一版 often 就好了。
Clyde011 发表于 2026-9-16 12:25 | 显示全部楼层
想问下你 FreeRTOS 心跳和 PendSV 优先级怎么配的?如果 PendSV 被设得比其他中断低太多,ISR 里提交的置位请求要等很久才被 PendSV 处理,表现出来就像'置了但没生效'。这个优先级关系是 ST 官方例程最容易配错的地方。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

200

主题

200

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0