No ADC interrupt after deep sleep on LPC845

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

No ADC interrupt after deep sleep on LPC845

1,193 Views
davidingleby-od
Contributor I

Hello,

We have an LPC845 application that uses the internal  ADC and this is working without a problem until we enter and exit deep sleep mode, whereupon no further ADC interrupts are generated.

The following code is used to enter deep sleep with a WKT interrupt waking the device after a variable period of time:

void sleep(uint32_t timeout)
{

// Setup the WKT timer and configure power down control
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_ADC);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_GPIO0);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_GPIO1);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_GPIOINT);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_IOCON);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_SWM);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_WKT);
Chip_PMU_SetPowerDownControl(LPC_PMU, PMU_DPDCTRL_LPOSCEN | PMU_DPDCTRL_LPOSCDPDEN | PMU_DPDCTRL_WAKEUPPAD | PMU_DPDCTRL_WAKEUPPAD2);
Chip_SYSCON_PeriphReset(RESET_WKT);
Chip_SYSCON_EnablePeriphWakeup(SYSCON_STARTER_WKT);
NVIC_EnableIRQ(WKT_IRQn);

// Record current peripheral power status ready for wakeup
// and configure power down configuration
LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG;
Chip_SYSCON_SetDeepSleepPD((1<<SYSCON_PDRUNCFG_BOD) | (1<<SYSCON_PDRUNCFG_WDTOSC));
Chip_SYSCON_DisableBODReset();

// Turn all LEDs off
Chip_GPIO_SetPinState(LPC_GPIO_PORT, 0, GPIO_LED_RED, pinHigh);
Chip_GPIO_SetPinState(LPC_GPIO_PORT, 0, GPIO_LED_GREEN, pinHigh);
Chip_GPIO_SetPinState(LPC_GPIO_PORT, 0, GPIO_LED_BLUE, pinHigh);

// Turn off peripheral clocks to save power
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_ADC);
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_UART0);
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_UART1);
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_UART2);
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_IOCON);
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_SWM);
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_GPIO0);
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_GPIO1);

// Set the WKT to timeout * 10
Chip_WKT_Start(LPC_WKT, WKT_CLKSRC_10KHZ, timeout * 10);

// Enter sleep awaiting WKT interrupt
Chip_PMU_Sleep(LPC_PMU, PMU_MCU_POWER_DOWN);

// Stop the WKT on wakeup
Chip_WKT_Stop(LPC_WKT);

// Jumps the system timer forward by the sleep period
Platform_jumpTick(timeout);

// Re-initialise ADC
adc_init();

}

and this is the IRQ handler which re-enables the peripheral clocks upon WKT interrupt:

void WKT_IRQHandler(void)
{
Chip_WKT_ClearIntStatus(LPC_WKT);
SCB->SCR &= ~(1<<2);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_ADC);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_UART0);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_UART1);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_UART2);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_GPIO0);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_GPIO1);

}

The application also uses three UARTs and a number of other peripherals which work after deep sleep exit so its only the ADC that is the problem.

To ensure that the ADC is re-initialised and re-calibrated after deep sleep we also call adc_init() again after exit:

void adc_init(void)
{
// Setup ADC for 12-bit mode and normal power
Chip_ADC_Init(LPC_ADC, 0);

// Enable clock, and divide-by-1 at this clock divider
LPC_SYSCON->ADCCLKDIV = 1;
LPC_SYSCON->ADCCLKSEL = 0;

// Calibrate ADC
Chip_ADC_StartCalibration(LPC_ADC);
while (!(Chip_ADC_IsCalibrationDone(LPC_ADC))) {}

// Setup for maximum ADC clock rate using synchronous clocking
Chip_ADC_SetClockRate(LPC_ADC, 10000000);

// Setup a sequencer to read from ADC0
Chip_ADC_SetupSequencer(LPC_ADC, ADC_SEQA_IDX, (ADC_SEQ_CTRL_CHANSEL(0) | ADC_SEQ_CTRL_MODE_EOS));

// Enable the clock to the Switch Matrix before assigning pins
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_SWM);

// Configure the SWM for P0_7 as the input for the ADC0
Chip_SWM_FixedPinEnable(SWM_FIXED_ADC_0, 1);

// Disable the clock to the Switch Matrix to save power
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_SWM);

// Clear all pending interrupts
Chip_ADC_ClearFlags(LPC_ADC, Chip_ADC_GetFlags(LPC_ADC));

// Enable ADC overrun and sequence A completion interrupts
Chip_ADC_EnableInt(LPC_ADC, (ADC_INTEN_SEQA_ENABLE | ADC_INTEN_OVRRUN_ENABLE));

// Enable ADC NVIC interrupt
NVIC_EnableIRQ(ADC_SEQA_IRQn);

// Enable sequencer
Chip_ADC_EnableSequencer(LPC_ADC, ADC_SEQA_IDX);

// Manual start for ADC conversion sequence A
Chip_ADC_StartSequencer(LPC_ADC, ADC_SEQA_IDX);

}

We have checked all the PDRUNCFG, NVIC and SYSAHBCLK0CTRL registers after exit and these all indicate that the ADC is functional but we do not get any further ADC interrupts until we hard reset the device.

Any help would be very much appreciated.

David

Labels (1)
0 Kudos
Reply
1 Reply

1,098 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello David Ingleby-Oddy,

How about reset  the ADC module after wake up, refer to the reset function under SDK:

static void RESET_SetPeripheralReset(reset_ip_name_t peripheral)
{
const uint32_t regIndex = ((uint32_t)peripheral & 0xFFFF0000u) >> 16;
const uint32_t bitPos = ((uint32_t)peripheral & 0x0000FFFFu);
const uint32_t bitMask = 1u << bitPos;

assert(bitPos < 32u);

/* reset register is in SYSCON */

if (0u == regIndex)
{
/* set bit */
SYSCON->PRESETCTRL0 &= ~bitMask;
}
if (1u == regIndex)
{
/* set bit */
SYSCON->PRESETCTRL1 &= ~bitMask;
}
}

If still can't work, there is low power and ADC demo under SDK, you can have a look.


Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
Reply