STM32 HAL Library simple C coding error - c

I am using the STM32 HAL Library for a micro controller project. In the ADC section I found the following code:
uint32_t WaitLoopIndex = 0;
/...
.../
/* Delay for ADC stabilization time. */
/* Delay fixed to worst case: maximum CPU frequency */
while(WaitLoopIndex < ADC_STAB_DELAY_CPU_CYCLES)
{
WaitLoopIndex++;
}
It is my understanding that this code will most likely get optimized away since WaitLoopIndex isn't used anywhere else in the function and is not declared volatile, right?

Technically yes, though from my experiences with compilers for embedded targets, that loop will not get optimised out. If you think about it, having a pointless loop is not really a construct you are going to see in a program unless the programmer does it on purpose, so I doubt many compilers bothers to optimise for it.
The fact that you have to make assumptions about how it might be optimised though means it most certainly is a bug, and one of the worst types at that. More than likely ST wanted to only use C in their library, so did this instead of the inline assembler delay that they should have used. But since the problem they are trying to solve is heavily platform dependent, an annoying platform/compiler dependent solution is unavoidable, and all they have done here is try to hide that dependency.
Declaring the variable volatile will help, but you still really have no idea how long that loop is taking to execute without making assumptions about how the compiler is building it. This is still very bad practice, though if they added an assert reminding you to check the delay manually that might be passable.

This depends on the compiler and the optimization level. To confirm the result, just enter debug mode and check the disassembly code of the piece of code.

Related

Static variable doesn't initialize to given value

