如何在嵌入式项目中组织代码?

时间:2023-01-16 17:01:41

Highly embedded (limited code and ram size) projects pose unique challenges for code organization.

高度嵌入(有限代码和ram大小)项目对代码组织提出了独特的挑战。

I have seen quite a few projects with no organization at all. (Mostly by hardware engineers who, in my experience are not typically concerned with non-functional aspects of code.)

我见过很多没有组织的项目。 (主要是硬件工程师,根据我的经验,他们通常不关心代码的非功能方面。)

However, I have been trying to organize my code accordingly:

但是,我一直在尝试相应地组织我的代码:

  1. hardware specific (drivers, initialization)
  2. 特定硬件(驱动程序,初始化)

  3. application specific (not likely to be reused)
  4. 特定应用(不太可能重复使用)

  5. reusable, hardware independent
  6. 可重复使用,硬件独立

For each module I try to keep the purpose to one of these three types.

对于每个模块,我尝试将目的保持为这三种类型之一。

Due to limited size of embedded projects and the emphasis on performance, it is often keep this organization.

由于嵌入式项目的规模有限以及对性能的重视,通常会保留这个组织。

For some context, my current project is a limited DSP application on a MSP430 with 8k flash and 256 bytes ram.

在某些情况下,我目前的项目是MSP430上的有限DSP应用程序,具有8k闪存和256字节RAM。

6 个解决方案

#1


7  

I've written and maintained multiple embedded products (30+ and counting) on a variety of target micros, including MSP430's. The "rules of thumb" I have been most successful with are:

我已经在各种目标微处理器(包括MSP430)上编写和维护了多个嵌入式产品(30多个和计数)。我最成功的“经验法则”是:

  • Try to modularize generic concepts as much as possible (e.g. separate driver code from application code). -- It makes for easier maintenance and reuse/porting of a project to another target micro in the future.
  • 尝试尽可能模块化通用概念(例如,从应用程序代码中单独的驱动程序代码)。 - 它使项目的维护和重用/移植更容易在未来的另一个目标微型。

  • DO NOT start by worrying about optimized code at the very beginning. Try to solve the domain's problem first and optimize second. -- Your target micro can handle a lot more "stuff" than you might expect.
  • 不要一开始就担心优化代码。尝试首先解决域的问题并优化第二个。 - 你的目标微处理器可以处理比你预期的更多“东西”。

  • Work to ensure readability. Although most embedded projects seem to have short development-cycles, the projects often live longer than you might expect and another developer will undoubtedly have to work with your code.
  • 努力确保可读性。虽然大多数嵌入式项目似乎都有较短的开发周期,但项目的寿命通常比您预期的要长,而另一个开发人员无疑必须使用您的代码。

#2


2  

I've worked on 8-bit PIC processors with similar limitations.

我曾经研究过具有类似限制的8位PIC处理器。

One restriction you don't have is how many comments you make or what you choose to name your methods, variables, etc.. Take advantage. Speed and size constraints do sometimes trump organization, but you can always explain.

你没有的一个限制是你做了多少评论或者你选择用什么方法命名你的方法,变量等。利用。速度和尺寸限制确实有时胜过组织,但你总能解释。

Another tip is to break up a logical source file into even more pieces than you need, then bind them by #includeing them in a compilation unit. This allows you to have lots of reusable code (even one routine per file) but combine in whatever order you need. This is useful e.g. when trying to meet compilation unit size restrictions, or to pick and choose which common subroutines you need on the next project.

另一个技巧是将逻辑源文件分解成比你需要的更多的部分,然后通过#include它们在编译单元中绑定它们。这允许您拥有大量可重用的代码(每个文件甚至一个例程),但可以按您需要的顺序组合。这很有用,例如在尝试满足编译单元大小限制时,或者选择下一个项目所需的常用子例程。

#3


2  

I try to organize it as if I had unlimited RAM and ROM, and it usually works out fine. As mentioned elsewhere, do not try to optimize it until you absolutely need to.

