Keil+Simulink生成Xcp标定协议A2L文件
由于最近要为ECU移植XCP协议,所以记录一下,我使用的MCU为NXP S32K144,IDE选用MDK(官方IDE S32DS无代码联想功能,所以放弃,本来用vscode+ld+make来开发,但是发现还是用keil比较方便,具体方法,可以在S32DS生成外设配置,然后将Generated Code 拷贝到Keil中去,Keil中已自带S32K144官方驱动,但是版本较老,编译出错的地方需要及时修改),Xcp协议可以参考Vector 官方提供的Xcp_Basic SDK
- 定义一个Keil 链接脚本.sct文件(S32K144_64_flash_user.sct),至于怎么使用,请参阅其他文章,对S32K内存进行分区,该文件决定了链接后的可烧写、调试文件axf或hex中内存分布,以及运行时MCU flash+ram分布,同时还在编译过后的.map文件中提供分区变量具体的内存地址信息,供生成A2L文件使用。
- 此处目的在于将测量变量(Measurement)和标定变量(Characteristic)分配到单独的内存分区里,便于管理,便于上位机Xcp_Master寻址。这里在S32K P_Flash 两个扇区上分别为 标定 和测量变量分了两个区(对应加载地址LR_Adrr,对应Xcp参考页),以及Ram上分了对应的两个区(对应运行地址ER_Adrr,对应Xcp工作页)
- m_flash_upload_start 0x00001000 Measurement Flash分区起始地址,0x1000=4096/1024=4KB,S32K一个扇区为4KB,所以为第二个扇区
- m_flash_upload_size 0x00000800 长度2K
- m_flash_cali_start 0x00001800 CharacteristicFlash分区,第三扇区
- m_flash_cali_size 0x00000400
#define m_interrupts_start 0x00000000
#define m_interrupts_size 0x00000400
#define m_flash_config_start 0x00000400
#define m_flash_config_size 0x00000010
#define m_flash_upload_start 0x00001000 //如果使能加解密功能,第一扇区不能保存数据(会被擦除)
#define m_flash_upload_size 0x00000800
#define m_flash_cali_start 0x00001800
#define m_flash_cali_size 0x00000400
#define m_text_start 0x00002000
#define m_text_size 0x0007E000
- S32K144_64_flash_user.sct中宏定义
LR_m_data_upload_Rom m_flash_upload_start m_flash_upload_size
{
ER_m_data_upload_Ram m_data_upload_start m_data_upload_size
{
* (section_upload)
}
}
LR_m_data_cali_Rom m_flash_cali_start m_flash_cali_size
{
ER_m_data_cali_Ram m_data_cali_start m_data_cali_size
{
* (section_cali)
}
}
- Sector划分,关于加载地址和运行地址请自行百度,简单的说,比如变量LR分配到Flash,ER分配到Ram,则在S32K初始化流程中会将Flash中的变量拷贝到Ram对应的区中去运行(keil编译器会在__main函数中加入自带的库函数,使MCU上电时完成该任务,如果是其他编译器可能需要手动拷贝),这样对变量的测量和标定可以是读和写(Ram)(前提是切换到工作页,参考页工作页的定义会在A2L文件体现),但是Ram区掉电及失,所以可以在标定的过程中使用EEPROM进行备份(暂时没调通S32K自带的片上EEPROM功能)进行备份,如果LR ER都是Flash区,则该变量就只能读不能写(S32K写入Flash需保证该位置是擦除状态,而擦除命令又是以扇区为单位,要擦只能擦整个扇区)。
#define Upload_Section __attribute__((section ("section_upload")))
#define Cali_Section __attribute__((section ("section_cali")))
- 定义两个宏定义,每次定义变量时,调用,就可以告诉编译器将该变量划分到对应的Section(分区,包含LR和ER)上去。
Upload_Section float me_Steerag_rate = 2.0f ;
Cali_Section float ca_Para1 = 1.0f ;
- 定义变量例子,这里定义了两个测试变量,一定要注意这两个变量的名字要和A2L的变量名对应,因为这两个变量的信息会存于.map文件,在调用Simulink
asap2post(".a2l文件地址",".map文件地址")
- 时会根据变量名来索引,将map文件中对应的地址填到A2L文件对应的位置,如下0x1FFF8000,0x1FFF880就是这个地址
/begin CHARACTERISTIC
ca_Para1
"This is Gain"
VALUE
0x1FFF8800 //characeristic 这里不能写 ECU Address?
Scalar_FLOAT32_IEEE //如果定义了这个数据类型,则要定义record_layout
0
untitled_CM_single_None
-2.0
10.0
/end CHARACTERISTIC
/begin MEASUREMENT
me_Steerag_rate
"steer wheel angle"
FLOAT32_IEEE
untitled_CM_single_deg_S
0
0
-250.0
250.0
0x1FFF8000 //都不用写ECU Address
/end MEASUREMENT
uint32_t upload_ram_start=0x1fff8000;
uint32_t upload_ram_end=0x1fff8000+0x800;
while(upload_ram_start != upload_ram_end)
{
*((uint32_t *)upload_ram_start)=(uint32_t)0x00000000;
upload_ram_start=upload_ram_start+4;
}
uint32_t cali_ram_start=0x1fff8800;
uint32_t cali_ram_end=0x1fff8800+0x400;
while(cali_ram_start != cali_ram_end)
{
*((uint32_t *)cali_ram_start)=(uint32_t)0x00000000;
cali_ram_start=cali_ram_start+4;
}
- 由于上面定义了分区,所以将Flash中的变量拷贝到Ram前需要清空该Ram区,将这段代码放大S32K startup.c 中的void
init_data_bss(void)函数中去
MCU 侧要做的工作暂时就只有这些,下一篇文章会初步解析A2L文件,以及用Simulink如何生成A2L文件并关联编译器生成的.map文件