You are on page 1of 13

SW Design and Coding Principles

Architecture Design
Scope of Architecture Design:
defines the SW Components of the system, their interfaces and interaction, communication between components
define a layer structure
Views of Architecture
Functional Architecture and Physical Architecture (Diagrams: UML, Use Case, Component, Interaction, State)
Specific SW Architecture Activities

Impact Factors
Available resources, requested performance, functional safety issues, reuse, maintainability
Razvan Ardelean

Architecture Design
SW Architecture Concepts: Layering

Architecture vs Detailed Design

Architecture
building blocks of the system, their interfaces, interactions, global concepts involving more components
Detailed Design
realization of the internals of the building blocks, describes the detailed interfaces for each component
Razvan Ardelean

Detailed Design
Common steps
Analyze the architectural description to understand the context of the SW component under design
Analyze SW component specific requirements
Identify additional functions from the relevant function area and are not necessarily covered by the requirements
Deal with complexity (if SW component complexity is high, divide in several SW subcomponents)
Consider reuse of SW-components (already tested, save time)
Define Quality criteria prioritization (memory consumption, CPU load, maintainability, reusability)
Decision for structured design or object oriented design
Structured Design
perform functional decomposition (support encapsulation, minimize dependencies, maintainability, testability)
static view by static function tree (function call overview)
design the functions behavior (consider design rules, maximum complexity)
categories of interfaces: global data, interface busses (CAN, LIN, SPI), services (callback functions)
traceability from the detailed SW design to the SW architecture description and requirements specification
Razvan Ardelean

Detailed Design
Mapping to the file structure
For each detailed SW design at least one source code file is required
Each source code file refers to exactly one SWDD
Macros
sometimes are necessary: reduce stack overhead, provide variability at compile-time, performance and ROM
size, define constants
Module global variables
respect naming convention and standardized types
where shared variables can not be avoided, a risk analysis is mandatory (protection needed?)
Function description and dynamic behavior
dynamic behavior - the principle workflow of a function and the relation between input and output parameters
for each function: signature, return value, list of parameters, description, precondition, post condition
Multitasking specific
reentrance and task safety, initialization of data, identify critical sections, shared variables analysis

Razvan Ardelean

Code according to Design


already studied different possibilities to write the code
based on timing requirements already know in which tasks and interrupts the code will execute
internal breakdown in modules and functions already done, interfaces are clarified
usage of Abstract Data Type (ADT): set of data and set of operations performed on data
data is kept private inside SW component
provide an interface to other SW components (xx.h file with get, set and other access functions)
data consistency and protection
various implementations while keeping the same interface
shared data analyzed and critical sections identified
thinking on next steps: unit testing, integration testing
number of internal interfaces as small as possible (integration effort)
simple functions, simple conditions (code coverage)
macros shall not generate code (breakpoints)
use data structures (struct ) and types (enum) (useful in the watch window)
Razvan Ardelean

Code according to Design


a module should be structured in a body (.c) and a header part (.h)
each module shall include its own header file
in a .h or .c file, include all .h files that declare symbols used by the file.(no unnecessary header files inclusion)
a ".c" file shall not be included in another file: it shall be compiled and provided as an object module
there shall be no definitions of objects or functions in a header file
functions shall have prototype declarations, the prototype shall be visible at both the function definition and call
the cyclomatic complexity number for a function should be smaller than 15 (>30 high risk; hard to test)
the static storage class specifier shall be used in definitions of objects and functions that have internal linkage
automatic variables defined inside functions must be initialized in the definition
objects shall be defined at block scope if they are only accessed from within single function
shared variables used in different preemptive tasks must be qualified as volatile (avoid unexpected optimization)
critical inputs and data must be checked for valid boundary values
enums should be used when defining groups of related integer constants instead of a series of #defines
identifiers in an inner scope shall not use the same name as an identifier in an outer scope, (name hiding)
Razvan Ardelean

Embedded software
The application is in close connection with the electronics or hardware
The target is a microcontroller specific for a functionality, not a PC with a general purpose processor
Inputs and outputs are signals, communication busses CAN, LIN, SPI
The application may be reused from one microcontroller to another (code according to ANSI C standard)
Special care for CPU load (execution time is critical)
Response time to signals is very important (real time response)
Power management is important for battery powered devices (transition low power - high power)
Why C language?
Portability
Code shall be efficient (real time)
Code shall be small (generated executable is small)
Hardware interfaces (direct access by addressing)
A compiler is available for every microcontroller

