问题1
1 现象:
刷新流程结束之后上位机通过22服务AFFC读取刷新计数时,刷新计数会偶发地置1
2 分析思路:
尝试用单步调试的方法复现该现象,程序中涉及到刷新计数的更新有两处,一是在34服务中擦flash前,二是在31服务中擦flash前,由于下载过程不涉及31服务擦flash,着重模拟34服务擦flash。
3 实际操作:
在CANoe中多次发送34 00 44 80 10 00 00 00 02 00 00,发现刷新计数可以正常的加1,也就是说每执行一次擦除flash的操作,刷新计数都可以正常的更新。接下来用上位机执行刷新操作,刷新计数也可以加1,但是第二次执行刷新操作时,刷新计数就置为1了。
经过多次尝试,终于稳定复现:在用上位机执行两次刷新操作后,刷新计数会置1,两次刷新操作本身没有太多差异,只能通过debug找问题。代码如下:
boolean UDS_SRV_I_34_Update_AppProgramming_Counter_Flag(void)
{
uint16 Programming_Cnt = 0;
boolean ck_status = TRUE;
/* Check App programming counter */
Flash_Read_ProgramCounter(&Programming_Cnt);
if(Programming_Cnt == MAX_APP_PROGRAMMING_COUNTER)
{
ck_status = FALSE;
}
else
{
/* Update number of times programming on NVM */
ck_status = TRUE;
if(
((Programming_Cnt & 0x00FF) == (FLASH_FILLING_BYTE << 0)) &&
((Programming_Cnt & 0xFF00) == (FLASH_FILLING_BYTE << 8))
)
{
Programming_Cnt = 1;
}
else
{
Programming_Cnt++;
}
}
if(ck_status == TRUE)
{
Flash_Write_ProgramCounter(Programming_Cnt);
}
return ck_status;
}
将断点打在第6行Flash_Read_ProgramCounter(&Programming_Cnt)处,在上位机第二次刷新执行34服务时会停在这里
点进去,这里主要做的事是从FLASH_DATA_BASE(0x80040000)这块地址读取存好的物流数据到FLASH_RAM_mirror中,然后从FLASH_RAM_mirror中特定位置读取计数
在读取刷新计数之前先瞅一眼FLASH里的状态
看到这里,果然是出了问题,在读flash里的值之前,flash里的值本身已经被修改了,往前找哪个地方涉及到flash的擦写
/* Erase Application Valid Flag */
FlashVal_Status = Flash_Write_ApplicationValidFlag(0x00);
/*Update the programming integrity and compatibility status to 0xFF ---awoys*/
FlashInt_Status = Flash_Write_ProgramIntegrityState(0xFF);
FlashCom_Status = Flash_Write_ProgramCompatibilityState(0xFF);
FlashCount_Status = UDS_SRV_I_34_Update_AppProgramming_Counter_Flag();
任意挑一个函数点进去
boolean Flash_Write_ApplicationValidFlag(uint8 ApplicationValidFlag)
{
boolean return_code;
FLASH_RAM_Mirror[RAM_AppValidflag_Base] = ApplicationValidFlag;
return_code = Flash_Update_Data();
return return_code;
}
这几个更新标志位的函数实现的逻辑是:更改对应的FLASH_RAM_mirror里存放的标志位,然后将整个数组通过Flash_Update_code()函数写入到FLASH_DATA_BASE中(这就要求在初始化函数中需要对这块ram进行初始化)
看到这里,立马去看FLASH_RAM_mirror这个数组里存放的值,果然全是0,
回头到初始化函数里,果然
void NvM_Flash_ReadAllData(void)
{
Copy_Bytes_NvM(FLASH_RAM_Mirror, (uint32)FLASH_DATA_BASE, FLASH_RAM_Mirror_Size);
}
这个初始化函数并没有被调用,所以RAM中全是0
4 复盘分析:
问题2
1 现象:
刷新流程结束之后上位机通过31子服务FF01更新兼容码时,程序会卡死
2 分析思路:
31服务通过CANoe测试过没有问题,直接DEBUG看问题出在哪
3 实际操作:
把断点打在31子服务FF01前
然后单步调试
当走到第1691行时,if(*(uint8*)BOOT_HEADER_APP_DEPEND == *(uint8*)APP_HEADER_DEPEND)
程序报错。点进去看,BOOT_HEADER_APP_DEPEND是boot中存放兼容码的flash,地址是0x80000000,再去看这块flash中存放的内容,发现是空的。
所以当程序访问这段地址后报错了。
再看下为什么这段地址是空的,这段地址是用来放boot兼容码及F183的,原本是用#pragma语句定义
#pragma section ".BootHeader" a
const typedef struct
{
uint8 App_Dependencies;
uint8 Boot_Software_Number[10];
} BootHeader bootheader = {0xB5, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}};
#pragma section
后面为了将bootheader声明成extern类型的变量,因此讲变量的定义放到了头文件中,那这个地方犯了一个错误,误以为把类型的声明套上#pragma,就可以将用该类型定义的变量定义到目标flash中,
#pragma section ".BootHeader" a
typedef struct
{
uint8 App_Dependencies;
uint8 Boot_Software_Number[10];
} BootHeader;
#pragma section
BootHeader bootheader = {0xB5, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}};
这样的写法无法将bootheader定义到.BootHeader区域中,所以0x80000000开始的这块地址是空的,当程序访问这块地址时,就会报错了。