打印
[其他ST产品]

测量单片机内部FLASH的真实大小

[复制链接]
866|35
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
说明
在Bootloader_Application工程告一段落后,想到还应该验证一下内部Flash。这是本工程的由来。

本文主要包含实现这个工程时遇到的一些问题以及个人的理解。

有一些单片机的内部FLASH会要比标定的大小要大,但是大多少呢?本文在尝试解决这个问题。

仓库链接: InternalFlash

文件修改
STM32CubeMX配置
硬件方面的配置是最简的,除了基本的时钟以外,配置了一个LED灯。主频是480M,没有使能MPU。

cfg文件
cfg文件未作改动,只是修改了本地的stm32h7x.cfg文件。它的路径是openocd\share\openocd\scripts\target\stm32h7x.cfg,将文件中的flash bank $_CHIPNAME.bank1.cpu0 stm32h7x 0x08000000 0 0 0 $_CHIPNAME.cpu0修改为flash bank $_CHIPNAME.bank1.cpu0 stm32h7x 0x08000000 0x200000 0 0 $_CHIPNAME.cpu0,代表着它拥有2MB的内存。

链接文件——STM32H750VBTX_FLASH.ld
修改了FLASH的大小:

MEMORY
{
      FLASH (rx)     : ORIGIN = 0x08000000, LENGTH = 2048K
      ……
}

此时编译没有任何问题,然后容量的会发生变化:

其实还修改了STM32H750VBTX_FLASH.ld,修改的位置放到了后面进行叙述。


使用特权

评论回复
沙发
慢动作|  楼主 | 2024-3-31 14:25 | 只看该作者
代码编写
主要分为两个部分,一部分是写,另外一部分是读验证。

数据写入
考虑到换算的直观,所以声明的是uint8_t类型的数组。

也就是数组中每个元素占用了8 bit(1B),由1KB = 1024 * 8bit,可得知1024个数组元素才构成1KB。如果有1MB的内存要验证,则需要1024 * 1024个数组元素。

我定义了一个KB的宏,值为1024,这意味着,我将以KB为单位进行验证。

数组的声明问题
这里面也有一些问题。声明的数组被copy一份到RAM_D1中去了,然后由于array太大,RAM_D1直接爆掉了。那我是怎么定义这个数组的呢:

uint8_t array[DATA_SIZE] = { 0 }; // DATA_SIZE = 1016 * 1024

使用特权

评论回复
板凳
慢动作|  楼主 | 2024-3-31 14:25 | 只看该作者
编译就出现了:

值得一提的是,这样的定义也是一样的结果:

uint8_t array[DATA_SIZE] = { }; // DATA_SIZE = 1016 * 1024

使用特权

评论回复
地板
慢动作|  楼主 | 2024-3-31 14:25 | 只看该作者
一致的原因是C语言标准中存在这一条,参见Array initialization - cppreference.com



解决这个问题有一个显而易见的思路,既然能够声明到RAM中,那也可以声明到内部的FLASH中。RAM没电就会掉数据嘛,那图片这样的数组怎么放的呢?图片肯定是放在内部FLASH中的,因此也可以断定,肯定是有这个解决办法的。还有一个办法是,一个从根本原因思考得来的,为什么数组的声明会到RAM中?第二个办法后面会有记录。

使用特权

评论回复
5
慢动作|  楼主 | 2024-3-31 14:26 | 只看该作者
解决办法一:变换声明方式
尝试变换声明方式:

uint8_t array[DATA_SIZE] = { 1 }; // DATA_SIZE = 1016 * 1024
1
然后编译出现:



这样的声明是将数组的第一个元素声明为1,而数组的其他元素还是0。参见Array initialization - cppreference.com



好像确实有点效果,虽然RAM_D1还是爆了,但是有点不同的是FLASH也确实占用了很多东西。为什么?我觉得还是和图片数组一个道理,如果你是个全为0的数组,那么说明这个数组很可能是在运行时决定具体内容的,由此断电可以不用保存,所以全部放在了RAM中了,当我们给数组中的某一位赋了具体的数值,那就得保存到FLASH中,可为什么RAM中也还是要占用空间呢?暂且留住这个疑问。

使用特权

评论回复
6
慢动作|  楼主 | 2024-3-31 14:26 | 只看该作者
然后我尝试将数组定义为:

const uint8_t array[DATA_SIZE] = { 1 }; // DATA_SIZE = 1016 * 1024
1
编译的结果确实是我想要的:



但问题是const声明的数组是没办法修改的呀。

static呢?结果和uint8_t array[DATA_SIZE] = { 1 }; // DATA_SIZE = 1016 * 1024的结果是一样的。

解决办法二:修改STM32H750VBTX_FLASH.ld
难道真的没有办法了吗?然后我想为什么不同的声明会占用RAM或者FLASH呢?根本的原因压根不在具体的声明上,而是在STM32H750VBTX_FLASH.ld上。

使用特权