我尝试组织它,好像我有无限的RAM和ROM,它通常工作得很好。如其他地方所述,在您绝对需要之前不要尝试优化它。

If you can get a pin-compatible processor that has more resources, it's better to get it working on that, concentrating on good structure and layout, then optimize for size later when you understand the code better.

如果你能得到一个具有更多资源的引脚兼容处理器,那么最好让它处理它,专注于良好的结构和布局,然后在你更好地理解代码时优化大小。

#4


2  

Except under exceptional circumstances (see note), the organisation of your code will have no impact on the final product. (contents of the code are obviously a different matter)

除特殊情况外(参见注释),您的代码组织对最终产品没有影响。 (代码的内容显然是另一回事)

So with that in mind you should organise your code as you would any other project.

因此,考虑到这一点,您应该像处理任何其他项目一样组织代码。

With that said, the following are fairly typical:

话虽如此,以下是相当典型的:

If this is a processor that you've worked on before, or will be working on in the future, you will usually want to keep a dedicated hardware abstraction layer that can be shared between projects in the future. Typically this module would contain items like routines for managing any uarts, timers etc.

如果这是您之前已经处理过的处理器,或者将来要处理的处理器,您通常需要保留一个专用的硬件抽象层,以便将来在项目之间共享。通常,此模块将包含用于管理任何uart,计时器等的例程。

Usually it's reasonable to maintain a set of platform specific code for initialisation and setup that performs all of the configuration and initialisation up to the point where your executive takes over and runs your application. It will also include platform specific hal routines.

通常,维护一组特定于平台的初始化和设置代码是合理的,这些代码执行所有配置和初始化,直到管理人员接管并运行您的应用程序。它还将包括特定于平台的hal例程。

The executive/application is probably maintained as a separate module. All of the hardware specific code should be hidden in the hal (as mentioned above).

执行/应用程序可能作为单独的模块维护。所有硬件特定代码都应隐藏在hal中(如上所述)。

By splitting your code up like this you also have the option of compiling and running your application as a simulation, on a completely different platform, just by replacing the hardware specific code with routines that mimic the hardware. This can be good for unit testing and debugging and algorithmic problems you might have.

通过像这样拆分代码,您还可以选择在完全不同的平台上编译和运行应用程序作为模拟,只需用模拟硬件的例程替换硬件特定代码即可。这可能适用于您可能具有的单元测试和调试以及算法问题。


Exceptional circumstances as might be imposed by unusual compiler restrictions. eg. I've come across some compilers that expect all interrupt service routines to be compiled within a single object file.

异常编译器限制可能导致的特殊情况。例如。我遇到过一些编译器,他们希望在一个目标文件中编译所有中断服务程序。

#5


1  

I've worked with some sensors like the Tmote Sky, I too have seen poor organization, and I have to admit i have contributed to it. Anyway I'd say that some confusion has to be, because loading too much modules or too much part of program will be (imho) resource killing too, so try to be aware of a threshold between organization and usability on the low resources.

我曾经使用过像Tmote Sky这样的传感器,我也看到了糟糕的组织,我不得不承认我已经做出了贡献。无论如何,我要说有些混乱,因为加载太多的模块或程序的太多部分也会(imho)资源被杀死,所以尽量了解组织和低资源可用性之间的门槛。

Obviously this don't mean let caos begin, but for example try to get a look on the organization of the tinyOS source code and applications, it's an idea on what I'm trying to say.

显然这并不意味着让caos开始,但是例如试着看看tinyOS源代码和应用程​​序的组织,它是我想说的内容的想法。

#6


1  

Although it is a bit painful, one organization technique that is somewhat common with embedded C libraries is to split every single function and variable into a separate C source file, and then aggregate the resulting collection of O files into a library file.

尽管有点痛苦,但是嵌入式C库中常见的一种组织技术是将每个函数和变量拆分为单独的C源文件,然后将生成的O文件集合聚合到库文件中。

