[SOLVED]Conditional Pre-processor

BobTPH

Joined Jun 5, 2013
9,264
One major use of conditionals is when code targets different target processors or different hardware platforms. The conditionals customize the code for each target.
 

Thread Starter

Kittu20

Joined Oct 12, 2022
484
One major use of conditionals is when code targets different target processors or different hardware platforms. The conditionals customize the code for each target.
Can you tell us what do you mean by different target processor and different hardware platform?

As far as I understand if I have written code for Atmel microcontroller then I cannot use same code for Microchip microcontroller. Because the architecture of both is different and the software development tool is also different.
 
Last edited:

djsfantasi

Joined Apr 11, 2010
9,186
As far as I understand if I have written code for Atmel microcontroller then I cannot use same code for Microchip microcontroller. Because the architecture of both is different and the software development tool is also different.
You can use the same code for different microcontrollers. First, some software development tools support different architectures and compile source code depending on the target microcontroller. Secondly, because of conditional pre-processor statements, code that is targeting only one architecture can be mcludex in the source and compiled only when the matching architecture is the target.
 

Thread Starter

Kittu20

Joined Oct 12, 2022
484
You can use the same code for different microcontrollers. First, some software development tools support different architectures and compile source code depending on the target microcontroller.
I'm not sure I fully understood your point. You haven't mentioned any specific microcontroller or software development tools

We can write code for both Arduino Uno and Arduino Mega on Arduino IDE.

By using one software development tool we can write code for different architecture and compiler compiles the code.
 

BobTPH

Joined Jun 5, 2013
9,264
In many applications, much if the code is generic C code that can operate on any microcontroller. Granted, you gave to write it that way in the first place to do this.

So you leave the generic code outside the conditionals. The code specific to the target is written inside conditionals.

That is only one way to achieve sharing code across different targets, and in my opinion, not a good way to do it. I prefer using libraries with the same interface, but different implementations for each target.
 

Papabravo

Joined Feb 24, 2006
21,306
There is another reason. What would you do if two different compilers were involved in processing the same source code?
One answer could involve the use of conditional compilation for some sections of code that treat certain operations differently. Specifically bit operations and addressing.
 

nsaspook

Joined Aug 27, 2009
13,549
I'm not sure I fully understood your point. You haven't mentioned any specific microcontroller or software development tools

We can write code for both Arduino Uno and Arduino Mega on Arduino IDE.

