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.

TMS320F28023: Halt Mode

Part Number: TMS320F28023
Other Parts Discussed in Thread: C2000WARE, CONTROLSUITE

Hi Champs,

I would like to the device to enter into and exit from low power mode, and the configuration and handler code shows below, can you please help to review the code? Is there any risk especially the disable and reenable interrupt ? 

1. Initialize code:

//pieier_table is global array 

volatile Uint16 pieier_table[12];



void init_f2802x_lpm(void)
{
       int i = 0;

       EALLOW;
      // Configure the GPIO17 pin as:
      // 00: GPIO17 - General purpose I/O 17 (default) (I/O)
     // 01: SPISOMIA - SPI-A Slave output/Master input (I/O)
// 10: Reserved
// 11: TZ3 - Trip zone 3 (I)
GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 0; //
GpioCtrlRegs.GPADIR.bit.GPIO17 = 0; // 0 - input mode; 1 - output mode
GpioIntRegs.GPIOLPMSEL.bit.GPIO17 = 1; // Choose GPIO8 pin for wakeup
EDIS;

// 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.WAKEINT = &f2802x_lpm_wake_isr;
EDIS;

com_data.sleep_mode_en = 0;

for(i=0;i<sizeof(pieier_table);i++)
{
pieier_table[i] = 0;
}

}

2. Background loop code:  

void f2802x_lpm_handler(void)//runs in background loop
{
    static TIMER_T tTime;           //3S时间计时
 
    App_TimeBase(S_BASE, &tTime);

    if((com_data.sleep_mode_en == 1)&&(System.Compressor.OnOffState == OFF))
    {
        if(tTime.DelayTime >= 2)
        {
            save_and_dis_all_interrupts();
 
            // Enable CPU INT1 which is connected to WakeInt:
            IER |= M_INT1;
 
            // Enable WAKEINT in the PIE: Group 1 interrupt 8
            PieCtrlRegs.PIEIER1.bit.INTx8 = 1;
            PieCtrlRegs.PIEACK.bit.ACK1 = 1;
            // Enable global Interrupts:
            EINT;   // Enable Global interrupt INTM
 
            // Write the LPM code value
            EALLOW;
            if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 1) // Only enter low power mode when PLL is not in limp mode.
            {
                tTime.DelayTime = 0; //clear the timer
                //GpioDataRegs.GPACLEAR.bit.GPIO6 = 1;
                LED_OFF;
                SysCtrlRegs.LPMCR0.bit.LPM = 0x0002;   // LPM mode = Halt
            }
            EDIS;
 
            // Force device into HALT
            __asm(" IDLE");                         // Device waits in IDLE until falling edge on GPIO0/XNMI pin
        }
    }
    else
    {
        tTime.DelayTime = 0;
    }
}

 

3. ISR code

__interrupt void f2802x_lpm_wake_isr(void)
{
    //GpioDataRegs.GPATOGGLE.bit.GPIO1 = 1; // Toggle GPIO1 in the ISR - monitored with oscilloscope
   recover_interrupts();
    EALLOW;
    PieCtrlRegs.PIEIER1.bit.INTx8 = 0;
    EDIS;
 
    PieCtrlRegs.PIEACK.bit.ACK1 = 1;
}

2 key functions:

void save_and_dis_all_interrupts(void)
{
    EALLOW;
    //Save all interrupt first
    pieier_table[0] = PieCtrlRegs.PIEIER1.all;
    pieier_table[1] = PieCtrlRegs.PIEIER2.all;
    pieier_table[2] = PieCtrlRegs.PIEIER3.all;
    pieier_table[3] = PieCtrlRegs.PIEIER4.all;
    pieier_table[4] = PieCtrlRegs.PIEIER5.all;
    pieier_table[5] = PieCtrlRegs.PIEIER6.all;
    pieier_table[6] = PieCtrlRegs.PIEIER7.all;
    pieier_table[7] = PieCtrlRegs.PIEIER8.all;
    pieier_table[8] = PieCtrlRegs.PIEIER9.all;
    pieier_table[9] = PieCtrlRegs.PIEIER10.all;
    pieier_table[10] = PieCtrlRegs.PIEIER11.all;
    pieier_table[11] = PieCtrlRegs.PIEIER12.all;
 
    PieCtrlRegs.PIEIER1.all = 0;
    PieCtrlRegs.PIEIER2.all = 0;
    PieCtrlRegs.PIEIER3.all = 0;
    PieCtrlRegs.PIEIER4.all = 0;
    PieCtrlRegs.PIEIER5.all = 0;
    PieCtrlRegs.PIEIER6.all = 0;
    PieCtrlRegs.PIEIER7.all = 0;
    PieCtrlRegs.PIEIER8.all = 0;
    PieCtrlRegs.PIEIER9.all = 0;
    PieCtrlRegs.PIEIER10.all = 0;
    PieCtrlRegs.PIEIER11.all = 0;
    PieCtrlRegs.PIEIER12.all = 0;
 
    EDIS;
}
 
