Layering Code Structure in Embedded Programming

Follow and star our public account for exciting content

Layering Code Structure in Embedded Programming

ID: Technology Makes Dreams Greater

Source: Online Materials

For a beginner transitioning from novice to expert, a learning model like identifying problemsengaging in thoughtproposing solutions is very effective.

1. Problems Encountered 

Through this period of coding practice, I have accumulated some coding experience, but I have also realized the flaws in my previous code structure: 

(1) Low Development Efficiency: Every time I use a certain resource on the chip (such as timers), I have to consult the technical manual, which is quite cumbersome.

  

(2) High Code Duplication: In each experimental source code, initialization functions like xtal_init and led_init have to be written each time.

  

(3) Difficult to Modify: The business logic in the code is mixed with SFR operations, making it less readable and harder to modify.

Due to the above issues, I decided to take some time to think about solutions.

2. Thoughts on Layering Inspired by Websites

Before learning embedded programming, I had experience in ASP.NET website development and had practiced its layering theory, which I will briefly mention below:

  

Generally, a moderately complex website can be divided into the following three layers:

(1) Data Access Layer (DAL): Responsible for interacting with the database, called by the business logic layer.

  

(2) Business Logic Layer (BLL): Calls the data access layer to obtain data and provides support for specific business needs.

  

(3) User Interface Layer (UIL): Responsible for presenting the final user interface.

Layering greatly improves code reusability and extensibility.

So, can we also use the idea of layering in embedded development to improve development efficiency and enhance maintainability and scalability? Below are some of my thoughts after consideration.

3. Layering in Embedded Projects

Of course, we cannot directly copy the specific layering ideas of ASP.NET; specific problems require specific analyses~

  

First, the core of embedded development is the chip, which provides fixed on-chip resources for developers to use. Moreover, it has a very important characteristic: it does not change with the project’s requirements. Therefore, it should be treated as the bottom layer, providing basic support for the upper layers. We will call it the Hardware Abstraction Layer (HAL).  

  

Having a chip is not enough; we usually expand some functional modules outside the chip to meet specific project requirements, such as: sensors, keyboards, LCD screens, etc. The characteristic of this layer is that it dynamically increases or decreases in modules according to project changes. This layer requires support from the internal resources of the chip, so it should be above the hardware abstraction layer and callable by the upper layer. We will call it the Functional Module Layer (FML).

  

OK, now that we have all the raw materials ready: chip + expansion modules, we can start the actual processing: we need to flexibly call the interfaces provided by the previous two layers to achieve specific project requirements. We will call it the Application Layer (APL).

  

Illustration:

Layering Code Structure in Embedded Programming

(1) Hardware Abstraction Layer (HAL)

Implements general configuration for on-chip resources (such as timers, ADC, interrupts, I/O, etc.), hiding the specific SFR operation details, and providing a simple and clear calling interface for the upper layer.

(2) Functional Module Layer (FML)

By calling HAL, it implements all external functional modules involved in the project, hiding specific module operation details, and providing a simple and clear calling interface for the upper layer.

(3) Application Layer (APL)

By calling HAL and FML, it implements the final application functionality.

4. A Small Trial 

OK, let’s take a specific example to illustrate the application of the layering concept.

Previously, I needed to complete a slightly comprehensive small experiment called the “Temperature Monitoring System”. The requirement analysis is as follows:

• The CC2430 node implements timed temperature collection and can indicate its sampling frequency through an LED.

• The node transmits data to the PC.

• The node can receive control commands from the PC to adjust the sampling rate and power mode.

• It has an automatic reset capability after shutdown.

• It can enter sleep mode and be awakened by a button.

From the above requirements, we can see that the core chip of this experiment is the CC2430, and the required external expansion modules are the LED and button, with the expected specific project requirements being the five points above.  

  

Next, we will use the layering theory mentioned above to plan the code structure for the “Temperature Monitoring System” experiment:

(1) Application Layer (APL)

[main.c] references hal.h, ioCC2430.h, and module.h to implement temperature collection, communication with the PC, shutdown reset, and other specific application requirements.

  

(2) Functional Module Layer (FML)

[module.h] defines a series of external functional modules (LED, button) and declares a series of related functions.

      

[module.c] references hal.h to implement the functions of each external module (LED, button).

  

(3) Hardware Abstraction Layer (HAL)

[ioCC2430.h] (system built-in): defines all SFRs and interrupt vectors of the CC2430.

[hal.h] includes common type definitions, common assignment macros, and configurations for on-chip resources of the CC2430 (I/O, serial communication, ADC, timers, power management, etc.).

(Note: Since the use of the external modules involved in this experiment—LED and button—is extremely simple, I have merged them into a single source file. If more complex modules are encountered, separate .h and .c files can be created, such as LCD.h, LCD.c.)

  

Through this design, its advantages gradually become apparent:

• Efficient Development Rate: After completing hal.h in the HAL layer, we can easily call it without repeatedly consulting the specific settings of the SFR. 

• Rapid Expansion: If we need to enhance system functionality, we only need to add the corresponding functional modules (i.e., .c files) in the FML layer and call them in main.c. 

• High Code Reusability: The SFR operations provided by the HAL layer can be used universally, and this layer can be directly used in new CC2430 projects with little to no modification. 

• Good Maintainability: The project code structure is clear, and the HAL and FML layers require little modification; only the APL needs to be modified.

5. Conclusion 

Perhaps for experts in embedded programming, the above theory may not be significant and may even contain considerable errors. However, for a beginner transitioning from novice to expert, a learning model like identifying problems → engaging in thought → proposing solutions is, I believe, worthwhile and necessary. As many people say: the process is more important than the conclusion.

Layering Code Structure in Embedded ProgrammingRecommended Reading:

Embedded Programming Series
Linux Learning Series
C/C++ Programming Series

Qt Advanced Learning Series
Follow the WeChat public account "Technology Makes Dreams Greater" and reply "m" to see more content.

Long press to follow the public account included in the image above.

Leave a Comment