你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

如何偏移KEIL 编译的 STM32 Flash的 RW 数据?

[复制链接]
Ghost-Girls 提问时间:2023-5-16 13:40 / 未解决

说明一下问题:

  1. 开发环境:KEIL MKD
  2. MCU:STM32F042F6P6,32K Flash,Paga = 1Kb,Sector = 4Kb.
  3. 我的编译的程序存放在0x08000000 ~ 0x0800 50a8中,0x080050a8~ 0x08006000之间的地址全部填0.
  4. 而我使用attribute特性定义了一个【需要读写】数组到指定的地址,地址为0x08006000. uint8_t attribute(( section(".ARM.__at_0x08006000") )) flash_writeread_test[28] = {}
  5. 我的这个数组的只有28个成员,而且是 unsigned char 类型的,28byte 也才占用到 0x0800601f,而后面的0x08006020就跟着 RW 的数据。问题来了,我这个数据如果要进行读写,就需要将整个Page擦除,如果没有将整个页读出来之后然后再写回去,那么必然会造成程序跑死。
  6. 我能想到的处理办法:
    1. 读出来,改需要修改的部分,然后写回去。

      虽然读写1Kb不算什么问题,但是,要是碰到了,读写个256Kb的Sector的,那不得卡上天。

    2. 直接定义为1024个成员的数组,填充完1Kb的Page。

      目前我使用的确实就是这个办法,但是,也有不好的地方,就是使用memcpy()的时候,都不能愉快的使用sizeof()了。

    3. 或是创建28个成员的数组,然后,再在数组地址的0x0800602c创建996byte个成员的数组占满整个Page。
    4. GCC编译器说是可以改.LD编译的链接文件实现指定地址写入数据。
    5. 既然GCC编译器可以修改编译链接问文件,那么KIEL应该也有类似的操作吧? 比如,能否通过修改分散加载文件(.sct)实现这个操作?(我个人认为是可以的,但是我不知道怎么实现。) https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=619873 下面这个代码是STMM32社区那边找到的,但据说没法实现功能。后面提问的,只能勾选了IROM2才能分配空间。
      LR_IROM1 0x08003000 0x0003CFFC  {    ; load region size_region
        ER_IROM1 0x08003000 0x0003CFFC  {  ; load address = execution address
         *.o (RESET, +First)
         *(InRoot$Sections)
         .ANY (+RO)
        }
          API_IROM1 0x0803FFFC 0x00000004  {
              *.o(apiSection)
        }
        RW_IRAM1 0x200000BC 0x00007F44  {  ; RW data
         .ANY (+RW +ZI)
        }
      }

下面是编译后,数据的空间占用情况:

Memory Map of the image

  Image Entry point : 0x080000c1

  Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00006618, Max: 0x00008000, ABSOLUTE, COMPRESSED[0x00006530])

    Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00006400, Max: 0x00008000, ABSOLUTE)

            省略掉上面的一串代码

    0x08003e54   0x08003e54   0x0000001a   Code   RO           91    .text.spi_write     main.o
    0x08003e6e   0x08003e6e   0x000001f6   Code   RO         1491    .text_divfast       c_p.l(aeabi_sdivfast.o)
    0x08004064   0x08004064   0x00000005   Data   RO          127    .rodata.btn_keys    main.o
    0x08004069   0x08004069   0x00000ffe   Data   RO          109    .rodata.srom        main.o
    0x08005067   0x08005067   0x00000001   PAD
    0x08005068   0x08005068   0x00000040   Data   RO         1674    Region$$Table       anon$$obj.o
    0x080050a8   0x080050a8   0x00000f58   PAD
    0x08006000   0x08006000   0x00000400   Data   RW          110    .ARM.__at_0x08006000  main.o


    Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x08006400, Size: 0x000010c0, Max: 0x00001800, ABSOLUTE, COMPRESSED[0x00000130])

还有个问题,就是它这个填0太过于占空间了,硬生生的多了20K的空间:

