P1 当把 RFD28F 添加进项目时,报错如下:
栈溢出 .text
E0562330: Relocation size overflow : "DefaultBuild\sample_control_codeflash.obj" - ".text" -00000b
(1)右键 Subproject 的 CC-RH —— LinkOptions Tab —— Section —— Section start address 查看段分布。
(2)查看 subproject 的 DefaultBuild 文件夹下的 map 文件(MULTI_COER.map)。发现 .data 的 end address 距离 eitbl_pe0.const 的 start adress 还有很大的空间,不可能会越界。应该不是 段大小设置的问题,应该是代码的问题。
(3)首先通过 CS+ 的 查找工具 ctrl+F(“Find in files”,search location 选择“main project and subproject”),通过关键字 "sample_control_codeflash" 找到文件 "sample_control_codeflash.c"。
(4)右键 "sample_control_codeflash.c",选择 property,将 “Set as build-target” 设置为否,即屏蔽该文件,不让该文件参与编译。
(5)再次编译时,发现是 sample 文件夹下的 source 所有文件的问题。将这些文件全部屏蔽。发现编译通过。
备注:一般而言,双击编译器报错的行,会跳转到网页告诉你大致是什么错误。但是本机不能上外网。另一个方法是【点击 Help—— Open Help for Property Panel】
注意: 在不同的页面点击 Help—— Open Help for Property Panel 其跳转的网页均不同。网页就是当前页的相关帮助信息。
(6)双击编译输出的错误行,根据错误码,可以判断是跳转的错误。猜想是指令出了问题,指令相关选项一般在 "Compile Options" Tab。在当前页点击 Help—— Open Help for Property Panel,会出现当前页的相关指引。找到 “Specify jump instruction”的说明,应该选择 jarl32
跳转指令,即选择 "Create jarl32 and jr32 instructions"。
解决办法:打开build_tool工具,选到Compile options
将Output code下面的Specify jump instruction设置为-Xcall_jump=32
最终,编译通过!
补充:但是办法只是并没有解决本质问题。
P2(接 P1)除了报错,还有一堆如下的 warning:
Section address is not assigned to ".R_RFD_CODE_CF.text"
Section address is not assigned to ".R_RFD_CODE_CF_RAM_NO_BGO.text"
...
备注:嵌入式的编译,一般要明白所有 warning 的原因,并消除所有的 warning,否则后面会出现各种奇奇怪怪问题。
既然 warning 是关于段的问题,因此我们去 map 文件查看,发现这几个段都处于 0xfdc0 24c0 ~ 0xfdc0 4041
,而根据芯片手册,FDC0 0000H ~ FDC0 FFFFH
属于 Local RAM(CPU0) ,而这些 函数文本 text 段理应放在 .text
(位于 code flash,根据手册,位于 0x00xx xxxx
开头的地址)
备注:对 section 地址的映射,可以在汇编代码里指出,也可以在 C 文件中用 pragma
关键字指出。
通过全局搜索 pragma
,我们找到 r_rfd_memmap.h
文件,里面对 warning 涉及的所有段都进行了 pragma section
创建。
如下列链接所述, 通过编译指示pragma section
,可以轻松地将多个对象定位到用户定义的section中。
再看 r_rf_cf_api.c
这个文件,这个文件是使用 define - include - undefine
的方式,将特定变量放在特定的段:
1)
#define R_RFD_EXTRA_START_SEC_CONST_UNSPECIFIED
#include "r_rfd_memmap.h"
2)
#define R_RFD_EXTRA_STOP_SEC_CONST_UNSPECIFIED
#include "r_rfd_memmap.h"
3)
#define R_RFD_VERSION_CF_START_SEC_CONST_UNSPECIFIED
#include "r_rfd_memmap.h"
4)
#define R_RFD_VERSION_CF_STOP_SEC_CONST_UNSPECIFIED
#include "r_rfd_memmap.h"
解决办法1:按照参考链接,在 link option 里将定义的段,分配到 0x0000 4000
后面的地址 【2023/10/11 注:0x0000 4000
是 code flash 的地址, BSS 段不可放于此处,应该放在地址为 0x0004 0000
的 data flash 空间】
解决办法2:在 r_rfd_memmap.h
里,将 warning 的这几个段,都改为 #pragma section default
P3 发现当读取寄存器的值时报不对齐错误
在执行完如下寄存器赋值局部变量语句时,
l_bu4_FSTATR = R_RFD_REG_FSTATR;
跳转到如下汇编,MAE 即 Miss Align Error,即地址不对齐错误
jr32 _Dummy ; MAE
上一条语句是下述的调用函数:
rfd_fv0_SetFaci(i_u2_TargetFACI)
{
if (i_u2_TargetFACI == R_RFD_FACI0)
{
bu4_CMN_FaciBaseAddress = R_RFD_BASE_FACI0;
}
}
========
#define R_RFD_BASE_FACI0 0xFFA10000UL
于是进入函数调试。
我们查看数据手册,寄存器 R_RFD_REG_FSTATR
是 FaciBaseAddress + 0x80
,即在 FACI 基地址上偏移 0x80。于是,关注FACI 基地址的赋值。
// R_RFD_REG_FSTATR 的定义由来如下:
extern T_u4 bu4_CMN_FaciBaseAddress;
#define FACI (*(volatile struct faciRegisters *)bu4_CMN_FaciBaseAddress)
#define R_RFD_REG_FSTATR (FACI.FSTATR)
通过调试,确定编译时,bu4_CMN_FaciBaseAddress
即为 FACI0 的地址 0xFFA10000
if (i_u2_TargetFACI == R_RFD_FACI0)
{
bu4_CMN_FaciBaseAddress = R_RFD_BASE_FACI0;
...
}
========
#define R_RFD_BASE_FACI0 0xFFA10000UL
我们再回到 bu4_CMN_FaciBaseAddress = R_RFD_BASE_FACI0;
对应的汇编代码。由于编译器会有优化策略,导致汇编代码有些理解不了的地方,我们勾选 Compile Options - Optimization-Level of optimization
为 Perform the default optimization
调整编译器优化策略为无策略。调整后,汇编代码如下:
bu4_CMN_FaciBaseAddress = R_RFD_BASE_FACI0;
movhi 0x3, r0, r2
movhi 0xffa1, r0, tp ; tp 即 r5
st.w tp -0x3458[r2] ; 0x00030000 - 0x00003458 = 0x2cba
由于 bu4_CMN_FaciBaseAddress
是全局变量,我们可以在 link options —— Output symbol information
里配置 Output symbol information
勾选为 Yes
。这样 .map
文件就记录了全局变量的地址信息。
我们发现 bu4_CMN_FaciBaseAddress
的内存地址为 0x2cba
,即汇编代码是成功将 tp (值为FACI0 的基地址:0xffa1) 写入变量bu4_CMN_FaciBaseAddress
。而 变量bu4_CMN_FaciBaseAddress
跟预期值不一致。手动修改 tp 寄存器的值,观察发现内存 0x2cba
的值依旧不变化。表明该地址无法执行写操作。
阅读代码,发现全局变量bu4_CMN_FaciBaseAddress
是未赋值的全局变量,应当放在 BSS 段。打开 Link Options —— Section —— Section start address
发现 _R_RFD_BSS,bss
段添加在了地址 0x00004000
后面,而该地址是 code flash ,是只读无法修改的地址。应该将该段添加在地址 0xFDC00000
里面,0xFDC00000 ~ 0xFDC0FFFF
地址是 Local RAM(CPU0)。
// Section Settings
0xFDC0 0000 .data.R
.bss
.stack.bss
但是,应该注意,苏工在设置heap 时,让 heap 范围为 .stack.bss
的 end 到 0xFDC10000:
/* board.c */
extern char _E_stack_bss[];
void rt_hw_board_init()
{
r_device_init();
rt_system_heap_init((VOID *)_e_STACK_BSS, (void *)0xFDC10000);
...
}
其中 _E_STACK_BSS
是编译器自动生成的,表示段 .stack.bss
的 end address;同理,表示 _S_STACK_BSS
表示段 .stack.bss
的 start address。
因此,对于 .R_RFD_BSS.bss
,必须放到 .stack.bss
前面:
// Section Settings
0xFDC0 0000 .data.R
.bss
.R_RFD_BSS.bss
.stack.bss
完整的段设置 section settings 如下:
0x0000 4000 .const
xxx
xxx
.data
.xxx.text
.xxx.text
0x0004 0000 EIINTTBL_PE0.const
EIINTTBL_PE1.const
EIINTTBL_PE2.const
EIINTTBL_PE3.const
0xFDC0 0000 .data.R
.bss
.R_RFD_BSS.bss
.stack.bss
补充1:要学会从导航栏 Help—Help 里寻找有用的信息,比如上述 _E_STACK_BSS
与 _S_STACK_BSS
的命名规则可以在帮助文档里的 Compiler—SECTION SPECIFICATIONS—Sections—Special Symbol 里找到。
补充2:注意 section settings 里将 .data 映射到 code flash(ROM),同时将其映射到 RAM 的段 data.R 放在 Local RAM 上。.data 与 .data.R 的映射关系在【 Link Options — Section — ROM to RAM mapped section】中添加 ,里面的值为 .data = .data.R