1 前言
这篇文章来简单介绍一下NXP针对core test为S32K3设计的SCST(core self-test code)软件,并且将描述如何将SCST集成在自己的工程中并将其应用起来。
2 SCST简介
SCST的原理如下:
SCST说白了就是针对S32K3的M7核的RTL模式,架构,指令集等等特征设计出可以测试M7核是否正常运行的一段汇编代码,这段代码里面无外乎就是主动去触发和响应中断呀,去做一些整型和浮点型计算,反正就是去干一些核经常干的事情,验证一下核的功能是否正常,此为SCST。
3 移植
- 先将SCST的所有文件移植到自己的工程里,如下:
- 添加SCST的头文件,c部分如下:
Assembly部分如下:
- 根据自己的编译器,添加相应的预宏定义,GCC对应__GNUC__,Green Hill对应__ghs__,IAR对应__IAR_SYSTEMS_ASM__。由于我这里使用的S32DS的工程,里面预宏定义已经定义了GCC,所以不需要再额外定义__GNUC__。
- 另外由于很多assembly文件都包含了c指令,所还需要增加一个编译选项,不同编译器根据下表来选择:
编译器选项 | options |
---|---|
GreenHills | -preprocess_assembly_files |
GCC | -x assembler-with-cpp |
IAR | 无需添加 |
-
除此之外,个别core test会用到一个reserved的地址M7_DEVICE_RESERVED_ADDR,所以需要在assembly的预宏定义中定义这个宏,如下:
-
修改链接文件将一些段链接到合适的位置,这些段应该所链接位置以及这些段的内容具体如下:
sector | 链接位置 | 描述 |
---|---|---|
.m7_scst_test_code | FLASH | 包含了SCST的所有测试代码 |
.m7_scst_test_branch_code0 | FLASH | 分支测试代码0 |
.m7_scst_test_branch_code1 | FLASH | 分支测试代码1 |
.m7_scst_test_shell_code | FLASH | 调用测试的接口函数 |
.m7_scst_vector_table | FLASH | SCST自定义中断向量表 |
.m7_scst_rom_data | FLASH | 常量 |
.m7_scst_ram_data | RAM | 全局变量 |
.m7_scst_test_shell_data | RAM | 调用测试的接口函数所用的全部变量 |
.m7_scst_ram_data_target0 | RAM | 恢复现场所用的数据0 |
.m7_scst_ram_data_target1 | RAM | 恢复现场所用的数据1 |
.m7_scst_ram_test_code | RAM | 给fetch test使用的变量 |
FLASH部分如下:
RAM的sram_data部分如下:
到此,移植准备工作全部完成了。
4 应用
SCST一共提供了50项测试,对应的测试项ID为0~49,截取一部分如下(其他请参考《M7_S32K3xx_SCST_User_Manual.pdf》):
表中详细列出了每一测试项的测试ID(测试项索引), 参考签名值(当前测试项的正确返回值,如果测试项返回结果不等于参考签名值,那么标定该测试项未通过),用户中断阻塞时间(测试过程中,会更换中断向量表,从而让用户ISR堵塞),测试执行时间(整个测试项所用的时间),所用栈大小(使用的栈为编译器所划的Stack)。那么怎么在代码中实现这些测试呢?
4.1 启动测试
启动SCST的测试项非常简单,只牵扯到一个函数,三个变量。其中一个函数为:
m7_scst_uint32_t m7_scst_execute_core_tests(m7_scst_uint32_t start, m7_scst_uint32_t end)
可以通过这个函数来启动SCST测试项,形参start为起始测试项ID,形参end为结束测试ID。举个例子,如果如下调用:
test_result = m7_scst_execute_core_tests(0,49);//启动第1测试项到第49测试项,依次进行
test_result = m7_scst_execute_core_tests(0,0);//测试第0测试项
test_result = m7_scst_execute_core_tests(1,1);//测试第1测试项
三个变量如下:
/*保存了最后一次测试项的ID,如果一次性启动所有测试项,中间有测试项出现错误未通过,
导致测试终止,那么则可以读取这个值来确定是哪个测试项未通过*/
extern m7_scst_uint32_t m7_scst_last_executed_test_number;
/*记录了最后一次测试项的返回值,如果一次性启动所有测试项,中间有测试项出现错误未通过,
导致测试终止,那么则可以读取这个值来了解未通过测试项的错误返回值*/
extern m7_scst_vuint32_t m7_scst_accumulated_signature;
/*指定注入错误通道,可以在启动测试项之前,通过指定这个参数来向指定测试项注入错误,
注入错误会导致测试未通过*/
extern m7_scst_uint32_t m7_scst_fault_inject_test_index;
4.2 使能FPU相关测试项
SCST50项测试有13项测试是针对FPU的,可以在m7_scst_configuration.h中配置是否使能FPU相关的core test选项,如下:
#define M7_SCST_SPFPU_TESTS 1U
另外,如果激活了FPU测试,那么就需要在编译选项中激活单精度FPU硬件,如下:
其他编译器对应编译选项如下:
编译器选项 | options |
---|---|
GreenHills | -fpu=vfpv3_d16 |
GCC | -mfpu=fpv5-d16 |
IAR | –cpu Cortex-M7.fp.sp |
4.3 49号测试项中的MPU配置
如果在应用代码中使能了MPU配置,那么其中49号测试项m7_scst_loadstore_test7对MPU的配置也有要求,具体要求以及MPU配置代码如下:
void MPU_config()
{
/*------------------------------------------------------------------------*/
/* MPU region 0 */
/*------------------------------------------------------------------------*/
*MPU_RNR = 0x00000000;
/* Configure MPU region 0 base address to SCST_RAM_TARGET0 */
*MPU_RBAR = (m7_scst_uint32_t)&SCST_RAM_TARGET0;
/* Configure MPU region 0
- XN: Not executable
- AP: S:RW U:RW Full access
- TEX: 0
- S: Not shareable
- C: Not cacheable
- B: Not bufferable
- SRD: 0b00000000
- SIZE: 32 B
- EN: Enabled
*/
*MPU_RASR = 0x13000009;
/*------------------------------------------------------------------------*/
/* MPU region 1 */
/*------------------------------------------------------------------------*/
*MPU_RNR = 0x00000001;
/* Configure MPU region 1 base address to SCST_RAM_TARGET1 */
*MPU_RBAR = (m7_scst_uint32_t)&SCST_RAM_TARGET1;
/* Configure MPU region 1
- XN: Not executable
- AP: S:RW U:-- Privileged access only
- TEX: 0
- S: Not shareable
- C: Not cacheable
- B: Not bufferable
- SRD: 0b00000000
- SIZE: 32 B
- EN: Enabled
*/
*MPU_RASR = 0x11000009;
/* Enable MPU
- PRIVDEFENA: 1 (Use default memory map as region -1 for privileged access)
- HFNMIENA: 0 (Disable MPU for handlers with priority less than 0)
- ENABLE: 1
*/
*MPU_CTRL = 0x00000005;
}
当然了,如果你没有使能MPU,那么就没有什么影响。
4.4 特殊的0~5号测试项
在50个测试中,0 ~ 5号测试项比较特殊,如果在Handle模式下启动0 ~ 5号测试项的话,那么就需要在m7_scst_configuration.h中配置一些宏,将其由默认值改为以下值:
#define M7_SCST_EXECUTION_MODE M7_SCST_HANDLER
#define M7_SCST_SVC_EXCEPTION_LOW 1U
#define M7_SCST_PENDSV_EXCEPTION_LOW 1U
#define M7_SCST_SYSTICK_EXCEPTION_LOW 1U
如果systick中断被使能了,那么还需要修改这个宏,如下:
#define M7_SCST_SYSTICK_IS_RUNNING 1U
4.5 应用代码示例
相关测试代码如下:
void SCST_example(void)
{
//给第10号测试项注入错误
m7_scst_fault_inject_test_index = 10;
//启动0~27号测试项
m7_scst_execute_core_tests(0, 27);
//判断最后一次测试项ID是否为10
if(m7_scst_last_executed_test_number != 10)
{
while(1);
}
//再次启动0~27号测试项
m7_scst_execute_core_tests(0, 27);
//判断最后一次测试项ID是否为35
if(m7_scst_last_executed_test_number != 27)
{
while(1);
}
//判断最后一次测试项返回值是否为35号测试的参考签名值
if(m7_scst_accumulated_signature == 0x7F0BF5A3U)
{
while(1);
}
//启动29~49号测试项
m7_scst_execute_core_tests(29, 49);
//判断最后一次测试项ID是否为48
if(m7_scst_last_executed_test_number != 49)
{
while(1);
}
//判断最后一次测试项返回值是否为49号测试的参考签名值
if(m7_scst_accumulated_signature == 0x2F6AB216U)
{
while(1);
}
//m7_scst_execute_core_tests(28, 28); //28号测试项暂时有问题,待解决
}
注意①:SCST测试项是可以在应用程序中周期性启动的。
注意②:在测试代码中,我跳过了第28号测试项,因为在测试过程中,发现该项测试无法通过,发现死在了一条STREX指令,这是因为这条指令是给FLASH的一个地址执行写操作,但是在MCAL代码中SystemInit中有一个配置MPU的操作,默认是将FALSH配置成了禁止写性所以我们有两种方法让第28测试项通过,第一种就是将FLASH的读写属性改成可写,第二种就是直接Disable MPU,具体如下:
/*配置FLASH区域为可写*/
rasr[2]=0x020B002BUL;
/*Disable MPU*/
S32_MPU->CTRL &= (~S32_MPU_CTRL_ENABLE_MASK);
个人觉得这应该是条bug,看官方是否会在后面将其修复。
至此,关于SCST的应用就全部介绍完毕了。