深入解析ESP32C3(2)- 存储类型和地址空间

发布时间:2024年01月22日

ESP32C3芯片的存储资源

? 384 KB 的ROM:用于程序启动和内核功能调用
? 400 KB 片上SRAM:用于数据和指令存储,时钟频率可配置,最大160 MHz。400 KB SRAM 中,有16 KB 配置为cache 专用
? RTC 快速存储器:为8 KB 的SRAM,可被主CPU 访问,在Deep-sleep 模式下可以保存数据
? 4 Kbit 的eFuse:其中1792 位保留给您使用,例如用于存储密钥和设备ID
? 支持最大16 MB 片外flash。(部分ESP32C3型号将flash封装内置)

系统结构和地址映射结构:

从上图可以看出,ESP32C3的存储介质,不管是类型,还是用途,都比较多的。ESP32C3是一个典型的哈弗结构处理器,拥有独立的数据总线和指令总线,数据地址空间和指令地址空间是分开的;即使是相同的存储位置,数据地址和指令地址是不一样的,即同序访问,如红色标注的ROM1、RAM1。图片中的颜色标注字体是为了更直观地理解内置ROM/SRAM的用途,我特意添加的。与常见的单片机不同,ROM/SRAM的用途不是单一的定义,程序不能任意使用所有内存,而是必须按硬性的地址映射来分配用途,见下表。

ROM0 :只允许指令总线访问,即固件程序存放于此
ROM1 :数据/指令总线都能访问,区别在于数据总线没有执行权限,只有读权限
SRAM0 :不允许数据总线访问,这块作为访问外部FLASH的缓存(CACHE)
SRAM1 :允许任意访问,且权限没有限制
RTC FastRAM :同SRAM1,区别在于它可用于深度休眠,保证数据不丢失

当然,从芯片开发者的角度来看,我们不必关心内置ROM,因为ROM已经固化了厂商的出厂固件,比如芯片的下载功能、启动模式等功能都基于此 ,出厂固件也称为第一级启动引导PBL(Primary Bootloader)。
接下来,分析下APP程序是如何使用片内RAM的。

APP程序的内存空间分布

以测试用例blink为例,编译完成后,可用命令直接查看blink.bin的内存占用情况、加载段的信息。

###查看blink.bin所需的RAM、ROM空间大小
PS G:\workspace\espressif\blink> idf.py size
Executing action: size
... ... ...
Total sizes:
Used stat D/IRAM:   54154 bytes ( 267142 remain, 16.9% used)
      .data size:    4504 bytes  #非常量静态数据
      .bss  size:    3688 bytes  #未初始化的数据
      .text size:   45962 bytes  #程序代码
Used Flash size :  140940 bytes
           .text:  101092 bytes  #程序代码
         .rodata:   39592 bytes  #只读数据
Total image size:  191406 bytes (.bin may be padded larger)

###查看blink.bin文件内各个内存段的大小、加载地址,以及内存段的类型
PS G:\workspace\espressif\blink> esptool.py --chip esp32c3 image_info G:/workspace/espressif/blink/build/blink.bin
... ... ...
Segment 1: len 0x09ba8 load 0x3c020020 file_offs 0x00000018 [DROM]
Segment 2: len 0x01198 load 0x3fc8b400 file_offs 0x00009bc8 [DRAM,BYTE_ACCESSIBLE]
Segment 3: len 0x052a8 load 0x40380000 file_offs 0x0000ad68 [IRAM]
Segment 4: len 0x18ae4 load 0x42000020 file_offs 0x00010018 [IROM]
Segment 5: len 0x060e4 load 0x403852a8 file_offs 0x00028b04 [IRAM]
Checksum: 6a (valid)
Validation Hash: 9a9fb7ee6e46797dcbf956965a0f9b6022122636ebd1d85606e455d19d67d043 (valid)

