How to keep your code loosely coupled

I currently have code for a infrared sensor board.
I need a delay between sensor powering on and taking the sample.

When I do:

sensor_on();
vTaskDelay(pdMS_TO_TICKS(200));
sensor = sensor_read();

My code is depending on FreeRTOS.
But functions like _delay_ms(200) block the OS for 200ms.

Sure you can solve this with all kinds of precompile if statements, but isn’t there a nicer way to make it loose coupled?

I do not understand the question. The very idea of vTaskDelay() IS to prevent the CPU from wasting CPU cycler on a wait and allow concurrent uses of the CPU by other tasks. If you do not want to depend on FreeRTOS (meaning pobably that you don’t want an RTOS under your code at all), there would be no other choice but to busy wait?

Normally this would be handed by some sort of abstration, eg

#ifdef FREERTOS_SUPPORT
vTaskDelay(…)
#else
otherDelay(…)
#endif

or a functional abstraction with different platform independent delay implementations.

Or are you looking for something completly different?

Sorry if my question wasn’t clear.

A lot of my low level driver code are just basic sensor control. (IO, I2C, etc)
When I use FreeRTOS functions in them I can not share my code to other developers that are not using FreeRTOS in their projects.

I normally solve all this with many precompile condition checks like you mentioned:
#ifdef FREERTOS_SUPPORT

But somehow I think there should be a nicer way to do this?

Again, you could use platform specific functional or syntactic abstractions.

Syntactic would be

#define PLATFORMDELAY(x) vTaskDelay(x) // FreeRTOS platform
or
#define PLATFORMDELAY(x) BusyWait(x) // barebones platform

etc.

Define “nicer” so we know what exactly your reservations are about either solution…

A nice way for us would be some form of auto detect.
So driver code is implemented in a project and the driver auto detect that the project has or has not FreeRTOS implemented.

That way we can say that the driver supports FreeRTOS without asking the developer to set defines in a header file.

Ok, now we are talking taste… I personally would NOT call that “nicer,” mostly because it requires additipnal cycles at runtime for a repetitive test. Also, each additional code automatically incurs more potential bugs, and with every new platform supported, more checks have to be made, bearing among other things the risk that checks that previously worked now fail.

These discussions have been around as long as there has been computing. There are arguments pro and against each approach. I don’t believe that’ll ever be settled for good.

Why not using the std/default FreeRTOS defines from FreeRTOS.h to auto-detect during compile time e.g. similar to this ?
FreeRTOS.h IS always included when using FreeRTOS.

#ifndef INCLUDE_vTaskDelay
BusyWait(x)
#else
vTaskDelay(x)
#endif

either defining a PLATFORMDELAY macro as proposed by @RAc or implementing an (OS) platform abstraction our_delay() function.

1 Like

Actually, one “reasonably modular” way out would be to use something like an “OS driver,” ie a function pointer table that is being filled at startup up time with platform specific callbacks. A delay fn could then for example be realized by something like this:

*(g_PlatformPtrTable[DELAYFNINDEX])(10);

but I hate to tell you that this will not make your life easier. As a teaser consider this scenario: On all RTOS, you will need some kind of conversion from “absolute times” (ms) to timer ticks depending on the timer granularity.

On most RTOSs it also holds true that delaying for one tick in practice means delaying by AT MOST the ms configured to make up one tick (because the wait may be scheduled in the middle of a time slice). Thus, delaying something that requires a “hard wait” on the hardware level may fail. I’ve been there many times.

But that means that your function pointer callback for delay can not point to the “pure delay” fn but one that rounds to at least two timer ticks. Yet this can lead to unwanted behavior in many other situations. Thus you would need at least two delay callbacks: One with a minimum requirement and one without one. Yet this would be an overkill on those platforms that do support fine granularity delays - just for the sake of code recyclability with other platforms.

It’s the typical engineering question - choose which death to die from, plague or cholera.

Thanks, I think I go with this one for now.