SamD10 sleep/standby - Page 1
Forum section: electronics / general

author: cv007
author_rank: Frequent Contributor
timestamp: April 01, 2021, 08:05:02 pm
content: I have been struggling with standby mode on the SAMD10D14AM, and now conclude I just don't know what that means in this case.samd10 datasheet 15.6.2.9QuoteSeems to indicate standby is simply like idle, but lower power. You end up either in the isr, and/or resume just after the wfi/wfe.Rtc section-8.6.8.1 Shutdown ModeQuoteNow I'm confused- what is shutdown mode. And how do I get there. This is the only place in the datasheet that says 'Shutdown Mode'.I have the rtc as a 32bit timer clocked by gen2/osculp32k (which is default/reset state), and when using it to wait (a waitms function), if I attempt to use standby I seem to just end up in some idle mode (everything works, but current same as sleep/idle, about 380ua). I can get standby to work sometimes (5ua), but then any wake goes to the reset vector as indicated above (Shutdown Mode, I guess). So I can get to 5ua, and I can wake from that via rtc, but just end up in the reset vector.So maybe I need to first figure out what the terms mean. I was assuming I could choose any sleep mode I thought was suitable, including standby, and wake from an rtc compare irq. The waitms runs at random intervals, and some of them are about 2-5 seconds apart so standby would be nicer as there is nothing else going on while waiting.

author: ataradov
author_rank: Super Contributor
timestamp: April 01, 2021, 09:20:25 pm
content: This is some copy-paste mistake. SAM D10 lowest power consumption mode is STANDBY, and device wake up after the WFI instruction.This is probably just a text that slipped from the RTC IP datasheet. The same RTC is used in other device, where there are modes that would reset the device. For example BACKUP mode in SAM L21. And there only limited number of peripherals are running (including RTC), and wake up would appear as a normal reset.With standby mode it is important to make sure that RUNSTBY bits on everything are configured to disable as much as possible. Currents like 5 uA are achievable only if most of the clocks and peripherals are disabled (RUNSTBY=0). Realistically only RTC and EIC clocked by 32 kHz clock may be running.

