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.

Does the pointer operation for PxOUT work correctly?

I would like to make sure whether the following code works correctly or not.

-----

static void setOUT(unsigned char *pPOUT) {
    *pPOUT |= BIT0;
}

void testFunc(void)
{
    unsigned char *pPOUT = 0;
    char cond;

    cond = 1; // for test

    switch(cond) {
    case 1:
        pPOUT = (unsigned char *)&P1OUT;
        break;
    case 2:
        pPOUT = (unsigned char *)&P2OUT;
        break;
    }
    if (pPOUT != 0) {
        setOUT(pPOUT);
    }
}

-----

By now, I have never tried to use pointer for PxOUT (*pPOUT). I have directly set the port such as

P2OUT |= BIT0;

P3OUT |= BIT5;

However, when I need to consider a code, which will be commonly used in different MSP430, I need to use the pointer.

So that's the reason why I would like to know the correct way.

  • It looks correct to me. But I do not understand why it is needed.

  • >But I do not understand why it is needed.

    I am thinking about serial (UART) communication using GPIO. This is to increase number of UART port in addition to the prepared UARTs. 

    In some MSP430 type, I may use P2OUT for the GPIO-UART process, and in other MSP430, I would like to use P8OUT. I would like to use common .c and  .h files for both of them using the pointer. 

    If there is other better approach, I would take that.

  • OKY said:
    I would like to make sure whether the following code works correctly or not.

    I guess it coincidentally will.

    Your pPOUT pointer points to an unsigned char. However, the original PxOUT register was a volatile unsigned char 'variable'. Since the setOUT function is short and immediately returns after performing the write, it will probably work as intended, as long as it isn't inlined by the compiler (because it is short).

    OKY said:
    However, when I need to consider a code, which will be commonly used in different MSP430, I need to use the pointer.

    Most projects use a project-specific definition header file. With project-specific defines:

    #define LEDPORT_OUT P1OUT

    The code then uses LEDPORT_OUT instead of the specific P1OUT.

    This won't work for precompiled libraries, but leads to way more efficient code.

  • static void setOUT(unsigned char *pPOUT) {
        *pPOUT |= BIT0;
    }

    Can someone tell me what the word 'static' does when used with a function?

  • Thank you very much for you reply, Jens-Michael.

    As you suggest, I will use 

    #define LEDPORT_OUT P1OUT

    instead of the function.

    I appreciate it.

  • Hello, Joseph.

    When the "static" is used for the function, this means that the function can be used only in the .c file.

    For example, you have 

    - FileControl.c

    - IOControl.c

    - SPIControl.c

    But, when you define

    static void setOUT(...) at IOControl.c, other two files (FileControl.c and SPIControl.c) cannot use the setOUT() function.

    If my understanding is right, the "static" is utilized when you would like to reduce "name conflict" among various .c files.

    In my style, unless the function is used in other .c files, I make the function as "static" in the first place. Then, if the function will be used in other .c file, I remove the static, and adding function prototype at .h file sharing the .h file between .c files which uses the function.

     

  • OKY

       Thank you for that clear explanation.

  • OKY said:
    If my understanding is right, the "static" is utilized when you would like to reduce "name conflict" among various .c files.

    More or less.

    Ironically, the meaning of 'static' isn't static at all :)

    Static is one of four storage types: extern, static, auto, register. For variables inside a function, auto is the default. For objects on top level, the default is extern. Extern objects are static too, but static objects aren't extern.
    So usage of 'static' is required to not use the default 'extern' - to not make an object globally visible rather than to make it not globally visible. Which has, of course, the very same effect :)

    Inside class definitions, however, a static function is a function the doesn't make use of instance variables and non-static member functions. It may be called on the class itself, rather than on a class instance. Whether it is globally available or not is determined by the public/private/internal keywords.
    Static variables inside a class are shared for all instances and also can be called in the class itself.

  • Thank you very much for you explanation, Jens-Michael.

    People may be confused with the 'static' keyword in 

    - static function used in a file (like a function in IOControl.c in the C languate)

    - static function in the class (in the C++ language)

    - static variable inside a function

    I do not still get used to the "static function in the class". I am on my way studying C++ language recently.

  • OKY said:
    I do not still get used to the "static function in the class". I am on my way studying C++ language recently.

    Static member functions can be used for different purposes. In singleton classes (non-instantiatable classes). Or as factory functions that instantiate a specific subclass rather than the class itself, based on function parameters. Or as replacement for a private constructor for managed classes. E.g. a class where every occurrence of the same creation parameters results in the same instance of the class, so one can compare the object pointer for checking identity. (and don't have - probably large - duplicate objects)

  • Thank you very much for the examples of using the static function in the class.

    My knowledge about design patterns was still limited. Your reply will strengthen my knowledge on them.

  • Jens-Michael Gross said:

     Extern objects are static too,....

    Thanks as always for your explanation. Could you elaborate a bit on your quote above.

    If 'extern' implies globally visible, and 'static' implies not globally visible, what do you mean when you say extern objects are static too?

  • Joseph Raslavsky said:
    If 'extern' implies globally visible, and 'static' implies not globally visible, what do you mean when you say extern objects are static too?

    Not exactly. Static doesn't imply "not being globally visible". It just does not imply "being globally visible". :)

    But actually, I wasn't precise enough with 'extern'.

    Declaring an object as extern, only tells the compiler that 'somewhere, but not necessarily here, there is a static object'. Based on an extern declaration, neither compiler nor linker will actually create the variable. You cannot define a variable as extern.

    To actually create the variable, the variable definition must not include the extern keyword. And to make it known to the linker, it must not contain the static keyword either.

    For convenience, a variable that has been declared with no keyword (outside a function, of course) will be implicitly created by the linker, if none of the compilation units contains a definition.

    The 'correct' way would be:

    unit1.h: 'extern int test;'
    unit1.c: '#include "unit1.h" '
                'int test = 0;
    unit2.c: '#include "unit1.h" '

    However, for variables that do not need to be initialized, or have to be initialized with 0 (except for CCS' old COFF format which didn't initialize uninitialized variables to 0), the following is normally used:

    unit1.h: 'int test;'
    unit1.c: '#include "unit1.h" '
    unit2.c: '#include "unit1.h" '

    The compiler will create a 'create this variable as needed' entry for the linker, and the linker will detect that neither uni1 nor unit2 actually define the variable, so it will be auto-created.

    I remember the old Borland C++compiler which complained if an extern declaration and a a definition were present in the same compilation unit. Which makes sense but isn't convenient.

    However, the second, convenient approach contains a certain risk: if two compilation units declare a variable that is externally visible and accidentally has the same name, the linker will join the two, with devastating results, assuming they are the same. The first approach will prevent this, as both units will actually define the variable and the linker will complain about a double-definition.

    Well, nobody ever said that C/C++ is a fool-proof language. It is, however, a convenient and efficient one, if you knwo what you're doing.

**Attention** This is a public forum