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.

CCS/TMS320F28388D: CPU2 BOOT from CPU1 Status

Part Number: TMS320F28388D
Other Parts Discussed in Thread: C2000WARE

Tool/software: Code Composer Studio

Hello,

I am using the TMS320F28388D controller and trying to perform the below operation, basically, I am programming to identify if a certain application will use 2 Cores or 1 Core (CPU) of the controller.

So if a program does not use CPU2, I will not be loading my Boot Loader into it so it will be a Single Core application.

The code works perfectly fine when connected to CCS debug mode and enables to use of only single-core, but when disconnected from CCS it does not work as expected, what is that I can do in CCS debug mode to expect the same behavior in CCS debug mode when it's not connected mode

My code is as below in CPU1 and CPU2:

    if( CPUID_1 == gu16CpuId )
    {

        Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);

    }
    if(CPUID_2 == gu16CpuId)
    {

        guniIpcRegs.gstrCpu2IpcRegs.CPU2TOCPU1IPCSET.bit.IPC16 = BIT_SET;

    }
    if( CPUID_1 == gu16CpuId )
    {
        while(!guniIpcRegs.gstrCpu1IpcRegs.CPU2TOCPU1IPCSTS.bit.IPC16){
            if(counter_exit > 0) {  //counter_exit = 1000
                counter_exit = counter_exit - 1;
            }
            else{
                break;
            }
        }        

        if(guniIpcRegs.gstrCpu1IpcRegs.CPU2TOCPU1IPCSTS.bit.IPC16){
            gu16ApplicationType = DUAL_CORE;
        }
        else{
            gu16ApplicationType = SINGLE_CORE;
        }

    }

thanks,

