ARM Cortex-M3 是 ARM 公司推出的一种高性能、低功耗、低成本的 32 位 RISC 微处理器架构,广泛应用于嵌入式系统中。本节将详细介绍 ARM Cortex-M3 架构的特点、内部结构、寄存器配置和中断处理机制。
ARM Cortex-M3 是一种基于 RISC(精简指令集计算机)架构的处理器。RISC 架构的特点是:
ARM Cortex-M3 处理器核包括以下几个主要部分:
从内存中取出指令并放入指令流水线。
将取出的指令解码为微操作,准备执行。
执行解码后的微操作,完成指令的功能。
ARM Cortex-M3 的内存地址空间通常分为以下几个区域:
MPU 可以配置多个区域,每个区域有不同的访问权限和属性。通过 MPU,可以保护关键的内存区域,防止非法访问。
NVIC 是 ARM Cortex-M3 中的重要组件,用于管理和控制中断。它支持多个中断源,并可以配置中断优先级和嵌套中断。
中断向量表包含各个中断向量的地址,处理器在发生中断时会跳转到相应的中断处理程序。中断向量表通常位于闪存的起始地址。
系统异常是一类特殊的中断,用于处理系统的各种异常情况,如复位、NMI、硬故障等。
Thumb-2 指令集是 ARM Cortex-M3 的一大特点,它结合了 16 位和 32 位指令的优势:
// 将寄存器 R1 的值加 1 并存储到 R2
ADD R2, R1, #1
// 将寄存器 R1 和 R2 的值进行逻辑与操作,结果存储到 R3
AND R3, R1, R2
// 将寄存器 R1 的值左移 2 位,结果存储到 R2
LSL R2, R1, #2
// 从地址 0x20000000 加载一个 32 位数据到寄存器 R0
LDR R0, [0x20000000]
// 将寄存器 R1 的值存储到地址 0x20000004
STR R1, [0x20000004]
// 从地址 0x20000008 开始批量加载 4 个 32 位数据到寄存器 R2-R5
LDM R2, R5, [0x20000008]!
// 从寄存器 R2 开始批量存储 4 个 32 位数据到地址 0x2000000C
STM R2, R5, [0x2000000C]!
// 无条件跳转到地址 0x00000100
B 0x00000100
// 跳转到地址 0x00000200,并将返回地址存储到寄存器 LR
BL 0x00000200
// 跳转到寄存器 R1 中的地址
BX R1
// 如果寄存器 R0 大于等于寄存器 R1,跳转到 label
CMP R0, R1
BGE label
中断向量表通常位于闪存的起始地址,包含各个中断和异常的处理程序地址。以下是一个典型的中断向量表布局:
// 中断向量表
VECTOR_TABLE:
.word _estack // 栈顶地址
.word Reset_Handler // 复位中断处理程序
.word NMI_Handler // NMI 中断处理程序
.word Hard_Fault_Handler // 硬故障处理程序
.word MemManage_Handler // 存储器管理故障处理程序
.word Bus_Fault_Handler // 总线故障处理程序
.word Usage_Fault_Handler // 使用故障处理程序
.word 0 // 保留
.word 0 // 保留
.word 0 // 保留
.word 0 // 保留
.word SVC_Handler // 服务调用处理程序
.word DebugMon_Handler // 调试监控处理程序
.word 0 // 保留
.word PendSV_Handler // 挂起服务处理程序
.word SysTick_Handler // 系统定时器处理程序
.word IRQ0_Handler // 中断 0 处理程序
.word IRQ1_Handler // 中断 1 处理程序
// 其他中断处理程序
中断处理程序的编写需要遵循一定的规范,以确保中断能够正确处理。以下是一个简单的中断处理程序示例:
// 外部中断 0 处理程序
void IRQ0_Handler(void) {
// 处理中断
// 例如:读取某个 GPIO 引脚的状态
uint32_t gpio_status = LPC_GPIO0->FIOPIN;
// 根据 GPIO 状态进行相应处理
if (gpio_status & (1 << 0)) {
// 引脚 0 高电平
// 执行相应操作
} else {
// 引脚 0 低电平
// 执行相应操作
}
// 清除中断标志
LPC_GPIO0->FIOPIN = 0x00;
}
// 系统定时器中断处理程序
void SysTick_Handler(void) {
static uint32_t counter = 0;
// 增加计数器
counter++;
// 每 10 次中断,执行一次任务
if (counter >= 10) {
// 执行任务
// 例如:更新某个外设的状态
counter = 0;
}
}
系统异常处理程序用于处理系统的各种异常情况。以下是一个简单的硬故障处理程序示例:
// 硬故障处理程序
void Hard_Fault_Handler(void) {
// 保存当前状态
uint32_t stacked_r0;
uint32_t stacked_r1;
uint32_t stacked_r2;
uint32_t stacked_r3;
uint32_t stacked_r12;
uint32_t stacked_lr;
uint32_t stacked_pc;
uint32_t stacked_psr;
__asm volatile (
"TST lr, #4\t\n"
"ITE EQ\t\n"
"MRSEQ r0, msp\t\n"
"MRSNE r0, psp\t\n"
"BIC r1, lr, #4\t\n"
"TST r1, #0xC\t\n"
"BNE lr_not_8_or_12\t\n"
"LDR r2, [r0, #24]\t\n" // stacked PC
"B lr_is_8_or_12\t\n"
"lr_not_8_or_12:\t\n"
"MOVS r2, lr\t\n"
"LSLS r2, r2, #30\t\n"
"LSRS r2, r2, #30\t\n"
"TST r2, #2\t\n"
"BNE in_handler\t\n"
"LDR r2, [r0, #18]\t\n" // stacked PC
"B lr_processed\t\n"
"in_handler:\t\n"
"LDR r2, [r0, #30]\t\n" // handler mode SP
"SUBS r2, r2, #4\t\n"
"LDR r2, [r2]\t\n" // stacked PC
"lr_processed:\t\n"
"LDR r3, [r2, #-4]!\t\n" // stacked PSR
"LDR r12, [r2, #-4]!\t\n" // stacked R12
"LDR r1, [r2, #-4]!\t\n" // stacked R1
"LDR r0, [r2, #-4]!\t\n" // stacked R0
"LDR r1, [r2, #-4]!\t\n" // stacked R1
"LDR r2, [r2, #-4]!\t\n" // stacked R2
"LDR r3, [r2, #-4]!\t\n" // stacked R3
"LDR lr, [r2, #-4]!\t\n" // stacked LR
"LDR pc, [r2, #-4]!\t\n" // stacked PC
);
// 打印硬故障信息
printf("Hard Fault!\n");
// 挂起系统
while (1) {
// 无限循环
}
}
JTAG(联合测试行动组)接口是一种标准的调试接口,支持边界扫描测试和调试功能。ARM Cortex-M3 支持 JTAG 接口,可以使用 JTAG 调试器进行调试。
SWD(串行线调试)接口是 ARM 公司推出的一种新的调试接口,比 JTAG 接口更简单、更高效。ARM Cortex-M3 支持 SWD 接口,可以使用 SWD 调试器进行调试。
以下是一个使用 SWD 接口进行调试的示例:
#include
#include "LPC17xx.h"
int main(void) {
// 初始化 GPIO
LPC_PINCON->PINSEL0 &= ~(0x3 << 0); // 设置 P0.0 为 GPIO 功能
LPC_GPIO0->FIOSET = (1 << 0); // 设置 P0.0 为高电平
LPC_GPIO0->FIODIR = (1 << 0); // 设置 P0.0 为输出
while (1) {
// 翻转 P0.0 引脚的状态
LPC_GPIO0->FIOSET = (1 << 0);
for (volatile int i = 0; i < 1000000; i++) {
// 延时
}
LPC_GPIO0->FIOCLR = (1 << 0);
for (volatile int i = 0; i < 1000000; i++) {
// 延时
}
// 设置断点
__asm volatile ("bkpt #0");
}
return 0;
}
常用的调试工具包括:
ARM Cortex-M3 架构具有高性能、低功耗和高可靠性的特点,适合应用于各种嵌入式系统。本节详细介绍了 ARM Cortex-M3 的内部结构、流水线操作、寄存器配置、中断处理和调试支持,为后续的学习和开发提供了坚实的基础。
ARM Cortex-M3 是 ARM 公司推出的一种高性能、低功耗、低成本的 32 位 RISC 微处理器架构,广泛应用于嵌入式系统中。本节将详细介绍 ARM Cortex-M3 架构的特点、内部结构、寄存器配置和中断处理机制。为了更好地理解这些内容,我们将重复一些前文的关键信息,并在此基础上继续深入探讨。
ARM Cortex-M3 是一种基于 RISC(精简指令集计算机)架构的处理器。RISC 架构的特点是:
ARM Cortex-M3 处理器核包括以下几个主要部分:
从内存中取出指令并放入指令流水线。
将取出的指令解码为微操作,准备执行。
执行解码后的微操作,完成指令的功能。
ARM Cortex-M3 的内存地址空间通常分为以下几个区域:
MPU 可以配置多个区域,每个区域有不同的访问权限和属性。通过 MPU,可以保护关键的内存区域,防止非法访问。
NVIC 是 ARM Cortex-M3 中的重要组件,用于管理和控制中断。它支持多个中断源,并可以配置中断优先级和嵌套中断。
中断向量表通常位于闪存的起始地址,包含各个中断和异常的处理程序地址。以下是一个典型的中断向量表布局:
// 中断向量表
VECTOR_TABLE:
.word _estack // 栈顶地址
.word Reset_Handler // 复位中断处理程序
.word NMI_Handler // NMI 中断处理程序
.word Hard_Fault_Handler // 硬故障处理程序
.word MemManage_Handler // 存储器管理故障处理程序
.word Bus_Fault_Handler // 总线故障处理程序
.word Usage_Fault_Handler // 使用故障处理程序
.word 0 // 保留
.word 0 // 保留
.word 0 // 保留
.word 0 // 保留
.word SVC_Handler // 服务调用处理程序
.word DebugMon_Handler // 调试监控处理程序
.word 0 // 保留
.word PendSV_Handler // 挂起服务处理程序
.word SysTick_Handler // 系统定时器处理程序
.word IRQ0_Handler // 中断 0 处理程序
.word IRQ1_Handler // 中断 1 处理程序
// 其他中断处理程序
系统异常处理程序用于处理系统的各种异常情况。以下是一个简单的硬故障处理程序示例:
// 硬故障处理程序
void Hard_Fault_Handler(void) {
// 保存当前状态
uint32_t stacked_r0;
uint32_t stacked_r1;
uint32_t stacked_r2;
uint32_t stacked_r3;
uint32_t stacked_r12;
uint32_t stacked_lr;
uint32_t stacked_pc;
uint32_t stacked_psr;
__asm volatile (
"TST lr, #4\t\n"
"ITE EQ\t\n"
"MRSEQ r0, msp\t\n"
"MRSNE r0, psp\t\n"
"BIC r1, lr, #4\t\n"
"TST r1, #0xC\t\n"
"BNE lr_not_8_or_12\t\n"
"LDR r2, [r0, #24]\t\n" // stacked PC
"B lr_is_8_or_12\t\n"
"lr_not_8_or_12:\t\n"
"MOVS r2, lr\t\n"
"LSLS r2, r2, #30\t\n"
"LSRS r2, r2, #30\t\n"
"TST r2, #2\t\n"
"BNE in_handler\t\n"
"LDR r2, [r0, #18]\t\n" // stacked PC
"B lr_processed\t\n"
"in_handler:\t\n"
"LDR r2, [r0, #30]\t\n" // handler mode SP
"SUBS r2, r2, #4\t\n"
"LDR r2, [r2]\t\n" // stacked PC
"lr_processed:\t\n"
"LDR r3, [r2, #-4]!\t\n" // stacked PSR
"LDR r12, [r2, #-4]!\t\n" // stacked R12
"LDR r1, [r2, #-4]!\t\n" // stacked R1
"LDR r0, [r2, #-4]!\t\n" // stacked R0
"LDR r1, [r2, #-4]!\t\n" // stacked R1
"LDR r2, [r2, #-4]!\t\n" // stacked R2
"LDR r3, [r2, #-4]!\t\n" // stacked R3
"LDR lr, [r2, #-4]!\t\n" // stacked LR
"LDR pc, [r2, #-4]!\t\n" // stacked PC
);
// 打印硬故障信息
printf("Hard Fault!\n");
// 挂起系统
while (1) {
// 无限循环
}
}
Thumb-2 指令集是 ARM Cortex-M3 的一大特点,它结合了 16 位和 32 位指令的优势:
// 将寄存器 R1 的值加 1 并存储到 R2
ADD R2, R1, #1
// 将寄存器 R1 和 R2 的值进行逻辑与操作,结果存储到 R3
AND R3, R1, R2
// 将寄存器 R1 的值左移 2 位,结果存储到 R2
LSL R2, R1, #2
// 从地址 0x20000000 加载一个 32 位数据到寄存器 R0
LDR R0, [0x20000000]
// 将寄存器 R1 的值存储到地址 0x20000004
STR R1, [0x20000004]
// 从地址 0x20000008 开始批量加载 4 个 32 位数据到寄存器 R2-R5
LDM R2, R5, [0x20000008]!
// 从寄存器 R2 开始批量存储 4 个 32 位数据到地址 0x2000000C
STM R2, R5, [0x2000000C]!
// 无条件跳转到地址 0x00000100
B 0x00000100
// 跳转到地址 0x00000200,并将返回地址存储到寄存器 LR
BL 0x00000200
// 跳转到寄存器 R1 中的地址
BX R1
// 如果寄存器 R0 大于等于寄存器 R1,跳转到 label
CMP R0, R1
BGE label
中断向量表通常位于闪存的起始地址,包含各个中断和异常的处理程序地址。以下是一个典型的中断向量表布局:
// 中断向量表
VECTOR_TABLE:
.word _estack // 栈顶地址
.word Reset_Handler // 复位中断处理程序
.word NMI_Handler // NMI 中断处理程序
.word Hard_Fault_Handler // 硬故障处理程序
.word MemManage_Handler // 存储器管理故障处理程序
.word Bus_Fault_Handler // 总线故障处理程序
.word Usage_Fault_Handler // 使用故障处理程序
.word 0 // 保留
.word 0 // 保留
.word 0 // 保留
.word 0 // 保留
.word SVC_Handler // 服务调用处理程序
.word DebugMon_Handler // 调试监控处理程序
.word 0 // 保留
.word PendSV_Handler // 挂起服务处理程序
.word SysTick_Handler // 系统定时器处理程序
.word IRQ0_Handler // 中断 0 处理程序
.word IRQ1_Handler // 中断 1 处理程序
// 其他中断处理程序
中断处理程序的编写需要遵循一定的规范,以确保中断能够正确处理。以下是一个简单的中断处理程序示例:
// 外部中断 0 处理程序
void IRQ0_Handler(void) {
// 处理中断
// 例如:读取某个 GPIO 引脚的状态
uint32_t gpio_status = LPC_GPIO0->FIOPIN;
// 根据 GPIO 状态进行相应处理
if (gpio_status & (1 << 0)) {
// 引脚 0 高电平
// 执行相应操作
} else {
// 引脚 0 低电平
// 执行相应操作
}
// 清除中断标志
LPC_GPIO0->FIOPIN = 0x00;
}
// 系统定时器中断处理程序
void SysTick_Handler(void) {
static uint32_t counter = 0;
// 增加计数器
counter++;
// 每 10 次中断,执行一次任务
if (counter >= 10) {
// 执行任务
// 例如:更新某个外设的状态
counter = 0;
}
}
系统异常处理程序用于处理系统的各种异常情况。以下是一个简单的硬故障处理程序示例:
// 硬故障处理程序
void Hard_Fault_Handler(void) {
// 保存当前状态
uint32_t stacked_r0;
uint32_t stacked_r1;
uint32_t stacked_r2;
uint32_t stacked_r3;
uint32_t stacked_r12;
uint32_t stacked_lr;
uint32_t stacked_pc;
uint32_t stacked_psr;
__asm volatile (
"TST lr, #4\t\n"
"ITE EQ\t\n"
"MRSEQ r0, msp\t\n"
"MRSNE r0, psp\t\n"
"BIC r1, lr, #4\t\n"
"TST r1, #0xC\t\n"
"BNE lr_not_8_or_12\t\n"
"LDR r2, [r0, #24]\t\n" // stacked PC
"B lr_is_8_or_12\t\n"
"lr_not_8_or_12:\t\n"
"MOVS r2, lr\t\n"
"LSLS r2, r2, #30\t\n"
"LSRS r2, r2, #30\t\n"
"TST r2, #2\t\n"
"BNE in_handler\t\n"
"LDR r2, [r0, #18]\t\n" // stacked PC
"B lr_processed\t\n"
"in_handler:\t\n"
"LDR r2, [r0, #30]\t\n" // handler mode SP
"SUBS r2, r2, #4\t\n"
"LDR r2, [r2]\t\n" // stacked PC
"lr_processed:\t\n"
"LDR r3, [r2, #-4]!\t\n" // stacked PSR
"LDR r12, [r2, #-4]!\t\n" // stacked R12
"LDR r1, [r2, #-4]!\t\n" // stacked R1
"LDR r0, [r2, #-4]!\t\n" // stacked R0
"LDR r1, [r2, #-4]!\t\n" // stacked R1
"LDR r2, [r2, #-4]!\t\n" // stacked R2
"LDR r3, [r2, #-4]!\t\n" // stacked R3
"LDR lr, [r2, #-4]!\t\n" // stacked LR
"LDR pc, [r2, #-4]!\t\n" // stacked PC
);
// 打印硬故障信息
printf("Hard Fault!\n");
// 挂起系统
while (1) {
// 无限循环
}
}
ARM Cortex-M3 支持多个中断源,并且每个中断源都有一个优先级。NVIC 可以配置中断优先级,以便在多个中断同时发生时确定处理顺序。此外,ARM Cortex-M3 还支持嵌套中断,即在处理一个中断时可以被更高优先级的中断打断。
中断优先级可以通过 NVIC 的中断优先级寄存器(IPR)进行配置。以下是一个配置中断优先级的示例:
// 配置中断 0 的优先级为 1
NVIC_SetPriority(IRQ0_IRQn, 1);
// 配置中断 1 的优先级为 2
NVIC_SetPriority(IRQ1_IRQn, 2);
// 假设中断 0 的优先级高于中断 1
// 中断 0 处理程序
void IRQ0_Handler(void) {
// 处理中断 0
// 例如:读取某个 GPIO 引脚的状态
uint32_t gpio_status = LPC_GPIO0->FIOPIN;
// 根据 GPIO 状态进行相应处理
if (gpio_status & (1 << 0)) {
// 引脚 0 高电平
// 执行相应操作
} else {
// 引脚 0 低电平
// 执行相应操作
}
// 清除中断标志
LPC_GPIO0->FIOPIN = 0x00;
}
// 中断 1 处理程序
void IRQ1_Handler(void) {
// 处理中断 1
// 例如:读取某个 ADC 的值
uint32_t adc_value = LPC_ADC->ADGDR;
// 根据 ADC 值进行相应处理
if (adc_value > 1000) {
// 执行相应操作
} else {
// 执行相应操作
}
// 清除中断标志
LPC_ADC->ADGDR = 0x00;
}
在上述示例中,如果中断 1 正在处理,中断 0 发生且优先级更高,那么中断 0 会打断中断 1 的处理,先处理中断 0。处理完中断 0 后,再继续处理中断 1。
JTAG(联合测试行动组)接口是一种标准的调试接口,支持边界扫描测试和调试功能。ARM Cortex-M3 支持 JTAG 接口,可以使用 JTAG 调试器进行调试。
SWD(串行线调试)接口是 ARM 公司推出的一种新的调试接口,比 JTAG 接口更简单、更高效。ARM Cortex-M3 支持 SWD 接口,可以使用 SWD 调试器进行调试。
以下是一个使用 SWD 接口进行调试的示例:
#include
#include "LPC17xx.h"
int main(void) {
// 初始化 GPIO
LPC_PINCON->PINSEL0 &= ~(0x3 << 0); // 设置 P0.0 为 GPIO 功能
LPC_GPIO0->FIOSET = (1 << 0); // 设置 P0.0 为高电平
LPC_GPIO0->FIODIR = (1 << 0); // 设置 P0.0 为输出
while (1) {
// 翻转 P0.0 引脚的状态
LPC_GPIO0->FIOSET = (1 << 0);
for (volatile int i = 0; i < 1000000; i++) {
// 延时
}
LPC_GPIO0->FIOCLR = (1 << 0);
for (volatile int i = 0; i < 1000000; i++) {
// 延时
}
// 设置断点
__asm volatile ("bkpt #0");
}
return 0;
}
常用的调试工具包括:
ARM Cortex-M3 架构具有高性能、低功耗和高可靠性的特点,适合应用于各种嵌入式系统。本节详细介绍了 ARM Cortex-M3 的内部结构、流水线操作、寄存器配置、中断处理和调试支持,为后续的学习和开发提供了坚实的基础。
ARM Cortex-M3 的内部结构包括:
流水线操作分为三个阶段:
寄存器配置包括:
存储器访问包括:
中断处理包括:
调试支持包括:
通过以上内容,我们对 ARM Cortex-M3 架构有了全面的了解。希望这些信息能够帮助你在嵌入式系统开发中更好地利用 ARM Cortex-M3 的优势。