Proteus中STM32F103 GPIOA触发BUS_FAULT故障排查求助
STM32F103 Proteus仿真总线错误(BUS_FAULT)排查方案
我已经确认开启了GPIOA的时钟,但Proteus里的STM32F103仿真还是跑不起来,日志反复弹出这个报错:
"Access to register of unclocked peripheral at 0x40010800 cause BUS_FAULT [U1_CM3CORE]"
以下是我的汇编代码:
.cpu cortex-m3 .fpu softvfp .thumb .equ RCC_BASE, (0X40021000) .equ RCC_APB2ENR, (RCC_BASE + 0x18) .equ RCC_APB2ENR_IOAEN, 0x00000004 .equ GPIOA_BASE, (0x40010800) .equ GPIOA_CRL, (GPIOA_BASE +(0x00)) .equ GPIOA1_CRL_MASK, (0b11 << 4) .equ GPIOA1_CRL_SET_PUSH_PULL_OUTPUT, (0b00 << 4) .equ GPIOA_BSRR, (GPIOA_BASE + 0x10) .global main main: LDR R0, =RCC_APB2ENR LDR R1, [R0] LDR R2, =RCC_APB2ENR_IOAEN ORR R1, R1, R2 STR R1, [R0] NOP NOP NOP NOP LDR R0, =GPIOA_CRL LDR R1, [R0] LDR R2, =GPIOA1_CRL_MASK MVN R2, R2 AND R1, R1, R2 ORR R1, R1, GPIOA1_CRL_SET_PUSH_PULL_OUTPUT STR R1, [R0] loop: LDR R0, =GPIOA_BSRR MOV R1, #(1 << 1) STR R1, [R0] BL delay LDR R0, =GPIOA_BSRR MOV R1, #(1 << (1 + 16)) STR R1, [R0] BL delay b loop delay: MOV R2, #50000 delay_loop: SUBS R2, R2, #1 BNE delay_loop BX LR
问题根源与解决步骤
1. GPIO引脚配置的位掩码和模式错误
STM32F1的GPIO CRL寄存器中,每个引脚对应4位(CNF[1:0] + MODE[1:0]),你的代码里只设置了2位的掩码和模式,导致配置不完整:
GPIOA1_CRL_MASK只覆盖了MODE位(低2位),没清除CNF位(高2位),残留的旧配置会导致外设状态异常GPIOA1_CRL_SET_PUSH_PULL_OUTPUT设为0b00 <<4是输入模式,不是推挽输出,后续操作输出寄存器会触发错误
修正代码:
.equ GPIOA1_CRL_MASK, (0b1111 << 4) // 覆盖PA1对应的全部4位 .equ GPIOA1_CRL_SET_PUSH_PULL_OUTPUT, (0b0011 << 4) // 推挽输出(CNF=00)+ 50MHz速率(MODE=11)
2. 优化时钟使能代码(可选)
原代码用LDR加载立即数可以简化为直接用立即数操作,减少指令周期:
// 替换原时钟使能代码段 LDR R0, =RCC_APB2ENR LDR R1, [R0] ORR R1, R1, #RCC_APB2ENR_IOAEN // 直接用立即数,无需LDR加载 STR R1, [R0]
另外,加的4个NOP完全没必要,硬件上时钟使能是立即生效的,仿真中也不需要额外等待。
3. Proteus仿真环境检查
- 确认选用的STM32模型是STM32F103C8T6(或对应型号),部分冷门模型的寄存器仿真逻辑有bug
- 打开Proteus的系统配置,确保勾选了「Peripheral Clock Simulation」选项,否则仿真不会识别时钟使能操作
- 清空仿真缓存,重新生成hex文件并加载,有时候旧缓存会导致配置不生效
修改后的完整代码
.cpu cortex-m3 .fpu softvfp .thumb .equ RCC_BASE, (0X40021000) .equ RCC_APB2ENR, (RCC_BASE + 0x18) .equ RCC_APB2ENR_IOAEN, 0x00000004 .equ GPIOA_BASE, (0x40010800) .equ GPIOA_CRL, (GPIOA_BASE + 0x00) .equ GPIOA1_CRL_MASK, (0b1111 << 4) .equ GPIOA1_CRL_SET_PUSH_PULL_OUTPUT, (0b0011 << 4) .equ GPIOA_BSRR, (GPIOA_BASE + 0x10) .global main main: // 使能GPIOA时钟 LDR R0, =RCC_APB2ENR LDR R1, [R0] ORR R1, R1, #RCC_APB2ENR_IOAEN STR R1, [R0] // 配置PA1为推挽输出 LDR R0, =GPIOA_CRL LDR R1, [R0] LDR R2, =GPIOA1_CRL_MASK MVN R2, R2 AND R1, R1, R2 ORR R1, R1, GPIOA1_CRL_SET_PUSH_PULL_OUTPUT STR R1, [R0] loop: // PA1置高 LDR R0, =GPIOA_BSRR MOV R1, #(1 << 1) STR R1, [R0] BL delay // PA1置低 LDR R0, =GPIOA_BSRR MOV R1, #(1 << (1 + 16)) STR R1, [R0] BL delay b loop delay: MOV R2, #50000 delay_loop: SUBS R2, R2, #1 BNE delay_loop BX LR
内容的提问来源于stack exchange,提问作者Long Phan
相关产品推荐
相关产品推荐