说明一下问题:

  1. 开发环境:KEIL MKD
  2. MCU:STM32F042F6P6,32K Flash,Paga = 1Kb,Sector = 4Kb.
  3. 我的编译的程序存放在0x08000000 ~ 0x0800 50a8中,0x080050a8~ 0x08006000之间的地址全部填0.
  4. 而我使用attribute特性定义了一个【需要读写】数组到指定的地址,地址为0x08006000. uint8_t attribute(( section(".ARM.__at_0x08006000") )) flash_writeread_test[28] = {}
  5. 我的这个数组的只有28个成员,而且是 unsigned char 类型的,28byte 也才占用到 0x0800601f,而后面的0x08006020就跟着 RW 的数据。问题来了,我这个数据如果要进行读写,就需要将整个Page擦除,如果没有将整个页读出来之后然后再写回去,那么必然会造成程序跑死。
  6. 我能想到的处理办法:
    1. 读出来,改需要修改的部分,然后写回去。

      虽然读写1Kb不算什么问题,但是,要是碰到了,读写个256Kb的Sector的,那不得卡上天。

    2. 直接定义为1024个成员的数组,填充完1Kb的Page。

      目前我使用的确实就是这个办法,但是,也有不好的地方,就是使用memcpy()的时候,都不能愉快的使用sizeof()了。

    3. 或是创建28个成员的数组,然后,再在数组地址的0x0800602c创建996byte个成员的数组占满整个Page。
    4. GCC编译器说是可以改.LD编译的链接文件实现指定地址写入数据。
    5. 既然GCC编译器可以修改编译链接问文件,那么KIEL应该也有类似的操作吧? 比如,能否通过修改分散加载文件(.sct)实现这个操作?(我个人认为是可以的,但是我不知道怎么实现。) https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=619873 下面这个代码是STMM32社区那边找到的,但据说没法实现功能。后面提问的,只能勾选了IROM2才能分配空间。
      LR_IROM1 0x08003000 0x0003CFFC  {    ; load region size_region
        ER_IROM1 0x08003000 0x0003CFFC  {  ; load address = execution address
         *.o (RESET, +First)
         *(InRoot$Sections)
         .ANY (+RO)
        }
          API_IROM1 0x0803FFFC 0x00000004  {
              *.o(apiSection)
        }
        RW_IRAM1 0x200000BC 0x00007F44  {  ; RW data
         .ANY (+RW +ZI)
        }
      }

下面是编译后,数据的空间占用情况:

Memory Map of the image

  Image Entry point : 0x080000c1

  Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00006618, Max: 0x00008000, ABSOLUTE, COMPRESSED[0x00006530])

    Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00006400, Max: 0x00008000, ABSOLUTE)

            省略掉上面的一串代码

    0x08003e54   0x08003e54   0x0000001a   Code   RO           91    .text.spi_write     main.o
    0x08003e6e   0x08003e6e   0x000001f6   Code   RO         1491    .text_divfast       c_p.l(aeabi_sdivfast.o)
    0x08004064   0x08004064   0x00000005   Data   RO          127    .rodata.btn_keys    main.o
    0x08004069   0x08004069   0x00000ffe   Data   RO          109    .rodata.srom        main.o
    0x08005067   0x08005067   0x00000001   PAD
    0x08005068   0x08005068   0x00000040   Data   RO         1674    Region$$Table       anon$$obj.o
    0x080050a8   0x080050a8   0x00000f58   PAD
    0x08006000   0x08006000   0x00000400   Data   RW          110    .ARM.__at_0x08006000  main.o


    Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x08006400, Size: 0x000010c0, Max: 0x00001800, ABSOLUTE, COMPRESSED[0x00000130])

还有个问题,就是它这个填0太过于占空间了,硬生生的多了20K的空间:

image-20230516005159-imp7kkx.png

RW的数据的执行地址是固定的 0x2000 0000,可以通过KEIL分配或者进行偏移什么的。

但是,RW的Load base加载地址,好像不能手动分配映射到具体地址?只能推挤在RO后面?

也就是下图中的RW INIT 的地址只能记在RO的后面。

image-20230516104437-ezkgkpc.png

RW的数据的执行地址是固定的 0x2000 0000,可以通过KEIL分配或者进行偏移什么的。

但是,RW的Load base加载地址,好像不能手动分配映射到具体地址?只能推挤在RO后面?

也就是下图中的RW INIT 的地址只能记在RO的后面。

收藏 评论0 发布时间:2023-5-16 13:40

举报

0个回答

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版