Hi James
>> But perhaps these are cleared automatically when entering a sleep mode that uses them? Or, maybe you only need to clear them if you plan on looking at them when you next wake up??
Since the LLWU is in fact only active when the LLS mode is entered I could imagine that only the flags for the enabled sources need to be cleared before entering/re-entering the mode. However, I also think that it is good practice to clear the flags consistently and this is always done and 'may' solve issues when not doing so, but I never tested doing it in a different fashion.
I have posted some more code from the uTasker project in case it gives any ideas. The actual LLWU is very simple (the uTasker project allows multiple interrupt handlers to be managed as well as multiple LLWU_Px pins to be assigned to each, which makes it look a bit more complicated, Most of the potentially more difficult stuff is correctly managing moving in and out of the modes, which is why I wrote that it will depend on how well the MQX / PE frame-work is prepared as to whether the "overall" operation is suitable. There is usually some preparation to be performed before going to the mode (as well as delaying in case of critical system operation) if you want to recover later, plus some clean-up work after the wake up - before the actual LLWU interrupt is called.
Regards
Mark
This is the interrupt routine that handles LLWU pins and modules as three separate entities (since the pins are spead over two registers and the modules over a third).
static __interrupt void _wakeup_isr(void)
{
fnHandleWakeupSources(LLWU_FLAG_ADDRESS, 0); // handle the LLWU_P0..P7 input source(s) that woke the processor
fnHandleWakeupSources((LLWU_FLAG_ADDRESS + 1), 8); // handle the LLWU_P8..P5 input source(s) that woke the processor
fnHandleWakeupSources((LLWU_FLAG_ADDRESS + 2), 16); // handle the LLWU_M0..7 peripheral source(s) that woke the processor
}
The generic handling routine (allowing a user interrupt callback on each possible source and also allowing multiple ones to be handled in case a wakeup was due to multiple sources at the same time) is below:
static void fnHandleWakeupSources(volatile unsigned char *prtFlagRegister, int iSouceStart)
{
register unsigned char ucBit;
register unsigned char ucFlags = *prtFlagRegister;// check whether a source woke the processor
if (ucFlags == 0) {
return;
}
ucBit = 0x01;
while (ucFlags != 0) { // while sources are flagged
if (ucFlags & ucBit) {
ucFlags &= ~ucBit;
*prtFlagRegister = ucBit; // reset the interrupt flag (write '1' to clear)
if (wakeup_handlers[iSouceStart] != 0) { // if there is a user handler for the source
uDisable_Interrupt(); // ensure interrupts remain blocked when user callback operates
wakeup_handlers[iSouceStart]();
uEnable_Interrupt();
}
}
iSouceStart++;
ucBit <<= 1;
}
}
The actual configuration of the pins (as noted, it looks complicated since it allow multiple pins to be configured at the same time and has a map to convert between port pins and LLWU pins available on the particular Kinetis part) does:
// The port inputs are now mapped to available LLWU pins (pins that do not have LLWU functionality will not be configured)
//
while (ulPortBits != 0) { // handle each bit on the port
if (waveup_interrupt->int_port_bits & ulBit) { // if the port bit is to be enabled
if (cWakeupPorts[waveup_interrupt->int_port][iBitRef] != NO_WAKEUP) {
int iShift = ((cWakeupPorts[waveup_interrupt->int_port][iBitRef]%4) * LLWU_PE_WUPE_SHIFT);
volatile unsigned char *ptrFlagRegister = LLWU_FLAG_ADDRESS + (cWakeupPorts[waveup_interrupt->int_port][iBitRef]/8);
unsigned char *ptrWakeupEnable = (unsigned char *)LLWU_BLOCK + (cWakeupPorts[waveup_interrupt->int_port][iBitRef]/4); // set the enable register pointer
unsigned char ucValueMask = (LLWU_PE_WUPE_MASK << iShift); // set the mask in the enable register
*ptrWakeupEnable &= ~ucValueMask; // disable the wakeup functionality
wakeup_handlers[cWakeupPorts[waveup_interrupt->int_port][iBitRef]] = waveup_interrupt->int_handler; // enter the user interrupt handler for this wakeup input
fnEnterInterrupt(irq_LL_wakeup_ID, waveup_interrupt->int_priority, _wakeup_isr); // ensure that the handler is entered
*ptrFlagRegister = (LLWU_F_WUF0 << (cWakeupPorts[waveup_interrupt->int_port][iBitRef]%8)); // reset pending flags
*ptrWakeupEnable |= (ucInterruptType << iShift); // set/enable the type required
}
else {
_EXCEPTION("Invalid wakeup port bit being selected!");
}
ulPortBits &= ~ulBit;
}
ulBit <<= 1;
iBitRef++;
}
For each pin enabled, the sequence (in the middle) is however:
1. Disable the pin's wakeup functionality (although it isn't actually function in the processor's RUN state any way)
2. Enter its (new) interrupt handler
3. Reset pending flags on the source
4. Set the pin mode to enable its operation
In fact there are only about about 4 lines of code that actually do any LLWU register/interrupt configuration - the rest is more overall system design/operation on the bigger scale.