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.

TMS320F28379D: Unable to debug Dual Core projects in TMS320F28379D

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE

We are trying to debug a dual core IPC example program with 2 separate projects for both CPU1 and CPU2 on RAM.

Below are the steps used to load the .out files and debug the projects that are already built.

  1. Launch the selected configuration for TMS320F28379D.
  2. Connect to target to CPU1 core and load CPU1.out file.
  3. CPU1 program halts at main.
  4. Connect to target to CPU2 core and load CPU2.out file.
  5. CPU2 program gets immediately executed..!

As the CPU2 is not halting at main(), sync between the two cores is not happenning properly and as a result data is not getting shared to CPU2 from CPU1.

We have tried the following alternatives but they didnt seem to work -

  1. Setting breakpoint at main() of CPU2.
  2. Enabling the run to main() option in properties for CPU2 program.
  3. Adding a IPC_WaitforFlag() in CPU2.
  4. Adding some delay in CPU2 code immediately after main().

The same programs seem to work fine in different system when run on RAM. Also, if the programs are executed on FLASH, both CPU1 and CPU2 codes halt at main() after loading the .out files.

Attached CPU1  program - 1.txt  and CPU2 program - 2.txt

What could be the reason for this behaviour in different systems. Are there any system level settings/configurations required to be made so that the issue is resolved?

  • Hi Gautham,

    Can you check the following?

    1. Are there any CPU2 calls in the CPU1 Code? For example, IPCBootCPU2(), Device_bootCPU2() etc.

    2. Can you try to use a multicore launch instead of manual sequential loading to CPU1 and CPU2? You can refer to the examples in C2000Ware_6_00_01_00\driverlib\f2837xd\examples\dual\ipc. Note that this involves creating a system.xml file which contains the multicore configuration. You can also start with an empty project from C2000Ware_6_00_01_00\driverlib\f2837xd\examples\dual and then edit the .c and syscfg files for CPU1 and CPU2 based on your project.

    3. Always make sure that CPU1 is loaded first (you are already doing this)

    Could you try this and let me know if it works for you?

    Thanks,

    Ira

  • Hi Gautham,

    Just saw that in your CPU1 code you have the following line

     

    This will cause the RAM build to break for sure.

    This is because _STANDALONE macro is not defined during a CCS debug session - it's only defined for production builds. So Device_bootCPU2(0 is never called in RAM build. 

    In FLASH mode (_STANDALONE + _FLASH defined): CPU2's boot ROM waits for CPU1 to send a boot command via Device_bootCPU2(). The JTAG debugger intercepts this handoff and can halt CPU2 at main(). This is why FLASH works reliably.

    In RAM debug mode: There is no boot ROM wait mechanism. When the debugger connects to CPU2 and loads CPU2.out, it writes directly to RAM and releases CPU2's execution. Without a "halt on connect" or "reset and halt" configured in the target configuration, CPU2 simply runs.

    IPC_sync() is designed for both cores to call it simultaneously (or within a short window). When CPU2 runs far ahead, the sync primitive breaks in a specific way:

    CPU2 runs first:

    1. CPU2 calls IPC_sync(IPC_CPU2_L_CPU1_R, IPC_FLAG17):

      • Sets CPU2→CPU1 FLAG17
      • Checks while(IPC_isFlagBusyRtoL(..., IPC_FLAG17)) → checks if CPU1→CPU2 FLAG17 is set
      • CPU1 hasn't set anything yet, so this flag is not set → condition is false  loop exits immediately
      • CPU2 passes the sync without waiting for CPU1 at all
    2. CPU2 enters for(;;) { NOP; } — waiting for IPC interrupts.

    CPU1 starts later (from debugger): 3. CPU1 calls IPC_sync(IPC_CPU1_L_CPU2_R, IPC_FLAG17):

    • Sets CPU1→CPU2 FLAG17
    • Checks while(IPC_isFlagBusyRtoL(..., IPC_FLAG17)) → checks if CPU2→CPU1 FLAG17 is set
    • CPU2 set this flag in step 1 and it is still set → condition is true  CPU1 waits forever

    Can you make the following change in your code and try?

    CPU1 code — add this right after Device_init() and before IPC_sync():

    Device_init();
    // ...
    IPC_clearFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG_ALL);
    
    // Signal CPU2 that CPU1 is initialized and ready
    IPC_setFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG31);
    
    // Now proceed to sync
    IPC_sync(IPC_CPU1_L_CPU2_R, IPC_FLAG17);
    

    CPU2 code — add this at the very first line of main(), before Device_init():

    void main(void)
    {
        // Wait for CPU1 to finish its init before proceeding
        // Must be first — before Device_init(), before IPC_clearFlagLtoR()
        while(!IPC_isFlagBusyRtoL(IPC_CPU2_L_CPU1_R, IPC_FLAG31));
        IPC_ackFlagRtoL(IPC_CPU2_L_CPU1_R, IPC_FLAG31);
    
        // Normal init follows
        Device_init();
        ...
        IPC_clearFlagLtoR(IPC_CPU2_L_CPU1_R, IPC_FLAG_ALL);
        ...
        IPC_sync(IPC_CPU2_L_CPU1_R, IPC_FLAG17);

    Thanks,
    Ira
  • Hi  ,

    I made the above modifications and tested, but the issue still persists. 

    When the build configuration of FLASH is set active, it works fine. But when the build configuration of RAM is set active, CPU2 code automatically starts execution immediately after loading.

    I have also implemented debug configuration (.XML) for the dual core projects which simultaneously loads both CPU1 and CPU2 projects into Core1 and core2. CPU1 halts at main() while CPU2 is already running.

  • Hi Gautham,

    Can you try with this CPU1 code? I have held CPU2 in reset until CPU1 is ready.

    #include "driverlib.h"
    #include "device.h"
    #include "ipc.h"
    #include "struct.h"

    #pragma DATA_SECTION(data1, "MSGRAM_CPU1_TO_CPU2")
    shared_t data1;
    //uint32_t data1;

    void main(void)
    {
    // Initialize device (basic system setup)
    Device_init();

    // Hold CPU2 in reset state immediately
    SysCtl_resetPeripheral(SYSCTL_PERIPH_RES_CPU2);

    uint16_t i = 0;

    #ifdef _STANDALONE
    #ifdef _FLASH
    // Boot CPU2 from flash - but it will still be held in reset
    Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);
    #else
    // Boot CPU2 from RAM - but it will still be held in reset
    Device_bootCPU2(BOOTMODE_BOOT_TO_M0RAM);
    #endif
    #endif

    // Initialize the PIE module and vector table
    Interrupt_initModule();
    Interrupt_initVectorTable();

    // Clear any IPC flags if set already
    IPC_clearFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG_ALL);

    // Now release CPU2 from reset - it will start executing
    SysCtl_releasePeripheral(SYSCTL_PERIPH_RES_CPU2);

    // Give CPU2 some time to initialize before attempting sync
    DEVICE_DELAY_US(1000);

    // Synchronize both the cores
    IPC_sync(IPC_CPU1_L_CPU2_R, IPC_FLAG17);

    // Enable global interrupts
    EINT;
    // Enable real-time debug
    ERTM;

    for (;;) {
    if (!IPC_isFlagBusyLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG0))
    {
    i++;
    data1.id = i;
    data1.value = 10.5 * i;
    IPC_sendCommand(IPC_CPU1_L_CPU2_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE, 0, (uint32_t)&data1,
    sizeof(data1));
    DEVICE_DELAY_US(200000);
    }
    }
    }

    Thanks,

    Ira

  • 1. Initial Setup:
    - Connect to CPU1 first and load CPU1.out
    - CPU1 will halt at main()
    2. First Run:
    - Let CPU1 run until it releases CPU2 from reset
    - You can set a breakpoint after the SysCtl_releasePeripheral(SYSCTL_PERIPH_RES_CPU2) line if you want
    3. CPU2 Connection:
    - Connect to CPU2 and load CPU2.out
    - With this solution, CPU2 should properly halt at main() because CPU1 is controlling its reset state
    4. Synchronization:
    - Resume both cores
    - They should now properly synchronize at their respective IPC_sync calls
    - CPU1 will start sending data to CPU2, and CPU2 will receive it via its interrupt handler

  • Also, make sure that Run to Symbol -> main On a program load or restart option is enabled for both the CPUs

  • Hi  

    I don't see - SYSCTL_PERIPH_RES_CPU2 constant and SysCtl_releasePeripheral(SYSCTL_PERIPH_RES_CPU2) function in the header file. As a result, i am not able to change the code s suggested. Can you help me if this is to be changed to some other variable/constant so that we can manually reset CPU2. i am using CCS Ver 12.8.1.

    Also, the option to run to main is  enabled for CPU2.

  • Hi Gautham,

    You can reset the CPU2 using direct hardware register writes. Can you try this? 

    #include "driverlib.h"
    #include "device.h"
    #include "ipc.h"
    #include "struct.h"

    // Needed for direct register access
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_sysctl.h"

    #pragma DATA_SECTION(data1, "MSGRAM_CPU1_TO_CPU2")
    shared_t data1;
    //uint32_t data1;

    void main(void)
    {
    // Initialize device (basic system setup)
    Device_init();

    // Put CPU2 in reset by setting the CPU2RESCTL.RESET bit
    // The key value (0xA5A5) is required to write to this register
    EALLOW;
    HWREG(DEVCFG_BASE + SYSCTL_O_CPU2RESCTL) = ((HWREG(DEVCFG_BASE + SYSCTL_O_CPU2RESCTL)
    & ~SYSCTL_CPU2RESCTL_RESET) | 0x1) // Set RESET bit to 1
    | (0xA5A5 << SYSCTL_CPU2RESCTL_KEY_S); // Set KEY field
    EDIS;

    uint16_t i = 0;

    // Initialize the PIE module and vector table
    Interrupt_initModule();
    Interrupt_initVectorTable();

    // Clear any IPC flags if set already
    IPC_clearFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG_ALL);

    #ifdef _STANDALONE
    #ifdef _FLASH
    // Boot CPU2 from flash
    Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);
    #else
    // Boot CPU2 from RAM
    Device_bootCPU2(BOOTMODE_BOOT_TO_M0RAM);
    #endif
    #endif

    // Release CPU2 from reset by clearing the CPU2RESCTL.RESET bit
    EALLOW;
    HWREG(DEVCFG_BASE + SYSCTL_O_CPU2RESCTL) = ((HWREG(DEVCFG_BASE + SYSCTL_O_CPU2RESCTL)
    & ~SYSCTL_CPU2RESCTL_RESET)) // Clear RESET bit
    | (0xA5A5 << SYSCTL_CPU2RESCTL_KEY_S); // Set KEY field
    EDIS;

    // Give CPU2 some time to initialize before attempting sync
    DEVICE_DELAY_US(1000);

    // Synchronize both the cores
    IPC_sync(IPC_CPU1_L_CPU2_R, IPC_FLAG17);

    // Enable global interrupts
    EINT;
    // Enable real-time debug
    ERTM;

    for (;;) {
    if (!IPC_isFlagBusyLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG0))
    {
    i++;
    data1.id = i;
    data1.value = 10.5 * i;
    IPC_sendCommand(IPC_CPU1_L_CPU2_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE, 0, (uint32_t)&data1,
    sizeof(data1));
    DEVICE_DELAY_US(200000);
    }
    }
    }

    This is based on C2000Ware 6.00.01.00 SDK. 
    This is not the cleanest way to do it but could you still try it for the time being and see if it resolves the issue? 

    Thanks,

    Ira

  • Hi  

    When i build the code, it throws an error - Identifier 'SYSCTL_O_CPU2RESCTL' is not defined. I observed that the programs work fine when built on RAM in a different laptop. When the same code is built on RAM in PC, it behaves differently. Are there any changes to be made at system level or in environment variables so that it works fine irrespective of system.

  • Hi Gautham,

    I hope you are including :
    #include "inc/hw_sysctl.h"

    and using C2000Ware 6.00.01.00 SDK, because the register is clearly defined there.

    So you shouldn't get an undefined error.

    Can you make sure you have included it and its in your project's include options as well?

    Thanks,

    Ira

  • Hi  

    The library is included correctly. But c2000 version that i am using is C2000Ware 5.02.00.00 SDK. Could that be an issue? i am trying to download the latest version now.

  • Hi  

    The library is included correctly. But c2000 version that i am using is C2000Ware 5.02.00.00 SDK. Could that be an issue? i am trying to download the latest version now.

  • Hi Gautham,

    Yeah, I would recommend trying with a newer C2000Ware as  5.02.00.00 is very old and there have been lot of bug fixes since then. Please try with 6.00.01.00 SDK or newer.

    Thanks,

    Ira

  • I have verified with 6.00.01.00 SDK  but still didn't resolved the issue.

  • Okay so you were able to do the register writes, but CPU2 is still not halting at main. Is that correct?

  • yes, the code is getting built but CPU2 is still not halting at main().

  • You are loading the CPU2 program after the line 
    // Give CPU2 some time to initialize before attempting sync
    DEVICE_DELAY_US(1000);
    right?

    CPU1 needs to execute till here before program can be loaded to CPU2 to make sure the sync happens properly.