The motivation for doing this is that for most normal linkers the unit of linkage is an object, for every object you either get the whole object or none of it. Since there is a 1-1 relationship between C files and object files, putting each symbol in it's own C file gives each one it's own object. This in turn lets the linker pull in only that subset of functions and variables that are actually used.

这样做的动机是,对于大多数普通链接器,链接单元是一个对象,对于每个对象,您要么获得整个对象,要么不获取整个对象。由于C文件和目标文件之间存在1-1关系,因此将每个符号放在其自己的C文件中会为每个文件提供自己的对象。这反过来又让链接器只引入实际使用的函数和变量的子集。

This sort of game doesn't help at all for headers they can happily be left as single files.

这种类型的游戏根本无法帮助他们乐于将其保留为单个文件。

#1


7  

I've written and maintained multiple embedded products (30+ and counting) on a variety of target micros, including MSP430's. The "rules of thumb" I have been most successful with are:

我已经在各种目标微处理器(包括MSP430)上编写和维护了多个嵌入式产品(30多个和计数)。我最成功的“经验法则”是:

  • Try to modularize generic concepts as much as possible (e.g. separate driver code from application code). -- It makes for easier maintenance and reuse/porting of a project to another target micro in the future.
  • 尝试尽可能模块化通用概念(例如,从应用程序代码中单独的驱动程序代码)。 - 它使项目的维护和重用/移植更容易在未来的另一个目标微型。

  • DO NOT start by worrying about optimized code at the very beginning. Try to solve the domain's problem first and optimize second. -- Your target micro can handle a lot more "stuff" than you might expect.
  • 不要一开始就担心优化代码。尝试首先解决域的问题并优化第二个。 - 你的目标微处理器可以处理比你预期的更多“东西”。

  • Work to ensure readability. Although most embedded projects seem to have short development-cycles, the projects often live longer than you might expect and another developer will undoubtedly have to work with your code.
  • 努力确保可读性。虽然大多数嵌入式项目似乎都有较短的开发周期,但项目的寿命通常比您预期的要长,而另一个开发人员无疑必须使用您的代码。

#2


2  

I've worked on 8-bit PIC processors with similar limitations.

我曾经研究过具有类似限制的8位PIC处理器。

One restriction you don't have is how many comments you make or what you choose to name your methods, variables, etc.. Take advantage. Speed and size constraints do sometimes trump organization, but you can always explain.

你没有的一个限制是你做了多少评论或者你选择用什么方法命名你的方法,变量等。利用。速度和尺寸限制确实有时胜过组织,但你总能解释。

Another tip is to break up a logical source file into even more pieces than you need, then bind them by #includeing them in a compilation unit. This allows you to have lots of reusable code (even one routine per file) but combine in whatever order you need. This is useful e.g. when trying to meet compilation unit size restrictions, or to pick and choose which common subroutines you need on the next project.

另一个技巧是将逻辑源文件分解成比你需要的更多的部分,然后通过#include它们在编译单元中绑定它们。这允许您拥有大量可重用的代码(每个文件甚至一个例程),但可以按您需要的顺序组合。这很有用,例如在尝试满足编译单元大小限制时,或者选择下一个项目所需的常用子例程。

#3


2  

I try to organize it as if I had unlimited RAM and ROM, and it usually works out fine. As mentioned elsewhere, do not try to optimize it until you absolutely need to.

我尝试组织它,好像我有无限的RAM和ROM,它通常工作得很好。如其他地方所述,在您绝对需要之前不要尝试优化它。

If you can get a pin-compatible processor that has more resources, it's better to get it working on that, concentrating on good structure and layout, then optimize for size later when you understand the code better.

如果你能得到一个具有更多资源的引脚兼容处理器,那么最好让它处理它,专注于良好的结构和布局,然后在你更好地理解代码时优化大小。

#4


2  

Except under exceptional circumstances (see note), the organisation of your code will have no impact on the final product. (contents of the code are obviously a different matter)

除特殊情况外(参见注释),您的代码组织对最终产品没有影响。 (代码的内容显然是另一回事)

