1+ /*
2+ Artemis Low Power: How low can we go?
3+ By: Nathan Seidle
4+ SparkFun Electronics
5+ Date: October 17th, 2019
6+ License: This code is public domain. Based on deepsleep_wake.c from Ambiq SDK v2.2.0.
7+ A big thanks to robin_hodgson for pointing out the HFRC shutdown requirement and
8+ turning off the SWD pins.
9+
10+ SparkFun labored with love to create this code. Feel like supporting open source hardware?
11+ Buy a board from SparkFun! https://www.sparkfun.com/products/15376
12+
13+ How close can we get to 2.7uA in deep sleep?
14+ This example shows how decrease the Artemis current consumption to ~2.4uA in deep sleep
15+ with a wake up every 5 seconds to blink the LED. The RTC is used to trigger an interrupt
16+ every second.
17+
18+ Note that Artemis modules with revision A1 silicon will use ~30uA. Please see the
19+ Ambiq errata for more information: https://www.ambiqmicro.com/static/mcu/files/Apollo3_Blue_Errata_List_v1_0_external_release.pdf
20+
21+ To monitor the current to the Edge cut the MEAS jumper, solder in headers, and attach
22+ a DMM via IC hooks (https://www.sparkfun.com/products/506).
23+
24+ The USB to serial bridge draws some current:
25+ Serial Basic C - ~1.2uA (https://www.sparkfun.com/products/15096)
26+ FTDI Basic - ~5.5uA (https://www.sparkfun.com/products/9873)
27+
28+ */
29+
30+ static uint32_t g_RTCseconds = 0 ;
31+
32+ void setup ()
33+ {
34+ Serial.begin (115200 );
35+ Serial.println (" Low power sleep example" );
36+
37+ pinMode (LED_BUILTIN, OUTPUT);
38+
39+ // Turn off ADC
40+ power_adc_disable ();
41+
42+ // Set the clock frequency.
43+ am_hal_clkgen_control (AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0 );
44+
45+ // Set the default cache configuration
46+ am_hal_cachectrl_config (&am_hal_cachectrl_defaults);
47+ am_hal_cachectrl_enable ();
48+
49+ // Initialize for low power in the power control block
50+ am_hal_pwrctrl_low_power_init ();
51+
52+ // Disabling the debugger GPIOs saves about 1.2 uA total:
53+ am_hal_gpio_pinconfig (20 /* SWDCLK */ , g_AM_HAL_GPIO_DISABLE);
54+ am_hal_gpio_pinconfig (21 /* SWDIO */ , g_AM_HAL_GPIO_DISABLE);
55+
56+ // These two GPIOs are critical: the TX/RX connections between the Artemis module and the CH340S on the Blackboard
57+ // are prone to backfeeding each other. To stop this from happening, we must reconfigure those pins as GPIOs
58+ // and then disable them completely:
59+ am_hal_gpio_pinconfig (48 /* TXO-0 */ , g_AM_HAL_GPIO_DISABLE);
60+ am_hal_gpio_pinconfig (49 /* RXI-0 */ , g_AM_HAL_GPIO_DISABLE);
61+
62+ // The default Arduino environment runs the System Timer (STIMER) off the 48 MHZ HFRC clock source.
63+ // The HFRC appears to take over 60 uA when it is running, so this is a big source of extra
64+ // current consumption in deep sleep.
65+ // For systems that might want to use the STIMER to generate a periodic wakeup, it needs to be left running.
66+ // However, it does not have to run at 48 MHz. If we reconfigure STIMER (system timer) to use the 32768 Hz
67+ // XTAL clock source instead the measured deepsleep power drops by about 64 uA.
68+ am_hal_stimer_config (AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
69+
70+ // This option selects 32768 Hz via crystal osc. This appears to cost about 0.1 uA versus selecting "no clock"
71+ am_hal_stimer_config (AM_HAL_STIMER_XTAL_32KHZ);
72+
73+ // This option would be available to systems that don't care about passing time, but might be set
74+ // to wake up on a GPIO transition interrupt.
75+ // am_hal_stimer_config(AM_HAL_STIMER_NO_CLK);
76+
77+ // Turn OFF Flash1
78+ if (am_hal_pwrctrl_memory_enable (AM_HAL_PWRCTRL_MEM_FLASH_512K))
79+ {
80+ while (1 )
81+ ;
82+ }
83+
84+ // Power down SRAM
85+ PWRCTRL->MEMPWDINSLEEP_b .SRAMPWDSLP = PWRCTRL_MEMPWDINSLEEP_SRAMPWDSLP_ALLBUTLOWER32K;
86+
87+ setupRTC ();
88+
89+ Serial.println (" Going to sleep..." );
90+ delay (100 ); // Wait for print to complete
91+ Serial.end (); // Disable Serial
92+
93+ // Enable interrupts to the core.
94+ am_hal_interrupt_master_enable ();
95+ }
96+
97+ void loop ()
98+ {
99+ // Go to Deep Sleep.
100+ am_hal_sysctrl_sleep (AM_HAL_SYSCTRL_SLEEP_DEEP);
101+ }
102+
103+ void setupRTC ()
104+ {
105+ // Enable the XT for the RTC.
106+ am_hal_clkgen_control (AM_HAL_CLKGEN_CONTROL_XTAL_START, 0 );
107+
108+ // Select XT for RTC clock source
109+ am_hal_rtc_osc_select (AM_HAL_RTC_OSC_XT);
110+
111+ // Enable the RTC.
112+ am_hal_rtc_osc_enable ();
113+
114+ // Set the alarm repeat interval to be every second.
115+ am_hal_rtc_alarm_interval_set (AM_HAL_RTC_ALM_RPT_SEC);
116+
117+ // Clear the RTC alarm interrupt.
118+ am_hal_rtc_int_clear (AM_HAL_RTC_INT_ALM);
119+
120+ // Enable the RTC alarm interrupt.
121+ am_hal_rtc_int_enable (AM_HAL_RTC_INT_ALM);
122+
123+ // Enable RTC interrupts to the NVIC.
124+ NVIC_EnableIRQ (RTC_IRQn);
125+ }
126+
127+ extern " C" void am_rtc_isr (void )
128+ {
129+ // Clear the RTC alarm interrupt.
130+ am_hal_rtc_int_clear (AM_HAL_RTC_INT_ALM);
131+
132+ // Check the desired number of seconds until LED is toggled.
133+ if (++g_RTCseconds >= 5 )
134+ {
135+ // Reset the seconds counter.
136+ g_RTCseconds = 0 ;
137+
138+ // Toggle LED
139+ digitalWrite (LED_BUILTIN, HIGH);
140+ delay (100 );
141+ digitalWrite (LED_BUILTIN, LOW);
142+ }
143+ }
0 commit comments