Bare-metal VLLS3 example with KDS on K10

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

Bare-metal VLLS3 example with KDS on K10

Jump to solution
2,582 Views
garylynch
Contributor IV

I am trying to generate a bare-metal test of the functionality of the VLLS3 mode on our MK10DN512 design using KDS 3.0.0 under Windows 7 in the simplest manner possible. That appears to be to put the processor to sleep when I close a switch on one GPIO port and wake it with a rising edge on the LLWU_P2 input, which I can also drive with a switch.

I have so far found examples that use another processor or are based on another IDE or build upon the HAL or some other framework that makes them difficult to understand for a beginner.

Has anyone built this project or something similar?

0 Kudos
1 Solution
1,517 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Gary Lynch,

Our FAE also transfer your question to me!

I already help you check your code, this code will enter in the DefaultISR, because I find in the void LLWU_init(void) function, it even didn't enable the LLWU module clock, then if you configure the LLWU register, it will enter in DefaultISR.

So you should write function LLWU_init(void) like this:

void LLWU_init(void) {

      /* + + + + + + + + + + + + + + + + + */

      /* Configure LLWU_P2 pin to trigger  */

      /* an interrupt on rising edge       */

      /* + + + + + + + + + + + + + + + + + */

// LLWU_PE1_REG(LLWU_BASE_PTR) =  (0x1U << 4);

//

  SIM_SCGC4 |= SIM_SCGC4_LLWU_MASK;

  LLWU_PE1 = LLWU_PE1_WUPE2(0X1);//rising wakeup

  LLWU_F1 = LLWU_F1_WUF2_MASK;

  return;

} /* END LLWU_init() */

Besides, I also help you do some modifications:

1, enable the internal pullup resistor in the PTE4 which used as the wakeup source.

2. The ENTER_VLLS3 function write as follows:

void ENTER_VLLS3(void)

{

volatile unsigned int dummyread;

SMC_PMPROT = SMC_PMPROT_AVLLS_MASK;

/* Set the STOPM field to 0b100 for VLLS3 mode */

SMC_PMCTRL &= ~SMC_PMCTRL_STOPM_MASK;

SMC_PMCTRL |= SMC_PMCTRL_STOPM(0x4);

SCB->SCR &= (unsigned int)~(unsigned int)(SCB_SCR_SLEEPONEXIT_Msk);

SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

/*wait for write to complete to SMC before stopping core */

dummyread = SMC_PMCTRL;

/* Now execute the stop instruction to go into LLS */

//stop();

__asm__("WFI"); //KDS

//asm("WFI"); //Iar

}

3. #define CLOCK_SETUP  as 0, then it will configure the system clock as the default clock, and also configure the according register as follows:

#if (CLOCK_SETUP == 0)

  #define DEFAULT_SYSTEM_CLOCK         20971520U           /* Default System clock value */

  #define MCG_MODE                     MCG_MODE_FEI /* Clock generator mode */

  /* MCG_C1: CLKS=0,FRDIV=0,IREFS=1,IRCLKEN=1,IREFSTEN=0 */

  #define SYSTEM_MCG_C1_VALUE          0x06U               /* MCG_C1 */

  /* MCG_C2: LOCRE0=0,RANGE0=2,HGO0=0,EREFS0=1,LP=0,IRCS=0 */

  #define SYSTEM_MCG_C2_VALUE          0x24U               /* MCG_C2 */

  /* MCG_C4: DMX32=0,DRST_DRS=0,FCTRIM=0,SCFTRIM=0 */

  #define SYSTEM_MCG_C4_VALUE          0x00U               /* MCG_C4 */

  /* MCG_SC: ATME=0,ATMS=0,ATMF=0,FLTPRSRV=0,FCRDIV=0,LOCS0=0 */

  #define SYSTEM_MCG_SC_VALUE          0x00U               /* MCG_SC */

  /* MCG_C5: PLLCLKEN0=0,PLLSTEN0=0,PRDIV0=0 */

  #define SYSTEM_MCG_C5_VALUE          0x00U               /* MCG_C5 */

  /* MCG_C6: LOLIE0=0,PLLS=0,CME0=0,VDIV0=0 */

  #define SYSTEM_MCG_C6_VALUE          0x00U               /* MCG_C6 */

  /* MCG_C7: OSCSEL=0 */

  #define SYSTEM_MCG_C7_VALUE          0x00U               /* MCG_C7 */

  /* OSC_CR: ERCLKEN=1,EREFSTEN=0,SC2P=0,SC4P=0,SC8P=0,SC16P=0 */

  #define SYSTEM_OSC_CR_VALUE          0x80U               /* OSC_CR */

  /* SMC_PMCTRL: LPWUI=0,RUNM=0,STOPA=0,STOPM=0 */

  #define SYSTEM_SMC_PMCTRL_VALUE      0x00U               /* SMC_PMCTRL */

  /* SIM_CLKDIV1: OUTDIV1=0,OUTDIV2=0,OUTDIV3=1,OUTDIV4=1 */

  #define SYSTEM_SIM_CLKDIV1_VALUE     0x00110000U         /* SIM_CLKDIV1 */

  /* SIM_SOPT1: USBREGEN=0,USBSSTBY=0,USBVSTBY=0,OSC32KSEL=3,RAMSIZE=0 */

  #define SYSTEM_SIM_SOPT1_VALUE       0x000C0000U         /* SIM_SOPT1 */

  /* SIM_SOPT2: SDHCsrc=0,USBsrc=0,PLLFLLSEL=0,TRACECLKSEL=0,PTD7PAD=0,FBSL=0,CLKOUTSEL=0,RTCCLKOUTSEL=0 */

  #define SYSTEM_SIM_SOPT2_VALUE       0x00U               /* SIM_SOPT2 */

