* Project : RTD AUTOSAR 4.7
* Platform : CORTEXM
* Peripheral : LPSPI
* Dependencies :
*
* Autosar Version : 4.7.0
* Autosar Revision : ASR_REL_4_7_REV_0000
* Autosar Conf.Variant :
* SW Version : 3.0.0
* Build Version : S32K3_RTD_3_0_0_D2303_ASR_REL_4_7_REV_0000_20230331
I am using the Lpspi_Ip_SyncTransmitHalfDuplex function with the TIMEOUT parameter and TransferType = LPSPI_IP_HALF_DUPLEX_RECEIVE. However, I believe there is an issue in this function.
Inside the while loop, the line ElapsedTicks = 0u; is executed in each iteration until ExpectedFifoReads == State->RxIndex.
For the TIMEOUT condition, the following code is used:
ElapsedTicks += OsIf_GetElapsed(&CurrentTicks, LPSPI_IP_TIMEOUT_METHOD);
if (ElapsedTicks >= TimeoutTicks)
{
Status = LPSPI_IP_TIMEOUT;
}
Here, the OsIf_GetElapsed function uses CurrentTicks, which is set before the loop as shown below:
CurrentTicks = OsIf_GetCounter(LPSPI_IP_TIMEOUT_METHOD);
If CurrentTicks were truly initialized before the loop and OsIf_GetElapsed measured the time elapsed since that point, everything would work as expected.
However, the OsIf_GetElapsed function internally calls OsIf_Timer_System_GetElapsed, which then calls OsIf_Timer_System_Internal_GetElapsed. In this last function, I believe something unintended happens:
uint32 OsIf_Timer_System_Internal_GetElapsed(uint32 * const CurrentRef)
{
...
*CurrentRef = CurrentVal;
...
}
Here, CurrentRef is updated. As a result, instead of measuring the time elapsed since the beginning of the loop, the function measures the time elapsed since the last OsIf_GetElapsed call. This causes the SPI transfer to fail to timeout as expected, and it ends up stuck.
When the line ElapsedTicks = 0u; inside the while loop is removed, the function behaves as expected.
Could you clarify if this is a known issue or if there’s an intended use case I might be missing?
We are using "The S32 Real-Time Drivers Version 4.0.0 is AUTOSAR 4.4.0 compliant. " on S32K314 target.
I have faced a similar issue. But im my case using FreeRTOS and during an operation:
Gmac_Ip_MDIORead()
There were unexpected timeouts executing many operartions.
I have investigated the OsIf_Timer_System_Internal_GetElapsed() and I think I could individuate the root cause:
The default configuration is done in
source\RTD\src\OsIf_Timer_System_Internal_Systick.c/OsIf_Timer_System_Internal_Init()
S32_SysTick->RVR = S32_SysTick_RVR_RELOAD(SYSTICK_MAX);
The SysTick is configured differently if the FreeRTOS is configured:
In port.c/vPortSetupTimerInterrupt()
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
But in the OsIf_Timer_System_Internal_GetElapsed() always the
SYSTICK_MAX used when the counter was overflowed:
if (SYSTICK_OVERFLOWED((CurrentVal), (*CurrentRef)))
{
/* overflow occurred */
dif = SYSTICK_DELTA_OUTER(CurrentVal, *CurrentRef, SYSTICK_MAX);
The below alternative solution for me has resolved the problem:
/*---------------------------------------------------------------------
Function: OsIf_Timer_System_Internal_GetElapsed
Purpose: The original implementation was fixed using the LOAD_VALUE instead of SYSTICK_MAX
Arguments: uint32 * const CurrentRef The tick counter of the last interrogation
The value is updated
Return: The number of elapsed ticks since last *CurrentRef
---------------------------------------------------------------------*/
uint32 OsIf_Timer_System_Internal_GetElapsed(uint32 * const CurrentRef)
{
uint32 CurrentVal = SYSTICK_GET_COUNTER();
uint32 dif = 0U;
if (SYSTICK_OVERFLOWED((CurrentVal), (*CurrentRef)))
{
/* overflow occurred */
dif = SYSTICK_DELTA_OUTER(CurrentVal, *CurrentRef, SYSTICK_GET_LOAD_VALUE());
}
else
{
/* overflow did not occur */
dif = SYSTICK_DELTA_INNER(*CurrentRef, CurrentVal);
}
*CurrentRef = CurrentVal;
return dif;
}
We are using "The S32 Real-Time Drivers Version 4.0.0 is AUTOSAR 4.4.0 compliant. " on S32K314 target.
I have faced a similar issue. But im my case using FreeRTOS and during an operation:
S32_SysTick->RVR = S32_SysTick_RVR_RELOAD(SYSTICK_MAX);
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
if (SYSTICK_OVERFLOWED((CurrentVal), (*CurrentRef)))
{
/* overflow occurred */
dif = SYSTICK_DELTA_OUTER(CurrentVal, *CurrentRef, SYSTICK_MAX);
The below alternative solution for me has resolved the issue:
uint32 OsIf_Timer_System_Internal_GetElapsed(uint32 * const CurrentRef)
{
uint32 CurrentVal = SYSTICK_GET_COUNTER();
uint32 dif = 0U;
if (SYSTICK_OVERFLOWED((CurrentVal), (*CurrentRef)))
{
/* overflow occurred */
dif = SYSTICK_DELTA_OUTER(CurrentVal, *CurrentRef, SYSTICK_GET_LOAD_VALUE());
}
else
{
/* overflow did not occur */
dif = SYSTICK_DELTA_INNER(*CurrentRef, CurrentVal);
}
*CurrentRef = CurrentVal;
return dif;
}
Hi @MehmetFatih ,
The value ElapsedTicks is reset in each iteration to isolate and measure the duration of data transmission or reception. By updating this value within the loop we ensure that only the time spent on receiving or transmitting the information is measured. This allows for accurate comparison with the proposed Timeout value, ensuring the system behaves as expected and can handle timeouts appropriately.
Please let us know if our understanding of your question is incorrect.
Have a nice day!
IsaulO.