I'm working on a C project for a Raspberry Pico microcontroller. I've installed the "Pico SDK" on a Raspberry Pi 5 (a "complete" Debian Linux system), and it's working well. One of the Example programs included in the SDK is a small application called bus_scan (source code here) - it scans an I2C bus to see which addresses respond to a read request, and prints a summary of the results.
The problem/question I have is WRT the following section of the code - which is included in main():
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c/bus_scan example requires a board with I2C pins
puts("Default I2C pins were not defined");
#else
// This example will use I2C0 on the default SDA and SCL pins (GP4, GP5 on a Pico)
i2c_init(i2c_default, 100 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
I'm under the impression that preprocessor directives can go anywhere in a program. However, I didn't like this being in main(), and so I moved it just below the #includes. When I re-compiled, many errors were generated.
I don't understand this type of code... some of the statements under the "preprocessor directive" look like function calls (perhaps to functions defined in the header files??).
Here's what I tried:
- removed the "preprocessor directives"
- placed all the "function calls" inside
main()
The re-compilation was successful, but this leaves me with a question:
What is the point of mixing preprocessor directives with function calls? Given this is an Example program (i.e. learning), what coding technique is being taught? This is a serious question - not trying to hold anyone up as a bad example or anything - but I'd really like to know if this is a technique I should be trying to learn.
#if !defined ...and#warningetc are preprocessor directives. The things below them is not, that's plain C code, function calls indeed, and as such it belongs inside a function and not on the top of main().The
#if defined/#ifndefetc patterns is sometimes called a "compiler switch" (kind of confusing term), meaning that "if something, use this code, otherwise use this other code" - evaluated at compile time. You can't move such things to arbitrary locations, nor can you just remove them at a whim.#include,#define,#ifetc is quite basic stuff and you really ought to study what they do before anything else.As for what this code does: it checks if you have used one several "board support" default projects and then makes assumptions of whether the I2C pins are routed to connectors or not. If there is I2C support on the board, it initializes the I2C hardware peripheral and sets up pin routing and pull resistors accordingly.
I would probably recommend to not use pre-made libs but to hack the I2C drivers yourself by hand. It will take much longer but by doing so, you will actually learn how things work.