By using one software development tool we can write code for different architecture and compiler compiles the code.
Yes, it's quick way to code hardware differences in the same family of products. The compiler sets a processor define for the selected target processor. In this case it's __32MK0512MCJ048__ or __32MZ1025W104132__ .
C:
int main(void)
{
#ifdef __32MK0512MCJ048__
#ifdef SHOW_LCD
    uint8_t rxe, txe, times = 0;
#endif
    uint8_t alter = 0;
#endif
    bool wait = true, fft_settle = false;
    uint8_t ffti = 0, w = 0;
    uint16_t fft_count = 0;

    /* Initialize all modules */
    SYS_Initialize(NULL);
    
    host_sm();

    /* Start system tick timer */
    CORETIMER_Start();
    delay_freq = CORETIMER_FrequencyGet() / 1000000;
    /*
     * software timers interrupt setup
     * using tickCount
     */
    TMR6_CallbackRegister(timer_ms_tick, 0);
    TMR6_Start(); // software timers counter

#ifdef __32MK0512MCJ048__
    TMR9_Start(); // IMU time-stamp counter
    QEI2_CallbackRegister(qei_index_cb, 0);
    QEI2_Start();
#endif
#ifdef __32MZ1025W104132__
    TMR2_Start(); // IMU time-stamp counter
#endif

#ifdef __32MZ1025W104132__
    cpu_serial_id = USERID & 0x1fffffff; // get CPU device 32-bit serial number and convert that to 29 - bit ID for CAN - FD
#else
    cpu_serial_id = DEVSN0 & 0x1fffffff; // get CPU device 32-bit serial number and convert that to 29 - bit ID for CAN - FD
#endif
    printf("\r\nPIC32 %s Controller %s %s %s %X ---\r\n", IMU_ALIAS, IMU_DRIVER, build_date, build_time, cpu_serial_id);
 

Papabravo

Joined Feb 24, 2006
21,306
sorry but i still don't understand benefits. If you can name the specific compiler and architecture in which you use conditional compilation , it may be great help.
I doubt that the information will be much help, but here it is. For the 8051 processor with a CAN controller (T89C51CC01 & T89C51CC03) from Atmel (now part of Microchip) we used the IAR compiler and the Kiel compiler. Those two compilers treat the addressable bits in the SFR registers with a different syntax making the use of conditional compilation both convenient and straightforward.

IMHO you should forget about conditional compilation until you run across a situation where the benefits are manifestly obvious. Learn to crawl and walk before trying to run a marathon.
 

djsfantasi

Joined Apr 11, 2010
9,186
I'm not sure I fully understood your point. You haven't mentioned any specific microcontroller or software development tools

We can write code for both Arduino Uno and Arduino Mega on Arduino IDE.

By using one software development tool we can write code for different architecture and compiler compiles the code.
My first point is just agreeing with you. I had in mind the Arduino IDE as an example. But in the second case where different code is required for different architectures, it can be maintained in one source code file with the use of conditional directives. Nsaspook and Papabravo have given good examples.
 

MrChips

Joined Oct 2, 2009
31,078
Conditional pre-processor is very handy and I use it all the time.
C:
// declare this in a header file
#def something

// do this in your code or code library
#ifdef something
  // something is chosen

#else
// something not chosen

#endif
It allows you to chose one part of the code over another depending on the user options and environment.
For example, something could refer to a different choice of LCD, or different pin assignments for a specific piece of hardware.
 

WBahn

Joined Mar 31, 2012
30,294
Can you tell us what do you mean by different target processor and different hardware platform?

As far as I understand if I have written code for Atmel microcontroller then I cannot use same code for Microchip microcontroller. Because the architecture of both is different and the software development tool is also different.
But the core logic for the same problem is the same. It's the stuff that is architecture-specific that is different between the two. So put the stuff for Atmel in one file and the stuff for Microchip in another and then use conditional pre-processor directives to select which file gets included. You can also do this at a finer level within the code, but it's generally harder to maintain.

Another common use is to wrap the contents of header files in a conditional that only gets included if a file-specific macro is defined. This prevents including the contents of a file multiple times, which can cause problems.
 

BobTPH

Joined Jun 5, 2013
9,264
I use

#if DEBUG

often for debug code that I don’t normally compile but can turn on when I need it.

#define DEBUG 1

to turn it on.
 

WBahn

Joined Mar 31, 2012
30,294
You don't even need to assign anything to the macro.

You can use

#define DEBUG

and then

#ifdef DEBUG

Of course, assigning it a value has the advantage that you can then assign different levels of debugging.
 

nsaspook

Joined Aug 27, 2009
13,549
Here is a header file example with conditionals for PIC18 or PIC32 compilation for structure binary transfer compatibility.

https://raw.githubusercontent.com/nsaspook/mbmc/new_solar/swm8722/solar18f8722/mbmc.h
C:
#if defined(__18CXX)
typedef struct celltype { // C18 uses byte alignment
#else
typedef struct __attribute__((aligned(1))) celltype
{ // force C32 to byte alignment, 32bit alignment is still critical
#endif

    uint16_t id, model; //      battery cell type S,M,L
    int32_t voltage, current, charge, cycles, noload, date;
    uint8_t cconline, online, discharged, dead, critical, valid, fresh, misc;
    float weight;
}
volatile celltype;

/*        hist[x].h[x]
 *        h0    Peukert Factor adjusted Ah usage this cycle, MUST BE INTERGER variable type!
 *        h1    Lowest discharge ever,
 *        h2    current lowest discharge,
 *        h3    avg discharge
 *        h4    Number of full charge cycles, 
 *        h5    Number of full discharge cycles
 *        h6    Real Ah usage this cycle,     MUST BE INTERGER variable type!
 *        h7    Min Batt Voltage
 *        h8    Max Batt Voltage
 *        h9    Lowest ESR Pre
 *        h10    Lowest ESR Post
 *        h11    Total charge cycles
 *        h12    Total kWH in
 */

#if defined(__18CXX)
typedef struct histtype { // C18 uses byte alignment
#else
typedef struct __attribute__((aligned(1))) histtype
{ // force C32 to byte alignment, 32bit alignment is still critical
#endif

    uint16_t rate, udod, bsoc, bound_rate, bound_factor, samplei, sampleo, ah, drate, esr, rest_rate, rest_factor, esrp;
    int16_t h[HPARAM_SIZE]; // h[6]=cumulative battery Ah cc and inv (real),h[0]=cumulative battery Ah cc and inv (p_adj)
    int32_t kwi, kwo, ttg, btest;
    int32_t ahi, aho, ahir, ahop, thermo; // A stored in battery, A taken from battery, A from raw pv, peukert adjusted A
    int32_t pv_eff, tot_eff; // pv generation eff factor, total system eff factor
    float peukert, cef, peukert_adj, cef_calc, cef_save;
}
volatile histtype;
 

nsaspook

Joined Aug 27, 2009
13,549
Another Pre-processor 'trick' if you're using an IDE like MPLABX. The mplabx IDE sets a #define XPRJ_<config> where <config> is the name (default or another name) of the current controller hardware configuration.

This can be useful as a 'key' if you have the same source code base for several related projects using the same board and processor but you have different controller peripheral(s) modes (blocking, interrupt, dma,etc...) for each separate configuration and different software functionality using Harmony or MCC generating complex code to setup the device.

For example here, the #ifdef XPRJ_nsensor will make the same board a network node with an interrupt driven CANBUS receiver and Ethernet instead of a vibration sensor node with a simple state machine CANBUS transmitter.
1673553971498.png1673554466684.png

You get automatic processor (the same here but it could be two different processors) reconfiguration switching when you change projects with no duplication of project function source code between projects.
 
Last edited:
Top