广告

一起学习一下怎么用LUT来减轻你的开发负担

2024-08-02 17:35:33 Jacob Beningo 阅读:
为多个项目甚至多个嵌入式目标配置嵌入式软件非常复杂。不过,嵌入式开发人员可以使用查找表(LUT)来减轻开发负担。

当今开发团队面临的一个重大挑战是编写可扩展且可配置的嵌入式软件。过去,嵌入式开发的重点是开发只能用于单一、短期产品的软件。然而,行业中出现了一个明显的转变,即开发可用于支持多个项目长达五年或更长时间的平台软件。这一趋势凸显了系统开发的复杂性和成本日益增加。jqoednc

为多个项目甚至多个嵌入式目标配置嵌入式软件非常复杂。不过,嵌入式开发人员可以使用查找表(LUT)来减轻开发负担。jqoednc

什么是LUT?

LUT是一种强大的数据结构,用于映射输入和输出值。LUT在加快执行速度方面的效率改变了游戏规则。系统无需在运行时执行计算或复杂的决策逻辑,而是可以快速从LUT中检索预先计算的结果,从而提高开发人员的效率。jqoednc

例如,假设您需要将摄氏度转换为华氏度。您可以在一个函数中实现如下转换:jqoednc

float celsius_to_fahrenheit(float celsius) {jqoednc

    return (celsius * 9.0 / 5.0) + 32.0;jqoednc

}jqoednc

虽然这种方法可以正常运行,但查找表可以提高运行效率。例如,您可以编写一个查找表来查找摄氏度的整数值,如下所示:jqoednc

// Example LUT for temperature conversionjqoednc

float celsius_to_fahrenheit[101] = {jqoednc

    32.0, 33.8, 35.6,..., 212.0jqoednc

};jqoednc

// Precomputed values floatjqoednc

convert_to_fahrenheit(int celsius) {jqoednc

    return celsius_to_fahrenheit[celsius];jqoednc

}jqoednc

LUT的执行速度要快得多,因为您只需提供一个输入值,函数就会通过将其索引到数组中来返回结果。jqoednc

虽然LUT确实会降低您的计算量,但它们会增加您的存储占用,因为这些查找值需要存储在闪存中。当我们使用LUT时,我们实际上是在以存储换取速度。您可能需要权衡对LUT的使用,但您会发现用于嵌入式软件的大多数表根本不占用太多闪存。jqoednc

表驱动设计

如果您研究一下软件行业其他领域的软件开发方法,您就会发现一种被称为表驱动设计的概念。表驱动设计是一种软件开发方法,其中决策逻辑被编码在表中,而不是复杂的控制流语句中(如嵌套的if-else或switch-case结构)。这种方法增强了代码的可读性、可维护性和灵活性。jqoednc

当客户要求更改软件时,我们不会大幅更改项目逻辑,而是根据客户的新偏好更新表格。虽然嵌入式开发乍一看似乎完全不同,但事实证明我们其实并没有那么不同。jqoednc

在嵌入式开发中,有多个领域可以利用表驱动设计和LUT来提高软件的可配置性、灵活性和可扩展性。以下是一些示例:jqoednc

  • 外围设备配置
  • 设备配置
  • 系统线程
  • 应用计算
  • 状态机
  • 电源管理
  • ETC

可能的用途几乎是无穷无尽的!让我们看一个我最喜欢的简单示例:配置微控制器的外围设备。jqoednc

创建gpio配置LUT

您可能最不希望使用LUT的地方就是配置微控制器外围设备。毕竟,我们习惯于让微控制器供应商为我们提供自动生成的内存映射结构。虽然我们非常感谢他们的努力,但您很快就会发现,这些工具和生成的代码没有为外围设备提供清晰的配置。它往往散落在整个代码中或出现在不显眼的地方。jqoednc

那么,如果您有一个GPIO外围设备并想为其创建一个LUT,您会怎么做?jqoednc

您可以遵循以下几个简单的步骤:jqoednc

  • 查看寄存器映射并按引脚列出gpio功能
  • 为这些功能创建一个结构
  • 创建一个结构数组来定义每个引脚的配置

在步骤1中,你可能会得到这样一个列表:jqoednc

  • 引脚名称
  • 引脚模式
  • 引脚状态
  • 引脚电阻状态
  • ETC

