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.

PRU-CGT: C Compiler for PRU does not initialize stack pointer.

Part Number: PRU-CGT
Other Parts Discussed in Thread: SYSCONFIG, TMDSCNCD263P

Tool/software:

I have a small project which uses an R5 core to initialize a PRU core.  The code that generated for the PRU core is created from a CCS project written in c-code. When this generated code is sent to the PRU from the R5, it does not run properly. The issue preventing proper operation is that the code generated for the PRU never initializes the stack pointer held at R2. 

Dependancies:

  • ti-cgt-pru_2.3.3
  • ti-cgt-armllvm_4.0.0.LTS
  • mcu_plus_sdk_am263px_10_01_00_31
  • sysconfig_1.22.0
  • TMDSCNCD263P - Sitara AM263Px Control Card

Basic build flow: The system level project (includes both the R5 and PRU core) can be built from the attached project files. The PRU core is built first, and it creates a header file from the c code which contains the hex version of the build artifacts. An assembly file is also saved for reference. The created header file is included (as part of the project configuration) in the the R5 build. When the R5 core runs, it initializes the PRU core and then transfers the instructions that were included from the header file.

It is not required to be able to debug the program, although debugging configurations and instructions are included in the files on how to replicate the problem on hardware. What can be seen is that the main.asm file created by the build of the PRU core has no instructions to initialize the value of the stack pointer, which should be held in R2. The first instructions generated are to decrement the stack pointer (standard operation when entering the main function).

Please note that I have 2 other E2E posts regarding this with the current remedy being to add an inline assembly command at the start of the main loop to force R2 to a correct value. This is a fragile and temporary workaround. The generated code should be initializing the value of R2 prior to entering the main function, but that is not happening.

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1493084/am263p4-pru-stack-pointer-initialization-when-using-c-code

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1466734/am263p4-pru-register-init-when-compiling-from-c-code

