The exact use-case is for i2c transfer timeout. In the i2c state machine, I start the timer immediately after the start bit and see 991us delay on the logic analyzer before the data. If I remove the timer, the delay is approximately 10us. Therefore the added delay by the call to FreeRTOS’s xTimerChangePeriod is 980us, very close to the 1ms expected tick rate. The delay seems to be the same every time.
Let me share some code snippets :
The i2c interrupts only generate direct-to-task notifications:
void I2cMasterx_MASTER_InterruptHandler( i2c_master_common_ctx_t *ctx )
{
/* ACK the bus interrupt flag */
*ctx->IFSxCLR = ctx->MASTER_INT_MASK;
BaseType_t xHigherPriorityTaskWoken;
xTaskNotifyFromISR( ctx->xI2cMasterxTaskHandle,
I2CMASTER_EVENT_MASTER_INT,
eSetValueWithOverwrite,
&xHigherPriorityTaskWoken );
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
The timer callback function as well only generates direct-to-task notifications (here the timer ID is used to pass a context containing the task handle to notify):
static void vI2cMasterxTimerCallback( TimerHandle_t xTimer )
{
i2c_master_common_ctx_t * ctx = (i2c_master_common_ctx_t *)pvTimerGetTimerID( xTimer );
xTaskNotify( ctx->xI2cMasterxTaskHandle, I2CMASTER_EVENT_TIMEOUT,
eSetValueWithOverwrite );
}
Finally, the i2c bus peripheral registers are all written inside of a FreeRTOS task that implements a state machine. This loop starts by waiting for a task notification:
uint32_t ulNotificationValue;
/* wait for a notification indefinitely */
while ( pdTRUE != xTaskNotifyWait( 0, 0xFFFFFFFF, &ulNotificationValue,
portMAX_DELAY ) ) ;
And then later the timer is enabled like so:
xTimerChangePeriod( i2c_ctx->xI2cMasterxTimerHandle, expiryTime,
(TickType_t)0 );
In the case where transfer was successful, the timer is stopped before completion:
xTimerStop( i2c_ctx->xI2cMasterxTimerHandle, (TickType_t)0 );