cancel
Showing results for 
Search instead for 
Did you mean: 

xTimerChangePeriodFromISR is not working as expected in UART interrupt callback

npatil15
Associate III

Hello,

I have modbus master application (Free RTOS using CMSIS lib), in which modbus constructure init the timer_ with osTimer.

osTimerId_t ModbusMaster::createTimer_(const char* name)
{
  osTimerAttr_t attr{};
  attr.name = name;
  auto t = osTimerNew(responseReady_, osTimerOnce, this, &attr);
  return t;
}

So Modbus master send request to slave and start timer to wait for response, at start stagingLength_ = 0

__HAL_UART_ENABLE_IT(uart_, UART_IT_RXNE);
HAL_UART_Receive_IT(uart_, &mbMsg_.payload.rawResponse.rawData[stagingLength_], 1);
osStatus_t stat = osTimerStart(timer_,1500);

Now as soon as I got first character received, I will change the period of timer to 3.5 character silence time and once that silence time is expire, the time will invoke its callback as responseReady(). Here below the value 1000 is not match with silence time but keep as big as possible.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if( xTimerChangePeriodFromISR((TimerHandle_t) timer_, pdMS_TO_TICKS( 1000 ), &xHigherPriorityTaskWoken ) != pdPASS )
{
    //this code doesnt come here, so call is not failing here
}
stagingLength_++;
__HAL_UART_ENABLE_IT(uart_, UART_IT_RXNE);
HAL_UART_Receive_IT(uart_, &mbMsg_.payload.rawResponse.rawData[stagingLength_], 1);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}

Now, ideally for modbus slave it doesnt take more than 10ms to respond. but the real issue is, if I remove the xTimerChangePeriodFromISR() then I will receive all correct data, as previously I have initialize timer with big value which give good bandwidth to receive all bytes. but if I keep the function xTimerChangePeriodFromISR() then I get random data, like, 3/6/ or 0 bytes sometime. 

Looks like the call xTimerChangePeriodFromISR() is disturbing the timer.

I have also tried below but still very inconsistence behaviour, didnt able to implement at least silence time logic.

  xTimerResetFromISR((TimerHandle_t)timer_, &xHigherPriorityTaskWoken);
  xTimerStopFromISR( (TimerHandle_t)timer_, &xHigherPriorityTaskWoken );
//////////////////////////////////////////////
// These both function passed but disturb the timer and not get complete data
  if(xTimerStopFromISR( (TimerHandle_t)timer_, &xHigherPriorityTaskWoken) != pdPASS)
  {
    int test = 0;
  }
  if(xTimerStartFromISR( (TimerHandle_t)timer_, &xHigherPriorityTaskWoken) != pdPASS)
  {
    int test = 0;
  }
//////////////////////////////////////////
  xTimerResetFromISR(timer_, &xHigherPriorityTaskWoken);
//////////////////////////////////////////
/// These below function both fails so ideally not efect on current timer and then it works///////
  osStatus_t stat;
  stat = osTimerStop(timer_);  // Stop the timer
  if(stat != osOK)
  {
    int test = 0;
  }
  stat = osTimerStart(timer_, 1/*silenceTimeoutTicks_*/);
  if(stat != osOK)
  {
    int test = 0;
  }
/////////////////////////////////

 

Help me with suggestion whats make it wrong, does it is possible that reducing timer value is not possible and which creates issue with the logic ?

Thanks,

Nitin 

7 REPLIES 7
TDK
Super User

If ARR is preloaded, which is the default behavior, you need to generate an update event after writing to ARR before the update to the timer period (ARR) takes place.

If you feel a post has answered your question, please click "Accept as Solution".

Hello,


@TDK wrote:

If ARR is preloaded, which is the default behavior, you need to generate an update event after writing to ARR before the update to the timer period (ARR) takes place.


He's speaking about the Timer service in the FreeRTOS and not about the GP timer ;)

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
avburmel
Associate III

Hello @npatil15
Try to reset timer (call xTimerResetFromISR) before changing the period.


 

I will try and let you know, but just to understand, is it the theoretical requirements for this timer to reset before reconfigure ?

 

Thanks,

Nitin

MFARH.1
ST Employee

Hello @npatil15 ,

The issue most likely arises from mixing the CMSIS-RTOS and FreeRTOS timer APIs, as well as modifying the timer period within an ISR. I recommend that you:

  • Choose a single timer API (either CMSIS or FreeRTOS) and consistently use it,
  • Avoid changing the timer period inside the ISR; instead, reset the timer,
  • Handle complex timeout logic within a dedicated task if necessary.

Regards,

Maher

Hello,

Instead of resetting time at each character, I have tried to reset only at once and it works. But this is just for testing, because it has to reset at each character to re-check silence timeout.

So if I reset at each character I found that it was not missing last character, instead it was missing in between character and timeout is perfectly working fine. 

So my thought is, may be calling this timer reset functionality adding some delays which cause to missed some bytes in between the frame. That why it works when I reset only once at first character.

 

Also one more thoughts, free rtos working with 1ms tick cycle and uart received bytes at micro seconds, so that may be the reason when we use any free rtos function call in interrupt handler that may add minimum 1ms of delay which cause to missed characters on uart ?

I have thread which only take modbus request which i have process and wait for response, until thread is blocked, so cant use thread to monitor local Haltick logic to invoke callback when timeout occurs.

So help me with logic or any alternative strategy to build this.

Thanks,

Nitin

Hello.

FreeRTOS timer is a task, usually low-priority, that receives commands through a queue. The queue with your command will be processed when this task gets CPU time. So, if you want this timer to work correctly, it's really necessary to ensure that higher priority tasks free up enough CPU time. Otherwise, the queue will overflow or the event won't occur on time.

 

As alternative strategy you can try using one of the hardware timers with interrupt for your case.