学习STM32中的疑惑,希望小伙伴能帮忙看看

2019-07-20 08:28发布

    各位小伙伴,最近学习STM32F407遇到了很多的问题,有的问题被我解决了,有点还迟迟没有解决。通过遇到的这些问题,我有很多疑问,希望有知道的小伙伴能够解惑,谢谢各位啦。 内存管理1.png 内存管理2.png 内存.png

1、在学习了内存管理一节当中,为什么要管理STM32内部的内存(SRAMIN和SRAMCC)?  难道STM32内部管理机制不好么?  STM32内部是怎么管理这些内存的?  在哪里可以看到呢?

2、汇编文件startup_stm32f40_41xxx.s中分配的堆和栈是分配在那一片内存上的呢?  SRAMCC还是SRAMIN呢?  全局变量和静态变量又是在哪里?

3、SRAMIN一共有128KB的大小,内存池占用了100KB,内存管理表大概占用了将近7BK,也就是说对于SRAMIN这片内存,用户自己使用了107KB的空间,只能使用mymalloc函数来申请空间。值留下了20KB左右的空间。如果第二个问题中的堆栈是在这里分配的,那么岂不是那个汇编文件就只有20KB的空间可以给堆栈使用。

4、SRMCC主要是用来干什么的? 从原子哥的注释可以看到是给CPU使用的,但是具体作用呢?  ·

5、既然SRAMCC(共64KB)主要是给CPU使用的,意思是不是说用户不能使用呢?  还是说用户根本就访问不到这里的存储空间?    SRAMCC分配了60KB的内存池,内存管理表使用了3.75KB,将近4KB,也就是说我们把SRAMCC全部都自己管理了。

6、Execution Region指的是哪个地方呢? 是内存么?  如果是,那么指得是SRAMCC还是SRMIN呢?

7、STM32的flash采用总线是的总线接入,那么它的flash的存储空间是可以任意访问的。也就是说我们下载进入flash中的代码是可以直接在flash中执行的,不用加载到ram。从网上博客了解到,其实代码需不需要加载到RAM,其实是可以自己控制的,分散加载脚本就是用来干这个的。那么,MDK是怎么判断用户的代码是否需要加载到RAM中呢?  还是所有的都不加载?  

   暂时先这些问题吧,希望知道的朋友能够答疑解惑,谢谢各位小伙伴了

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
4条回答
513393302@qq.co
1楼-- · 2019-07-20 12:12
本帖最后由 513393302@qq.com 于 2018-4-25 17:40 编辑

为你点赞!能思考到这么多问题来,我想你应该是很喜欢专研的一列人,加油。
我只能回复一些我知道且明确的给你,毕竟有许多地方需要相互学习。

1、在学习了内存管理一节当中,为什么要管理STM32内部的内存(SRAMIN和SRAMCC)?  难道STM32内部管理机制不好么?  STM32内部是怎么管理这些内存的?  在哪里可以看到呢?
回复:STM32内部的内存是固定的,每申请一个全局变量(数组、结构体)那么这部分内存就被占用了 。在实际应用中有些函数需要一个很大的内存,但是做完事情后这部分内存就不需要了,如果用全局变量来实现,这样就太浪费了,如果定义局部变量那么栈(实际也为全局数组)就要定义很大,所以采用内存管理,在需要大内存的地方向内存池申请内存,用完了就释放,这样别的地方还可以向这个内存池申请内存。
STM32是没有MMU单元,所以没有内存管理机制。如果采用C语言标准库中的内存申请和释放函数,那么这个是向堆(实际也为全局数组)中申请内存的,而且效率不高。
对于CPU而言,所有的外设(外设、SRAM、FLASH)都是通过内存访问和控制的,通过不同地址来区分控制的区域,比如FLASH的起始地址为0X08000000,当你想这个地址进行读写的时候,CPU就知道是去操作FLASH,当你向0X20000000进行读写的时候,CPU就知道是去操作SRAM。其它外设都是如此,比如你向0X40011000进行读写,那么CPU就知道是去操作串口1的SR寄存器。
可以通过对应的数据手册,比如《STM32F4XX中文参考手册.PDF》中第2.3章节“存储器映射”,或者<STM32F405XX STM32F407XX>PDF中第4章节《Memory mapping》
2、汇编文件startup_stm32f40_41xxx.s中分配的堆和栈是分配在那一片内存上的呢?  SRAMCC还是SRAMIN呢?  全局变量和静态变量又是在哪里?
回复:
堆和栈是通过链接文件来决定存放的地址,在链接文件中定义两个扇区,用来存放堆和栈,IAR中的链接文件名后缀为.icf,SW4STM32的链接文件名的后缀为.ld,KEIL MDK中也有链接文件,文件格式不记得了,可以百度出来。链接文件用来指出每个区域存放的地址(常数、代码、堆栈),这部分可能表述的不专业。
堆栈的地址可以通过修改链接脚本来修改存放的地址,STM32F407内部的SRAM分为 SRAM和CCM。
全局变量和静态变量全部存放在堆中,栈中用来存放局部变量。

