FreeRTOS+UDP: Reasons behind TICK_RATE limit

Hello, I am currently evaluating FreeRTOS+UDP to add IP functionality to an existing, FreeRTOS-based product. I have now gotten to the point where the sources are ported over and our firmware compiles, so far so good. One of the things I had to do in order to get there is lower the tick rate of our product from 1024Hz to 512Hz to meet the “< 1000Hz” limitation asserted in the source. Unfortunately, this has repercussions on other systems in our firmware and it is unlikely we will be able to ship with the lower tick rate. With that in mind, I have a couple of questions on the topic: * What is the reason behind the limitation? * Is it a hard limit or could it be stretched to accomodate our 1024Hz tick rate? * Where would I start if I wanted to modify FreeRTOS+UDP to accomodate higher tick rates? In the event that the information is relevant: we use a cortex M4 based STM32 MCU, and are looking at different solutions for the network connection itself (off-the-shell ethernet module for prototyping). Thank you in advance, François.

FreeRTOS+UDP: Reasons behind TICK_RATE limit

I am not aware of any reason why FreeRTOS+UDP would have a clock limitation, and in fact just checked the following project: http://www.freertos.org/AtmelSAM4ERTOS_Demo.html and that is uising a 1KHz tick. I suspect somewhere in your code (or maybe our code?) a delay will be specified using either the pdMSTOCICKS() macro, or the pdTICKRATEMS macro (which was the old way of doing it) – and those will only work up to a 1KHz tick rate as they cannot specify a fraction of a millisecond. Once you go over 1KHz the macros no longer work, and will most likely either result in a divide by zero error, or simply a delay of 0. Regards.

FreeRTOS+UDP: Reasons behind TICK_RATE limit

That is very much in your code :). I am referring to these lines in FreeRTOSUDPIP.c:
#if configTICK_RATE_HZ > 1000
    #error configTICK_RATE_HZ must be less than 1000 to use FreeRTOS+UDP
