Code Review Checkpoints for Embedded Software

Embedded software is used in products that require high reliability, such as automobiles, industrial equipment, and medical devices. Therefore, "code review," which checks the quality of the source code itself in addition to unit testing and integration testing, is an extremely important process for reducing quality risks, and plays a central role in quality assurance alongside testing and static analysis.

However, standard code review criteria for web-based or enterprise systems cannot sufficiently cover risks unique to embedded development, such as interrupt handling, hardware control, and memory management.

In this article, we will explain the particularly important checkpoints for code review in embedded software, dividing them into five categories: readability and maintainability, safety and reliability, interrupts and concurrency, hardware control, and review practices.

Importance of Code Review in Embedded Development

A diagram showing five areas of code review for embedded software arranged radially around a central point. It lists five areas: readability and maintainability (whether the code is easy to read and modify), interrupts and concurrency, key points for effective review practices, safety and reliability, and hardware control code, showing that reviewing these areas in a balanced manner comprehensively improves the quality, reliability, and maintainability of embedded software.

Key point: Reviewing these five areas in a balanced manner comprehensively improves the quality, reliability, and maintainability of embedded software.

Because embedded software heavily depends on hardware, it is necessary to check code quality from perspectives different from those of general enterprise system development.

Addressing Quality Requirements Unique to Embedded Development

In code that controls hardware, understanding register operations and device specifications is essential. In addition, in concurrent processing using interrupts or real-time operating systems (RTOS), timing-dependent bugs and race conditions are likely to occur. Furthermore, in fields where safety is particularly critical, such as automobiles, industrial equipment, and medical devices, compliance with coding standards including MISRA C is also required, making verification through review indispensable.

Detecting Bugs That Cannot Be Found by Testing Alone

Code reviews can detect early bugs that are difficult to find by testing alone, such as uninitialized variables, missing boundary conditions, state transitions, interrupt conditions, and implementations inconsistent with timing constraints. In addition, the perspective of "whether the design is appropriate," which static analysis tools cannot judge, can only be verified through human review.

Benefits of Standardizing Review Perspectives

By creating checklists and standardizing review items, inconsistencies in reviewers' judgments can be reduced. It can also be used for training new employees, leading to improved review quality and preventing dependency on specific individuals.

Readability and Maintainability

Maintainable code not only improves the efficiency of bug fixes and feature additions, but also improves the quality of the review itself.

Appropriateness of Naming Conventions and Comments

Check whether variable and function names clearly convey their roles. It is also important to unify naming conventions across the entire project without overusing abbreviations or proprietary terms.

In addition, it is desirable to leave comments not only on "why that implementation was chosen," but also on hardware specifications, timing constraints, interrupt conditions, and preconditions of the system being controlled that form the basis of design decisions.

Organizing Conditional Branches

Care must be taken with code that has deeply nested conditional branches or complex conditional expressions, as these reduce readability. Check whether the code structure is easy to understand by utilizing early returns and function decomposition.

Function and Module Design

It is important to check whether a single function is assigned multiple responsibilities and whether there are complex dependencies between modules. In addition, if hardware-dependent parts and application logic are properly separated, maintainability and portability will also improve.

Duplicate Implementations

If the same process is scattered across multiple locations, consider consolidating the process. In addition, maintainability can be improved by converting magic numbers into constants and giving them easy-to-understand names.

Safety and Reliability

In embedded software, care must be taken because small implementation errors can lead to serious failures.

Memory and Data Safety

NULL pointer access, uninitialized variables or structures, integer overflow, and out-of-bounds array access are typical review items. Especially in C, undefined behavior is not detected as an error at runtime, so it is extremely important to detect out-of-bounds access and overflow during the review stage.

Compliance with Coding Standards

Compliance with coding standards, including MISRA C, is also an important item to check. Quality can be continuously ensured by checking whether the use of prohibited syntax and the reasons for deviating from the standards are properly managed, and by ensuring consistency with the results of static analysis tools.

Interrupts and Concurrency

In embedded software that uses interrupts or RTOS, bugs caused by concurrent processing are reviewed with particular emphasis.

Proper Handling of Shared Variables

Check whether mutual exclusion is properly implemented for variables shared between interrupt processing and tasks to prevent conflicts, and whether volatile is correctly applied to ensure the visibility of variables that are asynchronously updated, such as by interrupts or DMA.

However, volatile only suppresses optimization by the compiler (such as omitting or reordering variable access) and is not a substitute for mutual exclusion or memory barriers at the central processing unit (CPU) level. It is important to use it in combination with appropriate synchronization methods as necessary.

Minimizing Interrupt Processing

In interrupt service routines (ISRs), the basic rule is to avoid time-consuming operations and waiting operations, and to limit processing to the minimum necessary. By keeping processing times short, the impact on real-time performance can be suppressed.

Proper Mutual Exclusion

Check whether the order of lock acquisition is standardized, whether the design prevents deadlocks, and whether the RTOS application programming interface (API) is properly used.

Hardware Control Code

Reviewing hardware control code is a consideration unique to embedded software.

Appropriate Register Access

Check whether bit operations and mask processing are implemented according to the datasheet. Especially since bit position errors are difficult to find, cross-checking through reviews is effective.

Timing-Dependent Processing

Check whether the rationale for wait times is clear, whether timeout processing is implemented, and whether the code depends excessively on CPU performance. Furthermore, check whether the implementation properly evaluates not only the worst-case execution time (WCET) but also the effects of processing time variation (jitter) and interrupt latency, and ensure that the code operates stably even in different operating environments.

Key Points for Effective Review Practices

It is important to establish a system that allows for continuous improvement, rather than relying solely on individual experience for reviews.

Creating Checklists for Review Criteria

Organize check items for each item under review and create a checklist that reflects project-specific perspectives and past defect cases. Analyzing review results and continuously incorporating measures to prevent recurrence and updating review criteria will lead to quality improvement.

Combined Use with Static Analysis Tools

Static analysis tools are suitable for detecting items that can be mechanically determined, such as uninitialized variables, unused variables, and coding standard violations. On the other hand, design quality, such as the validity of function decomposition, consistency with design intent, and separation of hardware-dependent parts, must be confirmed through human review. By automating items that can be detected by static analysis and focusing manual reviews on design quality and hardware-dependent parts, both efficiency and quality can be achieved.

Improving the Quality of Review Feedback

In reviews, it is important to not only point out “Please fix this,” but also to clearly explain why it is a problem and how it relates to the coding standards. Reviews conducted with a focus on preventing recurrence will also improve the design capabilities and implementation quality of the entire team.

Back to The World of Embedded Software Top