The Cortex-M3 is an ARM processor core that is widely used in microcontroller units (MCUs) and other embedded systems. Like all processors, the Cortex-M3 utilizes registers to store data for processing operations. Understanding the registers is key to effectively programming the Cortex-M3.
The most basic registers on the Cortex-M3 can be grouped into the following categories:
- General purpose registers
- Special purpose registers
- System control registers
General Purpose Registers
The Cortex-M3 has 16 general purpose 32-bit registers named R0-R15. These registers can be used for various data processing operations and for storing variables, addresses, etc. The registers R0-R12 are for general usage while R13-R15 have special functions:
- R13 – Stack pointer (SP)
- R14 – Link register (LR)
- R15 – Program counter (PC)
The stack pointer register R13 holds the current position of the stack in memory. Pushing and popping stack frames utilizes the stack pointer to adjust the stack as needed. The link register R14 stores the return address when a function call occurs. And the program counter R15 contains the current instruction address being executed.
General Purpose Register Usage
The general purpose registers R0-R12 can be used to store data needed for program execution. For example: MOV R0, #5 ; Store value 5 in R0 MOV R1, R2 ; Copy contents of R2 to R1 ADD R3, R1, R2 ; R3 = R1 + R2
Registers can hold addresses that point to locations in memory. For example: LDR R0, =myVariable ; R0 contains address of myVariable LDR R1, [R0] ; Load value at address in R0 into R1 STR R2, [R0] ; Store R2 into address in R0
There are no specific rules for which registers must be used for particular operations or data types. The registers R4-R11 are commonly used as temporary registers during calculations.
Special Purpose Registers
In addition to the general purpose registers, the Cortex-M3 contains several special purpose registers that have predefined functions.
Program Status Register
The program status register (PSR) contains condition flags and status bits such as:
- Negative/positive flag
- Zero flag
- Carry/borrow flag
- Overflow flag
- Interrupt disable bit
These flags are automatically set or cleared based on the results of data processing instructions. The flags can be tested using conditional execution instructions.
Floating Point Registers
The Cortex-M3 supports single precision floating point operations through the use of floating point registers S0-S31. These registers can hold 32-bit floating point values for floating point arithmetic, comparison, and conversion operations.
PSR Registers
The PSR registers allow you to directly access the individual flags in the PSR:
- APSR – Holds negative, zero, carry, and overflow flags
- EPSR – Holds exception related flags
- IPSR – Holds exception number of current ISR
This gives you more flexibility for individually testing or modifying status flags.
System Control Registers
System control registers are used for configuring and controlling various processor functions:
Control Register
The control register (CONTROL) controls entry into thread mode, stack alignment, and endian format.
Vector Table Offset Register
The vector table offset register (VTOR) holds the offset address of the vector table which contains the reset and interrupt vectors.
Application Interrupt and Reset Control Register
The application interrupt and reset control register (AIRCR) is used to set priority grouping, register exceptions, and initiate a system reset.
System Control Register
The system control register (SCR) sets the sleep mode, SEVONPEND bit, and execution priority.
Configuration and Control Register
The configuration and control register (CCR) enables/disables stack alignment, div by 0 exceptions, non-maskable interrupt handling, and user mode access.
SHPR Registers
The system handlers priority registers (SHPR1-SHPR3) set priorities for exceptions and interrupts.
System Handler Control and State Register
The system handler control and state register (SHCSR) modifies interrupt control, checks pending exceptions, and enables debugging.
Memory Mapped Registers
In addition to the core registers, the Cortex-M3 has numerous peripheral and device registers that are memory mapped. This means the registers are assigned addresses within the memory map and can be accessed like normal memory using load and store instructions.
For example, registers controlling the GPIO ports, timers, ADCs, etc are all mapped to specific address locations. The memory map is defined for each particular MCU implementation.
Accessing Memory Mapped Registers
To access a memory mapped register, you first load its address into a register, then you can access the register using that address: LDR R0, =GPIOB_BASE ; R0 contains base address of GPIO Port B registers LDR R1, [R0, #0x14] ; Load Offset 0x14 from R0 into R1 STR R2, [R0, #0x18] ; Store R2 into Offset 0x18 from R0
The GPIOB_BASE is a symbolic constant defined in the vendor’s header file that provides the base address for Port B registers in the memory map. The offsets are defined to reach a particular control or data register within the GPIO region.
Cortex-M3 Register Summary
In summary, the key registers on the Cortex-M3 include:
- 16 general purpose registers R0-R15 for data operations
- Program status register for conditional flags
- Floating point registers S0-S31 for floating point math
- Special purpose registers like APSR, EPSR, IPSR for detailed status flags
- System control registers like VTOR, AIRCR, SCR for configuration
- Memory mapped peripheral registers for device/peripheral control
Understanding these registers is essential to effectively programming Cortex-M3 based microcontrollers. The general purpose registers and PSR form the core registers used for data processing and testing conditions. The system control, special purpose, and memory mapped registers provide processor configuration and peripheral access capabilities.
Cortex-M3 Register Usage Guidelines
Here are some guidelines for working with Cortex-M3 registers:
- Utilize R0-R3 for passing parameters between functions
- Use R4-R11 for temporary storage during calculations
- Reserve R12 for function scratch space if needed
- Let the compiler manage R13(SP), R14(LR), R15(PC)
- Store frequently accessed variables in registers for fast access
- Use the barrel shifter with registers to rapidly calculate offsets
- Initialize system control registers early in program execution
- Refer to memory map and enable necessary peripherals
- Use memory barriers when accessing memory mapped registers
Following these general guidelines will help optimize register usage and improve program execution speed and efficiency.
Cortex-M3 Register Configuration
Several key steps are involved in configuring Cortex-M3 registers for proper processor operation:
- Setup Clock – Configure system clock source and PLL to generate desired CPU clock frequency.
- Configure Flash Wait States – Set number of flash wait states needed to match CPU clock speed.
- Setup Stack Pointer – Initialize R13 SP register to point to last stack memory location.
- Set Vector Table Offset – Write VTOR register with address of interrupt vector table.
- Configure NVIC – Set priorities for enabled interrupts in NVIC priority registers.
- Enable Peripherals – Set needed peripheral clock enables and pinmux settings.
- Configure GPIO – Initialize any needed GPIO ports/pins for peripherals or I/O.
These steps initialize the processor clocks, memory access timing, interrupt handling, peripherals, and I/O for proper operation before the main program executes.
Cortex-M3 Register Optimization Tips
Some tips for optimizing register usage on the Cortex-M3 include:
- Minimize unnecessary data transfers between core and memory
- Use registers instead of RAM variables when possible
- Leverage load/store multiple instructions to maximize bus transfers
- Avoid unaligned accesses and use aligned access instructions
- Use circular addressing mode when processing sequential buffers
- Utilize barrel shifter to rapidly calculate offsets
- Order code to maximize pipeline efficiency
- Assign most critical code to fastest memory region
Properly utilizing the registers, pipelines, memory regions, and data transfer capabilities is key for optimized performance on Cortex-M3 based microcontrollers.
Common Questions about Cortex-M3 Registers
What is the difference between R14 and R15?
R14 is the link register and stores the return address when a function call occurs. R15 is the program counter and contains the current instruction address being executed.
How do you set or clear bits in the program status register (PSR)?
Use the MSR instruction to set or clear bits in the PSR. For example: MSR APSR_nzcvq, #0 ; Clear all APSR flags MSR APSR_nzcvq, #0x80000000 ; Set negative flag
What is a memory barrier and when is it needed?
A memory barrier ensures memory accesses are completed in order. This prevents reordering of reads/writes. Memory barriers may be needed when accessing memory mapped registers.
What happens to register contents during a function call?
R0-R3, R12, R14, R15 will be changed by a function call. R4-R11 should be preserved. To preserve R0-R3, they need to be pushed/popped in the called function.
How do you enable nested interrupt handling?
Set the PRIMASK PM bit to 0 to allow nested interrupts. The __enable_irq() and __disable_irq() intrinsics can be used to modify PRIMASK.
What is a dedicated register and how is it useful?
A dedicated register is permanently allocated to a particular variable. This saves instruction cycles to reload the register each time the variable is needed.
Real World Examples
GPIO Control
/* Enable Port F Clock */ SYSCTL_RCGCGPIO |= (1<<5); /* Set Pin 1 for Output */ GPIOF_DIR |= (1<<1); /* Set Output High */ GPIOF_DATA |= (1<<1); /* Toggle Output each 1ms */ while(1) { GPIOF_DATA ^= (1<<1); Delay_ms(1); }
This example shows accessing the memory mapped SYSCTL and GPIOF registers to configure GPIO Port F Pin 1 as a digital output. The output is set high then toggled each 1ms.
Integer Math
uint32_t x = 0x12345678; uint32_t y = 0x87654321; /* Addition */ uint32_t sum = x + y; /* Subtraction */ uint32_t diff = x – y; /* Multiplication */ uint32_t prod = x * y; /* Bitwise AND */ uint32_t and = x & y; /* Bitwise OR */ uint32_t or = x | y;
This code performs unsigned integer math operations using the general purpose registers to store the 32-bit integer values and results.
Fixed Point Math
fixed16_t x, y, z; /* Convert integer to fixed point */ x = int_to_fixed(1); /* Convert float to fixed point */ y = float_to_fixed(0.5f); /* Multiplication */ z = fixed_mul(x, y); /* Addition */ z = fixed_add(x, y); /* Subtraction */ z = fixed_sub(x, y); /* Convert result back to integer */ int result = fixed_to_int(z);
This example shows fixed point math operations using 16-bit fixed point values stored in the general purpose registers. Fixed point provides fractional math using integer operations.
Conclusion
In summary, understanding the Cortex-M3 registers is key to harnessing the capabilities of the processor and optimizing performance. The general purpose and special registers form the core set for data processing. While system control, PSR, and peripheral registers enable configuration, status checking, and hardware control. Properly utilizing these registers along with the tips provided can help developers create more efficient Cortex-M3 designs.