32位单片机的应用可移植性——现实还是神话?

原创 云深之无迹 2022-07-02 00:08


2008 年11月,ARM®宣布推出 Cortex™ 微控制器软件接口标准 (Microcontroller Software Interface Standard,CMSIS)。他们声称,对于新器件的软件开发项目或将现有软件在不同芯片厂商的基于 Cortex-M 的单片机之间移植时,这项标准可降低软件设计成本。这听起来很不错,但事实确实如此吗?本文将对这些说法进行研究以确定其真实度。我们先回顾一下典型单片机的元件,然后观察在典型外设固件库上添加一个抽象层能够实现或

无法实现什么样的结果。


根据 ARM 所言,CMSIS 是“适用于 Cortex-M 处理器系列的与厂商无关的硬件抽象层。CMSIS为不同芯片厂商和中间件提供商的处理器提供了简单一致的软件接口,这简化了软件重用,缩短了开发人员对于新单片机(MCU)的学习过程以及新器件的上市时间。CMSIS的问世使芯片厂商可将资源集中在突出其产品的外设功能上,无需在对单片机进行编程时保持各自不兼容的标准。”


为联系本文环境,我们需要了解一下单片机是如何设计的。单片机是高度集成的系统解决方案。实际上,可将其称为片上系统 (System on Chip, SoC)。与任何 SoC一样,该芯片的功能是通过与 CPU 内核集成在一起的

硬件外设进行定义的。当然,CPU 内核的性能和架构决定了可在芯片上执行的代码种类,但芯片与系统其他部分的交互要通过外设来进行。单片机外设的灵活性使其成为独特的 SoC。由于这种灵活性,单片机的设置和控制可能相当复杂。在实际进行任何操作前需要设置大量寄存器。为帮助设计人员完成此任务,芯片厂商提供了可简化代码开发的固件库。这些库包括了用于设置所有

寄存器以及控制单片机各个部分所必需的所有函数。由于各个芯片厂商的单片机具有不同的外设和功能,因此每个厂商都会提供一个独一无二的库,以使其产品在竞争对手中脱颖而出。我们来看一下单片机的哪些部分形成了各厂商之间的区别。


每个单片机制造商对实现整体系统集成 (即系统总线、时钟树和存储器)都有自己的方式,即使 CPU 内核相同时也是如此。凭借这些实现方案,各制造商建立了各自的优势,使自己的单片机成为更适合客户的解决方案。让我们来研究每一个系统组成:


• 时钟树提供系统的时钟脉冲,以协调所有其他功能的时序。时钟树旨在优化系统速度并使系统实现经济运行。芯片所含的功能和外设以及芯片旨在解决的问题直接影响着时钟树的结构。因此,各家制造商的时钟树结构不尽相同。此外,在进行任何操作前,都需要使用适当的值对时钟树寄存器进行编程。

• 系统总线的架构定义了所有 MCU 功能的集成方式。有些制造商会使用一条或多条外设总线,具体情况取决于所集成的外设。所有这一切都会改变需要设置的寄存器的种类和数量,以尽可能利用所有可用的功能。

• 尽管所有单片机都同时具有非易失性存储器(如闪存)和易失性存储器(如 SRAM),但每家制造商的具体集成方式都不相同。有些制造商将闪存存储

器直接连接到内核与总线矩阵,而其他一些制造商则将其连接到系统总线或总线矩阵。RAM 有时会分布于两个独立的存储器组,以允许内核和外设同时

访问。这些不同的存储器结构可能会影响代码的编写方式,当设计人员从一个制造商转到另一个时,这通常会对应用程序的性能产生直接影响。


每个制造商都在其单片机上提供了一系列标准和专用的硬件外设。


• 标准外设提供通用功能,例如通过 UART 或 SPI 实现串行通信。这些外设也可以是定时器或 PWM。标准外设在所有 MCU 制造商的产品中都很常见,

但它们可能会有某些增强功能,为客户提供更大的灵活性和 / 或更多功能。与单片机的任何其他部分一样,标准外设有自己的寄存器。尽管标准外设的

功能可能相同,但几乎每个制造商实现标准外设的方式都不相同,进而导致各个 MCU 厂商产品的寄存器结构也各不相同。

• 专用外设适用于某些应用独有的特定任务。例如,无刷电机控制 PWM、用于音频回放的 I2S 或加密 / 解密。根据复杂性的不同,这些专用外设可能只有几个寄存器,也可能有 30 个以上的寄存器。