3、SRAMIN一共有128KB的大小,内存池占用了100KB,内存管理表大概占用了将近7BK,也就是说对于SRAMIN这片内存,用户自己使用了107KB的空间,只能使用mymalloc函数来申请空间。值留下了20KB左右的空间。如果第二个问题中的堆栈是在这里分配的,那么岂不是那个汇编文件就只有20KB的空间可以给堆栈使用。
回复:
是的

4、SRMCC主要是用来干什么的? 从原子哥的注释可以看到是给CPU使用的,但是具体作用呢?  ·
回复:
CCM内存的主要的特点是CPU取值非常快(个人理解),这部分只能由CPU访问,所以不能用DMA来指定这个区域。主要用于跑算法、图片解码(STEMWIN)及运行操作系统的时候当操作系统内存(提升速度,但是如果调用操作系统的内存,则不能用DMA来指定这个内存)

5、既然SRAMCC(共64KB)主要是给CPU使用的,意思是不是说用户不能使用呢?  还是说用户根本就访问不到这里的存储空间?    SRAMCC分配了60KB的内存池,内存管理表使用了3.75KB,将近4KB,也就是说我们把SRAMCC全部都自己管理了。
回复:
用户可以访问这个CCM内存区域,可以直接通过访问地址0X20000000来实现访问。用内存管理来管理CCM,是为了提升内存使用率。

6、Execution Region指的是哪个地方呢? 是内存么?  如果是,那么指得是SRAMCC还是SRMIN呢?
回复:
没有找到Execution Region,如果是问__attribute__((at(0XXXXXXX))) 关键字,其意思是把这部分存放在一个指定的地址,如果想知道这个地址是什么,则看对应的 Memory mapping 即可。不同地址对应不同功能。

7、STM32的flash采用总线是的总线接入,那么它的flash的存储空间是可以任意访问的。也就是说我们下载进入flash中的代码是可以直接在flash中执行的,不用加载到ram。从网上博客了解到,其实代码需不需要加载到RAM,其实是可以自己控制的,分散加载脚本就是用来干这个的。那么,MDK是怎么判断用户的代码是否需要加载到RAM中呢?  还是所有的都不加载?

回复:
你说的分散加载脚本即为链接文件,此脚本中指出代码数据、常数、变量的存放地址,通过修改此链接文件即可修改地址,MDK是通过设置《Target》中的地址来指定代码存放区域。如果想把代码全部在RAM中运行,则你需要先把代码全部写入FLASH,然后代码中把FLASH中的代码数据全部拷贝到SRAM中,然后中断重映射到SRAM中。这部分我没有在STM32上操作过,只是猜测操作流程。





NewGuard
2楼-- · 2019-07-20 13:56
帮顶!
login_FAE
3楼-- · 2019-07-20 15:12
 精彩回答 2  元偷偷看……
