news 2026/4/26 5:07:59

第 11 章:HSEM 硬件信号量与无锁队列——解决优先级反转

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第 11 章:HSEM 硬件信号量与无锁队列——解决优先级反转

在第 10 章中,我们实现了基于 OpenAMP 的标准通讯。但在工业级实时控制中,OpenAMP 的包处理机制(Buffer 拷贝、中断路由、协议栈封装)在高频数据传输下会占用不少 M33 的 CPU 周期。

如果你需要以10kHz的速率同步 IMU 数据,或者在 M33 写入数据时绝不希望被 A35 侧的逻辑“卡住”(即避免优先级反转),我们就需要动用 MP257 的硬件利器:HSEM (Hardware Semaphore)


11.1 为什么需要硬件信号量?

在多核共享内存(DDR)时,如果 M33 正在写数据,A35 同时读,就会导致数据错乱。

  • 传统互斥锁的问题:如果 A35 抢占了锁但因为 Linux 内核调度延迟没释放,M33 就会在原地自旋(Spinlock)等待,失去了实时性。

  • HSEM 的优势:它是总线级别的硬件仲裁。M33 尝试Take锁,如果失败可以立即跳过执行其他逻辑,或者通过硬件状态位瞬时判断,不产生任何软件开销。


11.2 实战:HSEM 的原子操作

在 M33 侧,我们使用 HSEM 来保护关键的“写指针”。

#include "stm32mp2xx_hal.h"

#define IMU_HSEM_ID 0 // 使用第 0 号硬件信号量

uint8_t Try_Lock_Shared_Resource(void) {
/* 尝试获取信号量:单次非阻塞尝试 */
/* MasterID 为 1 (M33), ProcessID 设为 0 */
if (HAL_HSEM_Take(IMU_HSEM_ID, 0) == HAL_OK) {
return 1; // 锁定成功
}
return 0; // 锁定失败,被 A35 占用中
}

void Unlock_Shared_Resource(void) {
HAL_HSEM_Release(IMU_HSEM_ID, 0);
}

11.3 深度实战:无锁环形队列 (Lock-free SPSC Queue)

为了追求极致性能,我们通常采用单生产者单消费者 (SPSC)模型。

  • 生产者 (M33):只负责更新Head指针。

  • 消费者 (A35):只负责更新Tail指针。

  • 原理:由于指针更新是原子操作,且双方只写自己的指针,因此在单向传输 IMU 数据时,甚至可以完全不需要加锁

1. 共享内存结构定义

/* 映射到第 7 章定义的 0x90000000 区域 */
typedef struct {
volatile uint32_t head; // M33 更新
volatile uint32_t tail; // A35 更新
IMU_RawData_t data[256]; // 环形缓冲区
} LockFreeQueue_t;

LockFreeQueue_t *imu_queue = (LockFreeQueue_t *)0x90000000;

2. M33 极致推流代码

void Push_IMU_Data_Fast(IMU_RawData_t *new_data) {
uint32_t next_head = (imu_queue->head + 1) % 256;

/* 检查队列是否已满 */
if (next_head != imu_queue->tail) {
// 直接写入 DDR
imu_queue->data[imu_queue->head] = *new_data;

/* 内存屏障:确保数据写入完成后再更新指针 */
__DSB();

imu_queue->head = next_head;

/* 触发一次 IPCC 通知 A35 有新数据 (可选,或让 A35 轮询) */
}
}

11.4 解决优先级反转的策略

在实战中,如果 A35 需要下发配置给 M33(双向通讯),此时必须加锁。

  • M33 策略:使用HAL_HSEM_FastTake()。如果 A35 占着锁,M33 直接放弃本次操作,优先保证下一帧 IMU 的采集,而不是死等。

  • 硬件级公平:HSEM 确保了两个核心在总线请求上的优先级是可配置的。


11.5 A35 侧的配合 (Linux 视角)

在 Linux 侧,应用层可以通过mmap直接映射0x90000000

  • 逻辑:Linux 检查head != tail,读取数据后更新tail

  • 优点:无需经过内核驱动的读写拷贝,这就是所谓的“零拷贝 (Zero-copy)”


11.6 避坑指南:

  • 编译器优化陷阱:指针headtail必须声明为volatile,否则编译器可能会将其缓存在寄存器中,导致两个核看到的数值不一致。

  • 写缓冲区延迟:即使代码写完了,数据可能还在总线的 Write Buffer 里。在更新指针前,__DSB()指令是绝对不能省的

  • 对齐要求:MP257 的总线宽度较大,结构体IMU_RawData_t最好进行 8 字节或 32 字节对齐,以获得最佳传输速度。


总结: 本章我们放弃了繁琐的协议栈,回归到最原始、最高效的内存直接读写。这种 HSEM + 无锁队列的模式,是高性能嵌入式系统的终极方案。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 21:17:25

基于微信小程序的私人诊所管理系统毕设源码

博主介绍:✌ 专注于Java,python,✌关注✌私信我✌具体的问题,我会尽力帮助你。一、研究目的本研究旨在设计并实现一款基于微信小程序的私人诊所管理系统,以满足私人诊所对信息化管理的需求。具体研究目的如下: 首先,提…

作者头像 李华
网站建设 2026/4/18 21:17:35

通义千问3-Reranker实测:如何提升文档推荐准确率?

通义千问3-Reranker实测:如何提升文档推荐准确率? 1. 引言:为什么需要重排序技术? 你有没有遇到过这样的情况:在文档库中搜索某个关键词,系统返回了一大堆结果,但最相关的文档却排在了后面&am…

作者头像 李华
网站建设 2026/4/18 21:17:30

基于DeepSeek-R1-Distill-Qwen-1.5B的智能招聘助手开发

基于DeepSeek-R1-Distill-Qwen-1.5B的智能招聘助手开发 1. 引言 招聘工作一直是企业人力资源管理的核心环节,但传统招聘流程中,HR需要花费大量时间筛选简历、匹配岗位、生成面试问题,这些重复性工作不仅效率低下,还容易因主观因…

作者头像 李华
网站建设 2026/4/18 21:17:32

使用chainlit调用glm-4-9b-chat-1m:可视化对话界面搭建教程

使用chainlit调用glm-4-9b-chat-1m:可视化对话界面搭建教程 1. 学习目标与前置准备 想给大模型装上一个漂亮的聊天界面吗?今天我来手把手教你如何用chainlit为glm-4-9b-chat-1m大模型搭建一个可视化对话界面。学完这篇教程,你将能够&#x…

作者头像 李华
网站建设 2026/4/18 21:17:30

保姆级教程:用Ollama玩转Yi-Coder-1.5B代码生成

保姆级教程:用Ollama玩转Yi-Coder-1.5B代码生成 想快速上手一个强大的代码生成AI,但又不想折腾复杂的环境配置?这篇教程就是为你准备的! 1. 开篇:为什么选择Yi-Coder-1.5B? 如果你经常需要写代码&#xff…

作者头像 李华