Executing Cy_BLE_DeepSleepCallback() with interrupts disabled

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
samfriedman
Level 1
Level 1
5 sign-ins First reply posted First question asked

This is a follow up from https://community.cypress.com/t5/PSoC-6-MCU/MCWDT-Interrupt-not-working-as-Deep-Sleep-wakeup-source-.... I work with @RaMu_4639021  and we're continuing to track down the same issue, but I can't reply on that post. Our idle thread looks roughly like:

 

uint32_t int_status = Cy_SysLib_EnterCriticalSection();

eSleepModeStatus eSleepStatus = eTaskConfirmSleepModeStatus();

if (eSleepStatus != eAbortSleep )
{
    Cy_SysPm_DeepSleep(CY_SYSPM_WAIT_FOR_INTERRUPT);
}

Cy_SysLib_ExitCriticalSection(int_status);

 

It's important that interrupts remain disabled between the calls to eTaskConfirmSleepModeStatus and Cy_SysPm_DeepSleep(). However, if we execute Cy_SysPm_DeepSleep() in a critical section, the device will hang while executing Cy_BLE_DeepSleepCallback(). If we never start the BLE component (so the BLE component never registers a call back with Cy_SysPm_RegisterCallback()), then the device sleeps and wakes up as expected. Is it possible to configure Cy_BLE_DeepSleepCallback() so that it can be called in a critical section?

0 Likes
1 Solution

Hi Sam,

Your behavior  is unexpected, because BLE syspm callback does not use BEFORE_TRANSITION state (refer to Cy_BLE_DeepSleepCallback function).