对于GPIO,具体功能会因供应商不同而略有差异。jqoednc

在第2步中,您可以利用该列表创建一个结构。对于我的示例功能,结构可能如下所示:jqoednc

typedef struct {jqoednc

    Pin_t name;jqoednc

    PinMode_t mode;jqoednc

    PinState_t state;jqoednc

    PinResistor_t resistor;jqoednc

}GpioConfig_t;jqoednc

您会发现,每个结构部分都有一个自定义类型。这些类型通常是枚举,列出了可以使用的有效值。例如,模式可能定义如下:jqoednc

typedef enum {jqoednc

    INPUT,jqoednc

    OUTPUTjqoednc

} PinMode_t;jqoednc

最后,在步骤3中,使用该结构为每个GPIO引脚创建配置。如果我们只有一个带有8个引脚的GPIO端口,它可能看起来像下面这样:jqoednc

GpioConfig_t gpioConfigLUT[] = {jqoednc

    {PORT_A0, OUTPUT, HIGH, NO_PULL},jqoednc

    {PORT_A1, INPUT, HIGH, PULL_UP},jqoednc

    {PORT_A2, OUTPUT, LOW, NO_PULL},jqoednc

    {PORT_A3, INPUT, HIGH, PULL_UP},jqoednc

    {PORT_A4, INPUT, HIGH, PULL_UP},jqoednc

    {PORT_A5, INPUT, HIGH, PULL_UP},jqoednc

    {PORT_A6, INPUT, HIGH, PULL_UP},jqoednc

    {PORT_A7, INPUT, HIGH, PULL_UP},jqoednc

};jqoednc

如您所见,LUT是可读的。很明显,每一行都是一个引脚,并包含该引脚的配置。如果您需要添加引脚,则需要添加额外的行。如果您需要添加GPIO功能,则在结构上添加一个新功能,并在表中添加一列。如果您需要更改引脚的配置,则只需要更新表。jqoednc

LUT的重要之处在于,您可以编写一个配置函数来读取该表,然后将其映射到外围设备寄存器中!编写完该函数后,除非更改硬件,否则无需更改它。即便要改,您也会发现更新过程既快又省事。jqoednc

采取下一步行动

LUT是一种有效的工具,但嵌入式软件开发人员对其利用不足。您已经看到,为映射到硬件的外围设备配置创建一个配置LUT是多么快捷。只需几行代码即可循环遍历表并在内存中设置正确的位。jqoednc

我经常半开玩笑地说,我的嵌入式软件“全是LUT”。原因是如果它可以配置或将来可能会更改,我就会在我的软件中创建一个表来管理它。我为外围设备、外部设备、RTOS 启动的线程、应用程序代码、状态机等都创建了配置表。jqoednc

LUT需要一点额外的闪存空间来存储表,但我认为这是非常值得的。它让我能够创建可扩展的嵌入式软件,我可以根据需要快速轻松地重新配置,并且它也十分简洁易读。jqoednc

那么,接下来该怎么做呢?我建议您查看一下自己的软件,确定需要配置的区域。它可能是外围设备、线程代码、状态机或类似的东西。然后,设计一个LUT来管理软件的这一部分。jqoednc

获得LUT后,请尝试以下操作:jqoednc

  • 比较使用表格前后的闪存和RAM使用情况
  • 请同事比较一下两者,看看哪个更易读、更清晰
  • 更改配置并注意更改的难易程度
  • 添加新功能
  • 在不同的硬件上尝试LUT。注意需要更改的内容

如果您尝试了其中的一些操作,您很快就会发现在实施过程中利用LUT是多么重要。如果您有策略地使用LUT,您会发现您的代码将更具可配置性和可扩展性,这可能有助于您编写更高质量的软件并按时交付。jqoednc

(原文刊登于EDN姊妹网站Embedded,参考链接:Use LUTs to ease your development burden,由Ricardo Xie编译。)jqoednc

责编:Ricardo
本文为电子技术设计原创文章,未经授权禁止转载。请尊重知识产权,违者本司保留追究责任的权利。
  • 微信扫一扫
    一键转发
  • 最前沿的电子设计资讯
    请关注“电子技术设计微信公众号”
广告
热门推荐
广告
广告
广告
EE直播间
在线研讨会
广告
面包芯语
广告
向右滑动:上一篇 向左滑动:下一篇 我知道了