void recover_interrupts(void)
{
    EALLOW;
    PieCtrlRegs.PIEIER1.all = pieier_table[0] ;
    PieCtrlRegs.PIEIER2.all = pieier_table[1] ;
    PieCtrlRegs.PIEIER3.all = pieier_table[2] ;
    PieCtrlRegs.PIEIER4.all = pieier_table[3] ;
    PieCtrlRegs.PIEIER5.all = pieier_table[4] ;
    PieCtrlRegs.PIEIER6.all = pieier_table[5] ;
    PieCtrlRegs.PIEIER7.all = pieier_table[6] ;
    PieCtrlRegs.PIEIER8.all = pieier_table[7] ;
    PieCtrlRegs.PIEIER9.all = pieier_table[8] ;
    PieCtrlRegs.PIEIER10.all = pieier_table[9] ;
    PieCtrlRegs.PIEIER11.all = pieier_table[10];
    PieCtrlRegs.PIEIER12.all = pieier_table[11];
    EDIS;
}

 

 

  • Another question:

    Can you please help me to understand the below red marked items?

    If INTM = 0, the device will be exited from halt mode once IDEL instruction executed even no GPIO wake up signal generated, isn't it?

  • Jack,

    That being said here are my thoughts:

    1. If INTM = 1, the MCU will enter HALT mode as normal. once the valid GPIO external wakeup is received, the application will continue executing from the next line after the idle instruction. it will not jump to the WAKE_INT ISR.

    2.It seems like you are being needlessly complex with entering halt mode. You do not need to save then restore the entire PIEIER table. otherwise the code appears to be fine. you have the critical pieces of HALT mode entry and exit. The bare minimum is documented in the C2000Ware example (lpm_haltwake)

    For future reference please avoid dumping code in plain text into the body of the post. There is a code formatter tool in the Rich text editor with an icon of a window with </> in it. It has proper syntax highlighting that makes code much easier to read. I have edited your original post to show how this looks. Additionally, my reviewing your code does not preclude you from having to test your application and evaluate the risks associated with it in your application.

    Regards,
    Mark

  • Hi Mark,

    Thanks for your suggestion. I will pasted my code as your suggested in future.

    Regarding to your comment, "You do not need to save then restore the entire PIEIER table. ", but the reference manual says, Disable all interrupts with the possible exception of the HALT mode wakeup interrupt. The interrupts can be reenabled after the device is brought out of HALT mode, how to understand this?

    Actually, I didn't save and restore PIEIER table before with using the example code in controlsuite, but sometimes I find the device didn't wake up normally. And I'm sure that the GPIO wake up signal is pretty good, with 11ms low pulse, and the signal generated in every 2 seconds. 

    If no need to save then restore entire PIEIER, it seems that my code still have some risk that device won't be able to wake up, can you please share your comment of how to configure device to be able to wake up normally?

  • Ah, I appear to have been mistaken with my PIEIER comment, I mistakenly thought you were remapping the whole vector address table. This is actually a reasonably efficient way to disable all interrupts.

    The code looks fine, it was my misreading of it that was the problem.

    The only thing I would be careful with from an application standpoint is to ensure that your system is prepared to enter an LPM. I.e. ensure that the SPI isn't actively transmitting a message as the System clocks are disabled or something similar like actively toggling PWMs on a power stage. You must prepare the system to be halted. It could be a challenge recover the system if certain modules lose synchronization or even catastrophic!

    -Mark