Rust因其内置的内存安全机制而迅速流行起来。如果您在物联网领域工作,或者需要在安全可靠的软件系统上工作,Rust是一种不错的语言。
在前面的几篇文章中,我们一直在探索如何启动并运行微控制器的嵌入式应用。我们一直在研究如何使用一些Rust模板来开始使用嵌入式应用,而今天的文章将开始探索如何使用外设访问包(Peripheral Access Crate,PAC)访问微控制器上的底层内存映射寄存器。
Rust crate就像您项目中的积木或砖块。您用Rust编写任何内容,它都已经组织为一个包—本质上是一个独立的代码包,可保持模块化和可重用性。包有两种主要类型:二进制包,即您的完整应用(可视为具有主要功能的可执行文件)和库包,它们更像是其他项目可以轻松引入和使用的工具和功能集。这是Rust保持代码井然有序、易于管理和易于集成的方式,尤其是当项目变得越来越大时。
Rust的包管理器Cargo负责处理包的设置,并允许您将外部包添加为依赖项,就像在项目中堆叠更多砖块一样,而无需从头开始构建每一块砖块。您可以在Crates.io上找到大量预构建的包,涵盖从基本数据操作到更高级的内容(如加密或Web框架)的所有内容。此设置让您不必一切从头开始,因此您可以专注于项目中最独特的部分,同时知道您用来构建的“砖块”是可靠且经过测试的。
嵌入式开发人员可以创建专门用于开发嵌入式软件的包。例如,如果您查看下图,您会发现至少有四个主要包可用于开发嵌入式软件:
图1:嵌入式开发人员在Rust中使用各种包从低抽象级(硬件级)转移到高抽象级(应用代码)。(来源:Rust嵌入式工作组)
微架构包专注于处理微控制器系列(如ARM Cortex内核)的内核特定功能。它抽象了较低级的组件,如CPU内核、常用外设(例如用于系统计时的systick)以及所有内核特定实用程序。通过管理这些基本组件,微架构包为更高级的包提供了一个基础,可在此基础上保持类似体系结构的兼容性。
外设访问包(PAC)为特定微控制器的低级内存映射寄存器提供了一个安全且Rust友好的封装。此包由设备的SVD(系统视图描述)文件自动生成,该文件描述了每个外设的寄存器映射。它允许开发人员以在Rust中既安全又惯用的方式直接控制微控制器外设(如GPIO、ADC和I2C),从而更轻松地操作硬件而无需处理原始指针。
硬件抽象层(HAL)包位于PAC之上,提供更用户友好的高级接口,用于与硬件交互。开发人员无需直接处理单个寄存器,而是可以使用更直观的API,这些API为各种外设(如GPIO引脚、计时器和串行接口)提供通用抽象。HAL包通常设计为可在具有类似架构的不同微控制器之间移植,从而更容易编写可重用的代码。
板级包是此结构中抽象级最高的部分,专门针对特定的开发板。它将使用特定电路板所需的一切都打包在一起,包括板载外设和组件(例如LED、按钮、传感器)的预配置设置。板级包通常依赖HAL来简化板设置,提供现成的环境,用于在特定硬件上进行原型设计和开发应用,而无需手动配置所有内容。
在使用Rust开发嵌入式软件时,您可能接触到最多的是高层抽象,例如板或HAL包。但是,作为嵌入式开发人员,了解PAC的底层行为以及如何访问内存至关重要。您会发现并非所有微控制器都受Rust支持,这意味着您可能需要创建自己的PAC!(下次我们将详细讨论如何做到这一点)。
就像使用任何其他语言一样,如果您想在微控制器上使用外设,您需要某种方法来访问寄存器和内存映射。传统上,这是通过开发使用指针直接操作外设寄存器的驱动程序来实现的。在C或C++中,这需要大量工作,这就是为什么您的微控制器供应商通常会提供自己的库来为您完成这项工作。(如今,一个MCU的典型数据表通常长达1,000页)。
Rust中现有的库实际上并未涵盖自定义驱动程序开发。虽然我们可以使用FFI导入C/C++库,但Rust通过PAC提供了另一种选择。您可以使用名为svd2Rust的自动化工具,该工具可以读取芯片供应商提供的svd文件以自动生成PAC。这样,您就可以创建高性能、底层的嵌入式应用,从而以最小的代价实现对硬件的精细控制。
当您创建PAC或使用Rust社区生成的PAC时,它可让您轻松访问底层硬件。例如,如果您想将STM32L475微控制器上的GPIO 14设置为输出,则可以使用以下Rust代码:
gpiob.moder().modify(|_, w| w.moder14().bits(0b01));
从上面的语句中可以看出,PAC为我们提供了多个抽象层来直接操作内存。让我为您分解一下该语句的每个部分的作用:
如您所见,访问底层硬件变得非常简单。如果我们想设置输出位,我们可以按如下方式使用PAC:
gpiob.odr().modify(|_, w| w.odr14().set_bit();
如果您想要清除该位,请执行以下操作:
gpiob.odr().modify(|_, w| w.odr14().set_clear();
PAC公开了所有寄存器和内存映射,以便您可以轻松地从Rust内部访问它们。
任何嵌入式开发人员想要使用Rust执行的第一步都是访问他们的内存映射。PAC是实现这一目标的方法。您在本文中已经看到,它不是唯一对嵌入式有用的包。我们还有其他包,例如微架构、HAL和板级包。
此时,您可以按照以下几个步骤继续您的嵌入式Rust之旅:
在下一篇文章中,我们将研究如何使用您自己的SVD文件来生成外PAC。
(原文刊登于EDN姊妹网站Embedded,参考链接:Embedded Rust: Introduction to Peripheral Access Crates (PACs),由Ricardo Xie编译。)