Nagesh

  • Hello

    What behavior are you seeing? Is your CPU1 boot mode set correctly via the boot GPIOs? Is your CPU2 application entry address (code_start) at the 0x80000 address?

    Put an LED blink in each so you can see if they are reaching their applications.

    Best regards

    Chris

  • hello Chris,

    Yes i have used a led blinky patter to understand the flow, what I observed is when only single core is selected the controller is getting a reset. 

    i.e after executing the statement in CPU1.

    Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);

    Can you let me know why it could  get a reset, any suggestions to debug ?

    thanks,

    Nagesh 

  • Hello

    Are you disabling the watchdog? This gets enabled coming out of boot and will be disabled when connected via CCS.

    Best regards

    Chris

  • Hi Chris,

    Yes, the Watchdog is disabled, I tried to simulate the behavior in one of the example code and I could see a similar behavior trying to figure out why it's getting a reset.

    The situation is, the output file should be loaded only on CPU1. I have keet different led blinking pattern before booting CPU2 and after booting CPU2.

    I am using the example code provided in c28x_dual for F2838xD, i was not able to attach the complete project here hence attaching the updated code for the same.

    I have commented on some of the IPC as it was not required here for the example code. and highlighted the new code with BOLD. FLASH is selected.

    // FILE:   ipc_ex1_basic_c28x1.c
    
    int gu16ApplicationType = DUAL_CORE;
    void main(void)
    {
        int i;
        int k = 0;
        // Initialize device clock and peripherals
        Device_init();
    
        Device_initGPIO();
        GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
        GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
    
        for(k=0;k<20;k++)
        {
            // Turn on LED
            GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);
            DEVICE_DELAY_US(100000);
            GPIO_writePin(DEVICE_GPIO_PIN_LED1, 1);
            DEVICE_DELAY_US(100000);
        }
        // Boot CPU2 core
    #ifdef _FLASH
        Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);
    #else
        Device_bootCPU2(BOOTMODE_BOOT_TO_M0RAM);
    #endif
    
        // Clear any IPC flags if set already
        IPC_clearFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG_ALL);
        if( DUAL_CORE == gu16ApplicationType )
        {
           GPIO_setPadConfig(DEVICE_GPIO_PIN_LED2, GPIO_PIN_TYPE_STD);
           GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED2, GPIO_DIR_MODE_OUT);
           // Configure CPU2 to control the LED GPIO
           GPIO_setMasterCore(DEVICE_GPIO_PIN_LED2, GPIO_CORE_CPU2);
        }
        for(;;)
        {
            // Turn on LED
            GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);
            DEVICE_DELAY_US(500000);
            GPIO_writePin(DEVICE_GPIO_PIN_LED1, 1);
            DEVICE_DELAY_US(500000);
        }
    

    }

  • Hello Chris,

    I have one more observation from debugging further.

    I would like to know under what circumstances the CPU2 can cause a reset on the controller (F28388D) including CPU1.

    this happens only when the control card is not connected to CCS.

    Secifically it happens after executing "Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);" 

    Thanks,

    Nagesh

  • Nagesh,

    I will try to replicate and get back to you on that by end of day tomorrow.

    Currently I can only think of CPU2 having a watchdog reset which triggers an NMI on CPU2. Otherwise CPU2 isn't able to reset the whole device. If CPU1 isn't getting reset, then there is a couple different CPU2 reset sources. Look at the TRM chapter "C28x System Control"->"Resets".

    I also recommend after running standalone to reconnect to device with target config that has GEL removed. In the target config, go to the advanced tab, select CPU1, CPU2, etc and clear the path for the GEL. This way when you connect it won't reset the device and then you can load symbols to see where in code it currently is. You can also observe the IPC status register and other registers that can provide more debugging info.

    Best regards

    Chris

  • Hello Chris, 

    I found out where exactly its getting a reset, I am reusing the function 'void SysCtl_controlCPU2Reset(SysCtl_CoreReset control)' from the example code.

    under that 

        if(control != 0x0U)
        {
    
        }
        else
        {
      
            EALLOW;
            clearvalue = HWREG(DEVCFG_BASE + SYSCTL_O_CPU2RESCTL);
            clearvalue &= ~SYSCTL_CPU2RESCTL_RESET;
    
    
            HWREG(DEVCFG_BASE + SYSCTL_O_CPU2RESCTL) = (SYSCTL_REG_KEY &
                    SYSCTL_CPU2RESCTL_KEY_M) | clearvalue; // Causing reset after this macro, trying to understand the functionality of this macro, can i replace this 
                                                                                                   //will a register
    
            for(i=10;i>0;i--)
            {
                strGpioDataRegs.GPATOGGLE.bit.GPIO31 = 1;
                DGenerateMicroSecDelay(65535);
                DGenerateMicroSecDelay(65535);
                DGenerateMicroSecDelay(65535);
            }
    
            EDIS;
        }

    thanks

    Nagesh

  • Nagesh

    Yes what you are detailing there is when the CPU2 gets released from reset to boot. That statement is writing to the CPU2RESCTL register.

    I've taken the code you provided and checked out the scenario. I've confirmed that CPU2 is indeed getting an itrap, then watchdog is triggering a reset there and the WD reset comes to CPU1 as an NMI. Since in the example the CPU1 vector table isn't being setup, the NMI is going to the boot ROM NMI handler which doesn't handle CPU2 WD NMIs and therefore CPU1 gets reset since the NMIWD times out.

    If you add the following after Device_init(), you can see it hit the ESTOP in the NMI default handler on CPU1:

        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        //
        Interrupt_initModule();
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;

    You could modify that handler so that a CPU2 WD NMI is ignored for your scenario.

    Note that an easier way to debug this is:

    1. Load CPU1 app
    2. Connect to CPU2, reset via CCS, and run
    3. Reset CPU1 via CCS
    4. At 0xD00 on CPU1, write 0xFFFF, at 0xD01 write 0x5AFF, at 0xD04 write 0x0003
      1. This will emulate flash boot so you can leave debugger connected
    5. Run CPU1. This will enable CPU1 to run through boot and can easily see what CPU1/2 are doing

    Best regards

    Chris

  • hello, 

    Thank you for your analysis. 

    I am trying to update the NMI handler as you suggested and using the example code from TI provided in C2000Ware_3_03_00_00_Software

    C:\ti\C2000Ware_3_03_00_00_Software\driverlib\f2838x\examples\c28x_dual\nmi

    I have updated the nmi_isr to send the CPU2 back to reset as below, but I do not see it to be working as expected.

    I have not loaded any application on CPU2, just by booting by CPU2 without an application in it i am expecting nmi interrupt and in that interrupt sending the CPU2 back to reset in CPU1. Can you also check if possible if what I am doing is correct?

    void main(void)
    {
        Device_init();
        Interrupt_initModule();
        Interrupt_initVectorTable();
        SysCtl_clearAllNMIFlags();
        Interrupt_register(INT_NMI, &nmi_isr);
        SysCtl_enableNMIGlobalInterrupt();
        Interrupt_enable(INT_NMI);
        EINT;
        ERTM;
        Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);
        while(1)
        {
            while(nmi_isr_called != 1);
            if(nmiflagstatus != (SYSCTL_NMI_CPU2WDRSN | SYSCTL_NMI_NMIINT))        {            ESTOP0;        }
            nmi_isr_called = 0;
            nmi_isr_count++;   
        }
    }

    interrupt void nmi_isr(void)
    {
        nmi_isr_called = 1;
        unsigned long int counter = 0;
        unsigned long int i = 0;
    //Added to observe LED blinky if it enters nmi interrupt, but not observing the LED blinky pattern while(counter < 5) { counter = counter + 1; GPIO_togglePin(DEVICE_GPIO_PIN_LED1); for(i = 0; i < 100000; i++) asm(" RPT #255 || NOP"); } nmiflagstatus = SysCtl_getNMIFlagStatus(); nmisdflagstatus = SysCtl_getNMIShadowFlagStatus(); SysCtl_clearAllNMIFlags(); Device_bootCPU2(0x00); }
    thanks,
    Nagesh

  • Nagesh

    In the NMI handler, I'd move the NMI flag clear before the LED  blink to avoid the NMI WD from resetting CPU1.

    Device_BootCPU2() will not put CPU2 back into reset. You need to call the API SysCtl_controlCPU2Reset(). Details of this are in the driverlib file sysctl.h

    Best regards

    Chris