Reflections on the Underlying Architecture of ADAS

Introduction

This article has been in the works since September, and I finally clarified my thoughts this month, presenting some trade-offs. It has gone through three versions, and I still feel something is lacking; I hope for your guidance.

I have been pondering a question: what constitutes a good architecture? Our first-generation architecture was borrowed from foreign sources, and while the software is quite good, is it truly a good architecture? Different people have different perspectives, whether from a developer’s viewpoint or a user’s perspective, and there may be varying insights. Upon reviewing the foreign architecture multiple times, I often questioned whether it truly suits us. Flexibility, adaptation speed, iteration speed, platformization, and software portability—can our current capabilities hold up? We need to meet demands, maintain the system, have a certain level of adaptability, and improve iteration speed. The previous architecture was maintainable, but the toolchain was difficult to manage, and the iteration speed was slow; even minor changes had significant impacts. So, what is a good architecture from a practical standpoint? This article aims to evaluate software architecture from the perspectives of project management, project maintenance, and platform development.

During the project process, I sincerely discovered some pain points: the client’s requirements are repeatedly clarified, and interfaces are constantly pulled and changed, leading to a painful point: forced waste of manpower, unable to focus on key core modules. For example, the reporting of faults, DTC organization, and DCM modules consumed a significant amount of our manpower. I find it hard to imagine a UDS function consuming 3.5 full-time equivalents at peak manpower.

Moreover, the repeated changes in thresholds are truly unbearable; one moment it’s 6.5V, the next it’s 8V, then 9V, forcing us to constantly correct to meet client demands. There are also issues with module handover and maintenance, where veterans pass new modules to newcomers. How can newcomers quickly get up to speed with these modules? What should the growth path for newcomers look like? If the software architecture is set up too complexly, it becomes very unfavorable for newcomers to maintain.

These issues are somewhat intolerable. Of course, I must admit that the repeated clarifications of requirements have consumed a lot of our energy, but when we carefully sort through these problems and return to the essence of the issues, the software architecture plays a crucial role. A good software architecture can quickly iterate and trial-and-error when requirements are unclear, while also allowing for quick rollbacks.

I must also acknowledge that agile development and ASPICE have significantly impacted project development decisions, sometimes forcing us to make time-wasting and manpower-wasting decisions merely to comply with certain processes or to appease leadership’s keen interest.

Some Preliminary Thoughts on Software Architecture

Personally, I believe our previous software architecture was customer-demand-oriented, which was also a helpless move. Facing Tier 1, Tier 2, and Tier 3, the differing demands at various levels inevitably slowed down the iteration speed of software delivery. In the process of adaptation and implementation, various discomforts or the need to modify some critical code or make workarounds have led to additional waste of chip resources and manpower.

How can future architecture reduce manpower? The adaptation of toolchains and platformization must be key. By using tools, we can lower the maintenance costs for newcomers, and platformization can continuously enhance the robustness of the platform, thereby reducing the overall software maintenance costs. Of course, standardizing the development process is somewhat abstract but very useful. After arguing with clients for a month to align processes, the subsequent iterations genuinely become much faster, and many disputes are reduced.

Reflections on the Underlying Architecture of ADAS

An architecture should start from hardware to build a foundational software platform. When the hardware is determined, we should try to delineate what is unchanging and can be platformized, what is variable and cannot be platformized, what are customer demands, and what are project platform requirements.

For instance, our hardware types of faults are already certain and do not change with any project changes. The functional limits we can achieve are also completely determined with the hardware. When we adapt based on hardware, our driver code, such as SBC code, basic CAN Trcv drivers, various I2C, UART driver codes, SPI driver codes, ADC, and other basic driver codes must be adapted and confirmed. To consider load reduction, we need to adapt DMA or asynchronous interfaces. BSP also solidifies with the adaptation of DDR, EMMC, and UFS.

