STM32外部存储器使用资料,很有参考价值
最近在学习一些gui方面的操作,并且是要跑os的;突然就发现自己的硬件平台的内部SRAM资源不够用了(硬件平台:战舰V2,stm32f103ze、外扩SRAM:1M);怎么破,那只能把外部的SRAM给用起来,不用就是浪费啊,要知道SRAM可是不便宜啊; 然后就开始借鉴了配套例程:外部SRAM的使用;通过fsmc来控制实现,外部sram可以正常使用了,但是我想尝试下其他的方法来使用外部的SRAM: 1、 不使用attribute关键字来实现变量等在外部的分配,让编译器自己来完全支配,这样我们就不用计算我们指定的地址是否会重合等问题; 2、 让内部的64K SRAM、外部的1M SRAM都能用,而且让编译器自己处理使用; 3、 完全不使用内部的SRAM,只使用外部的SRAM
上网上查阅一些资料后,发现这个需要在2010年就有了,而且当时网友遇到的问题,我在实验中也遇到了,关键是前面的帖子,也没有很明确或是清晰的给出解释,有的帖子给的方法是可以实现要求的,但是没有说为什么这样可以,所以我自己一边实验一边验证,下面把自己遇到的问题和现象做一个记录: 1、 按照网友的方法来配置,让编译器自动处理SRAM的使用 (1) 实验前提,例程采用配套例程的:37外部SRAM实验;外部SRAM的初始化使用system_stm32f10x.c官方提供的fsmc初始化; (2) 工程配置 开启system_stm32f10x.c中的fsmc初始化外部SRAM函数; 配置工程中SRAM的分配,注意:SRAM部分有两块,两个√ 注意去掉main文件中的testsram[]的属性定义 (3) 实验结果,程序正常执行; 链接加载控制文件内容: 工程的map文件,如果对map文件不熟悉的可以自行查阅资料 是不是很明显:一大堆的变量和数据段都分配在了内部的SRAM,只有一个.bss段分配到了外部的SRAM 0x68000000地址处,为什么会这样,因为内部放不下了啊,另外咱们的testsram数组是没有初始化的,你试一下在定义时就初始化,看看地址有什么变化;要理解这里的原理,就需要对分散加载文件有深入的了解了,自行查找;
2、 完全不使用内部SRAM,只使用外部SRAM (1) 工程配置和上面的实验一致,只修改一个部分,去掉内部SRAM的配置 (2) 编译测试 编译是没有任何问题的,下载验证吧,程序跑不起来,失败了; 在线jlink调试一下: 看到了吧,死在这里和,硬件fault了;先不解释为什么; (3) 解决问题的过程 之前在网上搜到一些建议,但是我还是选择了,先用jlink调试一下看看; 我在用jlink在线调试操作过程是: 第一步:单步调试,看一下是哪里进入了硬件fault;我在void SystemInit (void)函数中增加了一些调试 目的是看一下,这的fsmc对外部的SRAM的操作是否正确,结果是正确的,说明官方的fsmc初始化没有问题,此时外部的SRAM已经可以正常使用了; 第二步:继续单步调试,发现是在这个地方进入了硬件fault了:static void SetSysClockTo72(void)函数的退出时 到这里你在执行单步一次,就会进入硬件fault,可以确定了是在函数返回时进入硬件fault,这里先不解释原因;
第三步:我借鉴了一下网友的建议,如下: 工程配置不用改动任何地方,还是只配置外部SRAM作为唯一的选择,注意这里和 的配置是不一样的,它的同时配置了外部和内部SRAM,如果这样那他所做的操作就有些多余了,不用修改启动文件就可以啊,就和我上面第1中的工程配置一样啊,编译器自己就可以处理了,不用你在修改启动文件啊,这也是该贴下面很多网友说不用修改启动文件中的 __initial_sp EQU 0x20000000 + Stack_Size 也可以正常运行;如果你按照下面的工程配置,再不添加启动文件中的__initial_sp EQU 0x20000000 + Stack_Size设置,你试一下可以正常运行吗?答案是:不能; 工程配置不变: 修改启动文件startup_stm32f10x_hd.s中的关于栈的位置定义:等价于强制把复位后的栈指针指向内部的SRAM位置处
好了,其它一切不变,编译下载吧
第四步:下载验证 成功运行程序 Sct文件内容:完全是把数据段放在了外部的SRAM中; Map文件内容:所有数据段都在了外部SRAM上面;
到这里,你会有疑问吧,那我们刚才设置启动文件中__initial_sp EQU 0x20000000 + Stack_Size的目的是啥啊,为啥在配置不变情况下,不加程序就不正常,加了就可以正常运行;后面解释,先附张图,自己先分析一下
这里分享一个巧合事件: 我在2、完全不使用内部SRAM,只使用外部SRAM -> (3)解决问题的过程 -> 第三步 中给出的结论:如果你按照我的工程配置,只启用外部sram配置选项,然后你又不设置启动文件中栈指针的设置,程序是不会正常启动的; 有的朋友可能在实验中会出现,即按照只使用外部sram配置,且不添加启动文件设置,程序也正常启动了,会说我的结论是错的,其实结论是对的,你这个配置下能正常运行程序,完全是个巧合,下面给出巧合呈现方法: 第一步:按照下面的配置、下载、运行程序,系统正常运行,没有任何问题
第二步:你为了推翻我的结论,在工程配置不变的情况下,只修改了启动文件的配置,删除了对栈指针的设置 接下来编译、烧写程序,进行验证(注意这个过程前提是,你的平台还在上次的程序下正常上电运行,这里直接按照第二步的设置编译后,用jlink下载验证,为了说明问题我把两次的程序作了小处理,说明确实是连个不同的程序;上面的LCD上显示是"WarShip ZG008",这里我们显示是 "WarShip ZG009") 程序正常运行了,你的结论是错的,别急:此时你把平台的电源断掉,在上电看看,程序能正常运行吗,不能吧; 原因我还没有深究,预估是,当你的平台正常运行下,你用jilink在线下载程序时,外设的配置还会保持之前的状态,至少fsmc的配置没有改变,仍然可以操作外部的sram,所以你删除了启动文件的配置后,下载程序仍正常运行,断电后在上电,就不行了;这里只是我的猜测,还没有验证;
到这里,大家是否明白了,这一切的设置,是不是都离不开一个东西:sp
3、 上面实验现象分析 第一步:要清楚,cm3的内核是在上电后进入复位中断处理,但是复位中断的pc值可不是存储在0x0000 0000 地址,而是下一个4字节的位置,0x0000 0000存储的是sp的栈指针; 第二步:通过调试,你可以看到,程序进入上电复位中断后,先跳转到SystemInit()函数,调试截图如下: LDR R0, =SystemInit BLX R0 当单步执行 BLX r0后,注意观察左边寄存器的变化,以及上面的汇编语句: 看到了:R13的sp值改变了,因为发生了函数调用,需要保存上下文环境,所有有PUSH的操作,切记,这里对栈进行了操作,即入栈,那么当你从systeminit()函数返回时,就要涉及到出站,这点很重要,这就是你进入硬件fault的根源;
第三步:分析上面工程配置1中的设置, 这种配置,你只改变了SRAM的配置,让外部和内部的都启用,让编译器自己解决分配问题;通过map文件你可以很清楚:编译器把大部分的数据段都还是放在了内部SRAM中,包括主要的__initial_sp栈顶指针,只把一个很大的内部sram放不下的main.c中定义的testsram[]放在了外部sram; 此时,堆栈指针在内部sram中,所以在复位中断中的函数调用引发的入栈、出栈可以完全正常运行;
第四步:分析上面工程2中的配置 这里分两种情况,工程配置不变下,是否设置启动文件的__initial_sp EQU 0x20000000 + Stack_Size; (1) 不修改启动文件中的栈的设置 此时通过编译后的map和调试文件可以知道: 当调用LDR R0, =SystemInit BLX R0 后会发生入栈的push操作,注意观察此时的R13的数值:0x680F 4AF8;已经指向了外部的sram; 此处发生了push入栈操作,但是重点是此时我们还没有对外部sram进行操作啊,试问你这个入栈能成功吗,不能,那么里面的数值是函数返回后的下一条PC值吗,肯定不是,是个垃圾值;然后,你调用pop操作,将一个垃圾值给了PC,那只能进入硬件fault了;
那我们找到了问题的根源,那咋改进呢:首先要明白一点,开发板硬件上电复位前,我们是无法完成STM32对外部SRAM的配置,只能上电后进行配置了才可以使用。也就是说,只有正常的硬件复位序列完成后,我们可以在Reset_Handler(复位中断服务程序)中完成对SRAM的配置,但是在这之前,局部变量和函数调用用到的Stack栈空间,我们都得使用STM32内部SRAM,明白了这点,很重要; (2) 修改启动文件,设置 __initial_sp EQU 0x20000000 + Stack_Size 此时,我们分析编译后的map、调试信息: 注意观察:此时的map中数据段信息,没有__initial_sp的值;我们在看一下,调试时的信息: 很清晰:此时发生函数调用时,我们使用的栈指向了内部的sram控件,R13 = 0x2000 0400;所以当发生push、pop操作时,数据都是正确的,PC也可以得到正确的数值,从而按流程执行; 所以我们在启动文件中添加的那一条:__initial_sp EQU 0x20000000 + Stack_Size很重要,就是强制把栈定义在了内部的sram中了,虽然通过map文件我们可以看到,在外部的sram中我们也分配了heap、stack的空间,但是我们的sp指针没有指向他们,其实这里还有很多扩展的空间;
到这里,分析完了,外部sram的用法,以及为什么会出现这种现象,其中涉及到map文件的解析;以及分散加载。Sct的知识,没有做仔细分析,合理安排、设计分散加载文件可以让你的工程的链接、加载更加符合你的设计要求,所以在工程设置中,IDE才允许我们设置使用自己定义的.sct文件;有时间,后面再细分析;
以上图文的Word格式文档下载(内容和本网页上的一模一样,方便大家保存):
12 STM32的外部SRAM使用的总结.docx
(1.78 MB, 下载次数: 3)
|