STM32H757xI项目移植IAR:仅将Flash读写段复制到RAM的配置
项目背景
基于STM32H757xI带QUADSPI扩展内存的自定义板项目,由TouchGFX Designer生成,原适配STM32CubeIDE,现移植到IAR。项目主体结构可正常编译,但ICF文件配置存在问题,无法实现CubeIDE中LD文件的逻辑:仅将Flash中的特定读写段(.data/.RamFunc系列)加载到RAM,而非全部内容。
CubeIDE中的LD配置(参考)
原LD文件中.data段的加载逻辑如下:
.data : { . = ALIGN(4); _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ *(.RamFunc) /* .RamFunc sections */ *(.RamFunc*) /* .RamFunc* sections */ . = ALIGN(4); _edata = .; /* define a global symbol at data end */ } >RAM_D1 AT> FLASH
当前编写的ICF代码
/*###ICF### Section handled by ICF editor, don't touch! ****/ /*-Editor annotation file-*/ /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ /*-Specials-*/ /*-Memory Regions-*/ define symbol __ICFEDIT_region_ROM_start__ = 0x08040000; define symbol __ICFEDIT_region_ROM_end__ = 0x080FFFFF; /* 1 Mbyte */ /*-Internal RAM Memory Regions-*/ define symbol __ICFEDIT_region_ITCMRAM_start__ = 0x00000000; define symbol __ICFEDIT_region_ITCMRAM_end__ = 0x0000FFFF; /* 64 Kbytes */ define symbol __ICFEDIT_region_DTCMRAM_start__ = 0x20000000; define symbol __ICFEDIT_region_DTCMRAM_end__ = 0x2001FFFF; /* 128 Kbytes */ define symbol __ICFEDIT_region_RAM_start__ = 0x24000000; /* 512 Kbytes */ define symbol __ICFEDIT_region_RAM_end__ = 0x2407FFFF; define symbol __ICFEDIT_region_RAM_D2_start__ = 0x30000000; /* 288 Kbytes */ define symbol __ICFEDIT_region_RAM_D2_end__ = 0x30047FFF; define symbol __ICFEDIT_region_RAM_D3_start__ = 0x38000000; /* 64 Kbytes */ define symbol __ICFEDIT_region_RAM_D3_end__ = 0x3800FFFF; define symbol __ICFEDIT_region_SDRAM_start__ = 0xD0000000; /* 3600 Kbytes */ define symbol __ICFEDIT_region_SDRAM_end__ = 0xD0383FFF; define symbol __ICFEDIT_region_SDRAM2_start__ = 0xD0384000; /* 4592 Kbytes */ define symbol __ICFEDIT_region_SDRAM2_end__ = 0xD07FFFFF; /*-Quad-SPI Memory Regions-*/ define symbol __ICFEDIT_region_QSPI_start__ = 0x90000000; define symbol __ICFEDIT_region_QSPI_end__ = 0x93FFFFFF; /* 64 Mbytes */ /*-Sizes-*/ define symbol __ICFEDIT_size_cstack__ = 0x1000; /* 2 Kb */ define symbol __ICFEDIT_size_heap__ = 0xC000; /* 2 Kb */ /**** End of ICF editor section. ###ICF###*/ define memory mem with size = 4G; define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__ ]; define region ITCMRAM_region = mem:[from __ICFEDIT_region_ITCMRAM_start__ to __ICFEDIT_region_ITCMRAM_end__]; define region DTCMRAM_region = mem:[from __ICFEDIT_region_DTCMRAM_start__ to __ICFEDIT_region_DTCMRAM_end__]; define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__ ]; define region RAM_D2_region = mem:[from __ICFEDIT_region_RAM_D2_start__ to __ICFEDIT_region_RAM_D2_end__ ]; define region RAM_D3_region = mem:[from __ICFEDIT_region_RAM_D3_start__ to __ICFEDIT_region_RAM_D3_end__ ]; define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__ to __ICFEDIT_region_SDRAM_end__ ]; define region SDRAM2_region = mem:[from __ICFEDIT_region_SDRAM2_start__ to __ICFEDIT_region_SDRAM2_end__ ]; define region QSPI_region = mem:[from __ICFEDIT_region_QSPI_start__ to __ICFEDIT_region_QSPI_end__]; //define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; //define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; define block FRAME_BUF with alignment = 4 { first section TouchGFX_Framebuffer }; initialize by copy { readwrite } except { section .isr_vector, section .text_init, section .text, section .rodata_init, section .preinit_array, section .init_array, section .data_init, section ExtFlashSection_init, section ExtFlashSection, section FontFlashSection_init, section FontFlashSection, section FontSearchFlashSection }; do not initialize { section .noinit, section .bss, section TouchGFX_Framebuffer, section BufferSection }; place in ITCMRAM_region { }; place in DTCMRAM_region { }; place in RAM_region { readwrite , section .bss, last section ._user_heap_stack }; place in RAM_D2_region { }; place in RAM_D3_region { }; place in SDRAM_region { block FRAME_BUF }; place in SDRAM2_region { section BufferSection }; place at start of ROM_region { readonly section .isr_vector }; place in ROM_region { readonly, first section .text_init, section .text,section .rodata_init, section .rodata, section .ARM, section .preinit_array, section .init_array, section .fini_array, section TextFlashSection, last ro code section .data }; //section .rodata, place in QSPI_region { first section ExtFlashSection, section FontFlashSection_init, section FontFlashSection, last section FontSearchFlashSection };
遇到的错误
错误1:RAM空间不足
Error[Lp011]: section placement failed unable to allocate space for sections/blocks with a total estimated minimum size of 0x27'02f0 bytes (max align 0x4) in <[0x2400'0000-0x2407'ffff]> (total uncommitted space 0x8'0000).
问题根源:initialize by copy { readwrite } 会尝试将所有读写段(包括QUADSPI中的段)复制到RAM,但RAM空间远不足以容纳。
错误2:ROM区域混合放置读写段
Error[Lp005]: placement includes a mix of sections with content (example "ro data init_array section .init_array in TouchGFXConfiguration.o") [suitable for placement in ROM] and sections without content (example "rw data section .data in HardwareMJPEGDecoder.o symbols: [JPEG_OUT_Read_BufferIndex, Jpeg_OUT_BufferTab, MCU_BlockIndex, semDecodingDone, DMA2D_CopyBufferEnd]") [suitable for placement in RAM] C:\MT\MT394\SW\Riverdi_7\MT394.251014.Riverdi7_Steam_gui_v1.4.2E_BK03_test_IAR_9.70_err_comp\EWARM\stm32h747xx_flash_CM7_example.icf 83
问题根源:在ROM区域的放置规则中加入了section .data,而.data是读写段,只能放在RAM,其初始化数据应放在ROM而非段本身。
解决方案
针对上述问题,对ICF文件做以下关键修改:
缩小initialize by copy的范围
替换原有的initialize by copy { readwrite } except ...,改为仅指定需要从Flash复制到RAM的段:initialize by copy { section .data, section .data*, section .RamFunc, section .RamFunc* };这样就不会将QUADSPI中的读写段(如果有的话)纳入复制范围,避免RAM被过度占用。
修正RAM区域的放置规则
明确指定RAM区域需要放置的段,包括.data系列、.bss和堆栈:place in RAM_region { section .data, section .data*, section .RamFunc, section .RamFunc*, section .bss, last section ._user_heap_stack };移除ROM区域中的.data段
删除ROM区域放置规则中的last ro code section .data,确保ROM只放置只读段:place in ROM_region { readonly, first section .text_init, section .text, section .rodata_init, section .rodata, section .ARM, section .preinit_array, section .init_array, section .fini_array, section TextFlashSection };调整do not initialize规则
移除.bss(IAR默认会自动清零.bss,无需手动标记不初始化):do not initialize { section .noinit, section TouchGFX_Framebuffer, section BufferSection };
完整修改后的ICF核心片段
// ... 保留原有的memory region定义部分 ... define block FRAME_BUF with alignment = 4 { first section TouchGFX_Framebuffer }; // 仅复制需要加载到RAM的读写段 initialize by copy { section .data, section .data*, section .RamFunc, section .RamFunc* }; do not initialize { section .noinit, section TouchGFX_Framebuffer, section BufferSection }; place in ITCMRAM_region { }; place in DTCMRAM_region { }; place in RAM_region { section .data, section .data*, section .RamFunc, section .RamFunc*, section .bss, last section ._user_heap_stack }; place in RAM_D2_region { }; place in RAM_D3_region { }; place in SDRAM_region { block FRAME_BUF }; place in SDRAM2_region { section BufferSection }; place at start of ROM_region { readonly section .isr_vector }; place in ROM_region { readonly, first section .text_init, section .text, section .rodata_init, section .rodata, section .ARM, section .preinit_array, section .init_array, section .fini_array, section TextFlashSection }; place in QSPI_region { first section ExtFlashSection, section FontFlashSection_init, section FontFlashSection, last section FontSearchFlashSection };
原理说明
.data和.RamFunc系列段是读写段,需要在RAM中运行,其初始化数据存储在Flash,通过initialize by copy实现启动时从Flash复制到RAM。- QUADSPI中的段是只读资源(如字体、图片),直接在QSPI Flash中访问即可,无需复制到RAM,节省RAM空间。
- ROM区域仅放置只读代码和数据,避免混合读写段导致的Lp005错误。
内容的提问来源于stack exchange,提问作者Yozora

