SOLID Principles and Layered Architecture: The Soul of Embedded System Design

Sharing Power Knowledge | Summary Notes on Embedded Learning

This is the third learning note related to embedded systems from Dream Chaser Power Electronics

Introduction

Recently, while learning embedded code, I have gained a lot of insights. I can appreciate many of the key points that experts incorporate when writing programs. I wondered how they could create so many variations with just a simple light control. They managed to unify various functionalities such as light control, current and voltage protection, and serial debug printing into a single task list using a simplified version of FreeRTOS. It took me a while to understand the overall structure, and I gradually discovered that this is indeed a profound knowledge area that cannot be explained in a short time. Today, I have organized an article where I only outline the main content and let AI help me elaborate and organize it. The result aligns with my expectations, so I am sharing it as a learning note.

SOLID Principles and Layered Architecture: The Soul of Embedded System Design

In embedded system development, code quality directly determines the product’s reliability, maintainability, and scalability. Many engineers may focus more on quickly implementing functionality in the early stages, neglecting the design of code structure, which leads to difficulties in maintenance, high upgrade costs, and even introduces hard-to-trace bugs.

SOLID principles and layered architecture are key concepts to address these issues. They are not only applicable to large software systems but are also crucial in embedded development (such as power control, motor drive, sensor data processing, etc.).

1. Why Do We Need SOLID Principles?

SOLID principles are the five core principles of object-oriented design, but they can also be applied in embedded C development through reasonable modular design. Their core goal is to reduce code coupling and improve maintainability.

(1) Single Responsibility Principle (SRP)

“A module should do one thing only”

  • Problem: In a power control system, if PWM driving, ADC sampling, protection logic, and communication reporting are all mixed in one function, modifying any part may affect other functionalities.

  • Solution:

    • The PWM module is responsible only for adjusting the duty cycle

    • The ADC module is responsible only for voltage sampling

    • Protection logic is encapsulated separately

    • Serial communication only handles data formatting and transmission

  • Advantages:

    • The code is easier to test (ADC sampling accuracy can be tested independently without affecting PWM)

    • Modifying the communication protocol (e.g., UART to CAN) does not affect control logic

(2) Open/Closed Principle (OCP)

“Open for extension, closed for modification”

  • Problem: If the control algorithm of a Buck power supply (e.g., PID to fuzzy control) needs to be changed, the traditional approach may require rewriting the entire control function, which can easily introduce new bugs.

  • Solution:

    • Define a unified control algorithm interface (e.g., <span>calculate(setpoint, feedback)</span>)

    • Different algorithms (PID, fuzzy control, sliding mode control) implement the same interface

  • Advantages:

    • New algorithms can be added without modifying existing code

    • Control strategies can be switched dynamically (e.g., adjusting PID parameters based on load)

(3) Liskov Substitution Principle (LSP)

“Subclasses must be substitutable for their base classes” (in C, this means that interface implementations must be consistent)

  • Problem: If there are multiple versions of the ADC driver (e.g., internal ADC vs. external ADC chip), but their behaviors are inconsistent (e.g., different return value ranges), it may lead to control anomalies.

  • Solution:

    • All ADC implementations must guarantee the same interface (e.g., returning a <span>0~30V</span> floating-point number)

    • Different implementations can be plugged in without affecting control logic

  • Advantages:

    • Hardware changes (e.g., replacing ADC chips) do not affect upper-level logic

    • ADC data can be simulated for testing

(4) Interface Segregation Principle (ISP)

“No module should be forced to depend on interfaces it does not need”

  • Problem: If the serial communication module exposes low-level register operations (e.g., <span>USART1->DR</span>), the control logic layer may inadvertently operate on the hardware.

  • Solution:

    • The control layer only depends on the <span>send_status(json)</span> interface, without caring how the serial port is implemented

    • The underlying serial driver can be replaced (e.g., DMA sending/polling sending)

  • Advantages:

    • Reduces bugs caused by unexpected dependencies

    • Upgrading communication methods (e.g., UART to SPI) does not affect business logic

(5) Dependency Inversion Principle (DIP)

“High-level modules should not depend on low-level modules; both should depend on abstractions”

  • Problem: If the control logic directly calls <span>HAL_UART_Transmit()</span><span>, changing the communication library (e.g., from HAL to LL) would require modifying a lot of code.</span>

  • Solution:

    • The control layer depends on abstract interfaces (e.g., <span>PowerMonitor.report()</span>)

    • The concrete implementation can be UART, CAN, or even wireless modules

  • Advantages:

    • Easily adapt to different hardware platforms

    • During unit testing, the communication module can be simulated

2. Why Do We Need Layered Architecture?

Layered architecture is the “skeleton” of embedded systems, making the code logic clear, responsibilities distinct, and easy to maintain.

Typical Layers (Using Buck Power Supply as an Example)

  1. Hardware Abstraction Layer (HAL)

  • PWM driving, ADC sampling, GPIO control, UART communication

  • Goal: Hide hardware details and provide a unified interface

  • Control Algorithm Layer

    • PID control, protection logic, state machine

    • Goal: Implement core business logic without relying on specific hardware

  • Application Layer

    • System scheduling, communication protocols (e.g., serial JSON reporting), user interaction

    • Goal: Coordinate various modules and handle high-level logic

    Advantages of Layered Architecture

    Maintainability: Modifying the ADC driver does not affect the PID algorithmPortability: When changing the MCU, only the HAL layer needs to be rewrittenTestability: Hardware can be simulated for unit testingTeam Collaboration: Different engineers can develop different layers in parallel

    3. The Importance of Code Style

    Even when following SOLID and layered architecture, poor code style can still lead to poor readability and maintainability. Key points:

    (1) Clear Naming

    • Bad: <span>void foo(int a, int b)</span>

    • Good: <span>void pwm_set_duty(float duty_cycle)</span>

    (2) Avoid Global Variables

    • Bad: <span>float voltage;</span> (modifiable by anyone)

    • Good: <span>float get_output_voltage(void)</span> (accessed through an interface)

    (3) Comments and Documentation

    • Comment on “why” rather than “what”

      c

      // Bad: "Set duty cycle"// Good: "Limit duty to 90% to prevent MOSFET overstress"pwm_set_duty(0.9f);

    (4) Error Handling

    • Bad: Ignoring errors (e.g., continuing operation after ADC read failure)

    • Good: Clearly handle exceptions

      c

      if(read_voltage(&amp;v)!= SUCCESS){enter_safe_mode();}

    4. Conclusion: Why Are These Concepts So Important?

    1. Reduce Bug Rates: A clear architecture reduces errors caused by unexpected coupling

    2. Enhance Development Efficiency: Modular design facilitates smoother team collaboration

    3. Extend Code Lifespan: Easy maintenance and upgrades even after 10 years

    4. Adapt to Changing Requirements: Easily cope with hardware changes, algorithm upgrades, and communication protocol modifications

    In the embedded field, hardware will iterate, and requirements will change, but good code design and style can keep you invincible.

    Please click the card below to follow Dream Chaser, and join me in learning power electronics technology👇🏻

    Leave a Comment