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.

TMS570LC4357: Cannot put flash banks to sleep while in sleep mode

Part Number: TMS570LC4357

Following this issue, trying to put the flash banks to sleep when getting the device to sleep (following the sequence described in section 2.4.3.1 of the reference manual) triggers prefetch errors on wakeup interrupts, ultimately keeping the VDDIO current around 30mA (~100mW) during sleep to keep one flash bank powered, which is too high for our application.
We tried to adapt the code from the TMS570LS0714PZ_LPMs_Wakeup repository to the TMS570LC device we are using, but did not meet the expected results, as the TMS570LC device lacks registers FBFALLBACK and FPAC2 to control flash bank fallback power mode, and only allows to change the current mode through the FBPWRMODE register.


Placing the shutdown / wakeup sequence and GIO interrupt handler in ram (section .ramTEXT) does not change the outcome.

Are we missing some configuration to put the flash to sleep while in sleep mode?

Here is our shutodwn / wakeup sequence:


#pragma SET_CODE_SECTION(".ramTEXT")

void systemPowerDown(uint32 mode)
{
    uint32_t flashFbPwrMode;
    uint32_t clkTest, csdis, cddis, ghvsrc, pllctl1, pllctl2, pllctl3;

    flashFbPwrMode = flashWREG->FBPWRMODE; // Save configuration to restore it on wakeup

    clkTest = systemREG1->CLKTEST;
    csdis   = systemREG1->CSDIS;
    cddis   = systemREG1->CDDIS;
    pllctl1 = systemREG1->PLLCTL1;
    pllctl2 = systemREG1->PLLCTL2;
    pllctl3 = systemREG2->PLLCTL3;
    ghvsrc  = systemREG1->GHVSRC;

    systemREG1->CLKTEST = (clkTest & ~(1 << 25)) | (1 << 24); // disable range detection
    pmmTurnOFFLogicPowerDomain(PMM_LOGICPD4);
    pmmTurnOFFLogicPowerDomain(PMM_LOGICPD5);

    while (flashWREG->FBBUSY & ((1U << 7) | (1U << 1) | (1U << 0))); // wait for all flash banks to be idle

    flashWREG->FBAC = (0x00 << 16) //OTP programming is disabled
                    | (0x0F); //VREAD setup for wakeup
    flashWREG->FPAC1 &= ~1U; // charge pump fallback power mode = sleep
    flashWREG->FBPWRMODE = (3U << (0 * 2)) // flash bank 0 power mode (0: sleep, 1: standby, 3: active)
                         | (0U << (1 * 2)) // flash bank 1 power mode (0: sleep, 1: standby, 3: active)
| (0U << (7 * 2));// flash bank 7 power mode (0: sleep, 1: standby, 3: active)

  // Disable clock sources and domains
    systemREG1->CSDISSET = mode & 0x000000FFU;
    systemREG1->CDDIS = (mode >> 8U) & 0x00000FFFU;

    /* Idle CPU */
    asm volatile (
        " WFI   \n" // Wait-For-Interrupt instruction
        " nop   \n" // 4 nopes to flush the pipeline
        " nop   \n"
        " nop   \n"
        " nop   \n"
);

    flashWREG->FBPWRMODE = flashFbPwrMode; //wake up flash
    systemREG1->CSDISCLR = (~csdis) & 0x31; // enable LF LPO, HF LPO and oscillator first
    if (mode & ~csdis & (1U << 1U)) // if LP mode disabled pll1
    {
        systemREG1->PLLCTL1 = (0U << 31U)   // no reset on slip
                            | (1U << 29U)   // bypass on slip enabled
                            | (0x1F << 24U) // output divider to max before lock
                            | (pllctl1 & 0x00FFFFFF);

        systemREG1->PLLCTL2 = (0U << 31U) // disable freq. modulation
                            | (pllctl2 & 0x7FFFFFFF);
    }
    if (mode & ~csdis & (1U << 6U)) // if LP mode disabled pll2
    {
        systemREG2->PLLCTL3 = (7U << 29U) // output divider to max before lock
                            | (pllctl3 & 0x1FFFFFFF);
    }

    systemREG1->CSDIS = csdis;
    systemREG1->CDDIS = cddis;

    // Wait until clocks are locked, then restore remaining pll parameters
    while ((systemREG1->CSVSTAT & (~csdis) & 0xFF) != ((~csdis) & 0xFF));

    systemREG1->PLLCTL1 = pllctl1;
    systemREG1->PLLCTL2 = pllctl2;
    systemREG1->GHVSRC = ghvsrc;

    // Resume oscillator monitoring
    systemREG1->CLKTEST = clkTest;

    pmmTurnONLogicPowerDomain(PMM_LOGICPD4);
    pmmTurnONLogicPowerDomain(PMM_LOGICPD5);
  gioInit();
}
#pragma SET_CODE_SECTION()
  • Hi France,

    Apologies for the delayed response, i am working on your issue now and will get back to you on this as soon as possible.

    --
    Thanks & regards,
    Jagadish.

  • Hi France,

    Currently i am lack of hardware to test this project at my end. However, we have one internal AI which can analyze all our old e2e database and all the documents related to this controller, i got some useful information when i feed your question to it. Could you please try these suggestions in first place?

    Key Issues Identified:

    1. You're experiencing prefetch errors on wakeup when trying to put flash banks to sleep
    2. The TMS570LC device lacks the FBFALLBACK and FPAC2 registers that exist in the TMS570LS series
    3. You're still seeing high current consumption (~30mA) during sleep mode

    Analysis of Your Code:

    Your implementation attempts to follow the power-down sequence from section 2.4.3.1 of the reference manual, but there are some differences between the TMS570LC and TMS570LS series that need to be addressed.

    Recommendations:

    1. Flash Bank Power Mode Handling:

      • For the TMS570LC, you're correctly using FBPWRMODE register, but you might need to adjust your approach
    2. Flash Wake-up Sequence:

      • The prefetch errors suggest the flash isn't properly ready when code execution resumes
      • Consider adding a delay or checking for flash ready status before resuming normal operation
    3. Modified Implementation:

    #pragma SET_CODE_SECTION(".ramTEXT")
    void systemPowerDown(uint32 mode)
    {
        uint32_t flashFbPwrMode;
        uint32_t clkTest, csdis, cddis, ghvsrc, pllctl1, pllctl2, pllctl3;
        
        // Save configurations to restore on wakeup
        flashFbPwrMode = flashWREG->FBPWRMODE;
        clkTest = systemREG1->CLKTEST;
        csdis   = systemREG1->CSDIS;
        cddis   = systemREG1->CDDIS;
        pllctl1 = systemREG1->PLLCTL1;
        pllctl2 = systemREG1->PLLCTL2;
        pllctl3 = systemREG2->PLLCTL3;
        ghvsrc  = systemREG1->GHVSRC;
        
        // Disable range detection
        systemREG1->CLKTEST = (clkTest & ~(1 << 25)) | (1 << 24);
        
        // Turn off logic power domains
        pmmTurnOFFLogicPowerDomain(PMM_LOGICPD4);
        pmmTurnOFFLogicPowerDomain(PMM_LOGICPD5);
        
        // Wait for all flash banks to be idle
        while (flashWREG->FBBUSY & ((1U << 7) | (1U << 1) | (1U << 0)));
        
        // Configure flash for sleep mode
        flashWREG->FBAC = (0x00 << 16) | (0x0F);
        
        // For TMS570LC, modify this approach:
        // 1. Make sure to keep Bank 0 active if your interrupt handler code is there
        // 2. Put other banks to sleep
        flashWREG->FPAC1 &= ~1U; // charge pump fallback power mode = sleep
        
        // IMPORTANT: Keep bank 0 active if your interrupt handler is there
        // Otherwise put all banks to sleep
        flashWREG->FBPWRMODE = (3U << (0 * 2))  // Bank 0: ACTIVE - keep active if interrupt handler is here
                             | (0U << (1 * 2))  // Bank 1: SLEEP
                             | (0U << (2 * 2))  // Bank 2: SLEEP
                             | (0U << (3 * 2))  // Bank 3: SLEEP
                             | (0U << (4 * 2))  // Bank 4: SLEEP
                             | (0U << (5 * 2))  // Bank 5: SLEEP
                             | (0U << (6 * 2))  // Bank 6: SLEEP
                             | (0U << (7 * 2)); // Bank 7: SLEEP
        
        // Disable clock sources and domains
        systemREG1->CSDISSET = mode & 0x000000FFU;
        systemREG1->CDDIS = (mode >> 8U) & 0x00000FFFU;
        
        /* Idle CPU */
        asm volatile (
            " WFI   \n"
            " nop   \n"
            " nop   \n"
            " nop   \n"
            " nop   \n"
        );
        
        // Wake-up sequence
        // First wake up flash banks - CRITICAL
        flashWREG->FBPWRMODE = flashFbPwrMode;
        
        // Add a small delay to ensure flash is ready
        for (volatile uint32_t i = 0; i < 100; i++) { }
        
        // Wait for flash to be ready
        while (flashWREG->FMSTAT & 0x00000100);
        
        // Restore clock configuration
        systemREG1->CSDISCLR = (~csdis) & 0x31;
        
        if (mode & ~csdis & (1U << 1U))
        {
            systemREG1->PLLCTL1 = (0U << 31U) | (1U << 29U) | (0x1F << 24U) | (pllctl1 & 0x00FFFFFF);
            systemREG1->PLLCTL2 = (0U << 31U) | (pllctl2 & 0x7FFFFFFF);
        }
        
        if (mode & ~csdis & (1U << 6U))
        {
            systemREG2->PLLCTL3 = (7U << 29U) | (pllctl3 & 0x1FFFFFFF);
        }
        
        systemREG1->CSDIS = csdis;
        systemREG1->CDDIS = cddis;
        
        // Wait until clocks are locked
        while ((systemREG1->CSVSTAT & (~csdis) & 0xFF) != ((~csdis) & 0xFF));
        
        systemREG1->PLLCTL1 = pllctl1;
    #pragma SET_CODE_SECTION()

    Additional Considerations:

    1. Interrupt Handler Placement:

      • Make sure your wake-up interrupt handler is placed in RAM or in a flash bank that remains active
      • If your interrupt handler is in flash, you must keep that bank active
    2. Flash Bank Organization:

      • Verify which flash banks contain your critical code sections
      • Keep Bank 0 active if it contains your interrupt handler or wake-up code
    3. Alternative Approach:

      • If keeping one flash bank active still consumes too much power, consider moving ALL critical wake-up code to RAM
      • Then you can put ALL flash banks to sleep
    4. Hardware-Specific Workaround:

      • The TMS570LC might have specific errata related to flash power management
      • Check the device errata sheet for any known issues with flash sleep modes
    5. Prefetch Buffer Handling:

      • Before entering sleep mode, consider explicitly flushing the prefetch buffer
      • After waking up, ensure the prefetch buffer is properly reinitialized

    --
    Thanks & regards,
    Jagadish.

  • Hi Jagadish,
    Thank you for your reply.

    The modified implementation changes 2 things:
    - it turns off banks 2 to 6, which do not exist;
    - it adds a small delay and checks the FMSTAT. As the prefetch error happens before the first line is executed on wakeup, this has no effect. A delay is already added when waiting or the PLL to lock. I added the FMSTAT check anyway, without any effect  on the issue.

    I already tried moving the only active interrupt handler (GIO) to RAM, it does not have any effect on the issue.
    Errata sheets did not feature anything related to sleep mode or putting flash banks to sleep.
    I don't see any reason why the prefetch buffer would cause any issue, all the surrounding code is in RAM, but I can try to disable it. Do you have a routine to do that ?

    Thanks.
    Kind Regards,
    Loïc

  • Hi Loic,

    Apologies for the delayed response!

    Let's focus on the prefetch buffer issue, which seems to be the root cause.

    Disabling the Prefetch Buffer

    Here's a routine to disable the prefetch buffer on the TMS570LC4357:

    void disablePrefetchBuffer(void)
    {
        /* Clear the PBENA bit in FRDCNTL register */
        flashWREG->FRDCNTL &= ~(1U << 0);
        
        /* Optional: Flush the pipeline with NOPs */
        asm volatile ("nop");
        asm volatile ("nop");
        asm volatile ("nop");
        asm volatile ("nop");
        asm volatile ("nop");
    }
    
    void enablePrefetchBuffer(void)
    {
        /* Set the PBENA bit in FRDCNTL register */
        flashWREG->FRDCNTL |= (1U << 0);
    }

    More Comprehensive Approach

    Since you're still encountering issues, let's try a more comprehensive approach:

    void prepareFlashForSleep(void)
    {
        /* 1. Disable prefetch buffer */
        flashWREG->FRDCNTL &= ~(1U << 0);
        
        /* 2. Wait for any ongoing flash operations to complete */
        while (flashWREG->FBBUSY & 0x83);
        
        /* 3. Set appropriate read wait states for low power mode */
        uint32_t temp = flashWREG->FRDCNTL;
        temp &= ~(0xFU << 8);          /* Clear current wait states */
        temp |= (0xFU << 8);           /* Set maximum wait states for reliability */
        flashWREG->FRDCNTL = temp;
        
        /* 4. Configure flash bank power modes */
        flashWREG->FBPWRMODE = (3U << 0)   /* Bank 0 active - contains critical code */
                             | (0U << 2);  /* Bank 1 sleep */
                             
        /* 5. Wait for power mode transition */
        volatile uint32_t delay;
        for(delay = 0; delay < 100; delay++); /* Short delay */
        
        /* 6. Verify flash status */
        while (flashWREG->FBSTAT & 0x00010000);
    }
    
    void restoreFlashAfterWakeup(void)
    {
        /* 1. Restore all flash banks to active mode first */
        flashWREG->FBPWRMODE = 0x0F;  /* All banks active */
        
        /* 2. Wait for transition to complete */
        volatile uint32_t delay;
        for(delay = 0; delay < 100; delay++); /* Short delay */
        while (flashWREG->FBSTAT & 0x00010000);
        
        /* 3. Restore original wait states if needed */
        uint32_t temp = flashWREG->FRDCNTL;
        temp &= ~(0xFU << 8);          /* Clear wait states */
        temp |= (0x2U << 8);           /* Set to default value (adjust as needed) */
        flashWREG->FRDCNTL = temp;
        
        /* 4. Re-enable prefetch buffer */
        flashWREG->FRDCNTL |= (1U << 0);
    }
    --
    Thanks & regards,
    Jagadish.