After the above modification, I can use your  code working ok on my side, it will wait about 5 seconds then enter in the VLLS3, the power consumption is about 8uA.

Then if you give a external rising wave in the PTE4 pin, the MCU will wake up and wait 5 seconds, enter the VLLS3 again...

You can test my project on your side, the project is the KDS3.0 project, please find the project from the attachment.

Wish it helps you!

If you still have question, please let me know!

Have a great day,
Jingjing

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

View solution in original post

0 Kudos
19 Replies
1,517 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Gary Lynch,

    Please tell me the full name of your chip, actually, you can refer to the other Kinetis K series code, the code is the same.

   You should create a KDS K10 project at first, configure the LLUW wake up pin,and enter in the VLLS3 mode, then use the pin to wake up the VLLS3 mode.

   You can create the the KDS project by yourself, then copy the other IDE's low power code to your KDS project, and assoicate the K10 reference manual to test it.

   If you want to learn it, I suggest you refer to the code which you find and create the KDS project by yourself at first, if you have any problem, please contact me.

Have a great day,

Jingjing

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

0 Kudos
1,517 Views
garylynch
Contributor IV

Mark and Jingjing,

I am pursuing suggestions from the two of you. I may not complete the process today and if not it will be next year before I get back to it, but I have one question already.

Mark's sample code contains an ISR with the keyword '__interrupt' in front of the function return value. I had a project with an ISR that worked without this keyword, but when I try to use it I get error messages:
     ../Sources/main.c:117:13: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'void'

This leads to a broader question. I have never found a reference for the syntax of the C dialect accepted by my compiler. Do I get that from:

  • Freescale,
  • Eclipse,
  • GNU,
  • Elsewhere?

As I said above I have Kinetis Design Studio 3.0.0 and GNU ARM C/C++ Cross Compiler 1.12.1.201502281154.

When it comes to pre-processor directives and #pragmas and contructs at the fringes of the grammar would this info be even distributed?

Thanks for your insights.

0 Kudos
1,517 Views
mjbcswitzerland
Specialist V

Gary

#define __interrupt

That is, the __interrupt keyword is not actually used by most compilers (eg. GCC, IAR, Keil, Green Hills). But it makes it cleared that the code is an interrupt so it nevertheless comes in handy.

The exeption is the Cosmic compiler which needs

#define __interrupt @interrupt

Regards

Mark

0 Kudos
1,517 Views
garylynch
Contributor IV

Ok, I'm stuck on a couple of points.

1.  Several sources say the last thing I have to do to enter
    VLLS3 mode is set the SLEEPDEEP bit in the system
    control register.  The K10 reference manual:
    - http://cache.freescale.com/files/32bit/doc/ref_manual/K10P144M100SF2V2RM.pdf

    mentions such a register in chapter 47 (Secured digital
    host controller) but it appears to be a different system
    control register. ARM's generic user guide:
    - http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/DUI0553A_cortex_m4_dgug.pdf

    documents such a register in section 4.3.6, but I can't
    find any way to access it.

    Many examples call a CMSIS function, __wfi(), at this
    point.  Are they the same thing? If so, why doesn't
    anybody say this?

2.  I want to bring my processor out of VLLS3 mode with a
    rising edge on the LLWU_P2 input. I already have a
    working interrupt for a rising edge on port E, pin 4;
    PORTE_IRQHandler(), which is the same pin. It would
    appear I would put all my recovery code in another ISR:
    LLWU_IRQHandler().

    The question is, when LLWU_IRQHandler() exits, does it
    return control to the statement after __wfi()? I can't
    find any indication of this.

0 Kudos
1,517 Views
mjbcswitzerland
Specialist V

Gary

The Kinetis manuals cover the Kinetis peripheras and its ARM Cortex implementation. For details of the ARM Cortex core you need to use documents from the ARM web site; the details of the sleep mode and control register for it are found in the ARM documentation.