如前文所述,每个MCU制造商都有自己的外设固件库,用以帮助客户实现设计并迅速进入原型设计阶段。固件库包括由芯片制造商开发的代码,用于设置芯片各部分中 (如时钟、总线和外设)的所有寄存器。提供可轻松设置各个寄存器的函数调用,以助于开发人员专注于输入应用程序所需的参数。函数负责将这些参数写入相应的存储器位置。通过使用固件库中的函数,开发人员不

必了解所有寄存器及其位置便可使芯片正常运行。这样可将节省下的时间集中在更特定于应用程序的任务上,例如为应用程序开发适当算法。


外设固件库还包括用于控制外设 (也通过寄存器完成)的函数。同样,开发人员无需关注寄存器的位和单元,只需为其代码选择正确的函数。抽象层可应用到外设固件库以帮助简化代码开发,这正是 CMSIS 发挥作用的地方。但还有一个疑问:这是否会产生代码兼容性问题?


现在我们已清楚地了解各个单片机制造商都能提供什么,我们可以看一下抽象层能为设计人员做些什么(如果有的话)。首先,我们来看 CMSIS 声称所能提供的功能,同时应记住前文所述的系统架构、外设和固件库。


对于CMSIS 版本 1.3


1. 内核外设访问层:包含用于访问内核寄存器和外设的名称定义、地址定义和辅助函数。它还定义了一个用于 RTOS 内核的器件无关接口,其中包含调试通道定义。


2. 这些软件层由芯片合作伙伴通过以下方式进行扩展:

    a) 器件外设访问层,提供所有器件外设的定义;

    b) 用于外设的访问函数(可选):提供用于外设的附加辅助函数。


仔细阅读此说明后,我们可以看到 CMSIS 提供了一种通用语言,通过它可描述 MCU 的不同元件。接下来,我们看一下两个不同的 “芯片合作伙伴”(使

用 ARM Cortex-M 处理器内核的 MCU 制造商)所生产的 MCU 中包含的部分功能。




显而易见的是,尽管这两个 32 位 MCU 制造商都使用Cortex-M3 内核,但主要功能仍有区别。表中列出的功能是单片机最标准的功能,即便如此它们仍有不同。这意味着,即使这两个制造商使用相同的内核,也需要对软件进行调整才能运行最基本的程序,例如翻转 I/O 或使用 UART。如果不进行一定程度的代码重写,而只是对基本参数进行调整,则无法在 A 和 B 之间移植软件。


根据定义,CMSIS 提供了用于访问内核元素的标准化语言,但芯片合作伙伴 /MCU 制造商必须提供自己的固件才能与器件外设进行交互。任何 MCU 的两个最基本功能都会涉及 (1)如何使系统架构与外设相关联,(2)如

何设计 MCU 外设的结构以实现所需控制和 / 或功能。这是制造商提供的固件库能帮助解决的问题,也是代码兼容性问题的核心所在。向这些库添加抽象层有助于提高可移植性,但无法解决两个MCU之间的所有功能差异。任何高级外设功能都无法移植到不存在该功能的另一MCU 上,无论是否有抽象层。单片机制造商实现的这些增强功能有助于使 MCU 从竞争对手中脱颖而出,并帮

助设计人员改进解决方案。但这会导致代码不兼容。


抽象层的概念与操作系统的设计有关。它创建了一种操作系统访问处理器 (正在运行该操作系统)的标准方式,并且可以简化更改处理器的过程。必须知道的是,处理器(微处理器单元,MPU)是系统元件集成度最低的内核,这使得各制造商的处理器的相似度要远大于MCU。此外,处理器上运行的代码是软件,而不是固件。也就是说,代码通常不控制任何硬件。另一方面,

单片机是片上系统,这意味着内核与集成外设之间的联系更为紧密。对于 MCU,如果要运行 RTOS,则抽象层的概念最有意义。另一方面,使用 RTOS 会使应用程序代码与硬件分离,进而去除单片机应用中常见的严格控制。


如果某个应用程序正在RTOS上运行,则可将其移植到任何支持该特定 RTOS 的单片机。在运行 Micrium µCOS II  的 Cortex-M3 单片机上开发的代码可移植到基于 MIPS M4K 的单片机,因为 µCOS II 在该平台上也可以运行。应用程序与硬件隔离,并且只要代码的新部分具有所有相关功能,移植就应该相对很容易。


但在另一方面,如果没有 RTOS,情况就不是这样了。如前文所述,每个制造商都会以自己的方式集成内核、存储器和外设。其中一些差异使得创建一个适用于不同制造商的标准抽象层非常困难,并且还有一个问题:他们想让这变得简单吗?