###以下是ESP32C3板子启动后加载blink.bin的日志
I (83) boot: End of partition table
I (87) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=09ba8h ( 39848) map
I (102) esp_image: segment 1: paddr=00019bd0 vaddr=3fc8b400 size=01198h (  4504) load
I (104) esp_image: segment 2: paddr=0001ad70 vaddr=40380000 size=052a8h ( 21160) load
I (116) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=18ae4h (101092) map
I (137) esp_image: segment 4: paddr=00038b0c vaddr=403852a8 size=060e4h ( 24804) load
I (145) boot: Loaded app from partition at offset 0x10000

APP程序需要占用一定的ROM、RAM;ROM用于存放程序指令和只读的数据,RAM可存放数据,也可存放程序。
对于ESP32C3芯片,ROM位于片外的FLASH存储空间,程序不能直接在外存储器上运行,而是先通过Cache 访问将外存储器由MMU映射到虚地址空间(见地址映射结构图),APP内存段的加载地址就在该虚地址空间中;RAM则位于片内SRAM、RTC Fast RAM,按总线访问,可分为IRAM(指令RAM)和DRAM(数据RAM)。
IDF默认为APP程序指定的RAM是SRAM,但我们可以根据实际需求(例如只有在RTC Fast RAM的代码和数据才能在deep休眠后不丢失),去改变程序代码或数据的分配位置。IDF开发平台提供了一个链接器脚本生成机制,这应该是乐鑫官方独创的。

自定义分配代码/数据到RAM

IDF提供了两种方式:

方式一:属性宏

宏定义文件位于\components\esp_common\include\esp_attr.h

// Forces code into IRAM instead of flash
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)
// Forces data into DRAM instead of flash
#define DRAM_ATTR _SECTION_ATTR_IMPL(".dram1", __COUNTER__)

在定义变量或声明函数时,设定属性宏,就可以告诉编译器在链接阶段分配相应的存储类型中。

#常量数据定义在DRAM,而不是FLASH,因为该常量被用于non-flash-safe中断函数
__NOINIT_ATTR uint32_t noinit_data; 

#使用IRAM_ATTR 宏在源代码中指定需要放入IRAM 的代码
void IRAM_ATTR gpio_isr_handler(void* arg)
{
// ...
//= noinit_data
}

方式二:链接器脚本生成机制

方式一的使用比较简单方便,但局限也很明显,处理不了整个目标源文件或复杂的函数调用关系。
链接器脚本生成机制定义了一套规则,可以让用户指定代码和数据在ESP-IDF 组件中的存放区域。IDF平台中,扩展名(.lf)的文件,就是这套规则的脚本。
?编译APP时,使用的默认脚本如下: components\esp_system\app.lf

[scheme:default]
entries:
    if APP_BUILD_USE_FLASH_SECTIONS = y:
        text -> flash_text
        rodata -> flash_rodata
    else:
        text -> iram0_text
        rodata -> dram0_data
    data -> dram0_data
    bss -> dram0_bss
    common -> dram0_bss
    if ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY = y:
        extram_bss -> extern_ram
    else:
        extram_bss -> dram0_bss
    legacy_bss -> dram0_bss
    iram -> iram0_text
    iram_data -> iram0_data
    iram_bss -> iram0_bss
    dram -> dram0_data
    rtc_text -> rtc_text
    rtc_data -> rtc_data
    rtc_rodata -> rtc_data
    rtc_bss -> rtc_bss

[scheme:rtc]
entries:
    text -> rtc_text
    data -> rtc_data
    rodata -> rtc_data
    bss -> rtc_bss
    common -> rtc_bss

[scheme:noflash]
entries:
    text -> iram0_text
    rodata -> dram0_data

[scheme:noflash_data]
entries:
    rodata -> dram0_data

[scheme:noflash_text]
entries:
    text -> iram0_text

[mapping:default]
archive: *
entries:
    * (default)

?机制的具体细节,请直接看官网编程指南-链接器脚本生成机制

与存储关联的内容,还有权限管理(PMS),本次就不在此展开。

文章来源:https://blog.csdn.net/Golden_Chen/article/details/135717495
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。