How to understand "vTaskDelayUntil"?

I have a trouble about “vTaskDelayUntil”
my code like following in my consumer task:

TickType_t last_wake_time = xTaskGetTickCount();
unsigned long long last_ts = time_now_us();
while(true){
  vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(10));
  current_ts = time_now_us();
  cycle_time = current_ts - last_ts;
  last_ts        = current_ts;
  xSemaphoreTake(lock, portMAX_DELAY);
  do_something();
  xSemaphoreGive(lock);
}

obviously, this task’s target is: execute “do_some_thing” every 10ms.
the “do_something” is almost an empty function, we can think its cost is 0.
this consumer’s priority is tskIDLE_PRIORITY + 6
another producer task like following:

while(true){
  recieve_msg(......);
  xSemaphoreTake(lock, portMAX_DELAY);
  fill_data for "do_something"
  xSemaphoreGive(lock);
}

obviously, the target of this producer task is: obtain data from outside, and fill_data for “do_something”.
its priority is tskIDLE_PRIORITY + 4
the receive_data is about 4ms(4000us) every time.

it is ok if the producer’s task is not running. in other word, the cycle_time is almost 10000 micro-second. this result match my expectation.
but, it is out of my expectation if the producer task is running. I found the “cycle_time” is about 2000 micro-second in the consumer task
I think I should change the process method in the consumer task, especially, modify the “vTaskDelayUntil”. but, I don’t know how to modify, I don’t know why the “vTaskDelayUntil” cannot match my expectation.
Is there anyone would like to teach me?

I would not expect the cycle time of the consumer task to depend on whether the producer task was running or not - so suspect there is something else wrong.

Which chip are you using? Do you have configASSERT() and stack overflow checking on? Do you check the return values of the API calls used to create the two tasks? (xTaskCreate() or xTaskCreateStatic()).

my target chip is arm-cortex-r52,
I didn’t apply configASSERT, I think I should apply it to check my program
But, I don’t know check what. Would you like to give me some suggestion?

The good thing is that configASSERT is already used in the FreeRTOS code itself helping a lot catching application code / API problems.

The key point about vTaskDelayUntil is that it resumes that task as soon as the time gets to be one period later than the last time it was supposed to have resumed the task last time, and the delays go to 0 if we ever “fall behind”. This says it tries to keep the rate of releasing as close as it can LONG TERM to the desired rate.

If something holds off one of the times the task runs after being released (like a higher priority task running) then the next delay will be “short”, but the average of all your cycle_times should be correct (as long as the system can keep up).

Note also, if ever something disturbs the last_wake_time variable, the whole timing gets broken, and possibly the system will stop blocking until it can catch up with the large “backlog” that has been created.