Software Architecture also called High Level Software Design is the first design step after analyzing all requirements for software. The goal is to define a software structure which is able to fullfill the requirements. Also the non-functional requirements, such as scalability, portability and maintainability have to be considered in this step.
This first design step could be more or less independent of a programming language. However, the programming language has to be defined prior to defining the interfaces.
The Static Architecture
The first step in designing software is to define the static architecture. Simply speaking this is a very high level outline of the components and layers of a software.
Even if there are no requirements which explicitly ask for some of the below listed features, it is good design style to adhere to the following principles:
Define layers which make the functional part of the software independent of a hardware platform. There should be a hardware abstraction layer which encapsulates microcontroller specific code and features within the layer. All other layers have to be free of controller specific code. Another layer called "Physical Layer" should adapt the functional software to the specific signals. This is a data processing layer which filters signals and prepares them to be presented in physical units and defined resolutions at its interface.
If necessary, design a layer to adapt to a special operating system. Operating systems may offer services and semaphores, but never use them directly in your functional software. Define your own services and semaphores and go through a special layer to adapt them to the operating system services.
Design any additional layers inside your functional software as appropriate.
Design components inside your functional software. Depending on your requirements and future strategies it may be wise to e.g. design communication protocol components in a way that they can be easiliy removed and replaced by another protocol, to adapt to different platforms and systems.
E.g. in the automotive industry the CAN bus is widely used for communication between the various electronic systems in a vehicle. However some customers require different communication systems as for example FlexRay or any proprietary system.
Your software can be designed in a way to modify the communication systems and protocols easiliy. Almost as easy as "plug and play", if the design is done properly.
Design an own framework which controls the calls and interactions of your software.
Consider organizational aspects in your architecture. Parts of the software may be developed by different departments or even outsourced to external companies. Your static architecture has to reflect this so that complete components or even layers can be assigned to a vendor. This has to be also reflected in the interface definition.
Of course this was only a very rough outline of how an architecture may look like and what we found to be the best way for many applications. However, your own system may require some additional features of the architecture.
The design of your interfaces is another element which adds to the stability, portability and maintainability of your software. The following things have to be observed:
Only use function calls as interfaces and refrain from using memory pools or any other globally shared elements as interface.
Make your interfaces as narrow as possible. Therefore use simple basic data types rather than complicated proprietary structures at the interfaces. It is sometimes amazing how simple interfaces can be if the functionality is distributed in a sensible way in approriate components.
Preferably make your interfaces uni-directional. This means that input components provide interfaces used by the processing components and layers. Avoid bidirectional interaction between the same components.
Describe your interfaces clearly. Already in the architecture the kind of information, the data witdth, resolution and sign has to be defined. This is especially important if components are developed by different vendors.
More details will be given in the description of module design related to the programming language C.
The Dynamic Architecture
Operating Systems and Timing
Basically there are two categories of microcontroller systems. The first one is EVENT driven, as e.g. cell phones and other modern communication equipment.
The other kind of application is TIME driven. These microcontroller systems usually have the task to measure and evaluate signals and react on this information accordingly.
This measuring activity means that signal sampling has to be performed. Additionally there may be activities like feedback current controls which have to be performed. Both activities imply by the underlying theories that sample rates have to be as exact as possible.
Both categories of systems are called REALTIME SYSTEMS, but they are like two different worlds!
The EVENT driven systems are comparatively simple. The are usually in an idle state until one of the defined events triggers a task or process, which is executed sequentially until it is finished and the system returns to the idle state. During the execution of such a task these systems usually do not react on other events.
This "first comes first serves" principle can be seen in a cell phone, where incomming calls are ignored after you started to dial an outgoing call.
TIME driven system are much more complicated. Usually all possible inputs to the system have to be sampled and all outputs have to be served virtually simultaneously.
This means that time slices have to be granted to the various activities and their duration has to be defined and limited to ensure the overall function of the system.
It would be too much to go into more details here. However there are some general rules which should be considered:
The CPU selection should be made according to the application. There are some CPUs which support time driven application in an optimized way. E.g. it is recommendable to have sufficient interrupt levels, CAPCOM units and I/O ports which can be accessed without delays for time driven applications.
In recent years some well known microcontrollers which originate in the event driven world were pushed into the time driven market. The ease of development and stability of the systems suffer from this. Although the attempt was made by the CPU manufacturer to cover for that by designing suitable peripheral units, the whole situation still looks like an odd patchwork rather than a sound design.
Operating systems can be event driven and non-preemptive for EVENT driven applications.
Operating systems should be time driven and preemptive for TIME driven systems.
Standard operating systems may fail you for high speed tasks, such as a 250 micro second cyclic tasks for feedback current controls. In this case you have to do this by timer interrupts outside of the operating system.
Therefore have a close look at the OS from the shelf before you base your system on it.