What You Can Learn from This Article
1. My understanding of architecture design after 12 years in embedded development;
2. The need for deliberate training in architecture design for embedded systems;
3. Some tips during the embedded system development process;
4. A demo for a smart home project that can be directly compiled and executed;
My Understanding of Architecture Design
1. Understanding the concept of architecture design
Most of the readers of this article are likely engaged in embedded development, and you may have noticed that many architecture design positions on job websites are geared towards web development, with very few positions for embedded system architects.
My understanding is that there are probably two reasons for this:
(1) Web Development: A multitude of opinions, no unified standards or leaders
Thanks to the development of mobile internet, the demand for frontend and backend development positions has surged, and various frameworks have emerged.
How to utilize these frameworks to provide high-performance services to users does not have a unified standard, leading to a multitude of opinions and consequently, a plethora of designer positions.
![Does Embedded Development Require Architecture Design?](https://ss.boardor.com/wp-content/uploads/2024/12/ff3cafcbd9522290f8d68f479b36d4f62e311aa100b31711dbd9ff342c4a4e5e-1.jpg)
(2) Embedded Development: Linux is the choice
In embedded system development, there is almost no room for choice regarding the operating system; most are ARM+Linux combinations.
At the Linux operating system level: the experts have designed the kernel and driver layers very well, and developers rarely need to make extensive modifications.
At the application level: if developers have no particular ambitions, they can simply implement the functionalities defined in the specifications.
As for the bosses, they only care about whether the product functions as expected; they don’t think about portability, scalability, execution efficiency, etc.
Even if the product needs to be updated, developers can just re-implement it; as long as the functionality is okay, that’s all that matters.
![Does Embedded Development Require Architecture Design?](https://ss.boardor.com/wp-content/uploads/2024/12/cbc3fd48cd1a7cc7770b1313ca53a407333a1daf270609df5deaeeef779da258-1.jpg)
2. The Importance of Architecture Design in Embedded Systems
Let me tell a short story.
A colleague wrote a program for a microcontroller product for a client, and after the colleague left, he handed the code over to me.
There was a small function in this product that needed modification, and at that time, I was handling another project, so with the boss’s permission, I sent the source code to the client and asked them to modify it themselves.
The client was very happy to receive the source code because once they understood it, they could develop similar devices themselves.
After some time, I asked the client: How’s the modification of that product’s functionality going?
He said: Not resolved yet, I lost the code you sent last time, it’s a real headache, and now I’m rewriting the code from scratch.
![Does Embedded Development Require Architecture Design?](https://ss.boardor.com/wp-content/uploads/2024/12/c256358873e7d7fb7a11e9c3cc6190d6760d4fba909ee06c92134fe20e7ae87b-1.jpg)
This story is true.
Code is composed of characters, and some code looks pleasing while some makes you question life.
Code without architecture design guidance has the following drawbacks:
(1) Code cannot be reused, and portability is troublesome.
(2) When requirements change, the code cannot be adjusted quickly.
(3) For existing code: developers are afraid to modify it, as one change can affect everything.
(4) Debugging bugs is very painful.
![Does Embedded Development Require Architecture Design?](https://ss.boardor.com/wp-content/uploads/2024/12/232b95e7c1ae2449cb9c62739a242af8cde4924fc5585b9012fe842dba9c3b91-1.jpg)
On the contrary, if the architecture design is good, it benefits all aspects:
For the project:
(1) Project cycle is controllable
(2) Code readability is good
(3) Functionality is extendable
(4) Modifying a single module does not affect other functionalities
(5) Parallel development
(6) Unit testing is convenient
For developers:
(1) Saves development time
(2) Global perspective, improving the ability to develop large projects
(3) Debugging is easy and quick
How to Conduct Architecture Design
1. Design Documentation
Once you enter the programming field, everyone knows to aim for high cohesion and low coupling, modular and layered design.
But how exactly should this be done?
How to accomplish things well within the set project cycle without exhausting yourself?
How to lay a good foundation for future maintenance?
…..
These questions may be well-planned at the beginning of the project.
However, during execution, people tend to become lazier and deviate more and more from the predefined direction.
My advice is:
Regardless of the size of the project or the length of the project cycle, there must be design documentation, and the level of detail in the design documentation should be flexibly adjusted based on the actual situation of the project.
The architecture design must be reflected in the design documentation. During implementation, strictly adhere to the requirements outlined in the documentation.
Aim for the best, and you will achieve the middle; aim for the middle, and you will achieve the lowest.
2. Physical Model of Program Files
(1) Layered Design
Business Layer
Functional Module Layer
Driver Layer
(2) Modular Design
Divide modules based on functionality
Modules interact through API interface functions
Design flexible API interface functions
3. Choice of Processes and Threads
In embedded systems, the functionality of the product can be achieved through the cooperation of multiple processes, or it can be implemented using multiple threads; there is no fixed standard for this choice, and it depends on the specific situation of the project.
My general approach is:
If the product functionality is not complex, try to use multiple threads;
If the product involves many functionalities, then place strongly related modules into independent processes.
![Does Embedded Development Require Architecture Design?](https://ss.boardor.com/wp-content/uploads/2024/12/edcce5838aae1f0260a94c6efc7f696fcae36d7bf06badfcfe56d4ffb701fedc-1.png)
(1) Use Processes
Each module compiles independently and does not affect each other.
If a problem like SegmentFault occurs, it is easy to locate the culprit.
Convenient for distributed deployment.
Code safety: except for integrators, others only need to clone the code for their respective modules, without permission or need to access others’ code.
However: it is necessary to consider the communication issues between processes, such as IPC calls, socket communication, and bus. (I generally use an MQTT bus to connect all communication modules within the local system)
(2) Use Threads
Creating threads is low-cost.
Threads share global variables (from another perspective, this is also a disadvantage).
Modules can call each other easily because function addresses are directly visible.
4. API Design
You can think of a module as a black box; given an input, it will return a definite result or execute a specific function,
Modules only need to define this API interface function.
As for how the module is implemented internally, everyone can showcase their skills.
Additionally, if you are an API designer, be sure to make it comfortable for the caller to use. Just as you would hand a pair of scissors to someone, you must offer the handle to them.
![Does Embedded Development Require Architecture Design?](https://ss.boardor.com/wp-content/uploads/2024/12/35aa1f21580df8ba842e8cc19e1542a58f99df230910ce7fdb3150206b20fdbf-1.jpg)
Another piece of advice is that during the early stages of project design, try not to make the API function design too rigid, as it can easily trap you.
For example:
(1) You can design variables with char *, using JSON format strings to pass data of arbitrary length and type.
(2) You can design variables with void *, to pass the addresses of any data type; this functionality has been used effectively in many projects, such as Qualcomm’s BREW platform and the ZWave platform in smart homes.
5. File Directory Design
This part is easy to understand; files with different responsibilities should be stored in corresponding directories: header files, library files, executable files, related documents. If this part is not well organized, when you hand the project over to other colleagues, they will undoubtedly be muttering: F-U-C-K Y-O-U!
6. Design of Compilation Scripts (Build Tools)
When we receive an embedded project, after determining the solution, the platform on which the program runs is usually fixed, mostly embedded Linux or its variants.
During the development phase, I have seen some developers cross-compile the code after debugging each functionality and then place it, followed by remote mounting via NFS or remote copying via SCP to execute on real devices. It looks exhausting.
In fact, you can compile a version for different platforms within the compilation script.
For example, when developing a product using the Ubuntu system, as long as the x86 platform can simulate the product’s functionality, directly compile the x86 version.
Once all functionalities are tested and confirmed on the x86 platform, then deploy it to the actual embedded system for integration testing; this approach can save a lot of time.
Demo Description
1. Introduction
This demo is extracted from a smart home project, illustrating the design of various functional modules; the functions themselves are not implemented, and it is merely used to showcase the design process.
2. Code Access
https://pan.baidu.com/s/1B3F9byydXeNWdtgYEEQNLg
Password: 3a9p
It can be directly compiled and executed under the Ubuntu 16.04 system.
3. System Architecture Diagram
![Does Embedded Development Require Architecture Design?](https://ss.boardor.com/wp-content/uploads/2024/12/cb4af1280b9c13f2a2e4d313eee0302fe724f63c7dce8c21e7c53821cbb46394-2.jpg)
4. Directory Structure
Makefile: Compilation script
application: Business layer
module: Functional module layer
driver: Hardware driver layer
5. Execution Sequence Demonstration
The orange arrows in the diagram indicate a control command sent from the cloud.
After the business layer receives the command, it parses the command and sends it to the Control module.
The Control module further parses the specific command and sends it to the ZigBee device while logging it.
![Does Embedded Development Require Architecture Design?](https://ss.boardor.com/wp-content/uploads/2024/12/cb4af1280b9c13f2a2e4d313eee0302fe724f63c7dce8c21e7c53821cbb46394-3.jpg)
Follow the public account below to learn more about electronic technology knowledge!