#endif
François

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Hi François, If I were you I’d disable the configTICK_RATE_HZ sanity check and try it out. PS. When working with 1024 Hz, please use pdMS_TO_TICKS for conversions: ~~~~~ /* Converts a time in milliseconds to a time in ticks. */ #define pdMS_TO_TICKS( xTimeInMs ) ( ( ( TickType_t ) ( xTimeInMs ) * configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) ~~~~~ This older macro will fail if configTICK_RATE_HZ equals 1024: ~~~~~ #define portTICKPERIODMS ( ( TickTypet ) 1000 / configTICKRATE_HZ ) ~~~~~ PS. Note that in the Labs section, you can find FreeRTOS+TCP: a TCP/IP stack which also contains UDP and much more. You can compile it for UDP-only:
#define ipconfigUSE_TCP    0
( see www.freertos.org/tcp ) Beside UDP, DHCP and some NameService protocols (LLMNR and NBNS) might be useful. Regards.

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Ah right – the macros I referenced previously must be used inside the stack itself. FreeRTOS+UDP is designed to be as small as possible, and as such uses FreeRTOS software timers to stimulate the periodic processing necessitated by the protocols (ARP timer, etc.) – you could change the code that specifies the frequency of these timers to not use the portTICKRATEMS macro and in so doing prevent the potential for the macro to generate a divide by zero and remove the #error. Regards.

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Thank you both! I do see that portTICKRATEMS which is equivalent to portTICKPERIODMS peppers the FreeRTOS+UDP code. I will take a stab at substituting the dozen-or-so calls to it with something based on pdMSTOTICKS. Simply disabling the check is not an option as:
100 / portTICK_RATE_MS
and other such lines become divisions by zero. I have briefly looked at FreeRTOS+TCP, but the “labs” label does not inspire confidence. How far is the project from being production-ready? Cheers, François.

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Salut François,
..looked at FreeRTOS+TCP, but the “Labs” label does not inspire confidence.
Haha, I didn’t know that the word “Labs” could have such an effect. The first release of +TCP was in September last year and that didn’t happen before more than a year of development and thorough testing. It was called “Labs” to reserve a bit more of freedom: features may still be added and documentation can still be completed. Personally, I applied +TCP in an audio device (multi-channel amplifiers) where it serves HTML, FTP and streaming audio. Many other users reported on this forum that they adopted +TCP in their projects. Gradually we are extending the number of network interfaces for different platforms ( “/NetworkInterface.c” ).
How far is the project from being production-ready?
There will be a new release of +TCP and +FAT within 1 or 2 weeks, but you can as well start with the current one (version 150406 from http://www.freertos.org/tcp ) In the new release, +TCP will only have minor changes, most of them aesthetic: ~~~~~ /* The socket type itself. */ – typedef void *xSocket_t; + typedef void *Socket_t;
 /* The xSocketSet_t type is the equivalent to the fd_set type used by the
 Berkeley API. */
– typedef void *xSocketSet_t; – typedef void *SocketSet_t; ~~~~~ +FAT will have some more structural ameliorations, and it now comes with more demo code. Regards

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Hi François, Because it is Sunday, a little more about the tick- or clock-rate: For a UDP stack, the clock-rate isn’t very important. The ARP tables and DHCP have relatively slow timers, in units of seconds. For TCP however, time must be accurate: ACK’s are sometimes sent after a 200 ms delay, and retransmissions are also well-timed. FreeRTOS+TCP has been tested mostly with a configTICK_RATE_HZ of 1000 Hz, but I assume that higher clock rates (including 1024) should work equally well. ( As you probably know… ) all FreeRTOS blocking functions have a parameter of type TickType_t. It defines the maximum number of clock ticks that a function should block. In the TCP and UDP source code, you might find code like this: ~~~~~ uint32t ulDelayMs = 2; TickTypet xTickCount = pdMSTOTICKS( ulDelayMs ); xSemaphoreTake( xSemaphore, xTickCount ); ~~~~~ Waiting for 1 clock tick is tricky: the function might return within a few uS if the clock tick is about to come. The above code will not work well with a 500 Hz clock, because pdMS_TO_TICKS(2) would return 1. On a lower clock rate, pdMS_TO_TICKS(2) will even return 0, hence the API won’t block at all. ( NB. the prefix “pd” is an abbreviation of the source file name “projdefs.h” ) If you want to write portable code that runs with every clock speed, you might want to use the following pdMS_TO_MIN_TICKS() : ~~~~~ #define pdMINTICKS( xTimeInTicks ) ( ( ( xTimeInTicks ) < ( TickTypet ) 2 ) ? ( ( TickTypet ) 2 ) : xTimeInTicks ) #define pdMSTOMINTICKS( xTimeInMs ) pdMINTICKS( ( ( ( TickTypet ) ( xTimeInMs ) * configTICKRATEHZ ) + 500 ) / ( TickType_t ) 1000 ) ~~~~~ It rounds up and it returns a minimum value of 2. Sorry for the use of a “ternary conditional operator”, the “a?b:c” expression. Regards.

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Actually, you get the same problem at higher ticks, If you want to be sure you delay at least 2 tick periods, you need to delay for 3, as a delay of 2 might return after a delay of only 1.0001 ticks. For bigger values the error is still there, it just isn’t as noticable. Also, your routine doesn’t “Round Up” but Rounds, so with a 100 Hz tick, a request for 22ms delay will give you a 2 tick, or 20ms delay (actually a 10.0001 – 20 ms delay). If you want to be absolutely sure that you never delay less than the spec you need to really round up (add +999 and then divide by 1000) and then add 1 to account for the short first tick.

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Heins, Thanks a lot for the help and explanations. I spent the last few days porting FreeRTOS+TCP over, and got it mostly working using out 1024Hz tick rate. A few things worth noting however:
  1. The licensing is hazy as there is no option today to purchase a commercial license.
  2. The rate at which gratuitous ARP messages is sent is non configurable and very agressive (every 20s), causing unwarranted power drain.
  3. portTICKPERIODMS is used in many place and causes problems (I had to address them manually). See below:
FreeRTOSARP.c:#define arpGRATUITOUSARPPERIOD ( 20000 / portTICKPERIOD_MS ) FreeRTOSDHCP.c: #define dhcpINITIALTIMERPERIOD ( 250 / portTICKPERIOD_MS ) FreeRTOSDHCP.c: #define dhcpINITIALDHCPTXPERIOD ( 5000 / portTICKPERIODMS ) FreeRTOSDHCP.c: #define dhcpMAXTIMETOWAITFORACK ( 5000 / portTICKPERIODMS ) FreeRTOSDHCP.c:#define dhcpDEFAULTLEASETIME ( ( 48UL * 60UL * 60UL * 1000UL ) / portTICKPERIOD_MS ) /* 48 hours in ticks. */ FreeRTOSDHCP.c:#define dhcpMINIMUMLEASETIME ( 60000UL / portTICKPERIOD_MS ) /* 60 seconds in ticks. */ FreeRTOSDHCP.c: (*1000) then ticks (/portTICKPERIOD_MS). */ FreeRTOSDHCP.c: xDHCPData.ulLeaseTime *= ( 1000UL / portTICKPERIOD_MS ); FreeRTOSDNS.c: xTimeout /= portTICKPERIOD_MS; FreeRTOSDNS.c:TickTypet xTimeoutTime = 200 / portTICKPERIODMS; FreeRTOSIP.c:#define ipINITIALISATIONRETRYDELAY ( ( ( TickTypet ) 3000 ) / portTICKPERIODMS ) FreeRTOSIP.c: #define ipconfigMAXIPTASKSLEEPTIME ( 10000UL / portTICKPERIOD_MS ) FreeRTOSIP.c: prvIPTimerReload( &xTCPTimer, ipTCPTIMERPERIODMS / portTICKPERIODMS ); FreeRTOSIP.c: ulNextInitialSequenceNumber += ipINITIALSEQUENCENUMBERFACTOR * ( ( xTimeNow – xStart ) * portTICKPERIODMS ); FreeRTOSIP.c: prvIPTimerReload( &xARPTimer, ipARPTIMERPERIODMS / portTICKPERIODMS ); FreeRTOSTCPWIN.c: return ( ( xTaskGetTickCount() – pxTimer->ulBorn ) * portTICKPERIODMS ); include/FreeRTOSIPConfigDefaults.h: #define ipconfigUDPMAXSENDBLOCKTIMETICKS ( 20 / portTICKPERIOD_MS ) include/FreeRTOSIPConfigDefaults.h: #define ipconfigMAXIMUMDISCOVERTXPERIOD ( 999 / portTICKPERIOD_MS ) include/FreeRTOSIPConfigDefaults.h: #define ipconfigMAXIMUMDISCOVERTXPERIOD ( 30000 / portTICKPERIOD_MS ) Cheers, Francois Edit: I cannot for the life of me get those lines to be correctly formatted, sorry 🙁

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Hi François, In the new release of FreeRTOS/Labs you’ll find the corrections made to eliminate the use of portTICK_PERIOD_MS. I hope they’re all correct now. There are only 3 occurrences of the macro left. Please download the newest release from here: http://www.freertos.org/tcp This ‘FreeRTOSLabs150825′ is updated silently: the official announcement will follow in September, when most people are back from their holidays. We should be on the beach right now 🙂 NB Some type names lost their x-prefix: ‘xSockett’ is now called ‘Sockett’. See also ipconfigENABLE_BACKWARD_COMPATIBILITY in include/FreeRTOS_IP.h
The rate at which gratuitous ARP messages is sent is non configurable and very aggressive (every 20s), causing unwarranted power drain.
I saw that too, now changed to: ~~~~~

ifndef arpGRATUITOUSARPPERIOD

#define arpGRATUITOUS_ARP_PERIOD    ( pdMS_TO_TICKS( 20000 ) )

endif

~~~~~ Twenty seconds is indeed extremely short. I like it while testing: after a reboot the devices make themselves known very quickly and all ARP tables are updated accordingly. What default value should be reasonable? 5 or 10 minutes?
The licensing is hazy as there is no option today to purchase a commercial license.
I’m sure that Richard can respond to this Regards, Hein

FreeRTOS+UDP: Reasons behind TICK_RATE limit

Hi Hein, Thanks for the switf reply!
In the new release of FreeRTOS/Labs you’ll find the corrections made to eliminate the use of portTICKPERIODMS. I hope they’re all correct now. There are only 3 occurrences of the macro left.
Two of those three are still troublesome (a division by 0, and a next ID incremented by 0). I will leave my typedef for portTICKPERIODMS set to 1 for now.
We should be on the beach right now 🙂
No rest for the wicked 😉 I have brought the latest changes over and made the minor adjustements to my code that were needed. Nice to see the style fall in line with the latest FreeRTOS code (one thing that did cause me some heartache though is the new FreeRTOS_errno stuff which defines success as 0, as opposed to other FreeRTOS APIs that return pdTRUE, or 1). Also happy to see the GCC port included.
Twenty seconds is indeed extremely short. I like it while testing: after a reboot the devices make themselves known very quickly and all ARP tables are updated accordingly. What default value should be reasonable? 5 or 10 minutes?
I think this really should be tuned on a case by case basis. Being very battery conscious, we would probably like it to happen on IP_Init, and every 10 minutes thereafter. Others I am sure would be fine with 20 seconds. Cheers, François.