Razvan Ardelean

Embedded software
Layering: Platform (HW dependent: scheduler, drivers) and Application (less HW dependent)
Define common types in platform, for portability we cannot relay on standard data types of the C language
Awareness of endian-nes: big/little endian (avoid unions for portability)
Special keywords:
volatile - prevents compiler optimizations (mandatory to be used for shared variables)
register - try to keep that variable in a CPU register (forces compiler optimizations)
static - used for a global variable, for a function, for a local variable
inline - the code of the function is inserted at the caller point instead of using the stack overhead
const - declare that a variable or a function parameter is constant
Bit manipulation: RAM space is small, every bit can be used (implementation: structure with bitfields)
Write efficient code: binary math (shift), avoid complex addressing and unsafe pointer arithmetic
Awareness of stack consumption: parameters and local variables
Keep the functions simple: no more than 100 ELOC, cyclomatic complexity smaller than 15

Razvan Ardelean

Safe code and robustness


The main requirement regarding the code : no bugs, specially those which can cause human injury
Bug classification:
by appearance: systematic, sporadic
by severity: minor, major, fatal
Consequences: cost of finding cause, cost of fixing and testing again, recall products, human injury
Usage of a well established process: SWDD, TDD (Test Driven Development), Code review, static code analyzer
Follow some coding rules -> reliability, portability, testability, customer satisfaction
Coding rules help prevent bugs
Arithmetic: division by zero, overflow/underflow
Syntax: = vs ==, missing ()
Logical: infinit loops, recusivity
Pointers: indexing, pointer arithmetic
Resource: local variables initialization
Multitasking: shared variables
Razvan Ardelean

Safe code and robustness


MISRA (Motor Industry Software Reliability Association): 2004 standard (121 required rules, 20 advisory rules)
All code shall conform to ISO 9899 Standard C, with no extensions permitted
Precaution shall be taken in order to prevent the contents of a header file being included twice
Assembly language shall be encapsulated and isolated
C macros shall only expand to a braces initialiser, a constant, a parenthesized expression, a type qualifier, a
storage class specifier, or a do-while-zero construct
In the definition of a function-like macro each instance of a parameter shall be enclosed in parentheses unless it
is used as the operand of # or ##.
Unions shall not be used
Functions shall not be defined with variable numbers of arguments
Functions shall not call themselves, either directly or indirectly
Identifiers shall be given for all of the parameters in a function prototype declaration
The number of arguments passed to a function shall match the number of parameters
All exit paths from a functions with non-void return type shall have an explicit return statement
If a function returns error information, then that error information shall be tested
Razvan Ardelean

Safe code and robustness


A function shall have a single point of exit at the end of the function
Functions shall have prototype declarations and the prototype shall be visible at both the function definition and call
The static storage class specifier shall be used in definitions and declarations of objects and functions that have
internal linkage
Identifiers in an inner scope shall not use the same name as an identifier in an outer scope, and therefore hide that
identifier
The address of an object with automatic storage shall not be assigned to another object which may persist after the
first object has ceased to exist
All automatic variables shall have been assigned a value before being used
Array indexing shall be the only allowed form of pointer arithmetic
If the bitwise operators ~ and << are applied to an operand of underlying type unsigned char or unsigned short, the
result shall be immediately cast to the underlying type of the operand
The right hand operand of a && or || operator shall not contain side effects
Bitwise operators shall not be applied to operands whose underlying type is signed
The unary minus operator shall not be applied to an expression whose underlying type is unsigned

Razvan Ardelean

Safe code and robustness


Numeric variables being used within a for loop for iteration counting shall not be modified in the body of the loop
For any iteration statement there shall be at most one break statement used for loop termination
The statement forming the body of a switch, while, dowhile or for statement shall be a compound statement
All ifelse if constructs shall be terminated with an else clause
An unconditional break statement shall terminate every non-empty switch clause
The final clause of a switch statement shall be the default clause
A cast should not be performed that removes any const or volatile
qualification from the type addressed by a pointer
Dynamic heap memory allocation shall not be used

PC-Lint static code analyzer


checks MISRA rules
can determine things that a compiler cannot because it looks across several modules rather than just one
messages: error, warning, info, note

Razvan Ardelean

You might also like