The Cortex instruction to command the sleep mode is  "wfi" (wait for interrupt) which is commanded in GCC or some other compilers with "asm("wfi")". IAR uses an intrinsic called __WFI() to do the same and Keil uses its intrinsic __wfi().

This controls the transition to the wait mode and a further ARM core register (SYSTEM_CONTROL_REGISTER) controls whether it goes to the standard wait or a SLEEPDEEP wait, where the core shuts off further clocks.

What happens outside the ARM core is up to the manufacturer's implementation based on these two states and the Kinetis then uses SMC_PMCTRL, MC_PMCTRL or SMC_STOPCTRL (depending on Kinetis part type) to further decide which clocks and power in the peripheral parts are stopped or removed in each of these states, thus generating more choices.

Pins can have interrupts assigned to them but the interrupts only operate when the processor is not in a Low Leakage power state. To exit the LL state a LLWU interrupt can be programmed on the same pin (when its function exists there) so that the same pin can wake the core.

After waking, the instruction after the wfi() is executed but interrupts are not yet enabled (they have to be disabled before executing the wfi() and remain disabled - it is not an interrupt that woke the processor but a 'masked, pending' interrupt). Which of your interrupts is taken then depends on what the code does - you don't need to use a LLWU interrupt handler if you don't want and you can use the pin handler exclusively, which will also have a pending interrupt at this moment if programmed for the same edge. Or you can allow both interrupt handlers to be called once you re-enable interrupts.

Finally note that the LLWU pin is only switched to this mode when actually in LL power mode so the pin acts exclusively as port interrupt before executing the "wfi" and exclusively as LLWU while in the LL mode, then the inverse after returning back to normal mode. You do have to be careful to clear LLWU interrupts that have fired before re-entering LL mode otherwise they will fire when not expected.

I also have various practical notes about the LLWU at http://www.utasker.com/kinetis/LLWU.html

Regards

Mark

1,517 Views
garylynch
Contributor IV

I have now coded and tested my first draft, source file attached. But first your questions/comments:

@Jingjing:


  • My processor is an MK10DN512VLQ10.
  • I based my test suite on examples I found on this forum, on Freescale app notes, and the processor data sheet.

@Mark:


  • I studied your code samples from 21 December, but they depend on your uTasker framework, which is a large black box for me--probably more work than understanding the K10.
  • It is still unclear to me how KDS distinguishes between a normal call to a function and an interrupt. An ISR must save and restore all the registers it clobbers, as well as end in an return-from-interrupt instruction, instead of return. Does the compiler rely on me using the standard ISR names from the CMSIS?
  • I implemented the pin interrupt on the corresponding LLWU input because "Power Management for Kinetis MCUs", AN4503, recommends it on p. 51, § 10.1.1.
  • You advised me to clear LLWU interrupts, but I can't find any instructions on how to do this. The Cortex M4 Generic User Guide goes so far as to state (p. 46): "The WIC is not programmable, and does not have any registers or user interface. It operates entirely from hardware signals."

The attached application is a simple finite state machine that powers up in normal run mode and relies on 2 switches to switch into and out of VLLS3 mode.

I have 3 software-controlled LEDs on the board and use different LED configurations to indicate the state of the FSM. I can't find absolute verification but suspect that the GPIO lines driving the LEDs will be tri-stated in the VLLS3 mode, so expect my LEds to be off in this state and not the status I write in firmware.

I drive the LEDs differently for 'awoken by LLWU' and 'awoken by GPIO pin' to assure me my processor awoke for the right reason.

According to the Cortex M4 Generic User Guide (p. 46) attaching a debugger to the processor disables the LLWU, so I ran all my tests in burn-and-learn mode, i.e. with the debugger detached.

When I run my test I see the normal run mode and in what shoiuld be VLLS3 mode the LEDs don't go dark, but assume the state I wrote in firmware. When I awaken the processor it indicates 'awoken by GPIO pin' state, leading me to believe it was never in VLLS3 mode.

Any suggestions would be appreciated, both about my code and how best to debug this without the debugger.

Thanks again.

0 Kudos
1,518 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Gary Lynch,

Our FAE also transfer your question to me!

I already help you check your code, this code will enter in the DefaultISR, because I find in the void LLWU_init(void) function, it even didn't enable the LLWU module clock, then if you configure the LLWU register, it will enter in DefaultISR.

So you should write function LLWU_init(void) like this:

