Regarding abstraction:
Why do you drown such a simple thing in a flood of abstraction layers? You can safely assume that every C programmer knows the meaning of
PORT |= (1<<pin);
PORT &= ~(1<<pin);
This is as readable as the code can get, as far as a C programmer is concerned. By hiding this code in abstraction layers, you make your code less readable to C programmers, although it may very well get more readable to non-programmers. But you want the former to read your code, not the latter.
The above is also the fastest possible, in terms of efficiency. It is quite likely that the compiler will translate such code directly to a single bit set/bit clear assembler instruction.
So my advise is to throw all the abstraction out. You don't want to hide the hardware away from the embedded C programmer. What you do need to hide away from them is the specific hardware implementations, so that they need not re-invent the wheel for every new project.
One such abstraction is when writing a hardware-independent API layer. Such as for example void led_set (bool lit);
. This function will light a LED on your board. You'd place it in the abstract file led.h
, which has no corresponding .c file. Because the .c file is implemented for your specific project only: in my_led.c
you'll have the actual implementation, which directly access the GPIO registers, sets up data direction & pull resistor regisers, handles signal polarity and so on.
Regarding your specific question:
There are no guarantees that GCC will inline that function as you expect: the inline keyword is pretty much obsolete, as the compilers nowadays are far smarter than programmers when it comes to deciding when to inline a function. I would say it is very likely, given that you compile with maximum optimization enabled. Only way to find out is to try.
But then it doesn't really matter the slightest whether or not the compiler inlines this function. You will not likely ever have such extreme real-time requirements that the function calling overhead will affect your program. We're talking tens of nano seconds here: not even the digital electronic integrated circuits on your board will respond fast enough for those extra CPU ticks to make a difference.
I work with MCU-based real-time embedded systems on daily basis and even in those systems, you rarely ever face a situation where extreme code optimization like this would matter. If you did, you would be using a DSP, not a regular MCU, most certainly not an AVR.
More importantly, your static const
reduced the scope of the constant to the local file, so that none else need to concern itself with it, nor will you clutter down the global namespace. This is good programming practice, and good programming practice wins over manual code optimization in 9 times out of 10.