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.

TMS320F28377D: Dual core offline burning issue

Part Number: TMS320F28377D
Other Parts Discussed in Thread: C2000WARE

Hi team,

Here're few questions may need your help:

The program architecture is as follows:

CPU1 is used for functions such as control algorithms and PWM, CPU2 is used for communication, and data exchange between CPUs is done through IPC.

The program needs to run offline, that is, write to flash. Both cores need to move some of the functions into ram to run faster, where the functions moved into CPU1 are as follows:

//Functions that need to be moved into ram to run 
#ifdef _FLASH
#pragma CODE_SECTION(EPWM2_ISR,"ramfuncs");
#pragma CODE_SECTION(Getresult,"ramfuncs");
#pragma CODE_SECTION(set_epwmcmp,"ramfuncs");
#pragma CODE_SECTION(PI_stop,"ramfuncs");
#endif

#ifdef _FLASH
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
Getresult();
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
set_epwmcmp();
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
PI_stop();
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
EPWM2_ISR();//interrupt function
#endif

In CPU2, the functions moved into ram are as follows: 

#ifdef _FLASH
// These are defined by the linker (see device linker command file)
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadSize;
extern Uint16 RamfuncsRunStart;
#pragma CODE_SECTION(IPC11_RX,"ramfuncs");
#pragma CODE_SECTION(CPU01toCPU02IPC1IntHandler,"ramfuncs");
#endif

#ifdef _FLASH
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
IPC11_RX();
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
CPU01toCPU02IPC1IntHandler();//interrupt function
#endif

When the receive function and IPC interrupt function in CPU2 are moved into ram, the program is stuck in the interrupt function of CPU2 and the program in CPU1 is functional. There are the following questions:

1) The CPU1 program does not run much differently in flash and in ram, and the difference in CPU2 is much greater. Is this normal? If an interrupt function is moved into ram, do the child functions used in the interrupt function also need to be moved into ram?

2) the program in CPU2 functions normally in flash and gets stuck in the IPC interrupt function once the interrupt function is moved into ram. Can these two cores run by moving functions into ram at the same time? Is it required to modify the cmd file?

3) In the routine, the cmd files for CPU1 and CPU2, the addresses of each partition are the same. According to the datasheet, each CPU has separate RAM and flash sections, and the RAM and flash sections of the two CPUs overlap at addresses after the flash initialization of the dual-core program. Does it contradict the description of the datasheet? Or need to define the ownership of each ram and flash in the cmd file?

The transmit function in CPU1 is as follows:

/* Data transmit  */
void IPC11_TX(Uint16 *AMBFB)
{
Uint16 i;
if(IPCRtoLFlagBusy(IPC_FLAG11) == 1)//Flag bit if CPU2 is set 
{
if((MemCfgRegs.GSxMSEL.bit.MSEL_GS0) == 1)//Set CPU1 as the master of the GS0 RAM 
{
EALLOW;
MemCfgRegs.GSxMSEL.bit.MSEL_GS0 = 0;
EDIS;
}
for(i=0;i<10;i++)//Write the data to the shared ram 
{
pusCPU01BufferPt[i] = AMBFB[i];
}
//Write the data in the shared ram to the location specified by the message ram of CPU2-1 
IPCLtoRBlockWrite(&g_sIpcController2, pulMsgRam2[1],(uint32_t)pusCPU01BufferPt,10,IPC_LENGTH_16_BITS,ENABLE_BLOCKING);
IPCRtoLFlagAcknowledge(IPC_FLAG11);
//IPCLtoRFlagClear(IPC_FLAG11);
}
}

The IPC interrupt routines in CPU2 are as follows: 

