The ARM Microcontroller Software Interface Standard (MSP) provides a standardized way to access and configure ARM Cortex-M microcontrollers. Properly registering and initializing the ARM MSP is crucial for developing robust and efficient firmware. This guide will walk through the key steps for registering and configuring the ARM MSP from scratch.
Understanding ARM MSP Register Addresses
The ARM MSP defines specific register addresses that correspond to different system control blocks like the System Control Space (SCS), Nested Vectored Interrupt Controller (NVIC), System Tick Timer (SysTick), and more. For example, the SCS registers start at address 0xE000E000. Knowing the address map is vital for properly configuring each system component.
Vendors may also include additional vendor-specific register blocks. Always check the reference manual for your specific ARM Cortex-M microcontroller to find the full register address map.
Enabling MSP Register Access in Startup Code
By default, access to the ARM MSP registers is disabled at reset. The startup code must enable MSP access by setting CONTROL.MPP[1:0] = 0x0 in theAuxiliary Control Register which is located at MSP address 0xE000ED14. This is typically done early on before initializing other system components.
For example: /* Enable MSP register access */ MOVW R0, #0xE000 MOVT R0, #0xE000 LDR R1, [R0, #0xED14] BIC R1, R1, #0x00000003 STR R1, [R0, #0xED14]
With MSP access enabled, the rest of the system can now be properly configured.
Initializing the Vector Table Offset Register
The Vector Table Offset Register (VTOR) holds the address of the exception vector table in RAM or ROM. This must be initialized before any exceptions can be serviced.
For example, to set the VTOR to the start of the vector table (0x00000000): /* Set VTOR to the start of vector table */ MOVW R0, #0xE000 MOVT R0, #0xE000 MOVW R1, #0x0000 MOVT R1, #0x0000 STR R1, [R0, #0xED08]
Configuring the System Tick Timer
The SysTick timer generates periodic interrupts for task scheduling and timekeeping. To enable it:
- Write the reload value to the SYST_RVR register to set the timer interval
- Configure the SYST_CVR register to reset the current value
- Enable the timer and choose the clock source using SYST_CSR
For a 1 ms tick with a 48 MHz system clock: /* Configure SysTick for 1ms ticks */ MOVW R0, #0xE000 MOVT R0, #0xE000 MOV R1, #48000 STR R1, [R0, #0xE010] ; SYST_RVR = 48000 MOVW R1, #0x0000 STR R1, [R0, #0xE014] ; SYST_CVR = 0 MOVW R1, #0x0007 STR R1, [R0, #0xE01C] ; SYST_CSR = 0x07
Setting Up the Nested Vectored Interrupt Controller
The NVIC handles enabling, prioritizing, and dispatching exceptions and interrupts. Several steps are required to configure it:
- Set NVIC register base address to 0xE000E100 using NVIC_BASE
- For each interrupt, enable using ISERx registers
- Set priority levels using IPxxRy registers
- Optionally set Group Priority and Subpriority fields
For example, to enable USART1 interrupts with Group 3, Subgroup 1 priority: /* NVIC Initialization */ MOVW R0, #0xE000 MOVT R0, #0xE000 LDR R1, =0xE000E100 STR R1, [R0, #0xED24] ; NVIC_BASE = 0xE000E100 /* Enable USART1 interrupts, Group 3 Sub 1 priority */ LDR R1, =0x00080000 STR R1, [R0, #0xED04] ; ISER0 = 0x00080000 MOVW R2, #0xE000 MOVT R2, #0xE000 LDR R3, [R2, #0xED20] BIC R3, R3, #0xFF000000 ORR R3, R3, #0x30000000 ; IPR4 USART1, Group 3 STR R3, [R2, #0xED20]
Configuring Cortex-M Priority Levels
The CORTEX_BASE register provides access to Cortex-M specific registers like PRIORITY and CONTROL. This allows configuring priority grouping and enabling fault exceptions.
For example, to set 8 priority levels with no subpriorities: /* Configure Cortex-M Priority Levels*/ MOVW R0, #0xE000 MOVT R0, #0xE000 LDR R1, =0xE000ED00 STR R1, [R0, #0xED28] ; CORTEX_BASE = 0xE000ED00 /* Set 8 priority levels, no subpriorities */ LDR R1, [R1, #0x04] BIC R1, R1, #0x000000FF ORR R1, R1, #0x00000007 STR R1, [R1, #0x04] ; Priority Grouping: 8 levels
Enabling Fault Exceptions
By default, fault exceptions like memory faults, bus faults, and usage faults are disabled after reset. The SHCSR register in the System Handler Control and State Register block is used to enable fault handling. /* Enable fault exceptions */ MOVW R0, #0xE000 MOVT R0, #0xE000 MOVW R1, #0xC0 STR R1, [R0, #0xED24] ; SHCSR MemManage, BusFault, UsageFault
Configuring ADC and GPIO Peripherals
Most ARM Cortex-M MCUs include a variety of integrated peripherals like ADCs, GPIO, Timers, Communication interfaces, etc. These are configured via their own peripheral register blocks.
For example, to enable an ADC in continuous conversion mode: /* ADC Initialization */ MOVW R0, #0x4000 MOVT R0, #0x4000 ; ADC Base MOV R1, #0x00000001 STR R1, [R0, #0x04] ; CR2 = 0x01 /* Configure GPIO pin as analog input */ MOVW R2, #0x5000 MOVT R2, #0x5000 ; GPIO Base MOV R3, #0x00000400 STR R3, [R2, #0x00] ; MODER Pin X = analog
Refer to the chip reference manual to find the base addresses for each peripheral and their configuration options.
Important Considerations When Configuring the ARM MSP
Here are some key points to remember when working with ARM MSP initialization:
- Always enable MSP access first before configuring registers
- Set the VTOR register to point to the vector table location
- Make sure to enable the peripherals, interrupts, and exceptions needed
- Set priority grouping and priority levels appropriately
- Configure SysTick and peripherals based on application requirements
- Reference the datasheet/reference manual for your specific MCU
- Double check your configuration for errors to avoid crashes or undefined behavior
Properly configuring the ARM MSP registers is critical for building robust embedded applications. With a good understanding of the register layout and configuration options, you can fully leverage the capabilities of ARM Cortex-M based microcontrollers.