To implement platformization, we must establish some basic software strategies, implementing reset, fault diagnosis, and basic internal communication platformization, distributing underlying functions across different chips or CPU cores. Platformization also means providing unified platform interfaces, with standardized modules outputting externally. I distinctly remember a module that started with Tlib, which could only call customer-specific interfaces, and these interfaces would connect with the platformized interfaces.

Of course, from the perspective of underlying software functions, there are also specialized customization needs such as state management mode switching. How to achieve high portability and easy modification of these requirements can be considered by first implementing underlying state management based on chips, integrating different chips into a large system state management, where different chips have their own independent state switching and retrieval interfaces. This is particularly evident in the project I am currently responsible for, which involves the main domain controller and auxiliary domain controller overlay. Managing the entire system state and ensuring proper notification and post-processing is very challenging due to the multitude of states and dispersed state inputs. However, it still needs to be implemented based on a Master-Slave architecture, while integrating the Master-Slave architecture into a large system state.

Reflections on the Underlying Architecture of ADAS

With platformized code, there will be platformized testing. Platformized testing can reduce the testing pressure of each sub-project and guide the testing processes and methods for each project. This topic is not discussed here, as testing is a very large subject with many implementation methods. Previously, I have seen virtual sensor interfaces supporting UT, various interfaces supporting RTE simulation, and various unit tests running on Windows computers to check software coverage, etc. This also places certain requirements on software coding standards, requiring a clear understanding of the upstream and downstream interfaces of the modules one is responsible for.

With toolchains come tools, with testing come problem-solving, and with problem-solving come more complex tools. To reduce manpower, we must introduce additional toolchains. In addition to various CP tools and AP tools, we also need to introduce reset troubleshooting tools, code generation tools, configuration tools (code configuration tools, binary configuration tools, file configuration tools), testing tools, special data acquisition tools, etc. The introduction of toolchains can effectively standardize and unify the processes that were previously passed down verbally, significantly lowering the threshold for newcomers to get started, but it also greatly increases the maintenance threshold for newcomers. Therefore, once a team experiences a large-scale personnel turnover, this architecture will become increasingly difficult to maintain, until the toolchain completely fails, reverting to a state of manpower stacking functions.

Furthermore, whether troubleshooting tools are temporary or formal requirements is worth discussing. After all, we are engineering, not research. When problems occur, how to quickly locate them becomes particularly important. These troubleshooting tools can be embedded in the project based on demand and load, allowing for dynamic solutions to be implemented by opening or closing these functions in various ways.

Practical Adaptation of Software Architecture

Practical Adaptation of Communication Architecture

Reflections on the Underlying Architecture of ADAS

CAN/Eth communication mainly addresses the issue of manually adapting CAN/Eth signals to the client-specified interfaces, avoiding rework caused by human error. I must admit that Autosar tools can sometimes be quite difficult to use. The work from the arxml provided by the client to the actual code generation involves a lot of workload, and there are many places in the CAN and Ethernet-related code imports that require manual modifications. How to quickly implement this workload through scripts or process optimizations is worth considering.

Most companies pay attention to the iteration of tools and the accumulation of related testing development for communication functions. I feel I cannot write too much here to avoid overstepping.

Thoughts on Lifecycle Management

From the design perspective, lifecycle management is intended to ensure the safe power-up and power-down of the entire chip and facilitate entry into special functional modes. The entire lifecycle state is broadcasted globally within the board, allowing both Master and Slave to obtain the corresponding peer state. When multiple slaves exist, it is also convenient to expand, and periodic interaction data can use various physical media such as SPI, UART, Ethernet, shared memory, etc.

Lifecycle management must be flexible and have a certain level of adaptability. Due to the relatively few lifecycle state machines in the project, we consider adopting a classic Master-Slave architecture, which is simple to develop, has clear logic, is easy to maintain, and can provide a certain level of functional safety assurance. The downside is that if there are significant logical changes in the states, the corresponding code adaptation workload is relatively large. From the perspective of software development, the development cost is low, and there is no need to pile up manpower.

