This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Define global variable

Other Parts Discussed in Thread: MSP430FG4619

Hi,

I have some trouble with the definition of a global variable. I wan't to use them to transfer a value from a interrupt to main main program. I use IAR Embedded Workbench and the MSP430FG4619.

I defined it in this way

source code of main.c
-------------------------------------
#include "constants.h"
  void main(void){
  extern volatile int test[48];
  ...
 
}
 
#include "interrupts.c"
---------------------------------------
 
source code of constants.h
---------------------------------------
volatile int test[48];
....
---------------------------------------
 
source code of interrupts.c
--------------------------------------
extern volatile int test[48];
test[1]=5;......
--------------------------------------
can anyone give me an advise, to find my misstake$=?
thanks Peter
  • You don't say what the problem is. Do you gettin fcompile ror linker errors? Does your program not work?

    Your 'constants.h' file should contain the 'extern' declaration. And one (and only one) of the C files (or maybe a separate 'constants.c') should hold the variable definition (without the 'extern' keyword, but maybe with initialisation values).
    Some compilers won't generate the variable if the compilation unit hold an extern declaration as well as an incomplete definition (without initialisation values), and count the incomplete definition as another (redundant) declaration.

    Another possible pitfall is the combination of pointers with volatile. (an array is a pointer to the first element of the array)
    I'm unsure here whether you defined a volatile pointer to values, which means the pointer itself can change at any time, moving the array location (but not its contents), or whether it is a non-volatile pointer to volatile values (which means the array contents can change at any time, but the array itself can be considered at a stable location unless the compiler sees that the pointer has been changed in the code)
    I'd have to look once more into the C++ language specification to determine where the volatile belongs to.

  • Thanks for your answer.

    I changed my variable from a array of int to int for testing purpose. Futhermore i include in my main.c a global.c with this code: volatile int test=1;

    in my main program and in the interrupt i include a global.h with this code: extern volatile int test; 

    In my Interrupt i change the value like this test=3; but after leaving the interrupt the variable has the value 1 again.

    Linking and compiling didn't produce an error.

    have you an idee whats going wrong?

  • Peter said:

    Hi,

    I have some trouble with the definition of a global variable. I wan't to use them to transfer a value from a interrupt to main main program. I use IAR Embedded Workbench and the MSP430FG4619.

    I defined it in this way

    source code of main.c
    -------------------------------------
    #include "constants.h"
      void main(void){
      extern volatile int test[48];
      ...
     
    }
     
    #include "interrupts.c"
    ---------------------------------------
     
    source code of constants.h
    ---------------------------------------
    volatile int test[48];
    ....
    ---------------------------------------
     
    source code of interrupts.c
    --------------------------------------
    extern volatile int test[48];
    test[1]=5;......
    --------------------------------------
    can anyone give me an advise, to find my misstake$=?
    thanks Peter

    The way you did it, test[48] is not external. It is already defined inside the same module. Thus you should delete the "extern volatile int test[4];" (in two places).

  • Thanks for your answer. unfortunately it doesn't work at all. My code look like this at the moment. the variable test has allways the value 1, only in debuggig mode when i set a breakpoint in the interrupt the value is 3. But after leaving it change back to 1. Has anyone an idea?

    source code of main.c
    -------------------------------------
    #include "global.c"
      void main(void){
       ...
      a = test;
       ...
    }
     
    #include "interrupts.c"
    ---------------------------------------
     
    source code of global.c
    ---------------------------------------
    volatile int test=1;
    ....
    ---------------------------------------
    source code of global.h
    ---------------------------------------
    extern volatile int test;
    ---------------------------------------
     
    source code of interrupts.c
    --------------------------------------
    #include "global.h
    #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCI0RX_ISR(void){
    ....
    test = 3;
    --------------------------------------
  • A moving target! The code in your original post needs to have two lines removed. 1. Remove "extern volatile int test[48];" in main.c 2. Remove "extern volatile int test[48];" in interrupts.c The code in your current post needs to have one line removed. 1. Remove #include "global.h" in interrupts.c Do not add something else or change something else. Do that later.
  • There is a chance that the debugger is fooling you. The 'volatile' keyword is only known during compilation of the source code. It determines the way the compiler will handle this variable when generating code. It does not tell the linker that this variable needs to be reloaded every time.
    Also, a=test; assigns the current value of test to a at the very moment this is executed. Maybe long before the ISR is called. If test changes, a won't change.

    Also, your structure of the code is unusual.

    You include all .c files into main.c. For the compiler, all code is in the same .c file in one piece.

    Normally, you compile each .c file as separate compilation unit and use the .h files to exchange the global definitions. If the .h files haven't changed and the .c files haven't, the compiler does not need to recompile everything if you only changed one part in one of the compilation units.

    Currently, your code looks like this to the compiler:

    source code of main.c
    -------------------------------------
    volatile int test=1;
    ....
      void main(void){
       ...
      a = test;
       ...
    }
    extern volatile int test;
     #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCI0RX_ISR(void){
    ....
    test = 3;
    ...
    }
    ------------------------

    This is what the compiler gets from the precompiler. All in a single file and in a wrong order.
    Having the extern declaration after the definition does not comply with the C standard. You should get a compiler warning, bu tthen, it depends on your compiler and most warnings are disabled by default so they won't disturb the programmer :)

  • Thanks for your answer, i tried to change my sourcecode like you say. Now it look like this:

    source code of main.c
    -------------------------------------
    include "functions.h"

    include "constants.h"

    include "global.c" 

    include "interrupts.c"

     void main(void){
       ...
         ...
    }

    source code of interrupts.c
    -------------------------------------
     #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCI0RX_ISR(void){
    ....
    test = 3;
    ...
    }
    ------------------------

    source code of global.c
    -------------------------------------
    volatile int test=1;
    ------------------------

    source code of functions.c
    -------------------------------------
    include "global.h"

    include "constants.h"

    include "function.h"
    ------------------------

    source code of global.h
    -------------------------------------

    #ifndef GLOBALH

    #define GLOBALH
    extern volatile int test;

    #endif
    ------------------------

    Unfortunately i get this error message now "Entry "" in module functions...redefined in module main" What is incorrect?

  • You misunderstood me.

    All .c files should be independenly compiled.

    You add them to the project, but do not include one .c file into another.

    Each .c file has a corresponding .h file which contains all the declarations (what's in the .c file) but not the definitions (how it's implemented). Into other .c files, you only include the .h files of the other .c files, if you need to tell the compiler that there's something you need.

    It looks like you've done both. Added functions.c to the project (as independent code module) and included it into main.c. This way, the code infunctions.c ha sbeen created twice. Once as an independent binary code block, and once again as part of the main.c code. So it exists twice now.

    Reorder your files as follows:

    main.c includes global.h, constants.h (and functions.h, if needed, but it isn't listed in your post) and holds the main() code.
    interrupts.c includes global.h and (if required) constants.g and/or functions.h and holds the interrupt code
    global.c includes (if at all) global.h and maybe constants.h (if required) and holds the variable definitions.
    functions.c should include functions.h and if required, globals.h and constants.h. And contain any commonly used functions. In your example, there are none, so functions.c and functions.h could be eliminated completely.
    global.h contains the declaration (extern) of test only.
    And interrupts.h, well, interrupts.c contains nothing that other modules need to know, so we don't need one at all.

    It's a good style to encapsulate any .h file with an #ifndef/#def/#endif block as you already did in global.h. It ensures that the header files is only included once, in case of it being included by other header files (maybe because it holds a type declaration that is required in a different header files).

    To make your code above compile and link, it should be enough to not include functions.c and change the include from global.c to global.h.

  • Thanks a lot for your answer. I reordered my files in the way you say. And now  i didn't get an error any more. In the interrupt i set my variable to 1. If  i have a "if" statement in the main function the program will stop there in debugging mode depending on the value of my variable. Thats work so far. But if i set the variable in one interrupt and want to read out the value with an other interrupt it didn't work.

    I also try to change the typ of my variable from a array of int to int with volatile or without.

    But it hasn't an effect on the result.

    i always lose my value.

    both main.c and interrupt.c has include the global.h

    what's going wrong?

     

  • Debugging ISRs with a debugger is a very complicated thing and you often get fooled.
    If you set a breakpoint in main to break inside an IF statement, this does not mean that after the comparison in the IF statement and the execution of the code inside the IF statement, the variable value stays the same. And ISR might have happened and altered the value. Also, if you break inside an ISR, the next IRQs may pile up, so you won't return to your main at once if you continue execution. First all the other ISRs are executed.
    Some people do an action that will trigger an ISR (or enter low power mode) and set a breakpoint at the statement right behind, wondering why there semms to be no effect. No ISR called and breakpoint reached. Fact is that a breakpoint is triggered when the instruction of the breakpoint is fetched. And this happens when the instruction before is being executed. So the breakpoint happens before the previous instruction has finished executing.

    If you don't consider all these (and some more) possible pitfalls, you might end up interpreting the debugger output in a completely wrong way.

    You need to be more detailed what your code is and where you set a breakpoint and what exactly happens.

  • Now i found out something extremely interesting. If i set a breakpoint in in a while(1) loop in the main loop and change the value of a global variable with a interrupt i can read out the value. Thats perfect. How long the breakpoint is in the while loop, he always make the loop. But if i delete the breakpoint the programm leave the while(1) loop.

    But why. To test if it is only a debugging problem i send a command to a screen before i execute the while loop. And a different command when i stay in the loop. When i run the program without debugging (not connected) i always leave the while loop and enter them and so on. Always when i leave the loop i lose my global values.

    Sounds like the watchdog but i shut him down with this command in the main.c

    void main(void)
    {
      WDTCTL = WDTPW+WDTHOLD; 

     ....

    screen_command(1);

    while(1){

        screen_command(2);

    }

        

    is it correct?  It's something wrong with the interrupts? Must i define special jump back points.

    thanks a lot peter

  • Ok, i found the problem. It has nothing to do with the global variables. They where defined well, the Problem was the Timer. There was a misstake in the definition and the lead to a reset of the device. The Timer Interrupt was on a very high value so it was execute after a long time. After the reset all values of all variables where gone.

    Now it works.

  • Oh, yes, the debugger isn't always teh best tool to find bugs. Sometimes (depending on the project rather often) it will cause more problems thanit solves. Therefore I prefer realtime-feedback such as debugging output or just an LED.

    I your case, the debugger has halted everything during inspection, so you only inspected a program period that was a small fraction of a timer interval. (just a few clock cycles until the debugger hit the breakpoint again). And the ISR altering the variable was executed within this interval.  Without debugger, time passed normally and the variable-changing ISR was executed only a few times (or not at all) before the timer interrupt did the reset.

    One thing that's important with teh debugger is that breakpoints are hit when an instruction is fetched. This is different from when it is executed.
    If you enter LPM and set a breakpoint to the next command after, the breakpoint will be hit (the instruction code is fetched) while the previous instruction for entering LPM is executed. So the breakpoint will be hit BEFORE LPM is entered and the ISR meant to exit LPM wasn't executed at all.

    Similar things (not only debugger-related) happen if you clear GIE. It's possible that an ISR kicks in after the instruction behind the GIE set command (DINT) has been executed. Because the command was already fetched and the ISR was in the queue before clearing GIE has become active. Happens often if teh IRQ source was asynchronous (e.g. a port interrupt or a timer clocked by a different clock source than MCLK)

**Attention** This is a public forum