在大多数单片机应用程序中,在内核上运行的代码与硬件外设之间的牢固连接非常关键。实际上,该连接使得创建任何种类的标准抽象层 (可在不同制造商的 MCU间转换)都很困难。抽象层可以对标准功能(例如 UART或 SPI)有所帮助。但即使是 UART,如果原始代码对9 位模式的 UART 使用了固件库函数,则在新 MCU 没有 9 位模式的 UART (即没有用于此用途的库函数)时,必须重写代码。更复杂的是,在大多数情况下设计人员不是通过标准函数来定义 MCU 的值,而是通过其独特的外设开发最优解决方案。例如,如果能以更高的精度和安全性控制电机,您将从竞争对手中脱颖而出。专用库正是在这里起作用,而使事情变得更加复杂。



外设固件库支持指定单片机上的所有外设,包括标准外设和专用外设。但为了更好地支持客户,某些制造商还为特定应用(如电机控制、图形和网络等)提供专用固件库。这些专用库总是专有的,在许多情况下包含无法在制造商之间转移的知识产权。在大多数情况下,所涉及的应用程序都很复杂,设计人员不会愿意从头开发应用程序。此外,制造商通常将其外设支持的所有特殊功能都集成到库中,在不对代码进行较大修改的情况下无法移植到其他制造商的 MCU 上。


在我们的示例中,厂商 A 和 B 的单片机都使用了ARM Cortex-M3 内核,并且都具有符合 CMSIS 标准的固件库。这是否意味着他们的库(例如电机控制库)可以互相移植?其实不见得。这两个制造商对外设和固件采用了完全不同的方法。厂商 A 使用专用算法库 (可能由多人经过数年开发而成)来最高效地利用其单片机上的专用外设。而厂商 B 则专注于使用更通用的外设并构建通用外设库,对于特定应用则使用示例代码和应用笔记进行说明。这两种完全不同的方法使得在这两个制造商的 MCU 之间移植程序(例如电机控制子程序)非常困难,尽管它们使用了相同的内核。此外,库函数的命名也不相同,

这意味着用户必须重写代码中的所有库函数调用,并且要弄清将哪些变量和值提交给函数。这完全不是所谓的可移植性。


设计人员关注的重点是开发特定最终用途代码时的速度、效率和可靠性。厂商 A 和 B 采用不同的方法来达到这些目标。厂商 A 使用基于专用硬件的方法,而厂商 B的方法更加专注于通用硬件。厂商 A 针对特定应用提供了经过潜心开发的专用库,以最大限度地利用其单片机的功能。而厂商 B 只提供基本构件,让开发人员构建自己的解决方案。在速度和可靠性方面,厂商 A 的方法占据优势,因为很大一部分的应用程序开发工作已经完成且经过测试,并

集成在其固件库中。至于效率方面,厂商 A 也有明显优势,因为其软件专为其硬件进行了优化。但是,这些优势没有一项与 CMSIS 或可移植性有关。对两个厂商的MCU 所进行的比较不应基于抽象层,而应该着重于使用某个 MCU 实现其预期最终用途的顺利程度。那些针对特定单片机开发了定制固件库的制造商具有明显优势。正在寻找控制器的设计人员可将精力放在比较特定

算法对其需求的适用程度上。尽管 CMSIS 这样的 API对于隐藏硬件复杂性(例如针对 RTOS)很有用,并在二者之间形成无缝接口,但无法保证软件在各个制造商间的可移植性。


要考虑的最后一点是单片机的基本宗旨。开发 MCU 的目的是为日常设备的控制带来可编程性和灵活性。通过集成 CPU、非易失性存储器和外设(模拟和数字),这一目标已经实现。无需那些使计算机变得通用的高级功能,单片机可充分利用少量硬件来实现所需功能。专用于 MCU 特定外设结构的固件库大幅减少了开发应用程序所需的时间和工作量。如前文所述,向这些库添加抽

象层有助于改进开发过程,对于跨项目重用代码也更为简单,但要付出一定代价。使用抽象层时存在代码变长和性能下降问题。添加抽象层使单片机更类似于计算机。这在某种程度上与形成单片机基本宗旨的特质相反。实际上,它使开发过程更为复杂,因为它要求应用程序遵守 CMSIS 的特定语言要求,而且无法保证代码兼容性。


https://www.arm.com/products/silicon-ip-cpu
评论 (0)
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