Reflections on the Underlying Architecture of ADAS

Thoughts on UDS Diagnostic Platformization

I must consider how the existing ADAS diagnostic architecture can quickly iterate and support project development. How can we platformize logistics data, factory data, and frozen frames? These are truly worth pondering.

This also brings us to the point that in ADAS or the current vehicle system, the diagnostic architecture is variable. Some hardware has multiple diagnostic nodes such as CAN and Ethernet. How can we accommodate these diagnostic nodes? In various diagnostic architectures, there needs to be a bridge for communication between the MCU and SoC, which I refer to as diagnostic middleware. This diagnostic middleware may bridge the diagnostics of CAN and Ethernet or aggregate diagnostic information from different sub-nodes. This middleware must also consider DoIP refresh or CANTP refresh protocols, supporting both master and slave.

Through such an architecture, we can quickly support data collection, testing, or rapid development of debugging tools without the need to establish a new communication link, as diagnostic data is inherently retrieved on demand, event-triggered, and low-frequency.

For example, during the current R&D phase, if a system state anomaly is detected, we may not want to read certain variables through a debugger or other tools. However, during mass production, we can disable this. Through the diagnostic middleware, we can deploy some DID to read specific data on the SoC, and during mass production, these functions can be removed from the SoC side. This way, it does not affect the development pace while effectively helping R&D quickly locate issues, and during mass production, it does not hinder information security.

Additionally, the entire UDS diagnostic platform must consider which data providers are platform solutions. A typical example is supplier logistics data and factory logistics data. This foundational data should provide a unified framework interface to meet different customer demands. We cannot adapt many places just to change a DID number. Of course, these are more about process guarantees. How to achieve process-oriented development, especially for modules like UDS that are relatively easy and suitable for newcomers to learn.

Reflections on the Underlying Architecture of ADAS

Thoughts on Integrating Fault Reporting Architecture

Regarding fault reporting, I must consider how to elegantly implement a cross-chip fault reporting architecture. Does the user have clear interfaces, clear configuration methods, and clear status feedback? As for how the code is generated and how the link is established after calling fault reporting, that is the responsibility of the fault reporting middleware. However, we must also be elegant; can our fault reporting middleware achieve functionality development through configuration like Autosar tools? This is worth pondering!

Initially, we expect to report relevant faults through configuration, considering fault ID, fault description, debounce strategy, fault suppression strategy, post-processing strategy, reporting chip, and other information. Additionally, we need to implement special handling for fault reporting to prevent load increases caused by frequent fault reports, while also considering fault recovery and timely transmission of faults, as well as the reporting strategy for faults. For instance, some faults may occur and recover frequently, which places a significant load requirement on fault handling. Under extreme conditions, this may lead to abnormal load increases.

Reflections on the Underlying Architecture of ADASReflections on the Underlying Architecture of ADAS

Thoughts on Exception Reset Management and System Tools Architecture

Real vehicle debugging is a troublesome task, but I must admit it is a necessary one. Regularly capturing reset information and fault information on the MCU can retain relevant information even without connecting a debugger. The MCU can effectively monitor the operational status of the SoC, and once an anomaly occurs, it can quickly determine what caused the anomaly. The common troubleshooting process is as follows:

Reflections on the Underlying Architecture of ADAS

There are many considerations here, and one crucial point to clarify is: we cannot obtain information through a debugger, as it would disrupt the relevant environment. Additionally, we must consider how to save data during reset restarts, as well as how to handle continuous resets, while also ensuring that these messages can be quickly transmitted during recovery. We must also consider how to convey fault information when the entire system cannot fully recover. The relevant considerations are as follows:

  • Modify the MCU’s link script to reserve a memory block for reset non-clear areas to save data.

  • We also need to consider how to quickly disable resets to ensure data can be read out when continuous resets occur.

  • Data transmission must be able to quickly convey information to the SoC or debugging tools during system recovery. Therefore, we have deployed relevant tools on the SoC that can effectively support dumping data from any address of the MCU, analyzing relevant assembly, dumping MCU register values, and as long as the SoC is not abnormal, we can quickly analyze the communication status of the SoC to perform self-checks on the entire system.

  • Data transmission must also consider external special debugging tools. When the SoC cannot effectively start, we should consider implementing data acquisition through a computer connected via Ethernet or CAN.