void LLWU_init(void) {

      /* + + + + + + + + + + + + + + + + + */

      /* Configure LLWU_P2 pin to trigger  */

      /* an interrupt on rising edge       */

      /* + + + + + + + + + + + + + + + + + */

// LLWU_PE1_REG(LLWU_BASE_PTR) =  (0x1U << 4);

//

  SIM_SCGC4 |= SIM_SCGC4_LLWU_MASK;

  LLWU_PE1 = LLWU_PE1_WUPE2(0X1);//rising wakeup

  LLWU_F1 = LLWU_F1_WUF2_MASK;

  return;

} /* END LLWU_init() */

Besides, I also help you do some modifications:

1, enable the internal pullup resistor in the PTE4 which used as the wakeup source.

2. The ENTER_VLLS3 function write as follows:

void ENTER_VLLS3(void)

{

volatile unsigned int dummyread;

SMC_PMPROT = SMC_PMPROT_AVLLS_MASK;

/* Set the STOPM field to 0b100 for VLLS3 mode */

SMC_PMCTRL &= ~SMC_PMCTRL_STOPM_MASK;

SMC_PMCTRL |= SMC_PMCTRL_STOPM(0x4);

SCB->SCR &= (unsigned int)~(unsigned int)(SCB_SCR_SLEEPONEXIT_Msk);

SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

/*wait for write to complete to SMC before stopping core */

dummyread = SMC_PMCTRL;

/* Now execute the stop instruction to go into LLS */

//stop();

__asm__("WFI"); //KDS

//asm("WFI"); //Iar

}

3. #define CLOCK_SETUP  as 0, then it will configure the system clock as the default clock, and also configure the according register as follows:

#if (CLOCK_SETUP == 0)

  #define DEFAULT_SYSTEM_CLOCK         20971520U           /* Default System clock value */

  #define MCG_MODE                     MCG_MODE_FEI /* Clock generator mode */

  /* MCG_C1: CLKS=0,FRDIV=0,IREFS=1,IRCLKEN=1,IREFSTEN=0 */

  #define SYSTEM_MCG_C1_VALUE          0x06U               /* MCG_C1 */

  /* MCG_C2: LOCRE0=0,RANGE0=2,HGO0=0,EREFS0=1,LP=0,IRCS=0 */

  #define SYSTEM_MCG_C2_VALUE          0x24U               /* MCG_C2 */

  /* MCG_C4: DMX32=0,DRST_DRS=0,FCTRIM=0,SCFTRIM=0 */

  #define SYSTEM_MCG_C4_VALUE          0x00U               /* MCG_C4 */

  /* MCG_SC: ATME=0,ATMS=0,ATMF=0,FLTPRSRV=0,FCRDIV=0,LOCS0=0 */

  #define SYSTEM_MCG_SC_VALUE          0x00U               /* MCG_SC */

  /* MCG_C5: PLLCLKEN0=0,PLLSTEN0=0,PRDIV0=0 */

  #define SYSTEM_MCG_C5_VALUE          0x00U               /* MCG_C5 */

  /* MCG_C6: LOLIE0=0,PLLS=0,CME0=0,VDIV0=0 */

  #define SYSTEM_MCG_C6_VALUE          0x00U               /* MCG_C6 */

  /* MCG_C7: OSCSEL=0 */

  #define SYSTEM_MCG_C7_VALUE          0x00U               /* MCG_C7 */

  /* OSC_CR: ERCLKEN=1,EREFSTEN=0,SC2P=0,SC4P=0,SC8P=0,SC16P=0 */

  #define SYSTEM_OSC_CR_VALUE          0x80U               /* OSC_CR */

  /* SMC_PMCTRL: LPWUI=0,RUNM=0,STOPA=0,STOPM=0 */

  #define SYSTEM_SMC_PMCTRL_VALUE      0x00U               /* SMC_PMCTRL */

  /* SIM_CLKDIV1: OUTDIV1=0,OUTDIV2=0,OUTDIV3=1,OUTDIV4=1 */

  #define SYSTEM_SIM_CLKDIV1_VALUE     0x00110000U         /* SIM_CLKDIV1 */

  /* SIM_SOPT1: USBREGEN=0,USBSSTBY=0,USBVSTBY=0,OSC32KSEL=3,RAMSIZE=0 */

  #define SYSTEM_SIM_SOPT1_VALUE       0x000C0000U         /* SIM_SOPT1 */

  /* SIM_SOPT2: SDHCsrc=0,USBsrc=0,PLLFLLSEL=0,TRACECLKSEL=0,PTD7PAD=0,FBSL=0,CLKOUTSEL=0,RTCCLKOUTSEL=0 */

  #define SYSTEM_SIM_SOPT2_VALUE       0x00U               /* SIM_SOPT2 */

After the above modification, I can use your  code working ok on my side, it will wait about 5 seconds then enter in the VLLS3, the power consumption is about 8uA.

Then if you give a external rising wave in the PTE4 pin, the MCU will wake up and wait 5 seconds, enter the VLLS3 again...

You can test my project on your side, the project is the KDS3.0 project, please find the project from the attachment.