晨曦的love
4楼-- · 2019-07-20 17:52
513393302@qq.co 发表于 2018-4-25 17:39
为你点赞!能思考到这么多问题来,我想你应该是很喜欢专研的一列人,加油。
我只能回复一些我知道且明确的 ...

    非常感谢大神的回复,可以看的出来回答的很用心,同时也让我理解了很多以前有些模棱两可的知识点。通过您的回答,我又在网上找了写资料帮助我消化。1、在学习了内存管理一节当中,为什么要管理STM32内部的内存(SRAMIN和SRAMCC)?  难道STM32内部管理机制不好么?  STM32内部是怎么管理这些内存的?  在哪里可以看到呢?
回复:STM32内部的内存是固定的,每申请一个全局变量(数组、结构体)那么这部分内存就被占用了 。在实际应用中有些函数需要一个很大的内存,但是做完事情后这部分内存就不需要了,如果用全局变量来实现,这样就太浪费了,如果定义局部变量那么栈(实际也为全局数组)就要定义很大,所以采用内存管理,在需要大内存的地方向内存池申请内存,用完了就释放,这样别的地方还可以向这个内存池申请内存。
STM32是没有MMU单元,所以没有内存管理机制。如果采用C语言标准库中的内存申请和释放函数,那么这个是向堆(实际也为全局数组)中申请内存的,而且效率不高。
对于CPU而言,所有的外设(外设、SRAM、FLASH)都是通过内存访问和控制的,通过不同地址来区分控制的区域,比如FLASH的起始地址为0X08000000,当你想这个地址进行读写的时候,CPU就知道是去操作FLASH,当你向0X20000000进行读写的时候,CPU就知道是去操作SRAM。其它外设都是如此,比如你向0X40011000进行读写,那么CPU就知道是去操作串口1的SR寄存器。
可以通过对应的数据手册,比如《STM32F4XX中文参考手册.PDF》中第2.3章节“存储器映射”,或者<STM32F405XX STM32F407XX>PDF中第4章节《Memory mapping》
    这个问题回答的非常详细,一针见血,也让我理解了为什么要自己管理STM32内部的SRAM。以前都是不知所以,现在找到了起因,感觉任督二脉被打通了的感觉,非常感谢!!
2、汇编文件startup_stm32f40_41xxx.s中分配的堆和栈是分配在那一片内存上的呢?  SRAMCC还是SRAMIN呢?  全局变量和静态变量又是在哪里?
回复:
堆和栈是通过链接文件来决定存放的地址,在链接文件中定义两个扇区,用来存放堆和栈,IAR中的链接文件名后缀为.icf,SW4STM32的链接文件名的后缀为.ld,KEIL MDK中也有链接文件,文件格式不记得了,可以百度出来。链接文件用来指出每个区域存放的地址(常数、代码、堆栈),这部分可能表述的不专业。
堆栈的地址可以通过修改链接脚本来修改存放的地址,STM32F407内部的SRAM分为 SRAM和CCM。
全局变量和静态变量全部存放在堆中,栈中用来存放局部变量。
      通过自己浏览MDK的工程文件,我找到了MDK的链接文件,名字是以 “工程名.sct” 结尾的那个,对于STM32F407ZGT6自身有两片内存,但是使用的就知识其中的一片,也就是Target中的那个IRAM1,可以看到它前面够个勾勾,而IRAM2则没有,也就是说,如果在工程中没有选中IRAM2,这片内存其实就是上面所说的SRAMCCM那片内存,如果开发人员不自己管理这片内存,而且在工程当中又没有选中,那么这片内存相当于没有使用,所以需要自己管理,当然也可以在工程当中选中,使用相应的配置使用这片内存。  从底下截图的连接脚本中就可以看出来这个工程只是用了SRAMIN,没有使用SRMACCM。

    另外,对于您回复的“全局变量和静态变量全部放在堆中”,其实我不是很理解,我的理解是:全局变量和静态变量是在RW段和ZI段,如果全局变量或者是静态变量有初始化,并且不为0,那么位于RW段。而没有初始化或者初始化为0的全局变量或静态变量是位于ZI段。在MDK当中,ZI段通常还包括了栈空间和堆空间。  所以在程序当中它们的属性应该是:代码——>Code   常量——>RO-data   初始化非0的全局变量和静态变量——>  RW-data     初始化为0的全局变量和静态变量——>ZI-data      局部变量——>ZI-data栈空间
  malloc分配的变量——>ZI-data堆空间。
    mdk.png 链接文件.png