System_Project.zip

  • Can someone from TI please respond to this?

  • Hi Nathan,

    Apologies for such delayed response. It needed  some additional before we could come back on this.

    I had followed up with our compiler team on this- 

    Please search the PRU compiler manual for the sub-chapter titled System Initialization.  It explains how startup code in the RTS library supplied with the compiler initializes the SP.  Note that it happens before main starts.  The most likely explanation is that, when integration into a larger SOC build occurs, this startup code is somehow left out.  That has nothing to do with the compiler. 

    Looks like somehow when the code is loaded from R5F, some initilization sections are not loaded correctly,

    Since we do not support elf load, user application needs to handle this. We have taken this as a backlog request, For now the recommendation is not to use C based compiler for PRU, instead use assembly compiler which does not has this dependency.

  • Unfortunately, we will not be changing to use assembly code for the PRU.

    I would be interested in recommendations on how to properly form this SOC project, and more likely the correct commands in the R5FSS0 to initialize the PRU.

  • Hi Nathan,

    We will work on the fix for elf loader. I will update you once I have some developments.

  • Hello Nathan,

    I am not sure if this would be helpful or not. But I have some examples on other PRU processors where we force the C startup routine to address 0x0 of the instruction RAM, like this:

    https://git.ti.com/cgit/pru-software-support-package/pru-software-support-package/tree/labs/Getting_Started_Labs/linker_cmd/AM335x_PRU.cmd

    /* Specify the sections allocation into memory */
    SECTIONS {
    	/* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading
    	   an ELF file, but useful when loading a binary */
    	.text:_c_int00*	>  0x0, PAGE 0

    Does adding those lines to your linker.cmd file cause initialization to occur properly?

    Regards,

    Nick

  • You can also verify the location of c_int00 by checking the generated .map file. If c_int00 is already at IRAM 0x0, then I would not expect that line of code to make a difference.

  • Thank you for the reply Nick. 

    I have verified that those lines are present in the linker file, all good there. But this doesn't address the issue I have, which is that the value of the stack pointer of the PRU program never gets initialized when loading the PRU from an R5 core. There's no instructions in the generated PRU instructions that do this, and I haven't been able to find any way of initializing the register used as the stack pointer from the R5 core.

  • What are your PRU build arguments? I would be curious to see if --disable_auto_rts is one of the build options - if so, we could try again with that argument removed.

    It looks like you have been referencing the PRU Getting Started Labs, which I wrote:
    https://git.ti.com/cgit/pru-software-support-package/pru-software-support-package/tree/labs/Getting_Started_Labs

    Unfortunately I am primarily a Linux developer, so I have mostly validated that code against Linux & CCS loading, not MCU+ drivers.

    Regards,

    Nick

  • I have been through the getting started labs for this on several occassions. There is no example in there where an R5 core loads a c-compiled PRU program. 

    For the PRU build options:


    Compiler:

    -O2 --include_path="C:/Software/50019F-HCS/50019F-COD001_System_Project/50019F-COD005_PRU_0_Project" --include_path="C:/ti/ti-cgt-pru_2.3.3/include" --include_path="C:/ti/mcu_plus_sdk_am263px_10_01_00_31/source" --include_path="../Current_Servo_PRU_0/Models/HCS_Current_Servo/HCS_Current_Servo_ert_rtw" --include_path="../../50019F-COD001_System/GlobalIncludes" --include_path="../Current_Servo_PRU_0/Shared_Includes" --include_path="../Current_Servo_PRU_0" --include_path="../Current_Servo_PRU_0/Models/HCS_Observer_Parameters/HCS_Observer_Parameters_ert_rtw" --include_path="../Current_Servo_PRU_0/Models/HCS_Resistance_Observer/HCS_Resistance_Observer_ert_rtw" --include_path="../Current_Servo_PRU_0/Models/HCS_Dither_Average/HCS_Dither_Average_ert_rtw" --include_path="../Current_Servo_PRU_0/Models/HCS_Hysteresis_Compensation/HCS_Hysteresis_Compensation_ert_rtw" --include_path="../ADC BIOS" --include_path="../EPWM BIOS" -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little -k

    Linker:
    -z -m"PRU0.Debug.map" --stack_size=0x1000 -i"C:/ti/ti-cgt-pru_2.3.3/lib" -i"C:/ti/ti-cgt-pru_2.3.3/include" --reread_libs --diag_suppress=10063-D --diag_wrap=off --display_error_number --warn_sections --xml_link_info="50019F-COD005_PRU_0_linkInfo.xml" --ram_model

    Hex Utility:
    --linkerfill --diag_wrap=off --array --array:name_prefix=PRU_0_image

  • Hello Nathan,

    Thank you for sharing.

    I am trying out a couple of things on this end to see if I can get C code loaded from an R5F on AM64x.

    Could I get you to share a snippet of your inline assembly workaround with me? I am curious to see if you did something different from Nilabh's screenshot here: https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1493084/am263p4-pru-stack-pointer-initialization-when-using-c-code/5757265#5757265 

    I see you are using the --keep_asm compiler setting (-k). I have used this to generate a starting point for assembly code in the past. Not sure if this generated output includes the generated c initialization functions? If so, maybe there would be a way to edit that assembly code the way you wanted, and then finish building the C project from the intermediate assembly code? (just tossing ideas out there, have not had time to evaluate at this point).

    Regards,

    Nick

  • Here is a screenshot of the inline assembly that we are currently using as a patch for this issue:

    This works, but requires us to derive the stack size of the main function in order to determine the correct initial value for the stack pointer.

  • Has anyone been able to look into this further?

  • Hey Nathan, thanks for checking in.

    Background - what are we working on now?

    The team is working on publishing a lot of our PRU projects right now, as well as creating training to show how to program the PRU (PRU Academy, you'll see it as a module in the AM26x academy: https://dev.ti.com/tirex/explore/node?node=A__AEIJm0rwIeU.2P1OBWwlaA__AM26X-ACADEMY__t0CaxbG__LATEST )

    For future readers, we are also creating PRU Academy for AM243x, AM62x, and AM64x. All the code will be in the OpenPRU repo here:
    https://github.com/TexasInstruments/open-pru

    The first step of the academy is to port the PRU Getting Started Labs to AM26x and add documentation around using PRU with an MCU+ core. Then we'll expand into training labs around all the other PRU features, like GPI/GPO, INTC, etc.

    How does that relate to your question? 

    I have been learning about the RTOS side of this so that I could write documentation about it. I did spend a couple hours digging into the stack pointer question, but it was slow going. For the first version of the academy we have pivoted to just documenting using assembly code with an MCU+ core. I hope to pivot back to the question of "how to get C code loaded properly from an MCU+ core" sometime next month, but we'll see.

    At this point, I am not sure if the easiest "low hanging fruit" is figuring out a special way to modify or load the hex array, or getting elf support into the MCU+ driver. I do not think there is a set timeframe for evaluating adding ELF support.

    Please feel free to ping us for updates.

    Regards,

    Nick