Wish it helps you!

If you still have question, please let me know!

Have a great day,
Jingjing

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

0 Kudos
1,517 Views
garylynch
Contributor IV

Jingjing,

Thanks for the assist!

I was able to import, build, and run your project, as written. As you stated, my board powers up drawing 207 mW. After about 5 seconds this load drops to 132 mW (The processor is by no means the only load on the board).

If I activate the switch on LLWU_P2 it jumps back up to 207 mW (but only for 5 seconds).

I presume you removed my LEDs and the first switch because you don't have the hardware to test my exact configuration.

The next stage will be to enter your changes into my app and see if I still get the desired behavior, but I have to ask several questions first.

  1. Mark states (08.01.2016 12:02, above) that the LLWU wakes up the processor via the 'reset path'. If we are using the reset vector, why do we even need to write an LLWU ISR?
  2. If we wake up via the reset vector, all my global variables will be reset to their power-up values. This totally negates the intent of maintaining RAM during the VLLS3 mode. The processor will not be able to tell the difference between recovery from sleep mode and a cold boot. What exactly happens when I close that switch?
  3. If I enable the pull-up resistor on PTE4, will it still be active in VLLS3 mode? The "K10 Sub-Family Reference Manual" says in table 7.2 on page 197 that the GPIO is "OFF, pins latched" and on page 1508 table 49-1 states that the GPIO in all stop modes is "disabled." I can't see how to reconcile these assertions.
  4. As a side topic, I would like to know how you exported the project to create the folder tree you sent. I have tried to use the Export wizard under File >> Export, but can find no entry for selecting a project. (Import works fine, however.)

Thanks for this big leap forward!

0 Kudos
1,517 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Gary Lynch,

Yes, I modified your code, and removed your LED, but the low power test on your side is correct, from your test result, your VLLS3 can be entered and waked up by PTE4. For details, you can check the project code which I give you, and add your own code in it.

Now answer your 4 questions:

1. I think you need to know the wakeup process from VLLSx.

VLLSx is wakeup from enabled LLWU input source by the reset, the following is the VLLSx reset recovery process:

1)Reset Vector Fetched,

2)Code execution begins

3)User should Check the source of the RESET in SRS registers

4)If Wakeup bit then you recovered from VLLS1, 2 or 3. You know the mode you recovered from by reading the PMCTRL_LPLLSM bits.

5)You can begin the process of determining what was the source of the wakeup or use the LLWU interrupt handler to do this after interrupts are enabled.

6)If RTC was enabled and not reinitialized do not reinitialize the RTC

7)Reinitialize PORT setup,

8)Module setup prior to clearing the LLWU ACKISO bit which releases the hold on the pins.

9)The LLWU interrupt is taken if the source of the wakeup was not cleared in reset source discovery. 

10)The module or pin interrupt is taken if the source of the wakeup was not cleared previously.

11)Main code execution continues

LLWU interrupt is just used to clear the reset source,LLWU pin flag, if you don't clear the LLWU wakeup flag and the according Port flag, it will still enter in reset and the according port interrupt.

2 User should Check the source of the RESET in RCM_SRS registers, Eg, this code:

  if((RCM->SRS0 & RCM_SRS0_WAKEUP_MASK) != 0x00U)

  {

    /* VLLSx recovery */

    if((PMC->REGSC & PMC_REGSC_ACKISO_MASK) != 0x00U)

    {

       PMC->REGSC |= PMC_REGSC_ACKISO_MASK; /* Release hold with ACKISO: Only has an effect if recovering from VLLSx.*/

    }

  }

3  No, don't worry, LLWU wakeup is just the rising edge, not the high voltage, it has no problem with internal pullup.

In VLLSx, GPIO is OFF, but LLWU pin is active, take care, PTE4 is not just the GPIO, but also the LLWU wake up pin!

4 you don't need to export all the folder, normally, we always create a new barebone project, then add the according file and folder is ok.

Wish it helps you!

If you still have question, please let me know!

Have a great day,

Jingjing

-----------------------------------------------------------------------------------------------------------------------

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

-----------------------------------------------------------------------------------------------------------------------

1,517 Views
garylynch
Contributor IV

Jingjing,