评论回复
7
慢动作|  楼主 | 2024-3-31 14:27 | 只看该作者
const uint8_t array[DATA_SIZE] = { 1 }; // DATA_SIZE = 1016 * 1024的声明只占用了FLASH,因为STM32H750VBTX_FLASH.ld写好了:

  /* Constant data goes into FLASH */
  .rodata :
  {
        ……
  } >FLASH
1
2
3
4
5
uint8_t array[DATA_SIZE] = { 1 }; // DATA_SIZE = 1016 * 1024的声明既占用了FLAHS又占用了RAM,因为STM32H750VBTX_FLASH.ld里边写好了的:

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
        ……
  } >RAM_D1 AT> FLASH

使用特权

评论回复
8
慢动作|  楼主 | 2024-3-31 14:27 | 只看该作者
x uint8_t array[DATA_SIZE] = { }; // DATA_SIZE = 1016 * 1024的声明只占用了RAM,是因为如下:

/* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
        ……
  } >RAM_D1
1
2
3
4
5
6
虽然看不明白,但是注释我是看的懂得。所以直接删去

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
        ……
  } >RAM_D1 AT> FLASH
1
2
3
4
5
最后的>RAM_D1就好了。

使用特权

评论回复
9
慢动作|  楼主 | 2024-3-31 14:27 | 只看该作者
好像挺有道理的,但实际上代码根本跑不了,不论怎么样往数组里写什么值,数组里的值都是0。所以我添加了另外一段定义:

  .data_flash :
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data_flash)           /* .data sections */
    *(.data_flash*)          /* .data* sections */
    *(.RamFunc)        /* .RamFunc sections */
    *(.RamFunc*)       /* .RamFunc* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } AT> FLASH
1
2
3
4
5
6
7
8
9
10
11
12
然后这样声明数组:

uint8_t  __attribute__((section(".data_flash"))) array[DATA_SIZE] = { 1 };  // DATA_SIZE = 1016 * 1024
1
然后程序就可以跑了。

数组里的值考虑到数组是uint8_t,因此数组中每一位的范围是0~255,所以记录一下有多少个0,然后读取数组的时候验证一下0的个数即可。

使用特权

评论回复
10
慢动作|  楼主 | 2024-3-31 14:27 | 只看该作者
数据验证
验证0的个数。如果不对就卡死。

然而实际上基本都会对,不会对的情况是数组大了超过了实际的FLASH大小。比如实际上FLASH并没有2MB,只有1MB,所以你要验证1.5MB就会失败,这种失败很好辩证,本项目下载进去后,灯亮了就是还没有到FLASH的极限。可以采用二分法,自己修改DATA_SIZE,不断地下载尝试。

总结
最后我测量出来的FLASH大小是1016KB,多一点就进了HardFault_Handler。超了的表现是:代码能够下载进去,但是调试就崩了。由于我在while中加了一段点灯程序,所以不用下载后都要调试一下,只需要看灯闪烁没闪烁即可。

使用特权

评论回复
11
中国龙芯CDX| | 2024-3-31 22:53 | 只看该作者
超了的表现是:代码能够下载进去,但是调试就崩了。

使用特权

评论回复
12
dspmana| | 2024-4-5 21:48 | 只看该作者
可以编写代码来读取单片机内部FLASH的大小

使用特权

评论回复
13
youtome| | 2024-4-6 15:30 | 只看该作者
可以通过编写简单的程序来测试FLASH的读写功能,从而验证其大小。

使用特权

评论回复
14
beacherblack| | 2024-4-7 14:22 | 只看该作者
可以使用第三方软件工具来测量FLASH大小,这些工具通常能够提供详细的芯片信息。

使用特权

评论回复
15
febgxu| | 2024-4-8 15:06 | 只看该作者
需要知道FLASH的起始地址。对于STM32系列单片机,FLASH的起始地址通常是0x08000000。这个地址可以从单片机的数据手册中找到。

使用特权

评论回复
16
lzbf| | 2024-4-8 19:49 | 只看该作者
使用编程器/调试器(如STLink、JLink等)可以读取单片机的内存映射。通过查看内存映射,可以确定内部FLASH的实际大小。

使用特权

评论回复
17
jackcat| | 2024-4-9 10:12 | 只看该作者
编译器在链接时会生成.map文件,其中包含了各个段的大小和地址信息,包括FLASH的占用情况。

使用特权

评论回复
18
plsbackup| | 2024-4-9 17:34 | 只看该作者
可以使用一些第三方工具,如STM32CubeMX,它可以帮助你配置和测量FLASH的大小。

使用特权

评论回复
19
sesefadou| | 2024-4-9 21:44 | 只看该作者
可以在代码中添加一些测量内部FLASH大小的函数。

使用特权

评论回复
20
macpherson| | 2024-4-10 15:11 | 只看该作者
查阅单片机的官方文档或数据手册              

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

57

主题

558

帖子

0

粉丝