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.

Problem to inline functions on Piccolo CCSv5



I am working on a PSU consistiong of 2 Phase PFC followed by a quasi resonant full bridge

My main interupt handler is below

#pragma CODE_SECTION(OnlyInterrupt, "ramfuncs")
interrupt void OnlyInterrupt(void){
    static int instance = 0;

    GPIO_set(GPIO_18);
    HandleADC();
    PCMCPSB_PeakCurrentModeControl();
    switch (instance){
    case 0:
    case 2:
        PCMCPSB_VoltageLoop();
        break;

    case 1:
    case 3:
        PFC_CurrentLoop();
        if (instance == 1){
            PFC_VoltageLoop();
        }else{
            PFC_InputConditioning();
        };
    }
    if (++instance > 3) instance = 0;
    GPIO_clr(GPIO_18);
}

Each of the functions called by this handler are declared inline for example

inline void PFC_InputConditioning(void){

   ...

}

yet when I trace the compiled code these the function is not being expanded inline.  The function contains a mix of C and inline assembly.  When I check the optimization level for the compiler  its set to 3.   Also as a result of the functions not being inline they are in slow FLASH not the faster RAM

What am I doing wrong?

Since each of these functions are only called once I could just get rid of the separate functions and just  put it all in one big function but I would prefer not to do that because I usually try to keep my functions small so they are easier to understand and tell the compiler to inline any functions that are only called once or are small enough not to worry about.

