前言
最近想在Tasking编译器的.lsl链接文件中定义一个ROM Section用做标定段,发现修改了.lsl链接文件后使用#pragma section farrom xxx修饰const常量,总是不能将常量放到我们指定的Memory Section中,测试了很多办法,最后才成功,通过本文将改过程记录下来,同时也总结了Tasking编译器关于内存分配的一些规则,希望对大家有帮忙。
AUTOSAR BSW Tool:Vector
AUTOSAR MCAL Tool:EB
Hardware Platform: Infineon Tricore TC387
Build Tool: Tasking
Debug Tool: UDE
关于Tasking编译器链接脚本的基本用法,可以参考:AURIX™ TC3xx MCAL中Link文件解析以及代码变量定位方法详解 (qq.com)
注:本文章引用了一些第三方工具和文档,若有侵权,请联系作者删除!
正文
我们在Tasking的链接脚本中定义了一个CAL_ROM Section段(注意:后文的测试过程中链接脚本没有再修改过)。
通过# pragma试图让我们的const常量CAL_ROM_TestData分配到CAL_ROM内存中去(期望CAL_ROM_TestData的内存地址为0x80003000)。
编译后查看Map文件,发现CAL_ROM_TestData并没有分配到CAL_ROM指定的起始地址处,_cal_rom_start的地址是0.
尝试办法1:CAL_ROM_TestData改为CAL_ROM_TestData[2]
结果1:失败,CAL_ROM_TestData并没有分配到CAL_ROM指定的起始地址处,_cal_rom_start的地址是0.
尝试办法2:CAL_ROM_TestData改为CAL_ROM_TestData[3]
结果2:成功,CAL_ROM_TestData分配到CAL_ROM指定的起始地址处(0x80003000),_cal_rom_start的地址也是0x80003000.
后面继续尝试了CAL_ROM_TestData[4], CAL_ROM_TestData[8], 也都达到目的了。
也就说,CAL_ROM_TestData能否分配到CAL_ROM指定的起始地址处和CAL_ROM_TestData的数据大小有关(8 bytes是个临界点,大于等于8 bytes就成功),至于为什么,我们后面再解释。
我们就是要定义一个小于等于8 bytes的数据,且要放到CAL_ROM地址处,那又该怎么办了?
尝试办法3:farrom改成nearrom.
结果3:失败,CAL_ROM_TestData并没有分配到CAL_ROM指定的起始地址处,_cal_rom_start的地址是0.
尝试办法4:变量前添加__far的修饰符。
结果4:成功,CAL_ROM_TestData分配到CAL_ROM指定的起始地址处(0x80003000),_cal_rom_start的地址也是0x80003000.
尝试办法5:类似办法4,变量前添加__near的修饰符。
结果5:失败。
尝试办法6:不用#pragma,改用__attribute__((section("CAL_ROM")))定义CAL_ROM_TestData.
结果6:成功,CAL_ROM_TestData分配到CAL_ROM指定的起始地址处(0x80003000),_cal_rom_start的地址也是0x80003000.
注意1:__attribute__((section(".rodata.CAL_ROM")))如果改为__attribute__((section("CAL_ROM")))也会失败。
办法6起始已经比较好了,任意字节的变量/常量都可以分配到我们指定的内存起始地址处了。但是,写代码很少人会使用__attribute__((section(".rodata.CAL_ROM")))这种方式定义变量,指定变量内存区域都是使用#pragma的方式。
继续想办法!!
尝试办法7:添加--default-near-size=0的编译选项。
使用#pragma进行内存分配,也就说回到我们最初的代码定义方式。
结果7:成功,CAL_ROM_TestData分配到CAL_ROM指定的起始地址处(0x80003000),_cal_rom_start的地址也是0x80003000.
小结:方法2,4,6,7都能让变量/常量分配到指定的内存地址处,但是,
方法2需要限定变量的大小,大于等于8字节的变量才能指定到特定内存地址处。
方法4,变量需要添加额外的__far修饰符。
方法6,不能使用常见的#pragma.
方法7,最符合我们常见的代码写法,也就说办法7是最优的办法。
到这里,我们找到了Tasking中指定变量内存地址的最优办法,但是大家一定会有很多的问题,比如:
问题1:什么nearrom和farrom?
问题2:__far和__near是什么?
问题3:--default-near-size=0是什么编译选项?
问题4:使用.rodata和.zrodata内存段存放了什么数据?
问题5:使用--default-near-size=0编译选项就没有任何弊端吗?
带着这些问题,我们继续下文的精彩分析。
注意:上面这些实验内容,写出来看着很容易,实际我是耗费大量的时间才找到上面的规律的(网上的内容参差不齐,关键的细节没有说明白的),看到这里,还不点个赞加个关注么!!!
1.用__far修饰的const变量会被分配在farrom中,__near修饰的const变量会被分配在nearrom中。
2.farrom可以是内存的任何地方(Anywhere),nearrom分配在一个256 MB的block的头16 KB位置(注意:这个256 MB的头16 KB理解不了,尝试了各种办法也没有找到这个nearrom在哪里)。
3.farrom是通过CPU间接寻址的方式访问,速度较慢,near是通过CPU直接寻址的方式访问,速度较快。
4.nearrom的数据最大长度是16Kb.
5.一个const变量没有添加__far或者__near的修饰符,那么编译器会根据default near size(默认是8 bytes)来自动分配const变量到nearrom还是farrom:
const变量大小 <= default near size(比如8 bytes) --> 编译会分配到nearrom
const变量大小 > default near size(比如8 bytes) --> 编译会分配到farrom
6.可以通过--default-near-size=xxx(或者-N=xxx)来指定default near size. 我们在上文中通过指定--default-near-size=0使得编译将没有添加__far或者__near修饰的const常量都分配到farrom.
7.尝试过很多办法,都没办法找到nearrom到底在哪里,也就是所,我们无法在链接文件中定义一块内存是nearrom。也就说无法通过#pragma section nearrom或者__near的修饰符让const变量放置到指定内存中,所以我们只能通过--default-near-size=0编译选项使得编译将器没有添加__far或者__near修饰的const常量都分配到farrom(因为farrom可以在任意内存位置,我们可以通过链接脚本指定)。
8..rodata中存放的是farrom数据,也就是const __far修饰的变量;.zrodata中存放的是nearrom数据,也就是const __near修饰的变量(.rodata中的数据访问慢些,.zrodata中的数据访问快些)。
使用GHS编译器是,如果我们想通过#pragma指定任意数据的内存地址,最好添加-sda = 0的编译选项,具体细节各位读者可以去深入研究。
问题1:什么nearrom和farrom?
答:nearrom是被CPU直接访问(快速)的rom内存,存在于一个256 KB block的头16 KB处,具体在哪,不清楚,尝试了各种办法,没办法通过链接文件定义nearrom内存(编译器特殊指定?)。farrom是被CPU间接访问(较慢)的ROM内存,可以存在与ROM的任何位置,可以在链接文件中自定义。
问题2:__far和__near是什么?
答:__far和__near用来修饰const变量或者变量,__far修饰的const常量分配在farrom, __near修饰的const常量分配在nearrom. 如果一个const常量没有被__far或者__near修饰,那么编译器会根据default near size的大小来自动分配const常量到nearrom还是farrom.具体规则如下:
const变量大小 <= default near size(比如8 bytes) --> 编译会分配到nearrom
const变量大小 > default near size(比如8 bytes) --> 编译会分配到farrom
问题3:--default-near-size=0是什么编译选项?
答:--default-near-size=0指定default near size为0,这样设置后,没有添加__far或者__near的变量都会分配到farrom/fardata/farbss中。
问题4:使用.rodata和.zrodata内存段存放了什么数据?
答:.rodata中存放的是farrom数据,也就是const __far修饰的变量;.zrodata中存放的是nearrom数据,也就是const __near修饰的变量(.rodata中的数据访问慢些,.zrodata中的数据访问快些)。
问题5:使用--default-near-size=0编译选项就没有任何弊端吗?
答:有。所有未添加__far/__near的数据都会放到farrom/fardata/farbss内存段中,访问速度会变慢。
End
「汽车电子嵌入式在CSDN上同步推出AUTOSAR精进之路专栏,本专栏每个模块完全按实际项目中开发及维护过程来详细介绍。模块核心概念介绍、实际需求描述、实际工程配置、特殊需求介绍及背后原理、实际工程使用经验总结。 目的是让读者看完每一个章节后能理解原理后根据需求完成一个模块的配置或者解决一个问题。」
点击文章最后左下角的阅读原文可以获取更多信息
或者复制如下链接到浏览器获取更多信息
https://blog.csdn.net/qq_36056498/article/details/132125693
文末福利
2.为便于技术交流,创建了汽车电子嵌入式技术交流群,可尽情探讨AP,CP,DDS,SOME/IP等前沿热点话题,后台回复“加群”即可加入;
注:本文引用了一些第三方工具和文档,若有侵权,请联系作者删除!
推荐阅读
汽车电子嵌入式精彩文章汇总第一期:20210530-20230703
汽车电子嵌入式精彩文章汇总第2期
汽车电子嵌入式精彩文章汇总第3期
【OS】AUTOSAR OS Event实现原理
【OS】AUTOSAR OS Spinlock实现原理(下篇)
【OS】AUTOSAR OS Spinlock实现原理(上篇)
CanNm处于PBS状态下接收到一帧诊断报文DCM会响应吗
TC3xx芯片CAN模块详解
AUTOSAR OS Alarm实现原理
AUTOSAR OsTask切换原理
TC3xx 芯片SPI模块详解
AUTSOAR ComStack如何实现PDU只收不发的
AUTOSAR OsStack监控原理
AUTOSAR架构下ICU唤醒详解
CanNm报文的触发发送详解
Can报文能发不能收问题分析
TC3xx芯片PFlash的ECC校验问题补充
AUTOSAR架构下唤醒源检测函数EcuM_CheckWakeup详解
什么是Copy Table及如何使用Copy Table
AUTOSAR架构下EcuM_StartupTwo函数功能详解
符合AUTOSAR标准的RTAOS-Schedule Tables详解(上篇)
AUTOSAR OS Schedule Table实现原理
符合AUTOSAR标准的RTAOS-Schedule Tables详解(下篇)
TJA1145收发器重要功能介绍
AUTOSAR架构下基于TJA1145收发器通信丢失问题分析
AUTOSAR架构下LIN报文发送失败问题分析
AUTOSAR项目实战(1)-数据地址访问对齐问题分析
AUTOSAR项目实战(2)-内存访问异常问题分析
AUTOSAR项目实战(4)-系统总线及外设错误问题分析
AUTOSAR项目实战(3)-OsCounter访问权限问题分析
AUTOSAR项目实战(4)-MCU模块配置实践
AUTOSAR架构下的Interrupt详解(上篇)
AUTOSAR架构下的Interrupt详解(下篇)
AUTOSAR项目实战(6)-Port及Dio模块配置实践
TJA1145异常设置唤醒源导致ECU休眠失败问题分析
End
欢迎点赞,关注,转发,在看,您的每一次鼓励,都是我最大的动力!
汽车电子嵌入式
微信扫描二维码,关注我的公众号