Keil MDK 4.23 仿真 STM32F4 配置总结与简单解析

这里的仿真是指电脑仿真,而不是在线仿真。

最近刚刚入门STM32F4系列,在MDK仿真问题上卡住了一段时间。查帖子,有的人说4.23不可以但高版本可以,有的人说高版本也不行,也有的人说4.23就能仿真。

我这里用的是MDK4.23实现STM32F407VET6的电脑仿真,不过其他型号STM32F4芯片、更高版本MDK应该也可以。

下面就从一个简单工程开始说明配置过程,图多也略繁琐,建议高手跳着看。

另外只是寻找仿真配置方式的读者可以直接跳到末尾看结论。



下文包含的内容:
1)建立简单的示例工程
2)解决第一个问题:仿真起始地址不对同时读权限错误
3)解决第二个问题:仿真出现HardFault
4)解决第三个问题:运行过程中地址读写权限错误
5)总结

- - - - - - - - - - - - - - - - 华丽丽的分割线 - - - - - - - - - - - - - - - - 


建立工程的过程很基本,就不多说了。






我们只是建立一个最简单的工程。需要的文件,除了MDK会自动添加Startup汇编代码之外,还有
stm32f4xx.h
system_stm32f4xx.c
system_stm32f4xx.h
main.c



main.c用户程序也写得很简单,基本的程序框架。



这时候看看默认的项目配置,Alt + F7,或者Project->Options for target "xxx"
在Target这一页,下方定义了各个段的地址和大小。IROM就是程序指令存放的位置了,IRAM是片上内存。

地址和大小应该是根据具体芯片样本的,如下图



这里样本中Flash就对应IROM,存放程序代码;样本中SRAM对应IRAM。
另外能看到,MDK配置中另一个IRAM是对应了CCM data RAM。



Linker页。这里会配置如何链接各obj文件来生成目标文件。这里也有区段的配置,不过默认是与前面Target页的配置保持一致。



Debug页,电脑仿真要选择左边Use Simulator,看情况如果从Startup开始调试,就可以取消复选框Run to main.



编译没有问题。



按Ctrl + F5开始仿真,这时候就遇到问题了,提示没有读权限。

- - - - - - - - - - - - - - - - 华丽丽的分割线 - - - - - - - - - - - - - - - - 

这时在工程目录里创建一个debug.ini文件(实际上文件名任意),输入内容

map 0x00000000,0x00010000 read

 


这句话是说,把芯片的地址0x00000000 ~ 0x00010000这段区域设置成可读的。



然后在Debug配置中引用这个初始化文件。

这时候再启动调试,应该不会报错了,但还是有问题:




从反编译窗口可以看出两个问题:
1)起始地址是0x0000 0000,这不是我们想要的地址。
2)在这个地址上,很大部分是0,即内容是空的。

如果这时候看看应该存放代码的区段,从0x0800 0000开始的内容:



这里是有内容的。

所以现在要做的,就是改变仿真CPU开始执行的地址。
方法还是通过初始化文件。修改前面那个debug.ini

map 0x00000000,0x00010000 read

 

FUNC void Setup (void) {

  SP   = _RDWORD(0x08000000);

  PC   = _RDWORD(0x08000004); 

  _WDWORD(0xE000ED08, 0x08000000);

}

 

Setup();

 



这段可以从MDK自带的例子中找到,地址是<Keil>\ARM\Boards\ST\STM32F4-Discovery\Blinky\Dbg_RAM.ini
(顺便说一句,遇到问题多看demo还是很有用的)
不过这个Dbg_RAM.ini文件没法直接用,我修改了一下。

说明:
在代码段一开始就是中断向量表。从startup就能看出来:

; Vector Table Mapped to Address 0 at Reset

                AREA    RESET, DATA, READONLY

                EXPORT  __Vectors

                EXPORT  __Vectors_End

                EXPORT  __Vectors_Size

 

__Vectors       DCD     __initial_sp               ; Top of Stack

                DCD     Reset_Handler              ; Reset Handler

                DCD     NMI_Handler                ; NMI Handler

                DCD     HardFault_Handler          ; Hard Fault Handler

                DCD     MemManage_Handler          ; MPU Fault Handler

                DCD     BusFault_Handler           ; Bus Fault Handler

                DCD     UsageFault_Handler         ; Usage Fault Handler

......

 


后面还有很多。第一个DWORD是栈顶指针,就是说CPU开始运行后栈寄存器SP应该指向的地方;第二个DWORD是Reset Handler地址,就是程序开始执行的地址。

