xQueueReceive timeout not working as expected with portTICK_RATE_MS

sreejeshkn wrote on Tuesday, December 10, 2013:

Hi Friends,

I am working on a project to develop UART-TCP bridge the interface demands a higher throughput; here length of the payload is not fixed so looking for inter-character gap to find end of the frame received from UART ISR.

Problem:

ser->tgap = 5; //Expecting 5ms timeout
xQueueReceive(com->rx_queue, &cByteRxed, (ser->tgap/ portTICK_RATE_MS));

But the “xQueueReceive” returns only after 5 SysTicks that is 10*5 = 50ms not 5ms always. According to FreeRTOS documentation it is possible to get timeout in ms irrespective of SysTick by using “timeout/portTICK_RATE_MS” not sure what is going wrong any suggestions would be grateful. Following are the configurations used.

Configuration:

OS version : FreeRTOS v5.03

"#define configCPU_CLOCK_HZ ((unsigned portLONG)96000000) "
#define configCPU_PERIPH_HZ (configCPU_CLOCK_HZ / configPCLK_DIV)”
"#define configTICK_RATE_HZ ( 100) /* SysTicks per 10ms*/ - FreeRTOSConfig.h "

#define portTICK_RATE_MS ( ( portTickType ) 100 / configTICK_RATE_HZ ) - portmacro.h”

Thanks!
Sreejesh

davedoors wrote on Tuesday, December 10, 2013:

The resolution of block times is set by configTICK_RATE_HZ. In you post that is set to 100, so you can ask for block times in multiples of 1/100th of a second, and no faster. See this post https://sourceforge.net/p/freertos/discussion/382005/thread/8fc54ac4/#0e0a

sreejeshkn wrote on Tuesday, December 10, 2013:

Hi Dave,
I just tested the same piece of code with same FreeRTOSconfig.h on a PC simulation of FreeRTOS 7.6 and I got a timeout of 4.90ms approximately. this experiment is confusing and made me to think some thing is missing with my version of FreeRTOS v5.03.

Thanks!.
Srijesh

richard_damon wrote on Wednesday, December 11, 2013:

Since configTICK_RATE_HZ = 100, portTICK_RATE_MS SHOULD be 10, but since your listed code was 100/config_TICK_RATE_HZ instead of 1000/config_TICK_RATE_HZ so it is 1. That error will make every delay 10 times too long.

note that if you correct this, timeout/portTICK_RATE_MS = 5/10 = 0 (by integer math), so the queue receive would not block but give you data if it is sitting in the queue already, else return an error.

One other thing to note, is that a value of 1 means till the next tick interrupt, which could be anywhere from now, to 10ms from now, that is the fundamental sampling error of the system (unless you know that a tick needed to have recently happened because you did a delay and nothing higher priority can take a long time.

sreejeshkn wrote on Wednesday, December 11, 2013:

Hi Richard, Thanks…
I understand the math of portTICK_RATE_MS but not sure about the behaviour xQueueReceive API, Is it possible to get a higher resolution timeout than Systick period?

I have Systick of 10ms is it possible to get a timeout of 5ms from xQueueReceive, or should increase the Systick frequency to 1000?.

davedoors wrote on Wednesday, December 11, 2013:

Is it possible to get a higher resolution timeout than Systick period?

No.

richard_damon wrote on Wednesday, December 11, 2013:

All FreeRTOS delays are specified in units of Timer Ticks and with integral parameters, thus you can not specify any time values more precisely than a timer tick. And as I mentioned before, the first timer tick of the delay is what is left of the current tick, so may be short, so delays should really be thought of as having a tolerance of +0/-1, and due to higher priority tasks delaying you, you may get error in the + side too.

If you really need to detect a 5ms gap, then you would need to raise the tick rate, I would say to at least 500 Hz (letting you test for a 4-6ms gap with a delay of 3) or 1000 Hz (letting your test for a 4-5ms gap with a delay of 5, or a 5-6ms gap with a delay of 6).

With a 100 Hz tick, the best you could do is use a delay of 2 to test for a 10-20ms gap, which may well work for the application, it sort of depends on the real latency reqirements for the system.

Another option, would be to add a little bit of intelegence to the unit and look for likely record gaps (like line breaks), and if you get one of those, the previous packet has been sent, maybe test for a minimal packet in length (so you don’t spam the network with lots of very short records), and no data is available in the queue (a 0 delay receive fails), then immediately send the packet. (This assumes that the TCP is really just a “stream” of bytes and the packeting isn’t important, i.e. it is a Serial over TCP protocol, not a TCP over Serial protocol (but that really should have some framing data in the serial stream that you could process).

sreejeshkn wrote on Wednesday, December 11, 2013:

Hi Richard,

The comments making sense to me and having similar test results. I will do changes to tick on 1000Hz and a gap of 6ms, get back to you with the result.

Yes…Your assumption is correct the software does serial data transmission over TCP protocol, but I do not have control over the serial device to apply framing on data bytes.
Since the serial device works on a request response basis I can control the traffic from TCP client part of the system.

Thanks alot for the detailed comments…

Regards,
Sreejesh

richard_damon wrote on Thursday, December 12, 2013:

Serial over TCP shouldn’t have problems with arbitrary block breaks in the TCP packets, as the program shouldn’t be expecting messages to be in lock step with the packets, the gap detection being there mostly to avoid a stall at the end of a message waiting for more. This case could have improvements in operations by having the code look for signs of a record break (like seeing a Carriage Return character) and sending the record right away.

The other case, TCP over Serial, would be where the other end of the serial wire is also converting between serial and TCP packets, with the goal of recreating the packets that it received. In this case gap detection is critical, (but also likely unacceptably slow) unless the serial data contains some meta-data in it to find the packet breaks.

sreejeshkn wrote on Thursday, December 12, 2013:

I totally agree with your suggestion, but the system requirement demands to follow GAP detection to find the end of frame because of variable length data frame, e.g. 3,35,128… in bytes.
Tested the code with tick frequency of 1000Hz and a gap of 6ms; Now there is a delay of 14/15ms over the channel when measure the delay from TCP client part (that is the time between Tx() to Rx()). I believe “xQueueReceive” is working as expected since I am running 8 Tasks with the same priority there is a delay of 8ms due to task switch on a round robin basis so the 14ms overall delay. I would try increasing the priority values of less critical tasks (Now all 8 application Tasks are in priority level 3 ).

I understand uxPriority = 3 is higher in priority than uxPriority = 8 !..

Thanks!.
Srijesh

rtel wrote on Thursday, December 12, 2013:

I understand uxPriority = 3 is higher in priority than uxPriority = 8 !..

Not it isn’t! 0 is the lowest priority and (configMAX_PRIORITIES - 1) is the highest priority.

The lower the number, the lower the priority - so it works in the logical and therefore expected way.

Regards.

sreejeshkn wrote on Thursday, December 12, 2013:

Thanks for the prompt reply…,
In my OS configuration configMAX_PRIORITIES is 5 so 5 is the highest priority and 0 is the lowest.

rtel wrote on Thursday, December 12, 2013:

No, if configMAX_PRIORITIES is 5 then there are 5 priorities, which means 0 is the lowest and 4 is the highest. In my post above I say (configMAX_PRIORITIES - 1) is the highest.

Regards.

sreejeshkn wrote on Thursday, December 12, 2013:

Thanks!.. I got the point.