Electronic – Why we use #pragma configs in PIC controllers

pic

Hi all I am new to the programming of PIC MCUs and I have with me PIC32 MCU. I have done a UART program in it and its working fine. I got the code for UART from Microchips website and its easily understandable. But I am confused with #pragma configs, I mean why this config bits are used. I did a little bit of google searching and found that all the #pragma configs can be found in c\program files\microchip\mplabc32\doc but I really don't know why we use it. Now lets say if I have to do a I2C communication then how would I know that which #pragma configs I need to include? I didn't find a good explanation for it on google. Can any PIC experts explain about it. Thanks.

#pragma config FNOSC = PRIPLL       //Primary Osc w/PLL (XT+,HS+,EC+PLL)
#pragma config POSCMOD = HS         //HS osc mode 
#pragma config FPLLMUL = MUL_18     //PLL Multiplier 18x Multiplier 
#pragma config FPLLIDIV = DIV_2     //PLL Input Divider 2x Divider 
#pragma config FPBDIV = DIV_1       //Peripheral Clock Divisor: Pb_Clk is Sys_Clk/2
#pragma config FPLLODIV = DIV_1     //System PLL Output Clock Divider: PLL Divide by 1

Best Answer

These #pragma configs configure settings which live in their own section of flash memory that is outside of your program code. They are available as soon as the PIC gets power, regardless where they are written in your code. This is important because sometimes they are needed before your program is executed.

For example, there are settings to select a clock source and convert it to the actual clock of your PIC. This can't be done in your program code because the clock must correctly configured before your code can run.

Another example is the code protection setting. If this is enabled, it is not possible to read the program memory of the PIC with a programmer. This discourages others from copying program memory and reverse-engineering your code. This can't be done with program code because it's possible put your PIC into programming mode before any of you program code executes, bypassing anything that enables code protection. In this way #pragma configs are essential because they allow configurations to be set before your code executes.

Not all settings set by #pragma configs are needed before your code executes. Some are just conveniences. For example, it is possible to use #pragma configs to set pins as digital I/O or analog input on startup. This could just as easily be done in your program code.

So why are these settings set with #pragma configs? Aren't they still C-code? They are, but they're special. They're a compiler directive. (Compiler directives start with a #.) Compiler directives are some of the first things that your compiler handles. You know #include foo, which instructs the compiler to paste the file foo right here? The compiler interprets all the #pragma configs at the same time - before it even looks at your other C code. This gives the compiler a chance to ensure that your #pragma configs will be written to the appropriate locations, separate from your program code.


About how to know what configs have to be set:

As now you know such configs exist, read through the list of configs, so you you get an idea what they are for. You don't need to know them by hard, you just need to know that a task you're working on may be affected by them.


EDIT: Explanation of your configs

The configs you list in your question are entirely clock-related. To understand, you have to understand how clock generation and distribution works. Have a look at page 3 of this document which shows a graph about it.

#pragma config FNOSC = PRIPLL       //Primary Osc w/PLL (XT+,HS+,EC+PLL)

This selects the primary oscillator as source of the clock, and the PLL will be used to further convert the clock. You may also have choosen NOT to use the PLL. Or another source like the secondary oscillator, an internal oscillator etc.

#pragma config POSCMOD = HS         //HS osc mode

Here, you select what's connected to the primary oscillator pins. usually, you can connect the clean signal of an oscillator module (EC), or you connect a crystal resonator below 4MHz (XT) or above (HS). Note that resonators need some additional circuit, which is provided (and selected) by this settings.

#pragma config FPLLIDIV = DIV_2     //PLL Input Divider 2x Divider 
#pragma config FPLLMUL = MUL_18     //PLL Multiplier 18x Multiplier 

Now, you have your initial clock, but usually, you want the PIC to run with a different frequency. The PLL allows to multiply your clock frequency by a certain factor, but it accepts only a limited input frequency (4-5MHz in this document). So, you divide the frequency by 2 before passing it to the PLL (so you have a 8-10MHz crystal?) and let the PLL multiply the frequency by 18 (resulting in 4Mhz*18=72Mhz?).

#pragma config FPLLODIV = DIV_1     //System PLL Output Clock Divider: PLL 

Divide by 1

The output frequency of the PLL can be divided again to get lower or intermediate frequencies. But here, you don't divide it (=divide it by 1).

So, you get the final frequency your PIC runs with. This all looks a bit weird, but it allows lots of input options and system frequencies.

The final frequency is used as system clock.

This all looks a bit weird, but it all allows to run the PIC at many different frequencies.

#pragma config FPBDIV = DIV_1       //Peripheral Clock Divisor: Pb_Clk is Sys_Clk/2

The system clock is divided once more to obtain the clock frequency of the peripherals like I²C / UART / ...
I don't know why the comment says division by 2 while the code says division by 1...

My datasheet also shows a reference clock with SPI, but it also notes that not all PICs have this feature.

Finally, have a look into the oscillator section of your actual PIC about which settings are available.