CMSIS-CORE: Peripheral Access

| CMSIS-CORE Version 4.30 CMSIS-CORE support for Cortex-M processor-based devices

- Main Page
- Usage and Description
- Reference

All Data Structures Files Functions Variables Enumerations Enumerator Groups Pages
Macros
Peripheral Access

Describes naming conventions, requirements, and optional features for accessing peripherals. More...

## Macros
#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.

## Description

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; /* Offset: 0x000 (R/ ) Receiver Buffer Register */
__OM uint8_t THR; /* Offset: 0x000 ( /W) Transmit Holding Register */
__IOM uint8_t DLL; /* Offset: 0x000 (R/W) Divisor Latch LSB */
uint32_t RESERVED0;
};
union {
__IOM uint8_t DLM; /* Offset: 0x004 (R/W) Divisor Latch MSB */
__IOM uint32_t IER; /* Offset: 0x004 (R/W) Interrupt Enable Register */
};
union {
__IM uint32_t IIR; /* Offset: 0x008 (R/ ) Interrupt ID Register */
__OM uint8_t FCR; /* Offset: 0x008 ( /W) FIFO Control Register */
};
__IOM uint8_t LCR; /* Offset: 0x00C (R/W) Line Control Register */
uint8_t RESERVED1[7];
__IM uint8_t LSR; /* Offset: 0x014 (R/ ) Line Status Register */
uint8_t RESERVED2[7];
__IOM uint8_t SCR; /* Offset: 0x01C (R/W) Scratch Pad Register */
uint8_t RESERVED3[3];
__IOM uint32_t ACR; /* Offset: 0x020 (R/W) Autobaud Control Register */
__IOM uint8_t ICR; /* Offset: 0x024 (R/W) IrDA Control Register */
uint8_t RESERVED4[3];
__IOM uint8_t FDR; /* Offset: 0x028 (R/W) Fractional Divider Register */
uint8_t RESERVED5[7];
__IOM uint8_t TER; /* Offset: 0x030 (R/W) Transmit Enable Register */
uint8_t RESERVED6[39];
__IM uint8_t FIFOLVL; /* Offset: 0x058 (R/ ) FIFO Level Register */
} 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:

val = LPC_UART2->DR // is the data register of UART1.

# 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; /* Offset: 0x000 (R/W) SysTick Control and Status Register */
  __IOM uint32_t LOAD; /* Offset: 0x004 (R/W) SysTick Reload Value Register */
  __IOM uint32_t VAL; /* Offset: 0x008 (R/W) SysTick Current Value Register */
  __IM uint32_t CALIB; /* Offset: 0x00C (R/ ) SysTick Calibration Register */
  } SysTick_Type;

- 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) /* SysTick Base Address */

- 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) /* SysTick access definition */

These definitions allow accessing peripheral registers with simple assignments.

- Example:
  SysTick->CTRL = 0;

# 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).

/* SCB CPUID Register Definitions */
#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 /*<< SCB_CPUID_REVISION_Pos*/)

The macros _VAL2FLD(field, value) and _FLD2VAL(field, value) enable access to bit fields.

## Macro Definition Documentation

#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);