BSPACM
20150113
Board Support Package for ARM Cortex-M Microcontrollers
|
The coding style for BSPACM is primarily the one the author converged to over the last twenty-five years, but has a few lingering influences from BSP430.
BSPACM's coding style may be obtained using the following Emacs ccmode style:
An acceptably close approximation can be had using the following Artistic Style (astyle) command line:
Where astyle and emacs reformat the other's code, astyle's decision is preferred.
Note in particular that the one-true-brace-style expects single statements in loop, if
and else
bodies to be enclosed in braces, e.g.:
Care is taken in BSPACM to conform to the rules for C regarding global identifiers. In particular, underscores may not appear at the start of an identifier (including macro parameters), and certain suffixes like _t
are reserved.
BSPACM
with or without prefix characters that indicate type information. The next section of the identifier encodes information about the BSPACM module to which it belongs.i
is used for int
, ul
for unsigned long
, v
for void
, and h
for a pointer-to-structure (for example, used as a device handle). The letter x
is used as a prefix for more complex types, such as const char *
, other pointers, and structures.s
is a struct
, u
is a union
, e
is an enum
. h
indicates a handle for (pointer to) a structure type. f
is used for a typedef describing a function prototype. t
is used for any typedef for a scalar type.struct
, union
, and enum
type directly (i.e. not through a handle), those types should have typedef aliases that use the tag as the type name.e
._Hz
.Anybody using a Cortex-M device should know that they are operating on a 32-bit device, and BSPACM is by design restricted to Cortex-M devices.
int
and unsigned int
are used in preference to size-explicit types for index variables, return values, etc. This follows POSIX API standards.uint32_t
is the core type for reference to system and peripheral memory mapped registers, even though some toolchains (ahem) typedef this to unsigned long
when it could just as well be unsigned int
. This follows ARM standards.uint16_t
, int8_t
, etc) are used in preference to short
and char
for integral values where space is at a premium and the values will never exceed the type used. Generally this applies only to stored data, but may also occur in temporary values used in expression evaluation, to make any truncation explicit.short
and long
integer types are not used directly.char
as the core type. char
is not used for non-text data.void
, though in some cases they may be pointers to uint8_t
to eliminate the need for casts when operating on octet data.const
qualifier.BSPACM places comparison operands which are lvalues on the right side of the operator, as with:
Yes, even if the conditional operator "couldn't possibly be mistyped" as an assignment operator. Up with it you must put.
Where a function implements an operation that may succeed or fail, that state reflected in the return value following standard POSIX conventions: a zero indicates a successful execution and a negative value indicates an error. Where useful information about a successful result may be expressed as a non-negative value (e.g., the number of bytes successfully transmitted), that may be included in the return value.
This is often counter-intuitive to programmers unfamiliar with POSIX, but the correct test to see whether the I2C addresses were successfully set is indeed:
Be aware that in BSPACM a generic header such as <bspacm/utility/led.h> will in turn include a device-specific <bspacm/utility/led_.h> to complete the necessary data structures and inline function definitions. This file is located by compiler flags that provide a prioritized list of locations to look for that file.
Include file protection symbols encode the path by which the include file is normally accessed, preceded by components from its containing path if appropriate, with non-alphanumeric characters replaced by underscores, and the resulting token expressed in upper case. For example, the generic header <bspacm/utility/led.h> is located at $(BSPACM_ROOT)/include/bspacm/utility/led.h
and is protected with:
When compiling for an EFM32 device the reference to <bspacm/utility/led_.h> will find the header located at $(BSPACM_ROOT)/device/efm32/include/bspacm/utility/led_.h
, and its include protection symbol is:
_INTERNAL
between the device-specific path and the relative name.See also bspacm_config for naming conventions and standards related overriding default configurations.
Every header file that does not include another BSPACM header file must include <bspacm/core.h> first to ensure the necessary preprocessor directives that are affected by <bspacm/config.h> are applied in the standard order.
<bspacm/core.h> may be expected to include the following external material:
The files <bspacm/device.h> and <bspacm/config.h> do not exist in the primary include directory, but in alternative hierarchies placed within the device and board subdirectories. <bspacm/config.h> in particular may also be superseded through use of an application-specific include hierarchy.
Every implementation file should include <bspacm/core.h> first to ensure that platform-specific overrides have been evaluated and are available to override defaults in other headers.
See also bspacm_config for naming conventions and standards related to feature tests.
Where a macro value is used for conditional compilation, the state of being true is determined with the following pattern:
This technique allows use of:
to denote that the feature is being explicitly disabled. Developers of application or infrastructure code should ensure that any feature test flag has a definition to either 1 or 0 (or to an expression that will evaluate to either a true or false value when used within a preprocessor condition). The documentation explicitly marks macro definitions that are expected to have such values with the @cppflag
annotation in the documentation block, which will produce:
@cppflag
may have values that include preprocessor operators like defined
which restrict their use to preprocessor directives.The ability to explicitly disable features that default to being enabled is critical and requires a value-based comparison. The subtraction of 0 in the conditional expression allows syntactic correctness when somebody inappropriately defines the feature flag with no value: such a case is equivalent to disabling the feature. For consistency these tests should be enclosed in parentheses. The syntax also makes clear that the code was not intended to be #ifdef FEATURE_FLAG
.
The correct way of detecting features when interoperating with external libraries using the null-definition style is:
The short-hand #ifdef
may be used instead of the defined()
test if no further conditions are required, but is discouraged for consistency.
BSPACM uses Doxygen for architectural and API documentation. The following macros are used in API documentation to highlight expectations of particular macros, variables, and functions.
Copyright 2014-2015, Peter A. Bigot