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.

TMS320F28388D: Placing inline functions in RAM (C2000ware 4.02, ARM Toolchain TI v20.02.7LTS)

Part Number: TMS320F28388D
Other Parts Discussed in Thread: C2000WARE

In order to update the firmware of the CM core of an F28388D I need to execute the updating code from memory that is not erased during firmware update.

My update procedure involves getting the data to be flashed from CPU2 via IPC and message RAM. This makes use of functions like IPC_waitForFlag() which are declared inline in ipc.h.

In my linker command file I have the following lines

to place everything that is needed during programming into RAM.

Eventually, I managed to make the whole procedure work using the following optimization settings:

Using this option, the inline function is properly inlined and everything is executed from RAM:

but during debugging with

 I observed, that the IPC_waitForFlag() jumped into Flash (which was erased already):

Now the question: How do I make those inlined functions be placed in RAM even when optimization is turned off?

Best regards

Johannes

  • Hi,

     I observed, that the IPC_waitForFlag() jumped into Flash (which was erased already):

    Since you are coping the entire code into RAM from flash, this should not matter with optimization on or off unless this function is never copied into RAM. If this function is not part of the two libraries you are copying into RAM then you need to explicitly mention this also in linker cmd file to get copied into RAM.

    Regards,

    Vivek Singh

  • Hi Vivek Singh,

    after inserting

    #pragma CODE_SECTION(IPC_ackFlagRtoL, ".TI.ramfunc")
    #pragma CODE_SECTION(IPC_waitForFlag, ".TI.ramfunc")
    #pragma CODE_SECTION(IPC_isFlagBusyRtoL, ".TI.ramfunc")
    #pragma CODE_SECTION(GPIO_writePin, ".TI.ramfunc")
    #pragma CODE_SECTION(GPIO_isPinValid, ".TI.ramfunc")
    #pragma CODE_SECTION(Flash_releasePumpSemaphore, ".TI.ramfunc")
    #pragma CODE_SECTION(Flash_claimPumpSemaphore, ".TI.ramfunc")

    my code also worked with optimization turned off.

    I find this requirement very counterintuitive!

    From my perspective those functions are part of driverlib (or the flash API) and the toolchain should place them into RAM when I request those libraries to be placed in RAM using the linker command file.

    Best regards

    Johannes

  • those functions are part of driverlib (or the flash API) and the toolchain should place them into RAM when I request those libraries to be placed in RAM using the linker command file

    I agree.  I am focused on a smaller part of the overall problem.  I am confident that solving this part will solve the rest.

    The first screenshot in your first post shows a few lines from your linker command file.  It creates the output section .TI.ramfunc.  For all of the object files that are brought in from the library F2838x_CM_FlashAPI.lib, the .text input sections should be part of .TI.ramfunc.  But that's not what happens.  Instead, the .text input sections from the object files brought in from the library F2838x_CM_FlashAPI.lib are part of some other output section.  (That other output section is probably .text, but that's not directly part of the problem.)  Why?

    I tried to reproduce this problem on a small scale.  But I cannot. 

    Please add the option --emit_references=link_references to your CCS project.  A screen shot is below.  Build the project again.  That causes the linker to create a report that shows, among other things, how sections reference one another.  It is contained in the file named link_references.txt in the directory named after the current build configuration, often Debug.  Put that file, along with the linker map file, in a zip and attach that zip to your next post.

    Thanks and regards,

    -George

  • Hi George,

    thank you for your response. I am attaching the linker output files (generated with and without optimization) link_references.zip

    I do not really understand all the details of the map file (generated with optimization turned off) but the following lines (related to inline functions) look a bit suspicious:

                      00207af4    00000008     fw_update_cm.obj (.tramp.IPC_waitForFlag.1)
                      00207afc    00000008     fw_update_cm.obj (.tramp.IPC_ackFlagRtoL.1)

    Best regards

    Johannes

  • Hi Johannes,

    Right -- it looks like the linker is creating far call trampolines for IPC_waitForFlag in the unoptimized case, and indeed according to the map file, it looks like IPC_waitForFlag is not included in .TI.ramfunc but is in the standard .text output section, which is itself being split (presumably in FLASH, based on what you've said).  I suspect this is why using the explicit CODE_SECTION pragma for IPC_waitForFlag works since it forces the placement explicitly.

    From what the map file indicates, it appears that these objects are not part of the driverlib_cm.lib library you've created.  Can you clarify the library structure, and also try including the .text sections from these object files specifically as part of your .TI.ramfunc output section definition in your linker command file?

    -Alan

  • Hi Alan,

    For my project I did not create driverlib_cm.lib, I just copied the one from C2000ware 4.02 into the project.

    I don't understand what you mean by "clarify the library structure".

    Please find attached an example project (based on led_ex1_blinky example from C2000ware 4.02). inline_function_placement_problem.zip

    My modifications are the following:

    The build configurations were changed from RAM to FLASH.

    driverlib_cm.lib was placed into RAM using

    I have added a function foo() to the CM part of the project that demonstrates the problem:

    GPIO_writePin() is placed in FLASH while the non-inlined function IPC_readCommand() is correctly placed in RAM.

    I hope this helps to further investigate the problem.

    Best regards

    Johannes

  • Hi Johannes,

    I asked you to clarify the content of driverlib_cm.lib because in the non-optimized version of your project, there appear to be calls into functions in other object files that are being placed in ROM.  For example, IPC_waitForFlag appears to be defined in ethernet_cm.obj, which is not a part of driverlib_cm.lib (correct me if I'm wrong) yet it is being called by something being placed in .TI.ramfunc (and run from RAM).  This is backed up from the link_references.txt that you sent, which shows that IPC_waitForFlag is being called from fw_copy_from_CPU2(), which is being placed in .TI.ramfunc (and run from RAM):

    Section .text:IPC_waitForFlag:fw_update_cm.obj:

    Section size: 40

    No symbols defined

    Input references:
    Section from symbol to symbol at offset
    ------- ----------- --------- ---------
    .TI.ramfunc:fw_copy_from_CPU2:fw_update_cm.obj fw_copy_from_CPU2 IPC_waitForFlag 40  

    To your point above that "From my perspective those functions are part of driverlib (or the flash API) and the toolchain should place them into RAM when I request those libraries to be placed in RAM using the linker command file", my suggestion was to ensure that the definitions of referenced functions are also included in .TI.ramfunc using the linker command file placement.  What happens if you include ethernet_cm.obj and fw_update_cm.obj as part of this?

    .TI.ramfunc : {
        -l F2838x_CM_FlashAPI.lib(.text)
        -l driverlib_cm.lib(.text,.const)
        ethernet_cm.obj(.text)
        fw_update_cm.obj(.text)
    } LOAD = CMBANK0_SECTOR0 | CMBANK0_SECTOR1, ...

    Otherwise you will end up with far call trampolines back into FLASH, which it sounds like is the root of your problem.

    Note that there are other functions from ethernet_cm.obj and fw_update_cm.obj being placed in .TI.ramfunc, but this is because the C section pragma was used to place them there.

    -Alan

  • Hi Alan,

    I guess, something like the following happens:

    As those functions (IPC_waitForFlag, IPC_ackFlagRtoL, ...) are declared static inline they are not part of driverlib_cm.lib but their compiled version is included into every object file the C source of which makes use of them (by including the header they are defined in).

    As long as optimization is turned on, they are inlined and as long as the function that uses them is placed in RAM the inlined stuff is also placed there.

    When optimization is turned off, the compiler will not inline them but rather create callable functions and put them into every object file that needs them.

    Finally, the linker chooses one of them to put in the out file. (But which one?)

    That's just an educated guess... I'm not a compiler expert!

    My problem is, that this behaviour is pretty unexpected: I use driverlib functions, I put driverlib's .text section into RAM but I also need to put the .text section of some other object file of my project into RAM in order to get certain driverlib functions (the static inline ones) placed into RAM. That's counter-intuitive!

    Furthermore, I can't control which of the "other object files" eventually will contain those functions. At least, I do not yet know how to do that!

    Best regards,

    Johannes

  • You incorrectly presume a static inline function always inherits the section of the caller.  Your description starts off mostly right ...

    As those functions (IPC_waitForFlag, IPC_ackFlagRtoL, ...) are declared static inline they are not part of driverlib_cm.lib but their compiled version is included into every object file the C source of which makes use of them (by including the header they are defined in).

    As long as optimization is turned on, they are inlined and as long as the function that uses them is placed in RAM the inlined stuff is also placed there.

    When optimization is turned off, the compiler will not inline them but rather create callable functions and put them into every object file that needs them.

    That's correct, until the last part of the final sentence.  Callable functions are created in every file that includes the header file with the static inline functions defined in it.  Just pretend the inline part of the static inline function is ignored.  The section these static functions are placed in is determined not by the caller, but by the default settings of the compiler for any static function.  

    this behaviour is pretty unexpected

    I understand why you think it through like that.  However, that's just not how it works.

    I have a solution to propose.  Apply the compiler build option --ramfunc=on not to the entire project, but to the C files that include the header files with the static inline functions.  Do it using the CCS feature for file specific options.  A screen shot is below.  It shows applying the option to the file led_ex1_c28x_cm_blinky_cm.c from the small example project you sent. 

    Thanks and regards,

    -George  

  • Hi George,

    thank you for taking the time explaining and trying to find a solution.

    I tried what you proposed: "Apply the compiler build option --ramfunc=on not to the entire project, but to the C files that include the header files with the static inline functions." This means that this option has to be applied to every file that includes driverlib_cm.h! In my case this also included the file with main(). This didn't work, since the code that copies the .TI.ramfunc code from FLASH to RAM  (at the beginning of main()) has to be executed from FLASH.

    So,  I applied the --ramfunc=on option only to the file that contains the firmware update stuff and it seems to work now even with optimization turned off. I will mark the issue as resolved even though I'm not entirely satisfied with the solution.

    Best regards,

    Johannes