Any help would be appreciated

  • You may be running into the compiler's internal size limit.  The "inline" keyword is only advisory, and if the function being inlined is too large or the resulting caller will be too large, the compiler will choose not to inline.  "Too large" in this case is a size that will tend to cause trouble for the compiler itself.

    You can raise that limit somewhat by using the --opt_for_speed option instead of --opt_for_space, if that is feasible.

    You can raise the limit specifically for functions that are called only once with the --single_inline option.

    You can force a function to be inlined every place it is called with the FUNC_ALWAYS_INLINE pragma, which will turn off the size limit entirely for the function named.  Use at your own risk.

  • FUNC_ALWAYS_INLINE looks like a possible solution.

    I can't find any information on this pragma however.  Can you give me a link to ether an example or the documentation so I can get the syntax correct.

  • It should be in section 6.10 with the other pragmas, but isn't.  It is present in the equivalent section, 6.9, in the C6000 compiler guide, SPRU187.  The text there says:

    The FUNC_ALWAYS_INLINE pragma instructs the compiler to always inline the named function. The
    compiler only inlines the function if it is legal to inline the function and the compiler is invoked with any
    level of optimization (--opt_level=0).


    The pragma must appear before any declaration or reference to the function that you want to inline. In C,
    the argument func is the name of the function that will be inlined. In C++, the pragma applies to the next
    function declared.


    The syntax of the pragma in C is:
     #pragma FUNC_ALWAYS_INLINE ( func );
    The syntax of the pragma in C++ is:
     #pragma FUNC_ALWAYS_INLINE;


                 Use Caution with the FUNC_ALWAYS_INLINE Pragma
        NOTE: The FUNC_ALWAYS_INLINE pragma overrides the compiler's inlining decisions. Overuse
                 of the pragma could result in increased compilation times or memory usage, potentially
                 enough to consume all available memory and result in compilation tool failures.

  • This does not appear to be working.  Have I possibly got one or more of the compile options set incorrectly?  I did a clean build of my project and the log from the console window is below.  Some of the functions appear to be inlined but not all and it appears to be the larger functions that are not.

    Are you sure that

    #pragma FUNC_ALWAYS_INLINE (func)

    Where func is the name of the function to inline works with the C2000 compiler?  It is not documented  but does compile without any warnings or errors.

    **** Build of configuration FLASH for project QPX750 ****

    C:\TI\ccsv5\utils\bin\gmake -k all
    'Building file: ../source/BG_Task.c'
    'Invoking: C2000 Compiler'
    "C:/TI/ccsv5/tools/compiler/c2000/bin/cl2000" -v28 -mt -ml -g -O0 --include_path="C:/TI/ccsv5/tools/compiler/c2000/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/csl" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/F2802x_headers" --diag_warning=225 --display_error_number --preproc_with_compile --preproc_dependency="source/BG_Task.pp" --obj_directory="source"  "../source/BG_Task.c"
    'Finished building: ../source/BG_Task.c'
    ' '
    'Building file: ../source/ComsTask.c'
    'Invoking: C2000 Compiler'
    "C:/TI/ccsv5/tools/compiler/c2000/bin/cl2000" -v28 -mt -ml -g -O0 --include_path="C:/TI/ccsv5/tools/compiler/c2000/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/csl" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/F2802x_headers" --diag_warning=225 --display_error_number --preproc_with_compile --preproc_dependency="source/ComsTask.pp" --obj_directory="source"  "../source/ComsTask.c"
    'Finished building: ../source/ComsTask.c'
    ' '
    'Building file: ../source/Interrupt.c'
    'Invoking: C2000 Compiler'
    "C:/TI/ccsv5/tools/compiler/c2000/bin/cl2000" -v28 -mt -ml -g -O0 --include_path="C:/TI/ccsv5/tools/compiler/c2000/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/csl" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/F2802x_headers" --diag_warning=225 --display_error_number --preproc_with_compile --preproc_dependency="source/Interrupt.pp" --obj_directory="source"  "../source/Interrupt.c"
    'Finished building: ../source/Interrupt.c'
    ' '
    'Building file: ../source/PFC_Task.c'
    'Invoking: C2000 Compiler'
    "C:/TI/ccsv5/tools/compiler/c2000/bin/cl2000" -v28 -mt -ml -g -O0 --include_path="C:/TI/ccsv5/tools/compiler/c2000/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/csl" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/F2802x_headers" --diag_warning=225 --display_error_number --preproc_with_compile --preproc_dependency="source/PFC_Task.pp" --obj_directory="source"  "../source/PFC_Task.c"
    'Finished building: ../source/PFC_Task.c'
    ' '
    'Building file: ../source/PSB_Task.c'
    'Invoking: C2000 Compiler'
    "C:/TI/ccsv5/tools/compiler/c2000/bin/cl2000" -v28 -mt -ml -g -O0 --include_path="C:/TI/ccsv5/tools/compiler/c2000/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/csl" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/F2802x_headers" --diag_warning=225 --display_error_number --preproc_with_compile --preproc_dependency="source/PSB_Task.pp" --obj_directory="source"  "../source/PSB_Task.c"
    'Finished building: ../source/PSB_Task.c'
    ' '
    'Building file: ../source/main.c'
    'Invoking: C2000 Compiler'
    "C:/TI/ccsv5/tools/compiler/c2000/bin/cl2000" -v28 -mt -ml -g -O0 --include_path="C:/TI/ccsv5/tools/compiler/c2000/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/csl" --include_path="C:/Documents and Settings/Warren/My Documents/CCSv5/QPX750/include/F2802x_headers" --diag_warning=225 --display_error_number --preproc_with_compile --preproc_dependency="source/main.pp" --obj_directory="source"  "../source/main.c"
    'Finished building: ../source/main.c'
    ' '
    'Building target: QPX750.out'
    'Invoking: C2000 Linker'
    "C:/TI/ccsv5/tools/compiler/c2000/bin/cl2000" -v28 -mt -ml -g -O0 --diag_warning=225 --display_error_number -z -m"QPX750.map" --stack_size=0x300 --warn_sections -i"C:/TI/ccsv5/tools/compiler/c2000/lib" -i"C:/TI/ccsv5/tools/compiler/c2000/include" --reread_libs --rom_model -o "QPX750.out"  "./source/main.obj" "./source/PSB_Task.obj" "./source/PFC_Task.obj" "./source/Interrupt.obj" "./source/ComsTask.obj" "./source/BG_Task.obj" -l"libc.a" "../source/IQmath.lib" "../source/SFO_TI_Build_V6b.lib" "../source/csl2802x_ml.lib" "../DSP2802x_Headers_nonBIOS.cmd" "../csl_28027.cmd"
    <Linking>
    'Finished building target: QPX750.out'
    ' '

    **** Build Finished ****

  • Are the functions you are trying to inline defined in the same file as where they are called?  Inlining happens during compilation, not during linking, so the compiler must be able to see the body of the called function if it is to insert it at the site of the call.  It's also possible (I'm not immediately sure) that if you use -O0, the definitions must be earlier in the file than the calls;  I'm pretty sure that's not required with -O2 and -O3.

    Is inlining really important?  You're saving only a few cycles by avoiding the calls, while you're potentially missing out on much larger improvements by using -O0 instead of -O2 and by not using --opt_for_speed.

  • Thanks for your help.

    Yes the functions are all in the same file and appear before they are used.

    Yesterday I managed to get enough improvement in interrupt timing by declaring each of of the functions called to be in ram with for example

    #pragma CODE_SECTION(PFC_CurrentLoop, "ramfuncs")
    #pragma FUNC_ALWAYS_INLINE(PFC_CurrentLoop);
    inline void PFC_CurrentLoop(void){
       ...
    }

    This still did not get the functions to be inline however it did  reduce the time spent in the interrupt significantly.  I now think that even without the function being inline performance will be acceptable.  Previously the interrupt was taking so long that by the time it had finished the next interrupt had already fired.

    I have now added --optforspeed=5 and -O2

    I think everything is now being compiled inline.  The interrupt is slightly faster but I think the main bottle neck was not the cycles lost to calls but the fact that the functions called were being put in Flash not RAM

    For example my  PFC_InputConditioning() function was filtering the measured AC input using a two pole, two zero filter, working the inverse square of the filtered result and then multiplying the result by the instantaneous measured AC input.  Most of this is written as inline assembly for speed but its still about 100 words of machine code

    Running from RAM seems to be about 40% faster than FLASH

    Thanks for your help.   I now spend 60% of my time servicing the interrupt and can continue with this project as things stood previously I could not process the interrupt each cycle.