3、SRAMIN一共有128KB的大小,内存池占用了100KB,内存管理表大概占用了将近7BK,也就是说对于SRAMIN这片内存,用户自己使用了107KB的空间,只能使用mymalloc函数来申请空间。值留下了20KB左右的空间。如果第二个问题中的堆栈是在这里分配的,那么岂不是那个汇编文件就只有20KB的空间可以给堆栈使用。
回复:
是的

4、SRMCC主要是用来干什么的? 从原子哥的注释可以看到是给CPU使用的,但是具体作用呢?  ·
回复:
CCM内存的主要的特点是CPU取值非常快(个人理解),这部分只能由CPU访问,所以不能用DMA来指定这个区域。主要用于跑算法、图片解码(STEMWIN)及运行操作系统的时候当操作系统内存(提升速度,但是如果调用操作系统的内存,则不能用DMA来指定这个内存)
        原来如此,这么一说,我就知道怎么使用这片空间啦,谢谢。   
5、既然SRAMCC(共64KB)主要是给CPU使用的,意思是不是说用户不能使用呢?  还是说用户根本就访问不到这里的存储空间?    SRAMCC分配了60KB的内存池,内存管理表使用了3.75KB,将近4KB,也就是说我们把SRAMCC全部都自己管理了。
回复:
用户可以访问这个CCM内存区域,可以直接通过访问地址0X20000000来实现访问。用内存管理来管理CCM,是为了提升内存使用率。

6、Execution Region指的是哪个地方呢? 是内存么?  如果是,那么指得是SRAMCC还是SRMIN呢?
回复:
没有找到Execution Region,如果是问__attribute__((at(0XXXXXXX))) 关键字,其意思是把这部分存放在一个指定的地址,如果想知道这个地址是什么,则看对应的 Memory mapping 即可。不同地址对应不同功能。
       这个应该说的是执行域,应用程序不是有加载域和执行域嘛(昨天刚刚学的,用上了,哈哈。。),之所以问这个问题是因为我前几天碰到了一个问题,可以看底下的截图,这里的加载域(
Execution Region) 没有空间了,当时其实不是很懂,找了很久,也是发的帖子解决的,其实就是内存上的问题,堆栈分配的不合理,某个地方使用太多导致的。这个问题主要是由于我移植的FreeRTOS的分配的内存空间太多了,而SRAMIN有没有那么大才导致出现这个问题的。
error.png
7、STM32的flash采用总线是的总线接入,那么它的flash的存储空间是可以任意访问的。也就是说我们下载进入flash中的代码是可以直接在flash中执行的,不用加载到ram。从网上博客了解到,其实代码需不需要加载到RAM,其实是可以自己控制的,分散加载脚本就是用来干这个的。那么,MDK是怎么判断用户的代码是否需要加载到RAM中呢?  还是所有的都不加载?

回复:
你说的分散加载脚本即为链接文件,此脚本中指出代码数据、常数、变量的存放地址,通过修改此链接文件即可修改地址,MDK是通过设置《Target》中的地址来指定代码存放区域。如果想把代码全部在RAM中运行,则你需要先把代码全部写入FLASH,然后代码中把FLASH中的代码数据全部拷贝到SRAM中,然后中断重映射到SRAM中。这部分我没有在STM32上操作过,只是猜测操作流程。





       再次感谢您,真的让我学到了很多,谢谢!!

一周热门 更多>