AnsweredAssumed Answered

QN908x and AN01786

Question asked by Xavier Vilajosana on Nov 10, 2017
Latest reply on Nov 14, 2017 by Rodríguez

Hi,

 

I looked at the AN01786 and tried to reproduce the measurements. I followed all the steps as indicated in the document. To give further details:

 

1) using MCUXpresso in WIndows

2) SDK 2.2 Beta

3) user project: qn908xcdk_wireless_examples_bluetooth_power_profiling_freertos

4) added the symbol cQN_UsePowerDownMode in the project configuration.

 

I flashed the code in the board and executed while running the debugger. The button interaction seems correct and leds change color until the device starts advertising. 

 

Then I moved forward and stopped the debugger and tried to measure consumption. The first think I noticed is that after pressing 1 time the button number 1 the device stops to be responsive, i.e despite I press the button 100 times it does not execute the next step in the state machine (i.e changing led color to green, red, etc...)

 

I started digging into the code and some things are not working well.

 

1) the Code example says the application starts in PM1 but looking the hardware_init function it starts in sleep

 

#if (cQN_UsePowerDownMode)
SetGpioWakeupLevel(BOARD_SW_GPIO, BOARD_SW1_GPIO_PIN, 0U);
SetGpioWakeupLevel(BOARD_SW_GPIO, BOARD_SW2_GPIO_PIN, 0U);
PM_SetReq(kPmSleep, kPmReqUserPolicy); // kPmReqBle);kPmPowerDown0
#endif

 

looking at the state machine in the function 

void BleApp_HandleKeys(key_event_t events)

 

I can see that the correct Power Levels are set  

... e.g., 

PM_SetReq(kPmPowerDown0, kPmReqUserPolicy);

 

and I assume those are entered not at tha moment but when the Idle task is executed, when the 

PM_PowerManagement();

function is called

 

My feeling is that the GPIO state interrupts from the buttons are not stored/recovered after kPmPowerDown0 and hence the board cannot wake up from the sleep mode. I tried several things such as calling the function 

 

/* Reinitialize peripherals after waked up from PD, this function will be called in critical area */
void BOARD_WakeupRestore(void)
{
/* Enable FPU after sleep */
#if ((__FPU_PRESENT == 1) && (__FPU_USED == 1)) || (defined(__VFP_FP__) && !defined(__SOFTFP__))
SCB->CPACR |= 0x00f00000; /* set CP10, CP11 Full Access */
#endif

/* initialize all the GPIO pins for keyboard */
GPIO_SetFallingEdgeInterrupt(GPIOA , sw_pins_mask);
GPIO_EnableInterrupt(GPIOA, sw_pins_mask);
NVIC_EnableIRQ(GPIOA_IRQn);

}

 

in board.c. I looked what component is calling that function and nobody calls it in this example. (Maybe the PM_Management internally but I looked at the assembler code and it does not look so)

 

Can you please let me know what I am missing? I assume that if someone has done the AN01786 the used code should be available somewhere. 

 

 

I also did another test. I took the code in the qn908xcdk_demo_apps_power_mode_switch example application. In there I can see a simple state machine that according to the sleep mode executes the required actions. As the code works (because I tested and measured it) I assumed that would work too if I replace the

PM_PowerManagement() function call in the Idle task.

 

Hence my idle task looked like this now:

static void App_Idle(void)
{
//PM_PowerManagement();
power_mode_t status = getPowerModeStatus(); // gets the status set by the button handler function
switch (status)
{
case kPmActive:
break;
case kPmSleep:
CLOCK_DisableClock(kCLOCK_Flexcomm0);
POWER_EnterSleep();
CLOCK_EnableClock(kCLOCK_Flexcomm0);
break;
case kPmPowerDown0:
__disable_irq();
switch_to_OSC32M();
POWER_LatchIO();
CLOCK_DisableClock(kCLOCK_Flexcomm0);
POWER_EnterPowerDown(0);
CLOCK_EnableClock(kCLOCK_Flexcomm0);
POWER_RestoreIO();
switch_to_XTAL();
/* after waking up from pwoer down, usart config is lost, recover it */
BOARD_WakeupRestore();
__enable_irq();
break;
case kPmPowerDown1:
/* Enable GPIO wakeup */
NVIC_ClearPendingIRQ(EXT_GPIO_WAKEUP_IRQn);
NVIC_EnableIRQ(EXT_GPIO_WAKEUP_IRQn);
__disable_irq();
switch_to_OSC32M();
#if (defined(BOARD_XTAL1_CLK_HZ) && (BOARD_XTAL1_CLK_HZ == CLK_RCO_32KHZ))
POWER_WritePmuCtrl1(SYSCON, SYSCON_PMU_CTRL1_RCO32K_DIS_MASK, SYSCON_PMU_CTRL1_RCO32K_DIS(1U));
#elif(defined(BOARD_XTAL1_CLK_HZ) && (BOARD_XTAL1_CLK_HZ == CLK_XTAL_32KHZ))
POWER_WritePmuCtrl1(SYSCON, SYSCON_PMU_CTRL1_XTAL32K_DIS_MASK, SYSCON_PMU_CTRL1_XTAL32K_DIS(1U));
#endif
POWER_LatchIO();
POWER_EnterPowerDown(0);
POWER_RestoreIO();
switch_to_XTAL();

NVIC_DisableIRQ(EXT_GPIO_WAKEUP_IRQn);
NVIC_ClearPendingIRQ(EXT_GPIO_WAKEUP_IRQn);

#if (defined(BOARD_XTAL1_CLK_HZ) && (BOARD_XTAL1_CLK_HZ == CLK_RCO_32KHZ))
POWER_WritePmuCtrl1(SYSCON, SYSCON_PMU_CTRL1_RCO32K_DIS_MASK, SYSCON_PMU_CTRL1_RCO32K_DIS(0U));
#elif(defined(BOARD_XTAL1_CLK_HZ) && (BOARD_XTAL1_CLK_HZ == CLK_XTAL_32KHZ))
POWER_WritePmuCtrl1(SYSCON, SYSCON_PMU_CTRL1_XTAL32K_DIS_MASK, SYSCON_PMU_CTRL1_XTAL32K_DIS(0U));
#endif
/* after waking up from pwoer down, usart config is lost, recover it */
BOARD_WakeupRestore();
__enable_irq();
break;
default:
break;
}
}

 

I tested again, and the same happens. While with the debugger I can execute correctly the application (I assume that PM is not executed when SWD or JTAG are active) as soon as I stop the debugger the device stays in PM0 and cannot recover it. 

To reflash it I need to reset it right before the debugger starts as it stays in PM0 and seems to be not responsive to the JTAG otherwise.

 

any help on this is welcome!

 

X

-

Outcomes