__interrupt void
CPU01toCPU02IPC1IntHandler (void)
{

tIpcMessage sMessage;
GPIO_WritePin(37,1);
IPCLtoRFlagSet(IPC_FLAG11);
// Continue processing messages as long as CPU01toCPU02 GetBuffer2 is full
while (IpcGet (&g_sIpcController2, &sMessage,
DISABLE_BLOCKING)!= STATUS_FAIL)
{
switch (sMessage.ulcommand)
{
case IPC_BLOCK_WRITE://CPU1 writes the data into the shared ram 
IPCRtoLBlockWrite(&sMessage);
IPC11_RX();
break;
case IPC_BLOCK_READ:
IPCRtoLBlockRead(&sMessage);//CPU2 writes data at the specified address to the shared ram 
break;
default:
//ErrorFlag = 1;
break;
}

}

// Acknowledge IPC INT1 Flag and PIE to receive more interrupts
IpcRegs.IPCACK.bit.IPC1 = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
GPIO_WritePin(37,0);
}

Could you help check this case? Thanks.

Best Regards,

Cherry

  • Hi Cherry,

    Can you ask the customer to try C2000Ware IPC example and run from flash?

    CPU1_FLASH and CPU2_FLASH build configuration.

    On CPU1, please define _STANDALONE in the predefined symbols.

    Does this application work for customer?

    Santosh

  • Hi Santosh,

    Thanks for your support.

    Running offline is OK. But once the function enters the ramfuncs program, it gets stuck in the interrupt program. 

    Thanks and regards,

    Cherry

  • Hi Cherry,

    I will refer to two examples from C2000Ware SDK which use both CPUs and I just verified on my setup.

    #1 - Dual Core LED example

    Path : C:/ti/c2000/C2000Ware_4_01_00_00/driverlib/f2837xd/examples/dual/led/CCS

    On CPU1, select CPU1_FLASH_STANDALONE build configuration

    On CPU2, select CPU2_FLASH build configuration

    Once, it flashed the images, disconnect the target and power cycle. it should work fine, both LEDs should be blinking. This example does not use interrupt. Just depends the IPC flag status between the cores.

    #2 C2000Ware Academy Solution:

    Path: C/ti/c2000/C2000Ware_4_01_00_00/training/device/f2837xd/module11_inter_processor_communications

    On CPU1, select CPU1_FLASH build configuration, open module11_cpu1_main.c file and update the parameter as highlighted below.

    In the project setting, add _STANDALONE predefined solution and also open file 

    #ifdef _STANDALONE
    #ifdef _FLASH
    // TODO check to see if this breaks.
    Device_bootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_FLASH);
    #else
    // TODO this breaks the RAM build.
    Device_bootCPU2(BOOTMODE_BOOT_TO_M0RAM);
    #endif
    #endif

    On CPU2, select CPU2_FLASH build configuration

    Once, it flashed the images, disconnect the target and power cycle. it should work fine, both LEDs should be blinking. This example use IPC interrupt. 

    For the lab, please IPC lab page in C2000 Academy:

    https://dev.ti.com/tirex/explore/node?node=A__Adlf59dR9TRikXjOlRRRsg__c2000Academy__jEBbtmC__LATEST

    The LED blinking rate can be modified:

    // Toggle LED1 at a rate 
    if (LedCtr1++ >= 5000) {
    GPIO_togglePin(DEVICE_GPIO_PIN_LED1);
    LedCtr1 = 0;
    }

    If this solution works for you, then you can use it as reference in customer project.

    Hope this helps.

    Thanks & Regards,

    Santosh

  • Hi Santosh,

    Thanks and I think there might be a misunderstanding. The current problem is that both CPU1 and CPU2 are able to run offline (the result is no problem).

    But the program in CPU2 is running very slowly, so the customer want to move the interrupt program in CPU2 to run in ram, but once moving it to ram, the program will get stuck in the interrupt program.

    Thanks and regards,

    Cherry

  • Cherry,

    Can you share the code for CPU2 so that we can review it? 

    Does it get stuck in ISR? Where is PC?

    Thanks & Regards,

    Santosh

  • Hi Santosh,

    Please see the following code:

    void InitIPC(void)//Initialize IPC 
    {
    IPCInitialize(&g_sIpcController1, IPC_INT0, IPC_INT0);
    IPCInitialize(&g_sIpcController2, IPC_INT1, IPC_INT1);//Invoke the IPC instance and configure as an IPC1 interrupt 
    Uint16 counter;
    pulMsgRam = (void *)CPU01TOCPU02_PASSMSG;//Message ram for CPU1-2 
    pulMsgRam2 = (void *)CPU02TOCPU01_PASSMSG;//Message ram for CPU2-1 
    pusCPU02BufferPt = (void *)(GS0SARAM_START + 15);//Sends an address pointer to the shared ram gs0 
    pusCPU02BufferPt_B = (void *)(GS0SARAM_START + 45);
    pulMsgRam2[1] = (Uint32)&usCPU02Buffer[0];//Place the address of the receive buf in the message ram of CPU2-1 
    pulMsgRam2[3] = (Uint32)&usCPU02Buffer_B[0];
    for(counter = 0; counter <15; counter++)
    {
    usCPU02Buffer[counter] = 0;
    usCPU02Buffer_B[counter] = 0;
    }
    }
    
    __interrupt void
    CPU01toCPU02IPC1IntHandler (void)
    {
    
    tIpcMessage sMessage;
    GPIO_WritePin(37,1);
    IPCLtoRFlagSet(IPC_FLAG11);
    // Continue processing messages as long as CPU01toCPU02 GetBuffer2 is full
    while (IpcGet (&g_sIpcController2, &sMessage,
    DISABLE_BLOCKING)!= STATUS_FAIL)
    {
    switch (sMessage.ulcommand)
    {
    case IPC_BLOCK_WRITE://CPU1 writes the data into the shared ram 
    IPCRtoLBlockWrite(&sMessage);
    IPC11_RX();
    break;
    case IPC_BLOCK_READ:
    IPCRtoLBlockRead(&sMessage);//CPU2 writes data at the specified address to the shared ram 
    break;
    default:
    //ErrorFlag = 1;
    break;
    }
    
    }
    
    // Acknowledge IPC INT1 Flag and PIE to receive more interrupts
    IpcRegs.IPCACK.bit.IPC1 = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    GPIO_WritePin(37,0);
    }

    The configuration in the main function is as follows: 

    InitPieVectTable();
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    EALLOW; // This is needed to write to EALLOW protected registers
    //PieVectTable.IPC0_INT = &CPU01toCPU02IPC0IntHandler;
    PieVectTable.IPC1_INT = &CPU01toCPU02IPC1IntHandler;
    EDIS; // This is needed to disable write to EALLOW protected registers
    
    InitIPC();
    
    EALLOW;
    CpuSysRegs.PCLKCR8.bit.SPI_B = 1;//Enables the spib clock 
    EDIS;
    //Reset 5500 chip 
    Reset_5500();
    spi_init();
    //Set up network information 
    set_network();
    //Turn on the server 
    TCP_server();
    //Set IPC flag bits 
    if(IPCRtoLFlagBusy(IPC_FLAG11) == 0)
    {
    IPCLtoRFlagSet(IPC_FLAG11);
    }

    Does it get stuck in ISR? Where is PC?

    It looks like it's actually stuck in the ISR, and once they move the interrupt function and the RX function to run in ram, the program will get stuck in the ISR. 

    Thanks and regards,

    Cherry

  • Cherry,

    I am assuming this code is for CPU1, is that correct?

    Does it get stuck in IPC ISR function CPU01toCPU02IPC1IntHandler() ?

    Can you put the breakpoint in the beginning of the ISR, and then narrow it down to the location when it gets stuck? 

    Does it get stuck at this line:

    while (IpcGet (&g_sIpcController2, &sMessage,DISABLE_BLOCKING)!= STATUS_FAIL)

    {
    }

    By any chance, is possible to get the trim-down project which can show the behavior? It is be even better if you try to reproduce using one of the C2000Ware IPC example.

    Thanks & Regards,

    Santosh