Describes naming conventions, requirements, and optional features for accessing peripherals.
More...
|
#define | _VAL2FLD(field, value) |
| Mask and shift a bit field value for assigning to result to a peripheral register.
|
|
#define | _FLD2VAL(field, value) |
| Extract from a peripheral register value the a bit field value.
|
|
The section below describes the naming conventions, requirements, and optional features for accessing device specific peripherals. Most of the rules also apply to the core peripherals. The Device Header File <device.h> contains typically these definition and also includes the core specific header files.
Most of the definitions can be generated using the CMSIS-SVD System View Description for Peripherals. Refer to SVDConv.exe for more information.
Each peripheral provides a data type definition with a name that is composed of:
- prefix <device abbreviation>_
- <peripheral name>
- postfix _Type or _TypeDef to identify a type definition.
Example: LPC_UART_TypeDef for the device LPC and the peripheral UART.
The data type definition uses standard C data types defined by the ANSI C header file <stdint.h>.
- IO Type Qualifiers are used to specify the access to peripheral variables.
IO Type Qualifier | Type | Description |
__IM | Struct member | Defines 'read only' permissions |
__OM | Struct member | Defines 'write only' permissions |
__IOM | Struct member | Defines 'read / write' permissions |
__I | Scalar variable | Defines 'read only' permissions |
__O | Scalar variable | Defines 'write only' permissions |
__IO | Scalar variable | Defines 'read / write' permissions |
- Note
- __IM, __OM, __IOM are added in CMSIS-Core V4.20 to enhance support for C++. Prior version used __I, __O, __IO also for struct member definitions.
The typedef <device abbreviation>_UART_TypeDef shown below defines the generic register layout for all UART channels in a device.
typedef struct
{
union {
__IM uint8_t RBR;
__OM uint8_t THR;
__IOM uint8_t DLL;
uint32_t RESERVED0;
};
union {
__IOM uint8_t DLM;
__IOM uint32_t IER;
};
union {
__IM uint32_t IIR;
__OM uint8_t FCR;
};
__IOM uint8_t LCR;
uint8_t RESERVED1[7];
__IM uint8_t LSR;
uint8_t RESERVED2[7];
__IOM uint8_t SCR;
uint8_t RESERVED3[3];
__IOM uint32_t ACR;
__IOM uint8_t ICR;
uint8_t RESERVED4[3];
__IOM uint8_t FDR;
uint8_t RESERVED5[7];
__IOM uint8_t TER;
uint8_t RESERVED6[39];
__IM uint8_t FIFOLVL;
} LPC_UART_TypeDef;
To access the registers of the UART defined above, pointers to this register structure are defined. If more instances of a peripheral exist, the variables have a postfix (digit or letter) that identifies the peripheral.
Example: In this example LPC_UART2 and LPC_UART3 are two pointers to UARTs defined with above register structure.
#define LPC_UART2 ((LPC_UART_TypeDef *) LPC_UART2_BASE )
#define LPC_UART3 ((LPC_UART_TypeDef *) LPC_UART3_BASE )
The registers in the various UARTs can now be referred in the user code as shown below:
Minimal Requirements
To access the peripheral registers and related function in a device, the files device.h and core_cm#.h define as a minimum:
- The Register Layout Typedef for each peripheral that defines all register names. RESERVED is used to introduce space into the structure for adjusting the addresses of the peripheral registers.
Example: typedef struct
{
__IOM uint32_t CTRL;
__IOM uint32_t LOAD;
__IOM uint32_t VAL;
__IM uint32_t CALIB;
- Base Address for each peripheral (in case of multiple peripherals that use the same register layout typedef multiple base addresses are defined).
Example: #define SysTick_BASE (SCS_BASE + 0x0010)
- Access Definitions for each peripheral. In case of multiple peripherals that are using the same register layout typdef, multiple access definitions exist (LPC_UART0, LPC_UART2).
Example: #define SysTick ((SysTick_Type *) Systick_BASE)
These definitions allow accessing peripheral registers with simple assignments.
Optional Features
Optionally, the file device.h may define:
- Register Bit Fields and #define constants that simplify access to peripheral registers. These constants may define bit-positions or other specific patterns that are required for programming peripheral registers. The identifiers should start with <device abbreviation>_ and <peripheral name>_. It is recommended to use CAPITAL letters for #define constants.
- More complex functions (i.e. status query before a sending register is accessed). Again, these functions start with <device abbreviation>_ and <peripheral name>_.
Register Bit Fields
For Core Register, macros define the position and the mask value for a bit field. It is recommended to create such definitions also for other peripheral registers.
Example:
Bit field definitions for register CPUID in SCB (System Control Block).
#define SCB_CPUID_IMPLEMENTER_Pos 24U
#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos)
#define SCB_CPUID_VARIANT_Pos 20U
#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos)
#define SCB_CPUID_ARCHITECTURE_Pos 16U
#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos)
#define SCB_CPUID_PARTNO_Pos 4U
#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos)
#define SCB_CPUID_REVISION_Pos 0U
#define SCB_CPUID_REVISION_Msk (0xFUL )
The macros _VAL2FLD(field, value) and _FLD2VAL(field, value) enable access to bit fields.
#define _FLD2VAL |
( |
|
field, |
|
|
|
value |
|
) |
| |
- Parameters
-
field | name of bit field. |
value | value of the register |
The macro _FLD2VAL uses the #define's _Pos and _Msk of the related bit field to extract the value of a bit field from a register.
Example:
id = =
_FLD2VAL(SCB_CPUID_REVISION, SCB->CPUID);
#define _VAL2FLD |
( |
|
field, |
|
|
|
value |
|
) |
| |
- Parameters
-
field | name of bit field. |
value | value for the bit field. |
The macro _VAL2FLD uses the #define's _Pos and _Msk of the related bit field to shift bit-field values for assigning to a register.
Example:
SCB->CPUID =
_VAL2FLD(SCB_CPUID_REVISION, 0x3) |
_VAL2FLD(SCB_CPUID_VARIANT, 0x3);