博主联系方式:QQ:1256153255 ,email:1256153255@qq.com
website for get 瑞萨RH850F1x开发板和瑞萨E1仿真器
1、简介
本文介绍了RH850 FCL的使用以及相关的经验技巧,使用的环境如下
MCU:瑞萨RH850F1K
型号:R7F701557
编译器:IAR for RH850
编译器版本:IAR Embeded Workbench for Renesas RH850 V2.10.1
IAR Embeded Workbench shared components V8.1.1.5550
仿真器:瑞萨E1仿真器
Flash烧录软件:Renesas Flash Programmer V3.08
FCL库版本:RENESAS_FCL_RH850_T01_V2.13
瑞萨的资料本身就少,而有讲解FCL的文章更是少之又少,搜索了FCL的资料,找来找去也就那几篇介绍的,而且大家用的还是瑞萨自己的CS+编译器,用的MCU系列也不是F1K的,所以看了很多遍都无济于事。
介于以上,自己就根据FCL库的官方介绍文档(RH850 Family Code Flash Library)一点点的摸索,这篇文档前后看了不下5遍,最终还是成功地将FCL移植到自己的开发板上了。
2、R7F701557资源介绍
既然在移植中使用的开发板芯片时R7F701557,那么就必须对R7F701557的片上资源(主要时ROM和RAM)有个明确的了解,查询芯片的用户手册得到
也就是说R7F701557的ROM:1MBytes RAM:64KBytes,地址范围分别如下。
3、Section配置
有前辈在blog中这样写到Section的配置
这样的配置方法都是在CS+中操作的,那么我用的IAR是否已经将这些Section配置好了?如果配置好了,那么在那里配置的?如果没有配置好,那么怎么配置?
首先从.map文件入手,看看是否已经有这些section了,查找之后确实有
File name:*.map
"ROM1ST", part 1 of 2: 0x2ba2
FCL_LIBRARY 0x1f8 0x28b0 <Block>
R_FCL_CODE_ROM 0x1f8 0x2c4 <Block>
R_FCL_CODE_ROM ro code 0x1f8 0x228 r_fcl_user_if.o [1]
R_FCL_CODE_ROM ro code 0x420 0x9c r_fcl_hw_access_asm.o [1]
R_FCL_CODE_USRINT 0x4bc 0x0 <Block>
R_FCL_CODE_USRINT ro code 0x4bc 0x0 r_fcl_hw_access_asm.o [1]
R_FCL_CODE_USR 0x4bc 0x1e0 <Block>
R_FCL_CODE_USR ro code 0x4bc 0x15a fcl_ctrl.o [1]
R_FCL_CODE_USR ro code 0x618 0x84 fcl_user.o [1]
R_FCL_CODE_USR ro code 0x69c 0x0 r_fcl_hw_access_asm.o [1]
R_FCL_CODE_RAM 0x69c 0x1508 <Block>
R_FCL_CODE_RAM ro code 0x69c 0x13ac r_fcl_hw_access.o [1]
R_FCL_CODE_RAM ro code 0x1a48 0x98 r_fcl_hw_access_asm.o [1]
R_FCL_CODE_RAM ro code 0x1ae0 0xc4 r_fcl_user_if.o [1]
R_FCL_CODE_ROMRAM 0x1ba4 0xeb4 <Block>
R_FCL_CODE_ROMRAM ro code 0x1ba4 0xb9a r_fcl_hw_access.o [1]
R_FCL_CODE_ROMRAM ro code 0x2740 0x318 r_fcl_user_if.o [1]
R_FCL_CODE_ROMRAM ro code 0x2a58 0x0 r_fcl_hw_access_asm.o [1]
R_FCL_CODE_RAM_EX_PROT
0x2a58 0x50 <Block>
R_FCL_CODE_RAM_EX_PROT
File name:*.map
"LOC1ST": 0x8000
FCL_RAM_BLOCK_FCL_RESERVED
0xfebe'0000 0x8000 <Block>
FCL_RESERVED uninit 0xfebe'0000 0x8000 main.o [1]
- 0xfebe'8000 0x8000
"RAM1ST": 0x80
FCL_RAM_BLOCK_R_FCL_DATA
0xfede'8000 0x80 <Block>
R_FCL_DATA uninit 0xfede'8000 0x80 r_fcl_user_if.o [1]
- 0xfede'8080 0x80
既然有这些section,那么是在哪里定义的呢?请看这两份文件layout.icf和lnkr7f701557.icf,这可是工程自带的,这两个文件里边应该是有猫腻的。关于.icf文件有看不懂的童鞋,请自行百度,此处不详述。
在layout.icf中有这样两段定义
File name:layout.icf
define block FCL_RAM_BLOCK_FCL_RESERVED with fixed order, alignment=4 { rw section FCL_RESERVED };
define block FCL_RAM_BLOCK_R_FCL_DATA with fixed order, alignment=4 { rw data section R_FCL_DATA };
keep { section FCL_RESERVED };
define block R_FCL_CODE_ROM with alignment=4 {ro code section R_FCL_CODE_ROM};
define block R_FCL_CODE_USRINT with alignment=4 {ro code section R_FCL_CODE_USRINT};
define block R_FCL_CODE_USR with alignment=4 {ro code section R_FCL_CODE_USR};
define block R_FCL_CODE_RAM with alignment=4 {ro code section R_FCL_CODE_RAM};
define block R_FCL_CODE_ROMRAM with alignment=4 {ro code section R_FCL_CODE_ROMRAM};
define block R_FCL_CODE_RAM_EX_PROT with alignment=4 {ro code section R_FCL_CODE_RAM_EX_PROT};
define block FCL_LIBRARY with fixed order, alignment=4 { ro section R_FCL_CONST,
block R_FCL_CODE_ROM,
block R_FCL_CODE_USRINT,
block R_FCL_CODE_USR,
block R_FCL_CODE_RAM,
block R_FCL_CODE_ROMRAM,
block R_FCL_CODE_RAM_EX_PROT
};
既然有了section的定义,那么每个section分配的地址空间又是在哪儿定义的?继续找,找到这里
File name:layout.icf
"ROM1ST":place in ROM_1ST_region
{
block CALLT,
block TRAP,
block FETRAP,
block HVTRAP,
ro,
block FCL_LIBRARY,
block .syscalltable,
block .hvcalltable,
block ROM_BLOCK
};
尤其要注意这里的FCL_LIBRARY
也就是说,那些R_FCL_CODE_*的block都是属于FCL_LIBRARY这个大的block,而FCL_LIBRARY这个block属于ROM1ST,而ROM1ST又是place in ROM_1ST_region。那么ROM_1ST_region在哪儿定义的?继续找,发现layout.icf中没有了,那就去lnkr7f701557.icf中找找看,结果还真找到了
File name:lnkrr7f701557.icf
define region ROM_1ST_region = mem:[from 0x00000000 to 0x000FFFFF]; // <code default> Code FLASH
至此也就明白了,FCL_LIBRARY下的block是在哪儿定义的,以及是在哪儿分配的地址空间。
OK,找完了ROM的section,还有两个在RAM中的section(R_FCL_DATA和FCL_RESERVED)也是同样的方法找
File name:layout.icf
"LOC1ST":place at start of LOC_1ST_region { block FCL_RAM_BLOCK_FCL_RESERVED };
"LOC1ST":place in LOC_1ST_region
{
rw section LOCAL1_RAM*
};
File name:lnkrr7f701557.icf
define exported symbol _LOC_1ST_BEG = 0xFEBE0000;
define exported symbol _LOC_1ST_END = 0xFEBEFFFF;
define region LOC_1ST_region = mem:[from _LOC_1ST_BEG to _LOC_1ST_END]; // LOCAL1_RAM Local RAM for PE1
很好,也找完了。
4、文件修改
fcl_descriptor.h
#define FCL_CPU_FREQUENCY_MHZ (80) /*!< CPU frequency in MHz */
#define FCL_AUTHENTICATION_ID {0xFFFFFFFF, \
0xFFFFFFFF, \
0xFFFFFFFF, \
0xFFFFFFFF} /*!< 128Bit authentication ID */
#define FCL_RAM_ADDRESS 0xFEDE0000 /*!< RAM address range blocked for FCL */
我们只需修改CPU频率和RAM地址
从上边可以知道557的CPU频率是80MHz,RAM起始地址是0xFEDE 0000。
5、main()函数执行
5.1 ret = R_FCL_Init (&sampleApp_fclConfig_enu);
该函数用于初始化FCL,这个函数在ROM中执行。
5.2 ret = R_FCL_CopySections ();
该函数用于将一些FCL代码块copy到RAM中一个特定的地址中。在这个位置上,虽然Code Flash不可使用但是代码依然可以被执行。
函数R_FCL_CopySections在ROM中被执行。
5.3 fpFct = ( uint32_t (*)() )R_FCL_CalcFctAddr ( (uint32_t)(&FCL_Ctrl) );
fpFct ();
这个函数用于计算一个从ROM复制到RAM的函数的新地址。也就是说R_FCL_CalcFctAddr是为了计算出一个新的RAM地址,这个地址用于在RAM中运行一个特定的函数,这个特定的函数是从ROM中搬到RAM中运行的。为了能够计算这个特定函数的新RAM地址,这个特定的函数必须是FCL linker segments之一。
R_FCL_CalcFctAddr在ROM中被执行。
其实看这两行代码还是挺有意思的,函数R_FCL_CalcFctAddr()的形参是地址,用法(uint32_t)(&FCL_Ctrl) 是取函数FCL_Ctrl的地址,也就是说作为R_FCL_CalcFctAddr()的实参。R_FCL_CalcFctAddr()的返回值是destination address也就是新的RAM地址,经过强制类型转换( uint32_t (*)() )之后,R_FCL_CalcFctAddr成了一个函数指针,返回值是一个指针,指向新的RAM地址。因此fpFct ();是在RAM中执行的。从而实现了将FCL_Ctrl从ROM搬到RAM执行。
5.4 最后就是while(1)这个主循环了。
由于FCL_Ctrl在RAM中执行,那么在仿真时就没法看到FCL_Ctrl函数体的执行情况了。
所以在此为了能够看到FCL_Ctrl的执行结果,就定义了一个全局变量test_value用于观察FCL_Ctrl的执行结果。
5.4.1 获取Flash的Block Counter
void FCL_Ctrl (void)
{
r_fcl_request_t myRequest;
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
r_fcl_request_t mySecRequest;
#endif
uint8_t writeBuffer_u08[512];
uint32_t readBuffer_u32[8];
uint16_t i;
REINITIALIZE_BUFFER;
FCLUser_Open ();
/* prepare environment */
myRequest.command_enu = R_FCL_CMD_PREPARE_ENV;
R_FCL_Execute (&myRequest);
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
while (R_FCL_BUSY == myRequest.status_enu)
{
R_FCL_Handler ();
}
#endif
/* get block count */
myRequest.command_enu = R_FCL_CMD_GET_BLOCK_CNT;
myRequest.bufferAdd_u32 = (uint32_t)&readBuffer_u32[0];
R_FCL_Execute (&myRequest);
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
while (R_FCL_BUSY == myRequest.status_enu)
{
R_FCL_Handler ();
}
#endif
test_value = myRequest.bufferAdd_u32;
// /* get block end address of block 2 */
// REINITIALIZE_BUFFER;
// myRequest.command_enu = R_FCL_CMD_GET_BLOCK_END_ADDR;
// myRequest.bufferAdd_u32 = (uint32_t)&readBuffer_u32[0];
// myRequest.idx_u32 = 0x2; /* result: 0x5fff */
// R_FCL_Execute (&myRequest);
// test_value = myRequest.bufferAdd_u32;
//
// /* erase block 2 and 3 */
// myRequest.command_enu = R_FCL_CMD_ERASE;
// myRequest.idx_u32 = 0x2; /* erased range = 0x4000 to 0x7fff */
// myRequest.cnt_u16 = 2;
// R_FCL_Execute (&myRequest);
// #if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
// while (R_FCL_BUSY == myRequest.status_enu)
// {
// R_FCL_Handler ();
// }
// #endif
//
// /* write 512 bytes to address 0x40000 (start of block 2) */
// REINITIALIZE_BUFFER;
// myRequest.command_enu = R_FCL_CMD_WRITE;
// myRequest.bufferAdd_u32 = (uint32_t)&writeBuffer_u08[0];
// myRequest.idx_u32 = 0x4000;
// myRequest.cnt_u16 = 2; /* written bytes = 256 * cnt_u16 */
// R_FCL_Execute (&myRequest);
// #if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
// while (R_FCL_BUSY == myRequest.status_enu)
// {
// R_FCL_Handler ();
// }
// #endif
// test_value = 0x4004;
FCLUser_Close ();
} /* FCL_Ctrl */
经Debug,返回值是38个Block,正确。
5.4.2 获取指定Block的end address
void FCL_Ctrl (void)
{
r_fcl_request_t myRequest;
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
r_fcl_request_t mySecRequest;
#endif
uint8_t writeBuffer_u08[512];
uint32_t readBuffer_u32[8];
uint16_t i;
REINITIALIZE_BUFFER;
FCLUser_Open ();
/* prepare environment */
myRequest.command_enu = R_FCL_CMD_PREPARE_ENV;
R_FCL_Execute (&myRequest);
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
while (R_FCL_BUSY == myRequest.status_enu)
{
R_FCL_Handler ();
}
#endif
/* get block count */
myRequest.command_enu = R_FCL_CMD_GET_BLOCK_CNT;
myRequest.bufferAdd_u32 = (uint32_t)&readBuffer_u32[0];
R_FCL_Execute (&myRequest);
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
while (R_FCL_BUSY == myRequest.status_enu)
{
R_FCL_Handler ();
}
#endif
test_value = myRequest.bufferAdd_u32;
/* get block end address of block 2 */
REINITIALIZE_BUFFER;
myRequest.command_enu = R_FCL_CMD_GET_BLOCK_END_ADDR;
myRequest.bufferAdd_u32 = (uint32_t)&readBuffer_u32[0];
myRequest.idx_u32 = 0x2; /* result: 0x5fff */
R_FCL_Execute (&myRequest);
test_value = myRequest.bufferAdd_u32;
// /* erase block 2 and 3 */
// myRequest.command_enu = R_FCL_CMD_ERASE;
// myRequest.idx_u32 = 0x2; /* erased range = 0x4000 to 0x7fff */
// myRequest.cnt_u16 = 2;
// R_FCL_Execute (&myRequest);
// #if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
// while (R_FCL_BUSY == myRequest.status_enu)
// {
// R_FCL_Handler ();
// }
// #endif
//
// /* write 512 bytes to address 0x40000 (start of block 2) */
// REINITIALIZE_BUFFER;
// myRequest.command_enu = R_FCL_CMD_WRITE;
// myRequest.bufferAdd_u32 = (uint32_t)&writeBuffer_u08[0];
// myRequest.idx_u32 = 0x4000;
// myRequest.cnt_u16 = 2; /* written bytes = 256 * cnt_u16 */
// R_FCL_Execute (&myRequest);
// #if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
// while (R_FCL_BUSY == myRequest.status_enu)
// {
// R_FCL_Handler ();
// }
// #endif
// test_value = 0x4004;
FCLUser_Close ();
} /* FCL_Ctrl */
经Debug,block2的end address返回值是0x0000 5FFFF,正确。
5.4.3 对Code Flash进行write,然后读取,确认数值是否正确
注意:write之前要先Erase
void FCL_Ctrl (void)
{
r_fcl_request_t myRequest;
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
r_fcl_request_t mySecRequest;
#endif
uint8_t writeBuffer_u08[512];
uint32_t readBuffer_u32[8];
uint16_t i;
REINITIALIZE_BUFFER;
FCLUser_Open ();
/* prepare environment */
myRequest.command_enu = R_FCL_CMD_PREPARE_ENV;
R_FCL_Execute (&myRequest);
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
while (R_FCL_BUSY == myRequest.status_enu)
{
R_FCL_Handler ();
}
#endif
/* get block count */
myRequest.command_enu = R_FCL_CMD_GET_BLOCK_CNT;
myRequest.bufferAdd_u32 = (uint32_t)&readBuffer_u32[0];
R_FCL_Execute (&myRequest);
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
while (R_FCL_BUSY == myRequest.status_enu)
{
R_FCL_Handler ();
}
#endif
test_value = myRequest.bufferAdd_u32;
/* get block end address of block 2 */
REINITIALIZE_BUFFER;
myRequest.command_enu = R_FCL_CMD_GET_BLOCK_END_ADDR;
myRequest.bufferAdd_u32 = (uint32_t)&readBuffer_u32[0];
myRequest.idx_u32 = 0x2; /* result: 0x5fff */
R_FCL_Execute (&myRequest);
test_value = myRequest.bufferAdd_u32;
/* erase block 2 and 3 */
myRequest.command_enu = R_FCL_CMD_ERASE;
myRequest.idx_u32 = 0x2; /* erased range = 0x4000 to 0x7fff */
myRequest.cnt_u16 = 2;
R_FCL_Execute (&myRequest);
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
while (R_FCL_BUSY == myRequest.status_enu)
{
R_FCL_Handler ();
}
#endif
/* write 512 bytes to address 0x40000 (start of block 2) */
REINITIALIZE_BUFFER;
myRequest.command_enu = R_FCL_CMD_WRITE;
myRequest.bufferAdd_u32 = (uint32_t)&writeBuffer_u08[0];
myRequest.idx_u32 = 0x4000;
myRequest.cnt_u16 = 2; /* written bytes = 256 * cnt_u16 */
R_FCL_Execute (&myRequest);
#if R_FCL_COMMAND_EXECUTION_MODE == R_FCL_HANDLER_CALL_USER
while (R_FCL_BUSY == myRequest.status_enu)
{
R_FCL_Handler ();
}
#endif
test_value = 0x4004;
FCLUser_Close ();
} /* FCL_Ctrl */
经Debug,地址0x0000 4004开始的4Bytes数据是0x04 0x05 0x06 0x07,正确。
解释:因为我们数据存储使用的是Motorola格式(高字节在前),所以Debug出来结果显示是0x07060504
关于Erase和Write质量要特别注意一点:
很多时候执行力Erase之后,返回的myRequest.status_enu为R_FCL_ERR_PROTECTION,这是由于Flash被保护起来了,解决办法就是使用RFP对真个chip进行Erase再进行这些指令。
有疑问或需要探讨的地方,欢迎留言交流
本店铺有瑞萨E1仿真器,瑞萨RH850F1x开发板(RH850F1L,RH850F1K,RH850F1H,RH850F1KM,RH850F1KH),CANPiggy/LINPiggy,CANBOX(CANcase XL/VN1630替代款),CANoe,GHS,欢迎大家进店咨询。