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.

TM4C1231H6PM: Errata SYSCTL#01

Part Number: TM4C1231H6PM

Hi All,

I have a system that samples data from some sensors and then goes into deep sleep mode. The way that the system gets waked up from deep sleep is through a GPIO interrupt from an outside source. There are multiple GPIO interrupt sources for my system, therefore my system can be waked up by different sources.

Later I realized that my system will occasionally not wake up from deep sleep mode. After looking into the TM4C123 errata, I realized that my system setup hits the SYSCTL#01 problem, With a Specific Clock Configuration, Device may not Wake From Deep Sleep Mode.

As a result I chose the workaround to disable the PLL before going into deep sleep mode and to enable the PLL whenever a GPIO interrupt is triggered (enable PLL within individual ISR)

Here is a problem; before entering deep sleep, I will disable PLL, however, if at this very moment before the deep sleep API is called, a GPIO interrupt comes in and enables the PLL, my system is then under the condition of the errata before going into deep sleep, which will render my system the chance of unable to be waked up from deep sleep.

// Pseudo Code

 

// typical GPIO ISR

void GPIO_ISR(){

Enable_PLL();

Do ISR stuffs ...

}

...

// clock setting for run state (wake state)

SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_XTAL_16MHZ | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN);

....

// .... procedures before entering deep sleep

SysTickDisable();

SystemDeepSleepClockSet(SYSCTL_DSLP_DIV_4 | SYSCTL_DSLP_OSC_INT30 | SYSCTL_DSLP_PIOSC_PD);

SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_XTAL_16MHZ | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN); // Disable PLL

SysCtlDeepSleepPowerSet(SYSCTL_TEMP_LOW_POWER | SYSCTL_FLASH_LOW_POWER | SYSCTL_SRAM_LOW_POWER);

SysCtlLDODeepSleepSet(SYSCTL_LDO_0_90V);

>>> Oh no GPIO interrupt comes in here and enables PLL <<<

SysCtlDeepSleep();

One thought I had for this problem was to enclose this section of the code within a critical section which should prevent interrupts from altering my PLL setting during this period. However, there still exists a small gap for interrupts between leaving the critical section and entering deep sleep. Therefore, this workaround of mine is not good enough.

Can anyone help me on this one? Is there any way that I can disable PLL and enter deep sleep smoothly without any interference? I would prefer not altering my system settings and not use PIOSC but any workarounds is deeply appreciated.

Thanks in advance!

Jacky

  • In the interrupt routine, can you check to see if the PLL is disabled? If it is, enable it, do your interrupt work and then disable it again before returning to the code that enters deep sleep.
  • Hi Bob,


    Thanks for the reply. Yes, I can check the status of PLL.

    By the way, my system uses FreeRTOS. The design of my system is that, if it's in run state, it will stay in run state unless there is an explicit command telling it to enter deep sleep. If it's in deep sleep state, and a GPIO interrupt is triggered, then the system will wake up, process the ISR and stay in run state (does not go in deep sleep unless a command tells it to do so).

    Here is a brief structure to the GPIO ISR taking your suggestion into account:

    void GPIO_ISR() {
    
    if (PLL is disabled) {
    enable_PLL();
    Do_ISR_Stuffs();
    disable_PLL();
    } else {
    Do_ISR_Stuffs();
    }
    
    }


    My Concerns:

    1. If my system is currently in deep sleep, which means the PLL is in disabled state, then a GPIO interrupt comes in, process the interrupt then disables the PLL, but since my system should stay in run state, I should have my PLL enabled.

    2. Same scenario as above, what if the Do_ISR_Stuffs() is actually sending a message queue to unblock a task? Would my unblocked task run properly if the PLL is disabled? 

    Thanks,

    Jacky

  • That is a good question. The instructions after the WFI instruction should re-enable the PLL. It makes sense to disable all interrupts, disable the PLL, then enable only the interrupts that are allowed to bring the system out of deep sleep (GPIO) and then execute the WFI instruction. After the WFI instruction, the PLL should be enabled and then other interrupts enabled.

    This brings to my mind a question independent of the PLL issue. What happens when you get the GPIO interrupt before you executed the WFI instruction and in the interrupt routine you unblock a task. When the interrupt returns, you might then execute the WFI instruction before the RTOS evaluates that the task is unblocked. You will then have to wait for the next GPIO event to wakeup the device again. It almost seems like you want a way in the GPIO interrupt routine to identify that you don't want to execute the WFI instruction when you return from the interrupt.
  • Hi Bob,


    Yeah, that was kind of the direction that I am heading into.

    By the way, I just found another potential solution to this problem, please let me know if this is ok.

    This solution requires the modification of the SysCtlDeepSleep() API.

    To be specific, instead of calling Enable_PLL() every time I enter the ISR(current code flow), I am going to place it within the SysCtlDeepSleep() API instead like so:

    void
    SysCtlDeepSleep(void)
    {
    //
    // Enable deep-sleep.
    //
    HWREG(NVIC_SYS_CTRL) |= NVIC_SYS_CTRL_SLEEPDEEP;
    
    //
    // Wait for an interrupt.
    //
    CPUwfi();
    
    //
    // Disable deep-sleep so that a future sleep works correctly.
    //
    HWREG(NVIC_SYS_CTRL) &= ~(NVIC_SYS_CTRL_SLEEPDEEP);
    
    >>> Insert Enable_PLL(); here<<<
    }

    Or I could just put the Enable_PLL() right after the SysCtlDeepSleep() call.

    This way, I will ONLY enable PLL when I am coming out of sleep. This will prevent any PLL modifications due to ISRs before going into deep sleep

    Let me know what you think.


    Thanks,
    Jacky

  • Yes, that is better. I was worried you needed to re-enable the PLL in your interrupt service routine because of the time to execute. However, if the ISR is short (as good ones are) you are better off not re-enabling until after the WFI instruction.