所以初始化文件debug.ini中在仿真开始时执行Setup()过程,把代码段0x0800 0000开始的第一个DWROD赋值给SP,把第二个DWORD赋值给PC,这样程序就可以从头开始执行了。
第三行_WDWORD(0xE000ED08, 0x08000000);
是对0xE000ED08这个寄存器赋值0x08000000。这个寄存器是SCB_VTOR,存放的是中断向量表的表头地址。

修改过debug.ini,按Ctrl + F5仿真



这样就可以了吗?按F11步进,发现又出错了。



这次不是MDK出错,而是仿真的CPU直接跳到了HardFault_Handler,就是说CPU认为出现了HardFault。
这个地方我好久才发现问题。原来是xPSR寄存器的初始值有问题。
PSR在ST官网的Cortex-M3 programming manual文档中有描述。



图3的APSR、IPSR和EPSR合并起来就是PSR寄存器。问题出在EPSR的24位T位上。这个位应该总是1,不是1就会出错。



所以要在初始化文件debug.ini中加入相应的初始赋值。同时,由于地址段0x00000000开始的那部分不再访问了,所以可以丢掉最初的map指令。
现在这个初始化文件debug.ini变成了

FUNC void Setup (void) {

  xPSR = 1<<24;

  SP   = _RDWORD(0x08000000);

  PC   = _RDWORD(0x08000004);

  _WDWORD(0xE000ED08, 0x08000000);

}

Setup();

 



多了xPSR = 1<<24;这一行对xPSR赋值。这下可以开始仿真了,按F11一步一步都能跑。

后面又遇到了问题,跑到SystemInit()函数里面:




提示0x4000 0000开始的一个地址段内访问错误。看样本地址空间说明,能看到这一段是外设(Peripherals)的地址空间。对UART、SPI、Timer等访问时就会访问到这个地址段。



同样会访问到的还有Cortex-M4's internal peripherals段、FSMC registers段等等,根据实际情况可以加入相应的map地址空间权限映射。
比如只增加Peripheral和Cortex-M4's internal peripherals,可以加入下面的指令:
map 0x40000000, 0x40007FFF // APB1
map 0x40010000, 0x400157FF // APB2
map 0x40020000, 0x4007FFFF // AHB1
map 0x50000000, 0x50060BFF // AHB2
map 0x60000000, 0xA0000FFF // AHB3
map 0xE0000000, 0xE00FFFFF // CORTEX-M4 internal peripherals

这样完整的初始化文件debug.ini是:

map 0x40000000, 0x40007FFF read write // APB1

map 0x40010000, 0x400157FF read write // APB2

map 0x40020000, 0x4007FFFF read write // AHB1

map 0x50000000, 0x50060BFF read write // AHB2

map 0x60000000, 0xA0000FFF read write // AHB3

map 0xE0000000, 0xE00FFFFF read write // CORTEX-M4 internal peripherals

 

FUNC void Setup (void) {

  xPSR = 1<<24;

  SP   = _RDWORD(0x08000000);

  PC   = _RDWORD(0x08000004); 

  _WDWORD(0xE000ED08, 0x08000000);

}

 

Setup();

 







现在可以顺利执行到用户代码init()了。


- - - - - - - - - - - - - - - - 华丽丽的分割线 - - - - - - - - - - - - - - - - 

总结:
仿真STM32F4时,系统只是简单加载了程序文件,而没有做一下关键的几个初始化:
1)根据仿真文件设置PC和SP初始值
2)设置xPSR初始值
3)设置地址空间的权限。

所以我们需要建立初始化文件来完成上述三个关键初始化。初始化文件代码我在这里重复贴一遍:

map 0x40000000, 0x40007FFF read write // APB1

map 0x40010000, 0x400157FF read write // APB2

map 0x40020000, 0x4007FFFF read write // AHB1

map 0x50000000, 0x50060BFF read write // AHB2

map 0x60000000, 0xA0000FFF read write // AHB3

map 0xE0000000, 0xE00FFFFF read write // CORTEX-M4 internal peripherals

 

FUNC void Setup (void) {

  xPSR = 1<<24;

  SP   = _RDWORD(0x08000000);

  PC   = _RDWORD(0x08000004); 

  _WDWORD(0xE000ED08, 0x08000000);

}

 

Setup();

 



代码中map命令用来设置地址空间权限,Setup过程用来对CPU寄存器赋初始值。

  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值