Not applicable
Sep 11, 2013
02:57 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sep 11, 2013
02:57 AM
Power consumption is always been a concern to most developer when design a new product.
In XMC1000 device, there is deep sleep mode where MCLK and PCLK is switch to standby clock.
Peripherals that continue to operate will run using the slow standby clock and can eventually generate an event to wake-up the CPU.
To enter this mode, application should:
Here's the example code for enter deep sleep mode:
In XMC1000 device, there is deep sleep mode where MCLK and PCLK is switch to standby clock.
Peripherals that continue to operate will run using the slow standby clock and can eventually generate an event to wake-up the CPU.
To enter this mode, application should:
1. Enable access to protected registers
2. Setup VDDC monitoring timer
3. Set PPB.SCR.SLEEPDEEP = 1
4. Put the ACMP into low power mode AND/OR Disable the ACMPs
5. Gate off any unused peripherals and wait for VDDC to stabilize
6. Slow down the MCLK, PCLK and RTC
7. Power Off the flash (via PWRSVCR.FPD)
8. Execute a WFE or WFI instruction
Here's the example code for enter deep sleep mode:
void DeepSleep(void)
{
volatile u32 idiv = 0;
__disable_irq(); //disable all interrupts
SCU_GENERAL->PASSWD = CLK002_DIRECT_ACCESS_ALLOW; // Open the lock that protects privileged bits.
while(((SCU_GENERAL->PASSWD)&SCU_GENERAL_PASSWD_PROTS_Msk)); // Loop until protection is removed.
SCU_CLK->CLKCR |= 0x3ff00000UL; // CNTADJ = 0x3ff, For VDDC monitoring
PPB->SCR |= PPB_SCR_SLEEPDEEP_Msk; // Setup for Deep Sleep instead of normal sleep
COMPARATOR->ANACMP0 |= COMPARATOR_ANACMP0_CMP_LPWR_Msk; // Put Comparator into low power mode
COMPARATOR->ANACMP0 &= ~(COMPARATOR_ANACMP0_CMP_EN_Msk); // Disable ACMP0
COMPARATOR->ANACMP1 &= ~(COMPARATOR_ANACMP1_CMP_EN_Msk); // Disable ACMP1
COMPARATOR->ANACMP2 &= ~(COMPARATOR_ANACMP2_CMP_EN_Msk); // Disable ACMP2
SCU_CLK->CGATSET0 = 0x07FFUL; // Gate Off all peripherals
WR_REG(SCU_CLK->CLKCR, SCU_CLK_CLKCR_CNTADJ_Msk, SCU_CLK_CLKCR_CNTADJ_Pos,(0x3FFU));
while ((SCU_CLK->CLKCR) & 0xC0000000UL); // Wait for VDDC to stabilize
/* Ramp down Frequency */
idiv = (SCU_CLK->CLKCR & SCU_CLK_CLKCR_IDIV_Msk)>>SCU_CLK_CLKCR_IDIV_Pos;
while (idiv < 255)
{
idiv = idiv << 2;
WR_REG(SCU_CLK->CLKCR, SCU_CLK_CLKCR_IDIV_Msk, SCU_CLK_CLKCR_IDIV_Pos, idiv);
WR_REG(SCU_CLK->CLKCR, SCU_CLK_CLKCR_CNTADJ_Msk, SCU_CLK_CLKCR_CNTADJ_Pos,(0x3FFU));
while ((SCU_CLK->CLKCR) & 0xC0000000UL); // Wait for VDDC to stabilize
if (idiv > 255)
idiv = 255;
}
/* Step Down PCLK to equal MCKL, set RTC to internal clock */
SCU_CLK->CLKCR = 0x3ff0FFFFUL; // CNTADJ = 0x3ff, MCLK = PCLK = 125kHz
while ((SCU_CLK->CLKCR) & 0xC0000000UL); // Wait for VDDC to stabilize
SCU_CLK->PWRSVCR |= SCU_CLK_PWRSVCR_FPD_Msk; // make sure flash powers down during deep sleep
SCU_GENERAL->PASSWD = CLK002_DIRECT_ACCESS_DISALLOW; // Close the lock opened above.
__WFI(); // Go To Deep Sleep
}
7 Replies
Not applicable
Mar 20, 2014
08:30 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mar 20, 2014
08:30 PM
Hi Jackson,
base on this code, MCU won't waked up by any interrupt event right?
How to create software event to awake MCU?
Regards,
iamten
base on this code, MCU won't waked up by any interrupt event right?
How to create software event to awake MCU?
Regards,
iamten
Mar 24, 2014
03:28 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mar 24, 2014
03:28 AM
IMO there are other issues:
The "while (idiv < 255)" can loop until idiv = 254, then idiv is multiplied by four (idiv = idiv << 2), causing an overflow since idiv is an 8 bit value.
The "if (idiv > 255) idiv = 255;" check after writing the value is useless.
I don't see why idiv needs to be declared volatile.
CNTADJ seems to be written twice (using different methods) - why?
Oliver
The "while (idiv < 255)" can loop until idiv = 254, then idiv is multiplied by four (idiv = idiv << 2), causing an overflow since idiv is an 8 bit value.
The "if (idiv > 255) idiv = 255;" check after writing the value is useless.
I don't see why idiv needs to be declared volatile.
CNTADJ seems to be written twice (using different methods) - why?
Oliver
Not applicable
Mar 25, 2014
02:42 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mar 25, 2014
02:42 AM
iamten wrote:
Hi Jackson,
base on this code, MCU won't waked up by any interrupt event right?
How to create software event to awake MCU?
Regards,
iamten
Hi iamten,
It is possible to wake up from interrupt as long as the peripheral did not turn off and the interrupt is enabled.
You can use the RTC to created an interrupt to wake up the MCU.
obetz wrote:
IMO there are other issues:
The "while (idiv < 255)" can loop until idiv = 254, then idiv is multiplied by four (idiv = idiv << 2), causing an overflow since idiv is an 8 bit value.
The "if (idiv > 255) idiv = 255;" check after writing the value is useless.
I don't see why idiv needs to be declared volatile.
CNTADJ seems to be written twice (using different methods) - why?
Oliver
Hi Oliver,
Basically the idea is to ramp down the SCU_CLK->CLKCR.IDIV in the step of 4 (e.g.: 0x01 -> 0x04 -> 0x08...)
So it doesn't really matters how you code it as long as the clock is ramp down slowly.
Mar 25, 2014
10:13 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mar 25, 2014
10:13 AM
Hello Jackson,
I did understand what you intended basically, but I'm afraid the code you posted doesn't work and can end with a very high clock and an illegal transition. Let me know if my error report was not clear enough, I can try to explain in other words.
Besides the error, I described also two more things I don't understand (volatile idiv, CNTADJ written twice) likely doing no harm. Nevertheless it would be interesting to know your intention behind this or whether I simply overlooked the reason.
Oliver
I did understand what you intended basically, but I'm afraid the code you posted doesn't work and can end with a very high clock and an illegal transition. Let me know if my error report was not clear enough, I can try to explain in other words.
Besides the error, I described also two more things I don't understand (volatile idiv, CNTADJ written twice) likely doing no harm. Nevertheless it would be interesting to know your intention behind this or whether I simply overlooked the reason.
Oliver
Not applicable
Mar 26, 2014
08:24 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mar 26, 2014
08:24 AM
Agree with Oliver's comments about the use of keyword volatile and multiple writes to CNTADJ (including in the while loop), which seem to be redundant.
Ditto about the check for idiv > 255. This should come before the write to IDIV bit field, otherwise divider is bypassed just before exiting the while loop?
Ditto about the check for idiv > 255. This should come before the write to IDIV bit field, otherwise divider is bypassed just before exiting the while loop?
while (idiv < 255)
{
idiv = idiv << 2;
if (idiv > 255)
idiv = 255;
WR_REG(SCU_CLK->CLKCR, SCU_CLK_CLKCR_IDIV_Msk, SCU_CLK_CLKCR_IDIV_Pos, idiv);
WR_REG(SCU_CLK->CLKCR, SCU_CLK_CLKCR_CNTADJ_Msk, SCU_CLK_CLKCR_CNTADJ_Pos,(0x3FFU));
while ((SCU_CLK->CLKCR) & 0xC0000000UL); // Wait for VDDC to stabilize
}
Mar 26, 2014
08:54 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mar 26, 2014
08:54 AM
Even better would be to use the correct condition for the while() loop:
As I wrote, the "idiv < 255" condition would pass until idiv=254.
Since we want to avoid idiv being larger than 255 after the multiplication, we have to guarantee that idiv*4 ("<<2" is useless obfuscation) will not overflow.
Therefore the max. value before the *4 operation is 63. 64 will overflow.
"while (idiv < 64)" or "while (idiv <= 63)" will do the job, no further test is needed.
The original code will overflow and write zero to CLKCR.IDIV with most starting values. For example, starting with idiv=1 produces 4-16-64-256. The latter will be masked to zero and MCLK will jump from 0,5MHz to 32MHz, far beyond the spec.
BTW: The XMC1100 documentation is rather vague about the influence of IDIV steps, there is still a "(TBC)" comment in 12.3.7.
Disclaimer: I didn't test what I wrote, so there is a certain chance of being wrong.
As I wrote, the "idiv < 255" condition would pass until idiv=254.
Since we want to avoid idiv being larger than 255 after the multiplication, we have to guarantee that idiv*4 ("<<2" is useless obfuscation) will not overflow.
Therefore the max. value before the *4 operation is 63. 64 will overflow.
"while (idiv < 64)" or "while (idiv <= 63)" will do the job, no further test is needed.
The original code will overflow and write zero to CLKCR.IDIV with most starting values. For example, starting with idiv=1 produces 4-16-64-256. The latter will be masked to zero and MCLK will jump from 0,5MHz to 32MHz, far beyond the spec.
BTW: The XMC1100 documentation is rather vague about the influence of IDIV steps, there is still a "(TBC)" comment in 12.3.7.
Disclaimer: I didn't test what I wrote, so there is a certain chance of being wrong.
Not applicable
Aug 07, 2017
03:54 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Aug 07, 2017
03:54 AM
Hi,
As far as I understand, when going to deep sleep mode the DCO1(96MHz oscillator) is disabled and then MCLK/PCLK is running from the standby clock (32kHz oscillator DCO2).
When the device wakes up from the deep sleep (e.g. via SysTick interrupt) I see that the MCLK/PCLK is switched back automatically to DCO1.
Is there an option to configure the device in such a way that after wake-up form deep sleep it:
- keeps DCO1(96MHz) off
AND
- runs from the standby clock (32kHz DCO2)?
Thanks.
PS: We are using a XMC1400 device
As far as I understand, when going to deep sleep mode the DCO1(96MHz oscillator) is disabled and then MCLK/PCLK is running from the standby clock (32kHz oscillator DCO2).
When the device wakes up from the deep sleep (e.g. via SysTick interrupt) I see that the MCLK/PCLK is switched back automatically to DCO1.
Is there an option to configure the device in such a way that after wake-up form deep sleep it:
- keeps DCO1(96MHz) off
AND
- runs from the standby clock (32kHz DCO2)?
Thanks.
PS: We are using a XMC1400 device