嵌入式软件系统概述
嵌入式软件开发路线图
随着嵌入式系统越来越复杂,嵌入式系统的软件开发难度越来越大,开发人员既需要对硬件很密切的了解,同时也需要对软件有着更高层次的视角。因此,传统的“游击式”开发已不可行,嵌入式软件团队也越来越大,集合了软件开发不同领域的专家。
嵌入式软件与桌面(通用)软件的对比
一般来说,嵌入式软件的约束比通用软件多得多。嵌入式开发的内存是有限的,这影响着嵌入式开发的语言选择和开发工具的使用。例如,某些编译器优化和解释器语言可能会不可用。此外,处于成本和功率的考量,对于 CPU 的选择也必须采用保守的方案。由于这些架构上的巨大差异,嵌入式系统的开发流程也经常采用交叉开发,即编译出来的程序运行环境和编译它的环境不一样,一般一端在目标板上,一端在宿主机上。
但是,在某些场景下,嵌入式软件也是不可或缺的。例如,大多数实时系统都在嵌入式系统上运行,它保证了给定时间要求下能够确定运行。嵌入式设备的可剪裁性,也使它绽放出无穷的可能性,它可以在技术层面和商业层面上都做到量身定制。
软件主导硬件
有关硬件的决策会对软件产生持久的影响。如果在硬件中减少费用或功耗,那么可能就会在编码上增加成本,反之亦然。但从目前的情况来看,还是偏向软件主导硬件。
软件和硬件的权衡
- 微处理器的选择
- 可能影响软件效率;
- 可能影响软件开发工具的可用性。
- 内存大小和组合
- 内存确切数量和大小应该尽可能晚地确定。
- 系统外设
- 需要重点考虑硬件费用;
- 有时可以由软件来替代,如定时器。
调试
- 在线仿真器
- 可以完全仿真芯片的行为
- 但价格昂贵,难以广泛应用
- 监控调试器
- 通过通信通道与板上的桩通信
- 但占用系统资源,在严格场合下不适用
- 片上调试
- 价格便宜,已于实现
现代嵌入式软件开发
目前嵌入式软件开发虽然依托传统方式,但比传统方法提供了灵活性。传统的软件堆栈,包括操作系统、中间件和底层应用程序代码逐渐不依赖于内部开发的手工编码来解决。微处理器供应商也在不断提供平台配置工具,为开发者提供加速的路径。
嵌入式软件架构综述
嵌入式软件架构一般分为两部分:业务逻辑和实施依赖硬件的逻辑。抽象层将所需的高级请求(业务逻辑)转换为操作系统的低级命令(实施依赖硬件的逻辑)。这两部分的解耦,让嵌入式软件的移植越来越方便。
更细致的嵌入式软件架构可以适用于特定的嵌入式系统。例如,非结构化单体架构是指单个模块之间通过错综复杂的结合形成应用,这种结构易于部署,但迁移困难;分层架构是当今嵌入式应用程序最广泛应用的架构,它具有较强的层次性,层与层之间结构清晰;事件驱动架构通过信息队列、信号量和事件标志来表示系统中发生了事件,具有很强的可扩展性和高内聚低耦合,但需要额外的开销;微服务架构是将应用程序构建为为业务领域开发的小型自治服务集合,它的耦合性最低,开发人员可以快速扩展或一致微服务,但是同样会在性能上有额外的开销,并且设计也会更复杂。
存储的架构
存储传输的主要方式就是:轮询、中断和 DMA。
轮询的优势是结构简单,并且没有资源共享的并发问题。但缺点是浪费处理周期,并且需要估算任务的执行时间,新加任务会对其他所有任务造成影响。
中断的好处是可以节省处理周期,避免不必要的开销。编写中断服务例程时,要注意避免内存分配,且应当使其尽可能简短。还有一种带有中断的轮询,它的中断优先于主循环,而不必要单独占用 CPU 时间,并且数据的延迟和抖动现象被优化。缺点是中断的设计会更加复杂。TODO
数据获取/存储相关的中断设计模式
线性数据存储设计模式:中断服务程序可以直接访问的共享内存位置。但线性的存储可能是危险的,因为需要考虑竞态条件。
双缓冲区设计模式:帮助缓解数据存储遇到的一些竞态条件问题。该缓冲区让 ISR 和应用程序均可以读写。
带有通知的循环缓冲区设计模式:使用信号量来判断循环缓冲区中是否有新的事件。
消息队列设计模式:类似于使用带有信号量的线性缓冲区。消息队列通常需要更多的 RAM、ROM 和处理能力。
资源同步
确保需要访问资源(如内存位置)的多个任务或任务和中断以协调的方式进行,从而避免竞态条件和内存损坏:
- 中断锁让系统不再响应中断,防止一些关键操作被打断。
- 抢占锁可用于确保任务在执行临界区时不间断,即禁用抢占调度程序。
- 互斥锁可以实现资源的独占,保护共享资源。它不会关掉中断或者禁用抢占调度程序。
活动同步
活动同步是关于协调任务执行的。在使用实时操作系统时,可以使用许多活动同步模式来协调任务执行。
TIP
例如,假设我们正在开发一个获取传感器数据并使用传感器值驱动电机的系统。我们很可能想要向运动任务发出信号,告诉它有新的数据可用,这样任务就不会对陈旧的数据采取行动。
发布和订阅模型
在物联网场景下广泛使用。物联网设备启动后连接到云,然后订阅它想要接收的消息主题,然后就可以等待数据被推送过来。
低功耗模型
关于低功耗设计模式,就是要尽可能保持设备关闭。除非发生唤醒事件,否则系统将一直处于低功耗状态;在唤醒操作完成后,系统由恢复到低功耗状态。