So with that in mind you should organise your code as you would any other project.

因此,考虑到这一点,您应该像处理任何其他项目一样组织代码。

With that said, the following are fairly typical:

话虽如此,以下是相当典型的:

If this is a processor that you've worked on before, or will be working on in the future, you will usually want to keep a dedicated hardware abstraction layer that can be shared between projects in the future. Typically this module would contain items like routines for managing any uarts, timers etc.

如果这是您之前已经处理过的处理器,或者将来要处理的处理器,您通常需要保留一个专用的硬件抽象层,以便将来在项目之间共享。通常,此模块将包含用于管理任何uart,计时器等的例程。

Usually it's reasonable to maintain a set of platform specific code for initialisation and setup that performs all of the configuration and initialisation up to the point where your executive takes over and runs your application. It will also include platform specific hal routines.

通常,维护一组特定于平台的初始化和设置代码是合理的,这些代码执行所有配置和初始化,直到管理人员接管并运行您的应用程序。它还将包括特定于平台的hal例程。

The executive/application is probably maintained as a separate module. All of the hardware specific code should be hidden in the hal (as mentioned above).

执行/应用程序可能作为单独的模块维护。所有硬件特定代码都应隐藏在hal中(如上所述)。

By splitting your code up like this you also have the option of compiling and running your application as a simulation, on a completely different platform, just by replacing the hardware specific code with routines that mimic the hardware. This can be good for unit testing and debugging and algorithmic problems you might have.

通过像这样拆分代码,您还可以选择在完全不同的平台上编译和运行应用程序作为模拟,只需用模拟硬件的例程替换硬件特定代码即可。这可能适用于您可能具有的单元测试和调试以及算法问题。


Exceptional circumstances as might be imposed by unusual compiler restrictions. eg. I've come across some compilers that expect all interrupt service routines to be compiled within a single object file.

异常编译器限制可能导致的特殊情况。例如。我遇到过一些编译器,他们希望在一个目标文件中编译所有中断服务程序。

#5


1  

I've worked with some sensors like the Tmote Sky, I too have seen poor organization, and I have to admit i have contributed to it. Anyway I'd say that some confusion has to be, because loading too much modules or too much part of program will be (imho) resource killing too, so try to be aware of a threshold between organization and usability on the low resources.

我曾经使用过像Tmote Sky这样的传感器,我也看到了糟糕的组织,我不得不承认我已经做出了贡献。无论如何,我要说有些混乱,因为加载太多的模块或程序的太多部分也会(imho)资源被杀死,所以尽量了解组织和低资源可用性之间的门槛。

Obviously this don't mean let caos begin, but for example try to get a look on the organization of the tinyOS source code and applications, it's an idea on what I'm trying to say.

显然这并不意味着让caos开始,但是例如试着看看tinyOS源代码和应用程​​序的组织,它是我想说的内容的想法。

#6


1  

Although it is a bit painful, one organization technique that is somewhat common with embedded C libraries is to split every single function and variable into a separate C source file, and then aggregate the resulting collection of O files into a library file.

尽管有点痛苦,但是嵌入式C库中常见的一种组织技术是将每个函数和变量拆分为单独的C源文件,然后将生成的O文件集合聚合到库文件中。

The motivation for doing this is that for most normal linkers the unit of linkage is an object, for every object you either get the whole object or none of it. Since there is a 1-1 relationship between C files and object files, putting each symbol in it's own C file gives each one it's own object. This in turn lets the linker pull in only that subset of functions and variables that are actually used.

这样做的动机是,对于大多数普通链接器,链接单元是一个对象,对于每个对象,您要么获得整个对象,要么不获取整个对象。由于C文件和目标文件之间存在1-1关系,因此将每个符号放在其自己的C文件中会为每个文件提供自己的对象。这反过来又让链接器只引入实际使用的函数和变量的子集。

This sort of game doesn't help at all for headers they can happily be left as single files.

这种类型的游戏根本无法帮助他们乐于将其保留为单个文件。