搜索
bottom↓
回复: 16

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

[复制链接]

出0入0汤圆

发表于 2015-1-12 12:49:54 | 显示全部楼层 |阅读模式
本帖最后由 fnems 于 2015-1-12 12:58 编辑

本帖只是对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文件(实际上文件名任意),输入内容
  1. map 0x00000000,0x00010000 read
复制代码

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



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

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




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

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



这里是有内容的。

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

  2. FUNC void Setup (void) {
  3.   SP   = _RDWORD(0x08000000);
  4.   PC   = _RDWORD(0x08000004);
  5.   _WDWORD(0xE000ED08, 0x08000000);
  6. }

  7. Setup();
复制代码


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

说明:
在代码段一开始就是中断向量表。从startup就能看出来:
  1. ; Vector Table Mapped to Address 0 at Reset
  2.                 AREA    RESET, DATA, READONLY
  3.                 EXPORT  __Vectors
  4.                 EXPORT  __Vectors_End
  5.                 EXPORT  __Vectors_Size

  6. __Vectors       DCD     __initial_sp               ; Top of Stack
  7.                 DCD     Reset_Handler              ; Reset Handler
  8.                 DCD     NMI_Handler                ; NMI Handler
  9.                 DCD     HardFault_Handler          ; Hard Fault Handler
  10.                 DCD     MemManage_Handler          ; MPU Fault Handler
  11.                 DCD     BusFault_Handler           ; Bus Fault Handler
  12.                 DCD     UsageFault_Handler         ; Usage Fault Handler
  13. ......
复制代码

后面还有很多。第一个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变成了
  1. FUNC void Setup (void) {
  2.   xPSR = 1<<24;
  3.   SP   = _RDWORD(0x08000000);
  4.   PC   = _RDWORD(0x08000004);
  5.   _WDWORD(0xE000ED08, 0x08000000);
  6. }
  7. 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是:
  1. map 0x40000000, 0x40007FFF read write // APB1
  2. map 0x40010000, 0x400157FF read write // APB2
  3. map 0x40020000, 0x4007FFFF read write // AHB1
  4. map 0x50000000, 0x50060BFF read write // AHB2
  5. map 0x60000000, 0xA0000FFF read write // AHB3
  6. map 0xE0000000, 0xE00FFFFF read write // CORTEX-M4 internal peripherals

  7. FUNC void Setup (void) {
  8.   xPSR = 1<<24;
  9.   SP   = _RDWORD(0x08000000);
  10.   PC   = _RDWORD(0x08000004);
  11.   _WDWORD(0xE000ED08, 0x08000000);
  12. }

  13. Setup();
复制代码






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


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

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

所以我们需要建立初始化文件来完成上述三个关键初始化。初始化文件代码我在这里重复贴一遍:
  1. map 0x40000000, 0x40007FFF read write // APB1
  2. map 0x40010000, 0x400157FF read write // APB2
  3. map 0x40020000, 0x4007FFFF read write // AHB1
  4. map 0x50000000, 0x50060BFF read write // AHB2
  5. map 0x60000000, 0xA0000FFF read write // AHB3
  6. map 0xE0000000, 0xE00FFFFF read write // CORTEX-M4 internal peripherals

  7. FUNC void Setup (void) {
  8.   xPSR = 1<<24;
  9.   SP   = _RDWORD(0x08000000);
  10.   PC   = _RDWORD(0x08000004);
  11.   _WDWORD(0xE000ED08, 0x08000000);
  12. }

  13. Setup();
复制代码


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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2015-1-12 19:16:18 | 显示全部楼层
感谢楼主分享  这个问题以前遇到过 但是没有想过怎么解决 非常感谢楼主 虽然一般都是直接硬件仿真 但还是需要学习一下

出0入0汤圆

发表于 2015-1-12 19:28:45 | 显示全部楼层
再次感谢 刚才试了一下 果然可以软件仿真了 并且试了一个LED灯反转的程序 发现可以通过示波器Logic Analyzer查看具体的波形

出0入0汤圆

 楼主| 发表于 2015-1-12 19:49:24 | 显示全部楼层
湛无双 发表于 2015-1-12 19:28
再次感谢 刚才试了一下 果然可以软件仿真了 并且试了一个LED灯反转的程序 发现可以通过示波器Logic Analyze ...


能硬件仿真肯定更方便,哈哈。
F103的版本还能看外设的具体配置,电脑仿真的时候Peripheral菜单下各个外设都能找到。
但F4系列都不再考虑模拟外设对话框了,所以相对来说排错的实用性降低了不少。

出0入0汤圆

发表于 2015-1-12 20:26:03 | 显示全部楼层
写的很仔细 ,楼主辛苦啦 !

出0入0汤圆

发表于 2015-1-12 21:34:10 | 显示全部楼层
不错的资料,学习了

出0入0汤圆

发表于 2015-1-12 21:42:09 | 显示全部楼层
好像用207的一个型号就可以仿真了,反正代码是兼容的。楼主这个也很不错,就是这样的话看外设寄存器不方便

出0入0汤圆

 楼主| 发表于 2015-1-12 22:30:39 | 显示全部楼层
本帖最后由 fnems 于 2015-1-12 22:31 编辑
albert.hu 发表于 2015-1-12 21:42
好像用207的一个型号就可以仿真了,反正代码是兼容的。楼主这个也很不错,就是这样的话看外设寄存器不方便 ...



没有FPU怎么破呢?外设也不一样吧
感觉一般用F4都是冲着FPU、DSP指令和高SYSCLK速度去的,这些都没法简单替换

出0入0汤圆

发表于 2015-1-29 22:36:11 | 显示全部楼层
写的很详细,点赞,其实以前的版本都是可以软仿的.只是不知道为什么版本越高级,对工程师要求越高.

出0入0汤圆

 楼主| 发表于 2015-1-30 21:43:35 | 显示全部楼层
swortering 发表于 2015-1-29 22:36
写的很详细,点赞,其实以前的版本都是可以软仿的.只是不知道为什么版本越高级,对工程师要求越高. ...

高版本没用过,因为没找到keygen,哈哈~

以前试着在万能的坛里找过,但没找到。
如果有适用于高版本MDK的和谐文件,能上传一下或者给个链接吗?

出0入102汤圆

发表于 2015-1-30 22:26:50 | 显示全部楼层
很详细的指导,感谢楼主。

出0入0汤圆

发表于 2015-4-22 18:17:02 | 显示全部楼层
学习了!!!!

出0入0汤圆

发表于 2015-4-22 21:54:30 | 显示全部楼层
楼主很用心,不错不错

出0入0汤圆

发表于 2017-9-6 16:21:59 | 显示全部楼层
好东西,楼主授人以鱼还授人以渔!

出0入0汤圆

发表于 2017-12-12 19:46:46 | 显示全部楼层
有用!!谢谢楼主分享!!

出0入0汤圆

发表于 2018-8-30 14:19:32 | 显示全部楼层
不错不错

出0入0汤圆

发表于 2022-5-13 19:04:02 | 显示全部楼层
楼主,用心了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-23 19:00

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表