This is a further refinement of the Cortex-M3 programming model, covering more specific implementation details and key operations:
1. Refinement of Register Groups
1. Detailed Explanation of Special Registers
CONTROL Register (32 bits, modifiable only at privileged level)
Bit 0 (`nPRIV`):
0 = Privileged mode (can access all resources)
1 = Unprivileged mode (restricted access)
Bit 1 (`SPSEL`):
0 = Use MSP (default)
1 = Use PSP (must be in unprivileged mode)
Example code (switching stack pointer in privileged mode):
__asm void SwitchToPSP(void) {
MRS R0, CONTROL
ORR R0, R0, 0x02 // Set SPSEL=1
MSR CONTROL, R0
BX LR
}
APSR (Application Status Register)
Flags:
N (Negative): Set to 1 when the result of the operation is negative.
Z (Zero): Set to 1 when the result of the operation is 0.
C (Carry): Set to 1 when there is an overflow in unsigned operations.
V (oVerflow): Set to 1 when there is an overflow in signed operations.
Usage: Conditional branches (such as `BEQ`, `BNE`) and data processing instructions depend on these flags.
2. Code Practice for Operating Modes and Privilege Levels
1. Privilege Level Switching
To elevate from unprivileged to privileged level:
Must be done through an exception (such as SVC call).
__asm void TriggerSVC(void) {
SVC 0x01 // Trigger SVC exception, parameter is 0x01
BX LR
}
// SVC Handler (privileged level)
void SVC_Handler(void) {
uint32_t *stack_frame;
__asm {
TST LR, 4 // Check EXC_RETURN Bit 2
ITE EQ
MRSEQ stack_frame, MSP // Use MSP
MRSNE stack_frame, PSP // Use PSP
}
uint8_t svc_number = ((uint8_t*)stack_frame[6])[-2]; // Extract SVC parameter
// Execute privileged operations…
}
3. Memory Mapping and MPU Configuration
1. Example of MPU Region Setup
Objective: Protect a certain area of SRAM (e.g., `0x20001000~0x20001FFF`) as read-only.
void ConfigureMPU(void) {
MPU->RNR = 0; // Select region 0
MPU->RBAR = 0x20001000 | (1 << 4); // Base address + Enable region
MPU->RASR = (0x01 << 1) | // 1KB Size (2^(1+1)=4)
(0x3 << 24) | // AP=011 (privileged read/write, user no access)
(1 << 0); // Enable region
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; // Enable memory protection exception
}
4. Refinement of Exception and Interrupt Handling
1. Interrupt Priority Configuration
NVIC Register Operations:
Setting priority: Each interrupt has 4 bit priority (actual chip may only support high bits, e.g., only high 3 bits).
// Configure UART1 interrupt priority to 2 (0 highest, 15 lowest)
NVIC_SetPriority(UART1_IRQn, 2 << (8 – __NVIC_PRIO_BITS));
NVIC_EnableIRQ(UART1_IRQn); // Enable interrupt
2. Best Practices for Interrupt Service Routines (ISR)
Clear interrupt flags:
void TIM2_IRQHandler(void) {
if (TIM2->SR & TIM_SR_UIF) { // Check update interrupt flag
TIM2->SR &= ~TIM_SR_UIF; // Manually clear flag
// Execute processing logic…
}
}
5. Key Operations of the Instruction Set
1. Implementation of Atomic Operations
Use `LDREX` and `STREX` to implement atomic read/write:
uint32_t atomic_increment(volatile uint32_t *value) {
uint32_t result;
do {
result = __LDREXW(value) + 1;
} while (__STREXW(result, value) != 0);
return result;
}
2. Low Power Instructions
Enter sleep mode:
__WFI(); // Wait for interrupt (enter sleep)
__WFE(); // Wait for event (requires wake-up source configuration)
6. Startup Process and Initialization Code
1. Key Steps in the Startup File (startup.s)
Initialize stack:
assembly
Reset_Handler:
LDR SP, =_estack // Load main stack pointer
BL SystemInit // Initialize clock, Flash, etc.
BL __libc_init_array // Initialize C++ global objects
BL main // Jump to main()
B . // Prevent runaway
2. Data Segment Initialization (.data and .bss)
Manually copy initialized data (when no startup file):
extern uint32_t _sdata, _edata, _sidata; // Linker script defined symbols
extern uint32_t _sbss, _ebss;
void SystemInit(void) {
// Initialize .data segment (copy from Flash to RAM)
uint32_t *src = &_sidata;
uint32_t *dst = &_sdata;
while (dst < &_edata) *dst++ = *src++;
// Zero out .bss segment
dst = &_sbss;
while (dst < &_ebss) *dst++ = 0;
}
7. Debugging and Troubleshooting Practices
1. Hard Fault Analysis
Capture HardFault LR and PC:
void HardFault_Handler(void) {
__asm(“TST LR, 4”); // Check stack frame source (MSP/PSP)
__asm(“ITE EQ”);
__asm(“MRSEQ R0, MSP”);
__asm(“MRSNE R0, PSP”);
uint32_t *stack = (uint32_t*)__get_MSP(); // Get stack pointer
uint32_t pc = stack[6]; // PC that triggered the exception
uint32_t lr = stack[5]; // LR that triggered the exception
while(1); // Breakpoint here to analyze pc and lr
}
2. Stack Overflow Detection
Use stack top fill pattern (Stack Canary):
#define STACK_CANARY 0xDEADBEEF
uint32_t *stack_end = (uint32_t*)&_estack;
*stack_end = STACK_CANARY;
// Regularly check if the stack top has been corrupted
if (*stack_end != STACK_CANARY) {
// Trigger error handling…
}
8. CMSIS Core Function Examples
1. Accessing Core Registers
Directly manipulate NVIC:
// Disable global interrupts
__disable_irq();
// Modify system tick
SysTick->LOAD = 0xFFFFFF; // Set reload value
__enable_irq();
2. Using CMSIS-RTOS for Task Scheduling
Create task (requires CMSIS-RTOS support):
osThreadId_t ledTaskHandle;
void led_task(void *arg) {
while(1) {
GPIOA->ODR ^= GPIO_ODR_OD5; // Toggle LED
osDelay(500); // Delay 500ms
}
}
int main(void) {
osKernelInitialize();
osThreadNew(led_task, NULL, NULL);
osKernelStart();
}
The programming model of Cortex-M3 requires developers to have a deep understanding of register operations, exception mechanisms, memory management, and low-level instructions. In actual development, attention should be paid to:
1. Privilege level switching must be done through exceptions or resets.
2. Interrupt service routines need to be efficient and timely in clearing flags.
3. Stack management is key to stability (especially in RTOS multi-tasking scenarios).
4. The CMSIS standard library can greatly simplify cross-platform development.
5. Debugging tools (such as J-Link) combined with HardFault analysis can quickly locate underlying issues.
It is recommended to combine with specific chip manuals (such as STM32F1xx) and ARMv7-M architecture reference manuals to deepen the practice of peripheral drivers and RTOS integration.