I have a static "init" variable to run a function once on startup, (RTOS) but it seems to initialize to a random value. If I remove the static tag, everything works great. (Except for the obvious issue of it running the init function every pass.) Could anyone give more insight as to why this isn't working or perhaps a better way to achieve this?
Example code:
void ManageStructures()
{
// Variable declarations/definitions
static uint8_t StructInitialized;
// Have also tried "static uint8_t StructInitialized = 0", neither worked
// Function prototypes
void InitStruct();
if (!StructInitialized)
{
StructInitialized= 1;
InitStruct();
}
Test = StructInitialized;
edit: I apologize for the lack of information. This is for a company and I am trying to stay within the bounds of our public information policy. The MCU is a STM32F7 series using the "Ac6 STM32 MCU GCC" toolchain. I am not well versed in compiler operations so it may take me longer to find answers to the compiler or makefile related questions.
edit: It has become clear that this is an issue with the compiler or linker scripts and not my code. That being said, it has also become abundantly clear that I need to learn more about toolchains, linker scripts, and compilers in general before getting to the root of this issue. I'll return to this question once I have become familiar enough to give valuable feedback or answer it myself. Thank you everyone for the feedback and direction!
It is common that embedded systems run with a "minimal startup" code, meaning that they never initialize .bss or .data during start-up. Meaning that if you write something like static int foo = 42;, the code will compile but the variable will never be set.
This isn't standard C compilant, so usually upon project creation you get an option from the IDE to have a "minimal" or "standard" startup.
This likely lies in the so-called "CRT" (C run-time) delivered with your tool chain and not in the RTOS. If you single step your program from where it actually starts (the reset vector) rather than from where main() starts, you'll be able to see exactly what the CRT does and doesn't.
Unfortunately debuggers often use a "dumbed-down mode", since embedded systems programmers are by default assumed to be completely incompetent nowadays. Meaning that they silently insert a breakpoint at main() and run until that point. You might have to "un-dumb" your debugger in order to debug the CRT.

Is it possible to disable gcc/g++ optimisations for specific sections of code?

I am compiling some code that works without optimisation but breaks with optimisations enabled. I suspect certain critical sections of the code of being optimised out, resulting in the logic breaking.
I want to do something like:
code...
#disable opt
more code...
#enable opt
Even better if I can set the level of optimisation for that section (like O0, O1...)
For those suggesting it is the code:
The section of the code being deleted is (checked by disassembling the object file):
void wait(uint32_t time)
{
while (time > 0) {
time--;
}
}
I seriously doubt there is something wrong with that code
If optimization causes your program to crash, then you have a bug and should fix it. Hiding the problem by not optimizing this portion of code is poor practice that will leave your code fragile, and its like leaving a landmine for the next developer who supports your code. Worse, by ignoring it, you will not learn how to debug these problems.
Some Possible Root Causes:
Hardware Accesses being optimized out: Use Volatile
It is unlikely that critical code is being optimized out, although if you are touching hardware registers then you should add the volatile attribute to force the compiler to access those registers regardless of the optimization settings.
Race Condition: Use a Mutex or Semaphore to control access to shared data
It is more likely that you have a race condition that is timing specific, and the optimization causes this timing condition to show itself. That is a good thing, because it means you can fix it. Do you have multiple threads or processes that access the same hardware or shared data? You might need to add a mutex or semaphore to control access to avoid timing problems.
Heisenbug: This is when the behavior of code changes based on whether or not debug statements are added, or whether the code is optimized or not. There is a nice example here where the optimized code does floating point comparisons in registers in high precision, but when printf's are added, then the values are stored as doubles and compared with less precision. This resulted in the code failing one way, but not the other. Perhaps that will give you some ideas.
Timing Loop gets Optimized Out: Creating a wait function that works by creating a timing loop that increments a local variable in order to add a delay is not good programming style. Such loops can be completely optimized out based on the compiler and optimization settings. In addition, the amount of delay will change if you move to a different processor. Delay functions should work based on CPU ticks or real-time, which will not get optimized out. Have the delay function use the CPU clock, or a real time clock, or call a standard function such as nanosleep() or use a select with a timeout. Note that if you are using a CPU tick, be sure to comment the function well and highlight that the implementation needs to be target specific.
Bottom line: As others have suggested, place the suspect code in a separate file and compile that single source file without optimization. Test it to ensure it works, then migrate half the code back into the original, and retest with half the code optimized and half not, to determine where your bug is. Once you know which half has the Heisenbug, use divide and conquer to repeat the process until you identify the smallest portion of code that fails when optimized.
If you can find the bug at that point, great. Otherwise post that fragment here so we can help debug it. Provide the compiler optmization flags used to cause it to fail when optimized.
You can poke around the GCC documentation. For example:
Function specific option pragmas
#pragma GCC optimize ("string"...)
This pragma allows you to set global optimization options for functions defined later in the source file. One or more strings can be specified. Each function that is defined after this point is as if attribute((optimize("STRING"))) was specified for that function. The parenthesis around the options is optional. See Function Attributes, for more information about the optimize attribute and the attribute syntax.
See also the pragmas for push_options, pop_options and reset_options.
Common function attributes
optimize The optimize attribute is used to specify that a function is to be compiled with different optimization options than specified on the command line. Arguments can either be numbers or strings. Numbers are assumed to be an optimization level. Strings that begin with O are assumed to be an optimization option, while other options are assumed to be used with a -f prefix. You can also use the '#pragma GCC optimize' pragma to set the optimization options that affect more than one function. See Function Specific Option Pragmas, for details about the '#pragma GCC optimize' pragma.
This attribute should be used for debugging purposes only. It is not suitable in production code.
Optimize options
This page lists a lot of optimization options that can be used with the -f option on the command line, and hence with the optimize attribute and/or pragma.
The best thing you can do is to move the code you do not want optimized into a separate source file. Compile that without optimization, and link it against the rest of your code.
With GCC you can also declare a function with __attribute__((optimize("O0")) to inhibit optimization.

How do I "tell" to C compiler that the code shouldn't be optimized out?

Sometimes I need some code to be executed by the CPU exactly as I put it in the source. But any C compiler has it's optimization algorithms so I can expect some tricks. For example:
unsigned char flag=0;
interrupt ADC_ISR(){
ADC_result = ADCH;
flag = 1;
}
void main(){
while(!flag);
echo ADC_result;
}
Some compilers will definitely make while(!flag); loop infinitive as it will suppose flag equals to false (!flag is therefore always true).
Sometimes I can use volatile keyword. And sometimes it can help. But actually in my case (AVR GCC) volatile keyword forces compiler to locate the variable into SRAM instead of registers (which is bad for some reasons). Moreover many articles in the Internet suggesting to use volatile keyword with a big care as the result can become unstable (depending on a compiler, its optimization settings, platform and so on).
So I would definitely prefer to somehow point out the source code instruction and tell to the compiler that this code should be compiled exactly as it is. Like this: volatile while(!flag);
Is there any standard C instruction to do this?
The only standard C way is volatile. If that doesn't happen to do exactly what you want, you'll need to use something specific for your platform.
You should indeed use volatile as answered by David Schwartz. See also this chapter of GCC documentation.
If you use a recent GCC compiler, you could disable optimizations in a single function by using appropriate function specific options pragmas (or some optimize function attribute), for instance
#pragma GCC optimize ("-O0");
before your main. I'm not sure it is a good idea.
Perhaps you want extended asm statements with the volatile keyword.
You have several options:
Compile without optimisations. Unlike some compilers, GCC doesn't optimise by default so unless you tell it to optimise, you should get generated code which looks very similar to your C source. Of course you can choose to optimise some C files and not others, using simple make rules.
Take the compiler out of the equation and write the relevant functions in assembly. Then you can get exactly the generated code you want.
Use volatile, which prevents the compiler from making any assumptions about a certain variable, so for any use of the variable in C the compiler is forced to generate a LOAD or a STORE even if ostensibly unnecessary.

Optimization of #define vs static const (in avr-gcc)

Although I welcome answers on this on a general scope, I'm asking primarily for avr-gcc to make this not too broad.
I have looked at some questions, particularly this and this one. They mostly look at semantic differences, e.g. that a static const can't be used in place of a constant expression. However, although talking about memory allocation in general, they don't speak about optimization.
Let's look at an example:
typedef struct {
GPIO_TypeDef *port;
uint8_t pin;
} gpio_pin_t;
static inline void gpio_pin_set(gpio_pin_t gpio, bool set) {
if(set) GPIO_SetBits (gpio.port, 1 << gpio.pin);
else GPIO_ResetBits(gpio.port, 1 << gpio.pin);
}
//elsewhere including above definitions
static const gpio_pin_t gpio_pin = {GPIOE, 8};
void some_function(bool enable) {
gpio_pin_set(gpio_pin, enable);
}
As you can see, I'm using structs, so the third established way (enum) is not an option here
Can I expect gcc to optimize the gpio.port and gpio.pin accesses in the inline function? If not, why so, and does gcc apply other optimizations when it sees consts?
In its full generality, what do I lose optimization-wise by using static const variables instead of defines, especially looking beyond simple integer constants?
It depends on compiler implementation.
If you never take it's address and the symbol is not exported (for C it is by default, hence you must use static) then the optimizer should kick in and optimize it. For simple types (int, float) you can reasonably expect it to work across the board, but for structs - better check yourself what the compiler does. For a simple struct like your my GCC optimize it, eliminating the struct and passing it's values directly, loading constants to CPU registers. For larger structures it may decide it's not worth it.
You may generate assembly listing of the code to check:
avr-gcc -O<opt> -S somefile.c
or
gcc -O<opt> -S somefile.c
Do not forget about optimization level!
Using #define sucks, because preprocessor is really dumb - it's just replaces code literally before it's compiled. Using const buys you better type safety. Consider this example:
#define BYTE_VALUE 257
static const uint8_t sc_value = 257; // at least will show warning
int my_byte = BYTE_VALUE; // no warning, but obviously it's a bug!
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.

Looking for a macro that can manipulate the compiler's optimization feature

Is there a way to mark a block of code or a function as an excluded part of the compiler's optimization feature?
I have a bug that occur only when the optimization feature is on. I have some guesses about where it might be, and this macro can be a nice help.
I would be VERY worried if I see code that has #pragma GCC optimize "O0" in it. I'd definitely require anyone working with me to make a very clear comment as to why that is necessary, and probably report the compiler bug that is the reason why it's not working with optimization to the compiler vendor.
And if you even thought about submitting something to a kernel mailing list or some such, I'd ensure wearing tripple or quadruple layers of asbestos, because the flames coming your way will be intense.
The right thing to do is figure out a workaround as to why your code isn't compiling correctly with optimisation on. There is probably something wrong with your code if you need this - typically that it relies on "how you think the compiler does something", which doesn't happen when you optimize the code. That's bad coding, and should definitely not be solved by disabling the compilers optimization.
In gcc, you can use the optimize pragma at function level to avoid optimizations.
#pragma GCC optimize "O0" can be applied for a function to prevent optimizations of that function. But I am not sure if there's a way to prevent a block of code being optimized.
So you can have an overall optimization setting for the whole program and this will override that setting with the given optimization for a function using optimize.

Resources