author: cv007
author_rank: Frequent Contributor
timestamp: April 02, 2021, 12:16:24 am
content: Should standby resume from where the wfi took place (or irq first if nvic irq enabled)? Its a little strange that when I can get to standby with the rtc set to wake (meter showing ~5ua is a good indication that I am in standby), in that case when wakeup takes place I am back to starting from reset vector.The following is a test, which tries to show... something useful. Everything is basically at the reset state, and the issue is not really that I cannot get to the low power state, it seems to be I do not know in what state it is supposed to wake. The below has a little bit of my code in, but I then wrote the setup to standby in 'normal' code (which my functions essentially do).The code will result in a blinks every 5 seconds IF swd is left connected, but then will also see ~370ua in the waiting period (same values I get in sleep/idle). So it seems the wakeup is what is expected, but not the power.If swd disconnected (which I seem to have to do to eliminate its presence) then will get 5ua, BUT on wake will go to reset vector. So it seems it is properly in standby going by the current seen, but then a wake ends up in reset.int main () {// 3.3v// 16 leds init to output low (no input), via libc_init_array in startup// ~5sec loop in startup, to allow swd hot-plugging// ~1ma during startup//all default values at this point, except vtor points to ram//waitms will enable rtc bus clock, set rtc to use gen2/osculp32k,//and enable rtc 32bit mode, using comp as irq source//boot indicator, so can see any resets, blink all ledsfor(auto& p : pins){ p.toggle(); waitms(20); p.toggle(); }//this works, so function is working//Pm.sleep( Pm.STANDBY ); //~4ua, no wakeupfor( ; ; ){for(auto i = 0; i < 4; i++){ pins.toggle(); waitms(50); } //blink 2 times//waitms already enabled rtc//manually do the standby here instead of in waitmsRTC_REGS->MODE0.RTC_READREQ = 0x8010; //read countwhile( RTC_REGS->MODE0.RTC_STATUS ){}RTC_REGS->MODE0.RTC_COMP = RTC_REGS->MODE0.RTC_COUNT + 32768*5; //set comp to +5secRTC_REGS->MODE0.RTC_INTFLAG = 1; //clear comp flagRTC_REGS->MODE0.RTC_INTENSET = 1; //enable comp irq//is already set in waitms to do the same thing, no need to set again//(it works)//irqFunction( //ram vector table// RTC_IRQn,// [](){ RTC_REGS->MODE0.RTC_INTENCLR = 1; }// ); //NVIC irq also enabledSCB->SCR or_eq SCB_SCR_SLEEPDEEP_Msk;__DSB();__WFI();}}

author: ataradov
author_rank: Super Contributor
timestamp: April 02, 2021, 12:33:22 am
content: It should wake up after the WFI instruction, or inside the IRQ handler if enabled.Here is a code I know works. I see nothing wrong with the code provided here, but a lot of library stuff is not shown, so who knows what may be wrong.Ignore the EIC stuff, it is obviously does not affect RTC wake up.Also, check the value of the PM.RCAUSE register to see what actually caused the reset.

author: cv007
author_rank: Frequent Contributor
timestamp: April 02, 2021, 08:54:11 am
content: I had to translate the provided main.c example a little, since it appears the includes I have use a different naming scheme. Tested, and it acts mostly the same- if swd pins left connected after programming then get the 1 blink in 8sec but the sleep current is 700ua, if swd pins disconnected and power up then get the same as I was seeing in my example but in this case the current remained at ~700ua and the wakeup went to reset (I had a couple led blinks before the loop so could tell where its at, plus the meter easily shows a startup where I always get ~1ma). Not sure where the extra 300ua is coming from or why the example is not going to the low power I was getting, but in any case it winds up at reset after wakeup.I took my test code and 'blinked' out rcause- in power up get POR as expected, then the wakeups will end up in reset and I get the BOD12 value (0x02). The BOD33 by default is not set to run in standby (runstdby=0) and BOD12 has no register in this mcu although it talks about a BOD12 register, so cannot change anyway.I'll keep plugging away, but I guess I can get the long term standby power of 5ua, I just cannot currently wake to next instruction from that state. I'm assuming when I get around to a pin wakeup it will be the same (pin wakeup will be for long term standby, the standby desired in waitms would be nice but can live without it). Maybe I'll check the bypass caps or see if I can look at the power with a scope when it wakes,Here is a simpler complete version in header code, which reproduces the problem. If swd attached, ~380ua in standby and stays in the loop, if swd detached and powered on, then 5ua in standby, but wakes to reset.#inlcude <sam.h>#define LED_TOG() PORT_IOBUS_REGS->GROUP.PORT_OUTTGL = 4;//#define WAIT_SEC(s) for(volatile uint32_t i = 0; i<90000*s; i++){}#define WAIT_SEC(s) for(volatile uint32_t i = 0; i<4000*s; i++){}int main () {GCLK_REGS->GCLK_GENCTRL = (1<<16)|(3<<8 )|0; //main clock to osculp32kPORT_IOBUS_REGS->GROUP.PORT_DIRSET = 4; //PA02 ledLED_TOG(); WAIT_SEC(5); LED_TOG();GCLK_REGS->GCLK_CLKCTRL = (1<<14)|(2<<8 )|4; //enable gen2->rtc__disable_irq(); //no irqNVIC_EnableIRQ(RTC_IRQn); //but use to wfifor( ; ; ){while( RTC_REGS->MODE0.RTC_STATUS ){}RTC_REGS->MODE0.RTC_COMP = 32768*5; //5secwhile( RTC_REGS->MODE0.RTC_STATUS ){}RTC_REGS->MODE0.RTC_CTRL = (1<<1); //enable rtcRTC_REGS->MODE0.RTC_INTENSET = 1; //enable comp irqSCB->SCR or_eq SCB_SCR_SLEEPDEEP_Msk; //standby__DSB();__WFI();RTC_REGS->MODE0.RTC_CTRL = 1; //reset rtcNVIC_ClearPendingIRQ(RTC_IRQn);LED_TOG(); WAIT_SEC(1); LED_TOG();}}edit- with the addition highlighted, I can now wake from standby properly. I standby at 5ua, and wake inside the loop. It appears the mcu wakeup into osc8m is causing a bod12 brownout I guess, and by using the osculp32k it is no longer requesting osc8m on wake so less current required and works properly. I had also tried the above with no led in use in the loop and made no difference, so its not the driving of an led after wakeup that is causing a brownout on wake (also tried simply killing some time after wake without success). Probably need to watch power on a scope to see what it looks like at wakeup, but hard to imagine a problem since the power source is 3v3 with 500ma+ capability.Watching the meter, it also seems to take about a second to get to the sleep current- it steps to ~300ua then a second later to 5ua. I guess that could be the synchronization of 2 slow clocks when setting up the rtc even if they are the same source, and some of it the meter.

author: ataradov
author_rank: Super Contributor
timestamp: April 02, 2021, 06:30:06 pm
content: Something is wring with your power supply or something like this. Can you show the schematic of your board?For me my code worked fine even with the debugger connected, since it is always connected on the SAM D10 Xplained board.You can try my exact file by using this project as a basehttps://github.com/ataradov/mcu-starter-projects/tree/master/samd10Just replace main.c and it should compile as is. That file was tested to work.

author: cv007
author_rank: Frequent Contributor
timestamp: April 02, 2021, 11:27:26 pm
content: I can also set gen0 to /4 division via gendiv before sleep, then restore to div1 after wfi and that also works (instead of switching gen0 to osculp32k, which was just to get an indication if related to clock speed after wakeup). If I use /2 then does not, so it seems <= 250kHz is what I currently need for wake to not trip bod12 (using defaults for osc8m, which is /8 and runstdby=0).I have also done this in my regular code in the waitms function and am now waiting at 4-5ua.auto waitms (u16 ms, bool stdby = false) { //0-65535ms, will init on first use//not shown-//check ms for 0//check if rtc bus is on and rtc ensbled, call init if not//calculate counts needed for ms//compare = count + ms counts//clear comp flag, enable comp irqirqFunction(RTC_IRQn,[](){ reg_.RTC_INTENCLR = CMP0bm; }); //also enables NVIC irq by defaultGclk.generatorDivide( Gclk.GEN0, 4 );//until cmp0 irq disabledwhile( reg_.RTC_INTENSET bitand CMP0bm ) {Pm.sleep( stdby ? Pm.STANDBY : Pm.IDLE0 );}Gclk.generatorDivide( Gclk.GEN0, 0 );}>Can you show the schematic of your board?If I had one, it would be the stick figure of schematics. I can describe it- 1 mcu, the 2 swd pins to header, 2 power pins to header, 1 100nf bypass cap next to mcu, other pins to leds on board, reset pin unused, header is close to mcu. Also tried on another assembled board which acts the same, and another with only mcu/cap soldered. Everything other than this peculiar standby problem works fine.Also tried running from lithium 3v battery, same. Also have an xplained tiny but cannot really duplicate what I have- I can do the same tests and they work ok, but so do my boards until swd disconnected, which I cannot easily do on the xplained board nor can I measure current easily without changes.I do not have the 4.7uf as they show in the power supply checklist, but have similar filtering 5" away at the power source. I assume like most they are showing the 100nf which is needed, and the 4.7uf as a 'typical example'. I can piggyback a 4.7uf on the 100nf, but I do not imagine that will make any difference, although my imagination does not have the final say.It could also be I somehow damaged these mcu's in the process of reflow. My process is not perfect, but has always worked ok to this point- get solder on pads using liberal amount of flux, and for a 0.5mm part the pad does not hold much (but I then know it is the correct amount), place mcu centered on pad, with flux, hot plate for 2-3 minutes until solder flows and mcu settles into place. The temperature is enough to do the job, but not too much as to cause smoke. I have done the same many times with success, so I sort of doubt that this time was the time I damaged the parts somehow but is possible. I do have about 8 other boards I have not tested yet, maybe one or more of them will act differently.There is a value in user row for BOD12, but it supposed to be hands off (default value is 0x70).At least I have something working now.

author: ataradov
author_rank: Super Contributor
timestamp: April 03, 2021, 12:17:04 am
content: Ok, with the BOD12 you may be running into errata 15513, see section 37.2.4 of the datasheet:Quote

author: cv007
author_rank: Frequent Contributor
timestamp: April 03, 2021, 01:42:10 am
content: That was an easy fix, and I get to write to secret registers which is a bonus. This is now the second time for me. For someone who does relatively simple things, I sure seem to be good at hitting the errata on this one.I did give a thorough reading of the errata to keep as a mental checklist from the previous dfll48m ondmand errata encounter, but I must have put the bod12 one on my mental 'not for me' list. I should have revisited the errata again when bod12 worked its way into the picture.It is good that there is some reasonable explanation, because a lot of my testing never really made any sense. If I could now remember what I was doing before I ran into this, that would also be good.Thanks.

author: pembd
author_rank: Newbie
timestamp: September 12, 2021, 05:22:57 am
content: Hello,One quick help needed, can you give me a sample code how to do this? I mean writing the given value to given address.I am using SAM D10 MCU.Appreciate your help.Regards,Pramod.

author: cv007
author_rank: Frequent Contributor
timestamp: September 12, 2021, 08:02:50 am
content: *(volatile uint32_t*)0x40000838 = 4;or if you wanted to modify the sysctrl.h header to add the 'hidden' register, change__IO uint32_t SYSCTRL_BOD33; /**< Offset: 0x34 (R/W 32) 3.3V Brown-Out Detector (BOD33) Control */__I uint8_t Reserved6;to__IO uint32_t SYSCTRL_BOD33; /**< Offset: 0x34 (R/W 32) 3.3V Brown-Out Detector (BOD33) Control */__IO uint32_t SYSCTRL_BOD12; /**< Offset: 0x38 (R/W 32) 1.2V Brown-Out Detector (BOD12) Control */__I uint8_t Reserved6;then useSYSCTRL_REGS->SYSCTRL_BOD12 = 4;or whatever your header requires (they may have changed header naming style).

author: ataradov
author_rank: Super Contributor
timestamp: September 12, 2021, 08:04:02 am
content: *((volatile uint32_t *)0x40000838) = 4 (or 6).cv007 got it first. Good timing.