In our project, we are reading switches using analog(Port AD)
My requirement is to wake up MCU from stop mode when the switch is pressed longer than 20ms.
How can I implement this?
Can you provide me some example to wake up MCU from stop mode when the switch is pressed.
There are more options for how to solve it.
The first option is using port interrupt with wake-up capability. Unfortunately, this interrupt may detect only a single edge type in the time (falling or rising). The edge type may be changed runtime, however, it is not an atomic operation and it might fail due to glitches at such asynchronous source like a push-button (we may simply miss next edge).
A partial workaround is detection just first edge (e.g. falling edge) and waits 20ms before a simple test of pin logic value. For these 20ms we may use any already initialized periodic interrupt or use one output compare timer channel.
The pins with interrupt and key-wakeup capability (Ports AD, S, P and L at S12ZVL) already contain a digital filter on each pin that prevents short pulses from generating an interrupt. A valid edge on an input is detected if 4 consecutive samples of a passive level are followed by 4 consecutive samples of an active level. Else the sampling logic is restarted. However, this does not fit with the requested 20ms interval (it is just at least 10us for MCU in stop mode).
The more robust solution is using any pin routed to the timer (port T, optionally rerouted to the port P or S). The timer may detect both edges and the time between them may by measured preciously. This allows also do an action only when push button is really released.
I attached simple example codes for the timer – generating intervals via output compare and time measurement via input capture.
Of course, there may be more ways how to do it.
I hope it helps you.
I implemented using Pin interrupts and Key-Wakeup (KWU). It is working fine for SW8 but it is not working for SW9.
My primary assumption is when we press a switch that time not getting the required voltage level.
I implemented it as follows.
//Digital Input Function Enable -- digital in  analog in
DIENADL_DIENADL0 = 1;
__asm(ANDCC #0x7F); // CCW settings: S = 0, I = 0
SCI0ASR1_RXEDGIF = 1; // clear flag
SCI0ACR1_RXEDGIE = 1; // edge interrupt enabled for wake up
//Interrupt enable register -  Enable  Disable
PIEAD_PIEADL0 = 1;
//1 - Pull-down device selected; rising edge selected
//0 - 0 Pull-up device selected; falling edge selected
PPSAD_PPSADL0 = 0;
//After come out of stop mode disable interrupts
SCI0ACR1_RXEDGIE = 0;
SCI0ACR1_RXEDGIE = 0;
DIENADL_DIENADL0 = 0;
#pragma CODE_SEG __NEAR_SEG NON_BANKED
if (PIFADL_PIFADL1 == 1
PIFADL_PIFADL0 = 1;
State = Operating;
#pragma CODE_SEG DEFAULT
Please suggest to me if you have any alternate solution or need some modification from the SW/HW side.
Yes, the problem with the voltage level make sense.
If we assume resistor values according to the scheme in this thread, then:
SW8=OFF, SW9=OFF Vad0=VDDX
SW8=OFF, SW9=ON Vad0=VDDX*(820+1500)/(820+1500+3000)=0.44*VDDX
SW8=ON, SW9=OFF Vad0=VDDX*(820)/(820+3000)=0.21VDDX
The influence of the MCU internal impedance will be rather negligible in this case.
According to the reference manual, the maximum low voltage is 0.35*VDDX for 5V VDDX voltage or 0.3*VDDX for 3.3V VDDX voltage
Just a few notes regarding your code:
1. the EnableInterrupts; macro is the same as __asm(CLI);
So, we may remove the __asm(CLI); line.
I would like to recommend enable interrupts just prior STOP instruction for avoiding interrupt triggers before STOP mode initialization. Lines EnableInterrupts; directly followed by __asm(STOP); are correct.
2. You don't need to clear S-bit in every STOP mode entry. It may be part of MCU's initialization (just once after MCU reset).
3. If you use this AD pin just for wake-up (no analog), you may set up a digital buffer once during initialization.
4. I would like to recommend strictly not use commands like PIFADL_PIFADL0 = 1; for flag clearing (for registers with two or more flags). This command will clear all pending flags in PIFADL register (it is read/modify/write command). Please use for example commands like PIFADL=0x01; or PIFADL = PIFADL_PIFADL0_MASK for clearing single flag. For more details please check AN2554 Clearing and Disabling Interrupt Flags
I hope it helps you.