Thoughts on Software Mass Production Configuration/Debbuging Configuration and Testing Architecture

Before discussing this architecture, we must talk about the previous virtual sensor interfaces. We all know that software is layered, and sensors have a dedicated layer of software modules that provide data upwards. The upper layer modules obtain data, perform diagnostics, use data, and execute logical operations. So how can we verify the feasibility of the upper layer modules? As long as we correct the sensor data providing interface to the virtual sensor interface, we can perfectly implement logical verification, conduct unit tests, and even MCDC.

Reflections on the Underlying Architecture of ADAS

The above functionality is relatively easy to implement on the SoC side; a JSON or YAML file can solve it. However, it becomes more challenging on the MCU side, especially when this aspect was not considered during design.

Of course, real engineering has many requirement changes. Voltage monitoring changes from 16V to 16.5V, then back to 16V, and then other changes occur, such as requiring no reset or temporarily requiring a special version to implement a reset, or not reporting DTC but implementing other processing logic, etc.

If it is on the SoC side, I can directly create a JSON configuration, modify the JSON file, and update the relevant configuration. However, on the MCU side, it is not so easy. Of course, we can use DFlash for storage, but from a design perspective, it seems unnecessary and will increase the performance loss related to DFlash. A more user-friendly solution is to specifically reserve a Flash area for design configurations, assisted by scripts to modify this Flash area, which can greatly improve operational performance and reduce NvM loss. When clients need to propose relevant requirement changes, they only need to update a small hex file to change 16V to 16.5V to complete the relevant development, and we can even delegate some of this work to the client, requiring them to implement relevant data calibration. Additionally, from the ASPICE perspective, following the configuration management process does not require going through the code change process, which can significantly reduce process pressure.

This functionality can also be used to enable or disable software debugging functions, allowing relevant test cases to be activated for testing, while effectively resolving the issue of developers responsible for related software modules coding test cases into the project during iterations.

Comparison Items

Without Flash Configuration

With Flash Configuration

Code Changes

Requires manual code modification and compilation

No code modification or compilation required

Software Requirement Changes

Requires new software requirements

Update configuration requirements in the SWE.1 configuration management section

Unit Testing

Required, and needs QAC

Not required

Integration Testing

Required

Required

Quality Testing

Required

Can reuse integration test cases

Software Release

Requires re-releasing the software package

Only need to release a small HEX, no need for a full release

Application Layer Software Integration

Requires re-integration

No re-integration required

Conclusion

First, we must acknowledge that these designs stand on the shoulders of giants and have encountered many pitfalls. The current software architecture is purely considered from the perspective of reducing manpower load, improving software maintainability, and enhancing problem traceability, striving to adopt a simple software architecture to ensure the platformization of core software. The entire software is divided into platform and project, enhancing software reusability and standardizing project development processes.

In the face of client variability, we aim to increase software reusability through software configuration, ensuring that software meets client demands, and even reverse some work back to clients for adaptation, reducing the overall manpower consumption of the team.

The entire software solution maintains a simple, clear, and understandable architecture, reducing software complexity and improving newcomers’ ability to get started with project software maintenance, and quickly responding to project demands.

However, for complex software requirements, the entire software architecture still cannot adapt well, leading to significant software changes and iterations. There are pros and cons to everything. At the same time, the entire architecture inherently increases the difficulty of platform development, especially the maintenance difficulty of the toolchain, making it challenging for newcomers to quickly get started.

Leave a Comment