I got this application to work (sort of), but still need a little clarification. Referring to your answers to my 4 questions (can't get the quote feature on this thing to work):

1 & 2. If I understand you correctly, in order to wake up the processor from VLLS3 mode with a rising edge of LLWU_P2, I need to configure the the LLWU interrupt in the SIM_SCGC4, LLWU_PE1, & LLWU_F1 registers. Then, after we are in VLLS3 mode and the edge occurs, it triggers both an LLWU interrupt AND a processor reset. Because the reset has higher priority it runs first.

To handle the wake-up from VLLS3 interrupt differently than a warm boot, I have to check the RCM_SRSx registers at the start of main() for the LLWU source and do my LLWU interrupt processing within the if() statement inside main().

If I do not disable the LLWU interrupt inside this if() statement it will fire as soon as I enable interrupts at the top of main(). If I configured a rising edge interrupt on the GPIO port that corresponds to LLWU_P2 (as recommended by Freescale in app note 4503, "Power Management for Kinetis MCUs", §10.1.1, pp. 50-51,

http://cache.freescale.com/files/32bit/doc/app_note/AN4503.pdf ).

then a 3rd interrupt will also be pending.

A further ramification of this is that there is no path back to the instruction after the call to __WFI(), so no point in doing anything there.

Is this description accurate?

4. I asked about how to Export because developers here share projects, both by placing code on a server and by checking files into & out of a version control system. If we just copy the projects in & out of the workspace with Windows Explorer, the project breaks in ways that are difficult or impossible to fix. I read somewhere that Export/Import would solve this problem, but I have yet to find instructions for using Export and the "Select" window of the Export Wizard doesn't even have an entry for projects.

I thank you for your help in getting this to work. Now I just want to understand how it works.

0 Kudos
1,517 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Gary Lynch,

  OK, you are really very careful, that's very good!

  1&2, your understanding is near the correct answer now.

  After the LLWU wakeup happens, then the MCU will reset, just as the AN4503 which you mentioned, you should clear the ISF flag in the LLWU ISR or the PORT ISR,if you don't clear it, of course the code will still in the port ISR and can't return back to the main.

  So, normally, we clear the ISF flag and the LLWU interrupt flag in the LLWU ISR, then after the interrupt is completed, the code will return back to the main code, take care it is not back to the  __WFI(), __WFI() is just used to enter the sleep mode and wait interrupt happens, when the accoding wakeup interrupt flag is set, the code will reset at first when in VLLSX mode.

4, You can try to use this :

  Select the project, right click, choose export, then General->File system->next

  Choose the directory, will export all the project.

Wish it helps you!

If you still have question, please contact with me!

Have a great day,

Jingjing

-----------------------------------------------------------------------------------------------------------------------

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

-----------------------------------------------------------------------------------------------------------------------

1,517 Views
mjbcswitzerland
Specialist V

2. A reset doesn't affect RAM content. As long as you see that the reset was due to a wakeup you can jump certain variable initialisation  so that values are retained across the reset.

3. Pull-up settings are retained in low leakage modes. In some cases it is also advisable to enable such to avoid inputs from floating; floating inputs can otherwise increase the low leakage power consumption.

Regards

Mark

0 Kudos
1,517 Views
garylynch
Contributor IV

2. I sure wish you hadn't said that! It means that you (and perhaps everyone else on this forum) use a different definition for 'reset' than I have assumed for my entire life:

Reset: To restore the processor to a known (and documented) state.

So:

A. What is the fundamental meaning of 'reset'?

B. What verb do I use when I want to set every sub-system of the process (including RAM) to a known state?

0 Kudos
1,517 Views
mjbcswitzerland
Specialist V

Gary

A reset sets the processor's registers to a defined state "according to the processor's specification".

Some registers are not affected and retain their pre-reset values. Some registers are random (especially after a power cycle). Some are write-once after a power on and hold the state through resets (sometimes watchdogs work like this to that they can't be modified until a power cycle - RTCs will retain registers through resets otherwise they wouldn't be of any use). Some times processors specify warm resets and cold resets to define differences in such circumstances.

RAM is usually random on power up (although in practice tends to take a certain pattern and sometimes will retain values even after some time in power down or have a sort of memory effect causing then to power up in a certain state after having held values for a long time - such things are also of relevance in security applications where no traces of previously stored values shoud be left even when powered off.

Unless there is a specific mechanism in the reset sequence, SRAM will retain its pre-reset value when a warm reset takes place.

Many applications use parts of RAM to store variables that are retained across warm SW resets (statics counters - eg. to count the number of warm resets that took place since the last power up - or communication mail boxed between applications; one application writes something into the mail box and resets - then the next application starts based on the mail box information).

- Reset is therefore defined by the processor in questions - mostly this is common between all processors but there may be some exceptions.

- Generally RAM is only "reset" to an initial, know state, when this is performed by the SW that runs after a restart.

- A HW SRAM reset doesn't exist in the Kinetis and also not in the majority of processors. It will retain data across resets and also in low leakage modes where the power isn't specifically cut to the SRAM (some modes will lose data so the RAM's content becomes 'random'). Modes that state that they retain SRAM data (in all or a part of SRAM) do so to allow such applications to be able to benefit from that.

- SDRAM will often lose content during resets because the processor reset causes its refresh cycle to be missed, which can lead to loss of internal data.

This is all very simple to test in the debuger - just command a reset and watch registers and SRAM content to see what happens to them.

Reards

Mark

1,517 Views
garylynch
Contributor IV

Ok, it is critical to my application to know the state of the RAM (specifically any global variables stored therein) after recovery from my chosen sleep mode (as of today that choice is still VLLS3).

If I return to run mode via the reset vector, it doesn't matter what code I put after the __WFI(); statement--it will never be executed.

Furthermore my understanding of 'reset' means I eventually wind up at statement 1 of main() before I have any control over the order of execution. I have noted (and Jingjing's sample code has a commented out statement to this effect) that I can check the state of the ACKISO bit in the REGSC register, determine that I have reset because of a recovery from sleep mode, and take action at statement 1.

But both ANSI C (§6.2.4 & 6.7.8, sub-part 10) and K&RII (§4.9) stipulate that globals initialized at compile time receive their initial values and that uninitialized globals get set to 0 BEFORE I get to statement 1 of main(). On other micros I have used, this is usually done in assembly-language startup code that executes between the reset vector and the start of main().

And yes I have used other microprocessors that have memory not subject to these restrictions, but that memory is accessible as a peripheral, the programmer must access it numerically--rather than symbolically, and thus it is invisible to the compiler.

I have parsed both the Freescale reference manual and the ARM generic user guide and can find no clue how or whether I can count on my globals riding through a low-power mode. I cannot count on anything I learn with the debugger since any feature not mentioned in the data sheet can be changed by the manufacturer without sending me a product change notice and my system will suddenly stop working.

That is why I am trying so hard to find out up front. Hope you will understand.

0 Kudos
1,517 Views
bobpaddock
Senior Contributor III

Gary Lynch wrote:

Furthermore my understanding of 'reset' means I eventually wind up at statement 1 of main() before I have any control over the order of execution.

But both ANSI C (§6.2.4 & 6.7.8, sub-part 10) and K&RII (§4.9) stipulate that globals initialized at compile time receive their initial values and that uninitialized globals get set to 0 BEFORE I get to statement 1 of main(). On other micros I have used, this is usually done in assembly-language startup code that executes between the reset vector and the start of main().

I have parsed both the Freescale reference manual and the ARM generic user guide and can find no clue how or whether I can count on my globals riding through a low-power mode.

What you seek is not being found in those documents because it is compiler specific.

For example in GCC using some versions of Newlib:

/*

* Order of priority before main() starts:

*      hardware_init_hook() from Newlib

*      software_init_hook() from Newlib

*      .init [AVR specific, crash on return on ARM code.]

*      constructor (optional priority.  0->100 is reserved for the implementation.) from GCC

*

*      destructor  (optional priority.  0->100 is reserved for the implementation.)

*      Code to register global destructors is only invoked when atexit is already in the executable.

*

* Note con/destructors are for C code not C++.  Good way to make modular files.

*

*      .fini [AVR specific, never called on ARM code.]

*

*      "An optional integer priority to control the order in which

*      constructor and destructor functions are run. A constructor

*      with a smaller priority number runs before a constructor with

*      a larger priority number; the opposite relationship holds for

*      destructors. A constructor that allocates a resource and a

*      destructor that deallocates the same resource, both functions

*      typically have the same priority. The priorities for

*      constructor and destructor functions are the same as those

*      specified for namespace-scope C++ objects."

*

*      The constructors with lower priority value would be executed

*      first. The destructors with higher priority value would be

*      executed first.

*

*/

#if 0

void hardware_init_hook( void ); /* Called by crt0.S at reset if exists. Called before _reset_init in vectors.c. C not yet been setup */

void hardware_init_hook( void )

{

}

void software_init_hook( void ); /* Called by crt0.S at reset if exists. Called before _reset_init in vectors.c. C not yet been setup */

void software_init_hook( void )

{

}

#endif

GCC Compiler directives:

#define NO_INIT_GCC __attribute__ ((section (".noinit"))) /* Do not zero variables declared such */

static uint8_t foo_u8 NO_INIT_GCC; /* Example */

#define ATTR_ALWAYS_INLINE __attribute__ ((__always_inline__))

#define ATTR_USED __attribute__ ((used))

#define ATTR_PURE __attribute__ ((pure))

#define ATTR_NO_INSTRUMENT_FUNCTION __attribute__( ( no_instrument_function ) )

#define ATTR_CTOR( priority ) __attribute__ ((constructor (priority) ))

#define ATTR_DTOR( priority ) __attribute__ ((destructor  (priority) ))

/*

*      "An optional integer priority to control the order in which

*      constructor and destructor functions are run.  A constructor

*      with a smaller priority number runs before a constructor with

*      a larger priority number; the opposite relationship holds for

*      destructors. A constructor that allocates a resource and a

*      destructor that deallocates the same resource, both functions

*      typically have the same priority. The priorities for

*      constructor and destructor functions are the same as those

*      specified for namespace-scope C++ objects."

*

*      The constructors with lower priority value would be executed

*      first. The destructors with higher priority value would be

*      executed first.

*

*      Priority 0->100 is reserved for the implementation.

*

*/

void foo( void ) ATTR_CTOR( 200U );

void foo( void )

{

}

/* Example, ATTR_DTOR is the same */

There is also the option of 'weak' linkage in vectors.c to get things to run before main()

/*

* Weak definitions of handlers point to a default_handler or empty

* handler if not implemented.

*

* A weak definition can be used to resolve any reference to that

* symbol in the same way as a normal definition.  However, if another

* non-weak definition of that symbol exists in the build, the linker

* uses that definition instead of the weak definition, and does not

* produce an error due to multiply-defined symbols.

*/

void _reset_init(void)                              __attribute__((noreturn, naked, aligned(8U))); /* Where execution will start */

void vectors_reset_init( void )               __attribute__ ((weak, alias("empty_handler_void")));

void HardFault_Handler( void )                      __attribute__ ((weak, alias("hardfault_default")));

void HardFault_Handler_init( void )               __attribute__ ((weak, alias("empty_handler_void")));

So yes you can maintain variables across reset.

Two things that are important.  Make sure any bootloader code does not use the same memory.

Do this in the linker script for your application.

Second place a CRC on data that is important and have a fallback position if the RAM did go bad.

1,517 Views
mjbcswitzerland
Specialist V

Gary

- The compiler doesn't need to handle interrupt specially since the Cortex HW handles saving and restoring registers.

- The output states are held in all low leakage states so it i normal that the state before entering the LL mode is retained during it.

- VLLS3 wakes up via the Reset path and so interrupt handling is in fact irrelevant - after a reset you an check to see whether the reset was due to wakeup

- It is not possible to debug in the LL states but you can still set a breakpoint on the instruction after the wfi() [for modes that can wake using this path] and let it run into the LL mode, so that it stops there when it has woken. You can then see what happes after you re-enable interrupts becausei t will then immediately handle your pin or LLWU interrupts. Again - the mode that you are testing will wake via reset and so cannot be debugged.

- To clear pending interrupts in the LLWU module you must write a '1' to the flag in the corresponding LLWU_Fx register.

- VLLS3 cannot be exited by a port change interrupt - only by LLWU event

- The best way to be sure that the processor is in the expected state is to measure the current that it consumes after the wfi() has been executed and before it is worken.

- Taking a quick look at our code I would suggest that you are not using the correct method for the K10 - the K10 has a Mode Control module and the mode is configured in MC_PMCTRL. You are using the the method for parts with a System Mode Controller, where SMC_VLLSCTRL doesn't exist in the K10. It just happens to have the same address as the MC_PMPROT register and so doesn't cause an exception but otherwise is uncompatible.

From the code that I attached previously, the instructions that you need instead are:

MC_PMPROT |= MC_PMPROT_ALLS; /* Allow Very Low Leakage */

MC_PMCTRL |= (MC_PMCTRL_RUNM_NORMAL_RUN | MC_PMPROT_AVLLS3); /* Set stop mode to VLLSx */

SYSTEM_CONTROL_REGISTER |= SLEEPDEEP; /* deep sleep rather than just wait */

__WFI();                   /* Set the wait mode */

Since you don't configure the LLWU you will presently only be able to exit using the reset line.

Regards

Mark

1,517 Views
bobpaddock
Senior Contributor III

""wfi" (wait for interrupt) which is commanded in GCC or some other compilers with "asm("wfi")""

In GCC such instructions must be marked as Volatile to prevent obscure issues with Code Motion; make sure the optimizer doesn't move it to a useless place resulting in hair pulling timing race debugging sessions.

What I use:

#define ATTR_NO_INSTRUMENT_FUNCTION __attribute__( ( no_instrument_function ) )

/*

* Wait for Interrupt:

*/

static inline ATTR_NO_INSTRUMENT_FUNCTION void wait4irq( void )

{

  __asm__ __volatile__ ("wfi");

}

Hair pulling timing race debugging sessions example:

http://blog.softwaresafety.net/2011/02/anatomy-of-race-condition-toyota-vs-avr.html

...Tune in tomorrow for an other episode of As The Stack Churns...

0 Kudos
1,517 Views
mjbcswitzerland
Specialist V

Gary

See the following for some details:

http://www.utasker.com/kinetis/LLWU.html

If you have a standard evaluation/development board you can try it with one of the binary files at http://www.utasker.com/kinetis.html

Attached is the low power switching and LLWU module code as reference, which is essentially compatible with all Kinetis parts and develpment environments.

Regards

Mark

0 Kudos