if you use SysPm without "order" field (was introduced in Syspm 4.20 refer to https://cypresssemiconductorco.github.io/psoc6pdl/pdl_api_reference_manual/html/group__group__syspm....  ) you should call  register_syspm_cb_task_lp (from P Yugandhar example) after Cy_BLE_Enable().

Regards,
Nazar

View solution in original post

0 Likes
8 Replies
Yugandhar
Moderator
Moderator
Moderator
500 solutions authored 1000 replies posted 5 likes given

Hello,

 In the BLE component,  please let me know the option chosen in the CPU Core field. Could you please check with setting the BLESS interrupt to the highest priority in the PSoC Creator ? If possible, please share your project for debugging at our end. 

Please refer to the 'CE212736_PSoC6BLE_FindMe' code example in the PSoC Creator. In this code example, the device enters low-power Deep Sleep mode when BLE is idle. It wakes up automatically when there is activity on the BLE connection. 

Thanks,

P Yugandhar.

0 Likes
samfriedman
Level 1
Level 1
5 sign-ins First reply posted First question asked

Hi,

We don't use PSoC Creator, so I don't have a project to share with you. We have the BLE component configured to run the Host and Controller on a single core (the M4). Changing the priority of the BLESS interrupt has no effect, because we disable ALL interrupts, regardless of priority.

The example you mentioned isn't helpful, because it goes to sleep with interrupts enabled. We already know that this is possible, but it does not work for our application. In an RTOS based applications like ours, we need to disable interrupts to avoid a race condition that exists if an interrupt fires while we are putting the device to sleep in the Idle thread. We specifically need to know if it is possible to put the BLE component into deep sleep while interrupts are disabled.

0 Likes

Hello,

Could you please let me know the reason to wrap Cy_SysPm_DeepSleep into Cy_SysLib_EnterCriticalSection() ?

Inside the DeepSleep function, it will enter into the criticalsection.

Thanks,

P Yugandhar.

0 Likes

There is a race condition if an interrupt occurs that unblocks a task before the device goes to sleep. In that case, because the FreeRTOS scheduler is disabled while going to sleep, the task will not run, control will return to the Idle task, and the device will go to sleep. The task will run after the device wakes from sleep the next time, from another interrupt, but that could be several hundred milliseconds later.


This is a simplified version of our sleep routine today. We've reduced the window of time where an interrupt could cause this race condition by moving the check that all tasks are still idle (eTasksConfirmSleepModeStatus()) as close as possible to the call to enter deep sleep. However, we still see cases where interrupts fire after that check and before the WFI instruction inside Cy_SysPm_DeepSleep(), causing us to hit this race condition where we go to sleep even though tasks are unblocked and ready to run.

void power_sleep_with_timer(uint32_t period)
{
    // The scheduler is already disabled when entering this function.
    // No other tasks will run until this functio exits.

    lp_wakeup_timer_start(period);

    disableSystick();

    // Check if any tasks have been unblocked by interrupts
    if (eAbortSleep != eTaskConfirmSleepModeStatus())
    {
        // If an interrupt occurs here that unblocks a task,
        // the system will still go to sleep instead of running the task.
        // Because the interrupt was already serviced, no interrupts are
        // pending, and the WFI instruction will put the device to sleep
        Cy_SysPm_DeepSleep(CY_SYSPM_WAIT_FOR_INTERRUPT);
    }

    enableSystick();

    lp_wakeup_timer_stop();
}

The following is what we would like to do instead. In this case, even if an interrupt occurs before we go to sleep, it will still be pending when we execute the WFI instruction. In that case, we will immediately exit from sleep, restart the scheduler, and run the unblocked task.

void power_sleep_with_timer(uint32_t period)
{
    // The scheduler is already disabled when entering this function.
    // No other tasks will run until this functio exits.

    uint32_t int_status = Cy_SysLib_EnterCriticalSection();

    // Interrupts are disabled, check if any task is ready to run
    if (eAbortSleep == eTaskConfirmSleepModeStatus())
    {
        goto exit;
    }

    lp_wakeup_timer_start(period);

    disableSystick();

    // If an interrupt has fired after entering the critical section,
    // then the following call will return immediately when it
    // executes the WFI instruction
    Cy_SysPm_DeepSleep(CY_SYSPM_WAIT_FOR_INTERRUPT);

    enableSystick();

    lp_wakeup_timer_stop();

exit:
    Cy_SysLib_ExitCriticalSection(int_status);

    // ISRs can now execute and will unblock tasks if necessary
}
0 Likes
lock attach
Attachments are accessible only for community members.

Hello,

Please refer to the attached file, where you can register syspm cb "Task checker" which will have higher order, so it will execute the latest in cb list.

Thanks,
P Yugandhar.

0 Likes

Hello,

Thank you for this proposal. Our version of the PDL (3.1) does not have an order field in the cy_stc_syspm_callback_t structure. The copy of cy_syspm.c that we have appears to execute callbacks in the order that they were registered (or sometimes in the reverse order). It seems that we could achieve something similar to what you propose by registering our task checker callback last during system initialization, but this is a brittle solution that could lead to non-obvious bugs during a later refactoring if the order of initialization of our drivers is changed. What version of the PDL has the order functionality that you utilize in your example?

Thanks,
Sam

0 Likes

Hi,

I tried implementing what I described above, adding this callback and ensuring it is the last registered, but it still doesn't work. This is because the task checker callback is executed in the "CHECK_READY" state, but the problematic BLE callback is executed in the "BEFORE_TRANSITION" state, which happens after "CHECK_READY". The task_checker callback can't execute in the "BEFORE_TRANSITION" state because the cy_syspm module doesn't check the result of callbacks executed in the "BEFORE_TRANSITION" state, so the task checker could not abort the sleep process there.

0 Likes

Hi Sam,

Your behavior  is unexpected, because BLE syspm callback does not use BEFORE_TRANSITION state (refer to Cy_BLE_DeepSleepCallback function).

if you use SysPm without "order" field (was introduced in Syspm 4.20 refer to https://cypresssemiconductorco.github.io/psoc6pdl/pdl_api_reference_manual/html/group__group__syspm....  ) you should call  register_syspm_cb_task_lp (from P Yugandhar example) after Cy_BLE_Enable().

Regards,
Nazar

0 Likes