前言
C40介绍
CT组件
↓
CT组件 C40_Ip
1、Name
2、FlsConfigSet
闪存驱动程序的运行时配置参数的容器。
实现类型:Fls ConfigType。
3、FlsGeneral
闪存驱动程序的一般参数的容器。这些参数总是预编译的。
- Name
- Enable development error check at IP level:
true: 启用了IP级别的开发错误检查。
false:禁用了IP级别的开发错误检查 - Fls ECC Handling HardfaultHandler:
启用禁用API以向闪存驱动程序报告数据存储(ECC)错误的前置处理器开关。
这是第一种ECC处理方法,它修改程序计数器以跳过导致故障的指令。
有关更多信息,请阅读IM中出现ECC错误时的异常处理程序一章。
true:HardfaultHandler API的ECC检查已启用。
false:HardfaultHandler API的ECC检查被禁用。 - Fls ECC Handling ProtectionHook:
启用禁用API以向闪存驱动程序报告数据存储(ECC)错误的前置处理器开关。
这是与AutosarOs兼容的第二种ECC处理方法。
有关更多信息,请阅读IM中出现ECC错误时的异常处理程序一章。
true: AutosarOs API的ECC检查已启用。
false:AutosarOs API的ECC检查被禁用。 - Fls Erase Verification Enabled:
预处理器开关,用于启用或禁用擦除空白检查。
在闪存块被擦除之后,擦除空白检查将寻址的存储器区域的内容与擦除的闪存单元的值进行比较,以检查该块是否已被完全擦除。
true:内存区域被检查为已擦除。
false:未选中要擦除的内存区域。 - Fls Write Verification Enabled:
预处理器开关,用于启用或禁用写验证检查。
在写入闪存块之后,写入验证检查将重新编程的存储器区域的内容与所提供的应用缓冲器的内容进行比较,以检查该块是否已被完全重新编程。
true:写入数据后直接进行比较。
false:写入日期不会在写入后直接进行比较。 - Fls Timeout Supervision Enabled:
编译开关以启用超时监控。
true:已启用读取/擦除/写入/比较作业的超时监督。
false:已禁用读取/擦除/写入/比较作业的超时监督。 - Fls Timeout Method:
用于FLS服务请求超时检测的计数器类型。
根据所选计数器类型,超时值将解释如下:
OSIF_COUNTER_DUMMY:统计等待循环的迭代次数。实际超时取决于许多参与者:操作类型、编译器优化、中断或系统中的其他任务等。
OSIF_COUNTER_SYSTEM:计数器系统微秒。
OSIF_COUNTER_CUSTOM:由定时服务的用户实现定义。 - Fls Async Write Timeout:
Fls Async Write Timeout是异步模式下写入操作的超时值。 - FIs Async Erase Timeout:
Fls Async Erase Timeout是异步模式下擦除操作的超时值。 - Fls Sync Write Timeout:
Fls Sync Write Timeout是同步模式下写入操作的超时值。 - Fls Sync Erase Timeout:
Fls Sync EraseTimeout是同步模式下擦除操作的超时值。 - Fls Async Abort Timeout:
Fls Abort Timeout是中止正在进行的操作的超时值。
超时也用于Fls Cancel API和Abort Erase suspend;如果启用并且闪存硬件通道不支持立即中止功能。
4、AutosarExt
此容器包含Fls驱动程序的全局非自动存储配置参数。
这个容器是一个MultipleConfigurationContainer,即这个容器及其子容器在每个配置集存在一次。
- Name
- FIs Enable User Mode Support:
启用此参数后,FLS模块将适应从用户模式运行,并采取以下措施:
为Fls IP配置REG_PROT,以便通过将REG_PROT_GCR中的UAA位设置为1,可以从用户模式访问受保护的寄存器。
有关此平台的更多信息和可用性,请参阅IM中的用户模式支持一章。 - Fls Synchronize Cache:
在每次闪存硬件操作后,通过使缓存无效来同步内存。
FLS驱动程序需要通过三种方法来保持内存一致性:
1.禁用数据缓存,或
2.将驱动程序操作的闪存区域配置为不可缓存,或者
3.启用FlsSynchronizeCache功能。
根据应用程序配置,一个选项可能比另一个更有益。
启用:FLS驱动程序将调用Mcl缓存API函数,以便在每次高电压操作(写入、擦除)之后和每次读取操作之前使缓存无效,以确保缓存和修改后的闪存同步。
如果启用,驱动程序将尝试仅使缓存中修改的行无效。
如果要无效的区域的大小大于缓存大小的一半,则整个缓存无效。
注意:如果启用,则必须启用MclLmemEnableCacheApi参数,并将MCL插件作为依赖项包含在内。 - FIs Data Error Suppression:
请参阅嵌入式闪存配置信息或受此字段影响的闪存块的系统内存映射。
禁用报告数据闪存访问的ECC事件。
Enable(启用)-数据闪存访问中的单比特和多位ECC事件被抑制。 - Fls Block 4 Pipe Select:
选择用于访问内部闪存块4的管道。
PFLASH有四个独立的命令管道,用于向不同的闪存块发出四个并行读取命令。
对块4的访问可以通过以下任何命令管道:
FLS COMMAND PIPE 0-Block 4访问始终通过管道0。
FLS COMMAND PIPE 1-Block 4访问始终通过管道1。
FLS COMMAND PIPE 2-Block 4访问始终通过管道2。
FLS COMMAND PIPE 3-Block 4访问始终通过管道3。
FLS ANY_COMMAND PIPES块4访问可以通过任何命令管道,基于哪个命令管道可用于块4访问。
5、FlsPublishedInformation
CommonPublishedInformation容器未包含的其他已发布参数。
请注意,这些参数没有任何配置类设置,因为它们是已发布的信息。
- Name
- Fls Erased Value:已擦除的闪存单元的内容。
- Fls ECC Value:ECC闪存线的内容。
开发注记:
S32K的flash组件使用(操作FLASH)_s32 design studio读取flash_阿衰0110的博客-CSDN博客
Flash的写遵循 :先擦除,后写入。(由于Flash的特性,写入要擦除)
但是C40中,每个扇区都有保护,在进行任何操作前要先进行读取是否上锁保护了,是则解锁,再进行操作。不然会进硬件错误中断。
JFlash擦除
在研究C40对Flash进行擦除写入时,老是进入硬件错误中断,仿真去查看情况,多仿真几次,发现出问题了,莫名其妙仿真跑不了,如何下别的程序也不行,后面直接用JLink对Flash进行擦除,可以下程序了,至于前面的问题,估计是Flash擦除写入时惊醒断点仿真,导致Flash触发保护了。后面擦除程序。以下是对Flash的擦除步骤
1.下载软件
若是下载了JLink驱动,会自己带有擦除软件。
2.创建项目
选择芯片
3.擦除全片
生成bin文件:
流程图:
S32 Design Studio生成BIN文件(srec 文件就是S19文件)-CSDN博客
S32 Design Studio IDE for Arm教程五之输出bin文件代码_s32 design studio 编译bin-CSDN博客S32K324 UDS Bootloader开发-下位机篇-FlashDriver的制作 - 知乎S32 Design Studio IDE for Arm教程五之输出bin文件代码_s32 design studio 编译bin-CSDN博客
官方的Boot例程讲解
S32K324 UDS Bootloader开发-下位机篇-FlashDriver的制作 - 知乎
FlashDriver是什么?
在ECU OTA 程序升级过程中,需要执行一段比较特殊的代码,这段代码实现对自身flash的擦除与写入,又称flash driver。
在OTA升级过程中,往往需要在发送app可执行文件之前,向底层先发送一段叫"flash driver"的二进制文件,这里简单总结一下这段“flash driver”二进制文件存在的意义。
1、在车载ECU控制器中,为了安全考虑,会尽可能的避免在代码中固化有对flash进行擦除或写入的操作,主要为了避免在程序跑飞时误调用该部分代码,使软件代码部分受到破坏;
2、flash driver的实现方式,可以将flash driver固化在底层flash中,在运行的时候将flash中的flash driver拷贝到ram中来运行,这是比较传统到方式,但是避免不了1中提到的安全性问题;
所以还有一种方式,就是将flash driver这段代码保存在PC端或后台,在每次执行OTA升级前,将这段代码先发送给底层,这样可以避免1中提到的安全性问题;
3、在升级过程中,flash driver必须在ram中运行的原因是:
在对flash进行读写操作时,flash中对应的应用程序文件将不能运行,所以必须将flash driver拷贝到ram区域,这是flash硬件性能决定到。
用KeilMDK实现FlashDriver的制作`_flash driver-CSDN博客
英飞凌AURIX 2G芯片Flash Driver开发 - 知乎
官方给出的常规的的C40 Flash 的API读写函数代码:
C40_Ip_StatusType C40Status;
/* Write data */
C40_Ip_MainInterfaceWrite(LogicalAddress, Length, SourceAddressPtr, FLS_MASTER_ID);
do
{
C40Status = C40_Ip_MainInterfaceWriteStatus();
}
while (STATUS_C40_IP_BUSY == C40Status);
这里调用完C40_Ip_MainInterfaceWrite()后,在调用C40_Ip_MainInterfaceWriteStatus()读取状态,直到读取状态返回非忙。
C40_Ip_MainInterfaceWriteStatus 函数解析:
......
PS:这里比较特殊的是:C40_Ip_MainInterfaceWrite()函数要求写入的地址必须是8字节对齐,且写入的数据长度必须为8的整数倍!该函数里面调用C40_Ip_MainInterfaceWritePreCheck()函数去检查参数。
/* Check length and u32offet should align with C40_WRITE_DOUBLE_WORD */
if ( ((LogicalAddress & (C40_WRITE_DOUBLE_WORD - 1U)) != 0U ) ||
((Length & (C40_WRITE_DOUBLE_WORD - 1U)) != 0U ) ||
(Length > C40_DATA_SIZE_BYTES_U32) ||
(0U == Length) ||
(NULL_PTR == SourceAddressPtr)
)
{
/* Wrong input parameters*/
ReturnCode = STATUS_C40_IP_ERROR_INPUT_PARAM;
写入函数代码:实现任意字节写入
#define SECTORLEN 8192U
C40_Ip_StatusType FLASH_HAL_WriteData(const uint32 i_startAddr,
const uint8 *i_pDataBuf,
const uint32 i_dataLen)
{
uint8 index = 0u;
uint8 lessWriteLen = 8u;
uint8 aDataBuf[8u] = {0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu};
uint32 writeDataLen = 0u;
boolean retstates = FALSE;
C40_Ip_StatusType C40Status;
C40_Ip_VirtualSectorsType VirtualSector;
C40_Ip_VirtualSectorsType endVirtualSector;
//The program flash start address is 0x400000u, 32 is the program flash VirtualSector begin
VirtualSector = (i_startAddr - 0x400000u)/SECTORLEN + FLS_MAX_DATA_SECTOR;
endVirtualSector = ((i_startAddr + i_dataLen) - 0x400000u) / SECTORLEN + FLS_MAX_DATA_SECTOR;
while(VirtualSector <= endVirtualSector) //******循环解锁 要写的扇区
{
if(STATUS_C40_IP_SECTOR_PROTECTED == C40_Ip_GetLock(VirtualSector))
{
C40_Ip_ClearLock(VirtualSector, 0);
}
VirtualSector++;
}
DisableAllInterrupts(); //******写的时候关中断
if(i_dataLen & (lessWriteLen - 1)) //******对8(7-1)求余数: 80余0、84余4,有余数进if分支
{
/*if write data more than 8 bytes*/ //******写的数据多余8 即不能被8整除,但又大于8 :9-15 17-23 25-31 ......
if(i_dataLen > lessWriteLen)
{
writeDataLen = i_dataLen - (i_dataLen & (lessWriteLen - 1)); //******减去余数,先写入8的整数倍
C40Status=C40_Ip_MainInterfaceWrite(i_startAddr,writeDataLen,i_pDataBuf, 0);
if(STATUS_C40_IP_SUCCESS == C40Status)
{
do
{
C40Status = C40_Ip_MainInterfaceWriteStatus();//******检查C40_IP_MainInterfaceWrite功能启动的硬件程序的状态。这里会清0 EHV
}
while (STATUS_C40_IP_BUSY == C40Status);//******等写入完成 连续写入要等待?
} //******这里主要是延时,虽然C40_Ip_MainInterfaceWrite返回成功,但是EHV再次调用返回错误,EHV仍未1。所以返回的成功是指上一次操作成功,但Flash状态不一定可以执行下一次操作
else
return C40Status; //写入失败,返回错误码
if(STATUS_C40_IP_SUCCESS == C40Status) //******写入余数 个数据
{
for(index = 0u; index < (i_dataLen & (lessWriteLen - 1)); index++)
{
aDataBuf[index] = i_pDataBuf[writeDataLen + index]; //******前面的填充要写的数据,后面的默认是0xff
}
C40Status=C40_Ip_MainInterfaceWrite(i_startAddr+writeDataLen,8u,aDataBuf,0);
if(STATUS_C40_IP_SUCCESS == C40Status)
{
do
{
C40Status = C40_Ip_MainInterfaceWriteStatus();//******检查C40_IP_MainInterfaceWrite功能启动的硬件程序的状态。这里会清0 EHV
}
while (STATUS_C40_IP_BUSY == C40Status);//******等写入完成 连续写入要等待?
} //******这里主要是延时,虽然C40_Ip_MainInterfaceWrite返回成功,但是EHV再次调用返回错误,EHV仍未1。所以返回的成功是指上一次操作成功,但Flash状态不一定可以执行下一次操作
else
return C40Status; //写入失败,返回错误码
}
else
return C40Status; //返回错误码
}
else //******写的少于8字节 比如1-7字节
{
for(index = 0u; index < i_dataLen; index++)
{
aDataBuf[index] = i_pDataBuf[writeDataLen + index]; //******前面的填充要写的数据,后面的默认是0xff
}
C40Status=C40_Ip_MainInterfaceWrite(i_startAddr+writeDataLen,8,aDataBuf,0);
if(STATUS_C40_IP_SUCCESS == C40Status)
{
do
{
C40Status = C40_Ip_MainInterfaceWriteStatus();//******检查C40_IP_MainInterfaceWrite功能启动的硬件程序的状态。这里会清0 EHV
}
while (STATUS_C40_IP_BUSY == C40Status);//******等写入完成 连续写入要等待?
} //******这里主要是延时,虽然C40_Ip_MainInterfaceWrite返回成功,但是EHV再次调用返回错误,EHV仍未1。所以返回的成功是指上一次操作成功,但Flash状态不一定可以执行下一次操作
else
return C40Status; //写入失败,返回错误码
}
}
else //******对8(7-1)求余数: 80余0、84余4,无余数进else分支。
{
C40Status=C40_Ip_MainInterfaceWrite(i_startAddr,i_dataLen,i_pDataBuf, 0);
if(STATUS_C40_IP_SUCCESS == C40Status)
{
do
{
C40Status = C40_Ip_MainInterfaceWriteStatus();//******检查C40_IP_MainInterfaceWrite功能启动的硬件程序的状态。这里会清0 EHV
}
while (STATUS_C40_IP_BUSY == C40Status);//******等写入完成 连续写入要等待?
} //******这里主要是延时,虽然C40_Ip_MainInterfaceWrite返回成功,但是EHV再次调用返回错误,EHV仍未1。所以返回的成功是指上一次操作成功,但Flash状态不一定可以执行下一次操作
else
return C40Status; //写入失败,返回错误码
}
EnableAllInterrupts();
return C40Status;
}