Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
mbed_power_mgmt.c
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017-2019 ARM Limited 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "platform/mbed_power_mgmt.h" 00019 #include "platform/mbed_interface.h" 00020 #include "platform/mbed_atomic.h" 00021 #include "platform/mbed_critical.h" 00022 #include "platform/mbed_error.h" 00023 #include "platform/mbed_stats.h" 00024 00025 #include "hal/sleep_api.h" 00026 #include "hal/us_ticker_api.h" 00027 #include "hal/lp_ticker_api.h" 00028 #include "platform/mbed_wait_api.h" 00029 00030 #include <stdio.h> 00031 00032 #if DEVICE_SLEEP 00033 00034 // deep sleep locking counter. A target is allowed to deep sleep if counter == 0 00035 static uint16_t deep_sleep_lock = 0U; 00036 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER 00037 static us_timestamp_t sleep_time = 0; 00038 static us_timestamp_t deep_sleep_time = 0; 00039 00040 static const ticker_data_t *sleep_ticker = NULL; 00041 #endif 00042 00043 static inline us_timestamp_t read_us(void) 00044 { 00045 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER 00046 if (NULL == sleep_ticker) { 00047 sleep_ticker = get_lp_ticker_data(); 00048 } 00049 return ticker_read_us(sleep_ticker); 00050 #else 00051 return 0; 00052 #endif 00053 } 00054 00055 us_timestamp_t mbed_time_idle(void) 00056 { 00057 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER 00058 return (sleep_time + deep_sleep_time); 00059 #else 00060 return 0; 00061 #endif 00062 } 00063 00064 us_timestamp_t mbed_uptime(void) 00065 { 00066 return read_us(); 00067 } 00068 00069 us_timestamp_t mbed_time_sleep(void) 00070 { 00071 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER 00072 return sleep_time; 00073 #else 00074 return 0; 00075 #endif 00076 } 00077 00078 us_timestamp_t mbed_time_deepsleep(void) 00079 { 00080 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER 00081 return deep_sleep_time; 00082 #else 00083 return 0; 00084 #endif 00085 } 00086 00087 #ifdef MBED_SLEEP_TRACING_ENABLED 00088 00089 // Length of the identifier extracted from the driver name to store for logging. 00090 #define IDENTIFIER_WIDTH 15 00091 00092 // Number of drivers that can be stored in the structure 00093 #define STATISTIC_COUNT 10 00094 00095 typedef struct sleep_statistic { 00096 char identifier[IDENTIFIER_WIDTH]; 00097 uint8_t count; 00098 } sleep_statistic_t; 00099 00100 static sleep_statistic_t sleep_stats[STATISTIC_COUNT]; 00101 00102 static sleep_statistic_t *sleep_tracker_find(const char *const filename) 00103 { 00104 char temp[IDENTIFIER_WIDTH]; 00105 strncpy(temp, filename, IDENTIFIER_WIDTH); 00106 temp[IDENTIFIER_WIDTH - 1] = '\0'; 00107 00108 // Search for the a driver matching the current name and return it's index 00109 for (int i = 0; i < STATISTIC_COUNT; ++i) { 00110 if (strcmp(sleep_stats[i].identifier, temp) == 0) { 00111 return &sleep_stats[i]; 00112 } 00113 } 00114 00115 return NULL; 00116 } 00117 00118 static sleep_statistic_t *sleep_tracker_add(const char *const filename) 00119 { 00120 char temp[IDENTIFIER_WIDTH]; 00121 strncpy(temp, filename, IDENTIFIER_WIDTH); 00122 temp[IDENTIFIER_WIDTH - 1] = '\0'; 00123 00124 for (int i = 0; i < STATISTIC_COUNT; ++i) { 00125 if (sleep_stats[i].identifier[0] == '\0') { 00126 core_util_critical_section_enter(); 00127 strncpy(sleep_stats[i].identifier, temp, sizeof(temp)); 00128 core_util_critical_section_exit(); 00129 00130 return &sleep_stats[i]; 00131 } 00132 } 00133 00134 mbed_error_printf("No free indexes left to use in mbed sleep tracker.\r\n"); 00135 00136 return NULL; 00137 } 00138 00139 static void sleep_tracker_print_stats(void) 00140 { 00141 mbed_error_printf("Sleep locks held:\r\n"); 00142 for (int i = 0; i < STATISTIC_COUNT; ++i) { 00143 if (sleep_stats[i].count == 0) { 00144 continue; 00145 } 00146 00147 if (sleep_stats[i].identifier[0] == '\0') { 00148 return; 00149 } 00150 00151 mbed_error_printf("[id: %s, count: %u]\r\n", sleep_stats[i].identifier, 00152 sleep_stats[i].count); 00153 } 00154 } 00155 00156 void sleep_tracker_lock(const char *const filename, int line) 00157 { 00158 sleep_statistic_t *stat = sleep_tracker_find(filename); 00159 00160 // Entry for this driver does not exist, create one. 00161 if (stat == NULL) { 00162 stat = sleep_tracker_add(filename); 00163 } 00164 00165 core_util_atomic_incr_u8(&stat->count, 1); 00166 00167 mbed_error_printf("LOCK: %s, ln: %i, lock count: %u\r\n", filename, line, deep_sleep_lock); 00168 } 00169 00170 void sleep_tracker_unlock(const char *const filename, int line) 00171 { 00172 sleep_statistic_t *stat = sleep_tracker_find(filename); 00173 00174 // Entry for this driver does not exist, something went wrong. 00175 if (stat == NULL) { 00176 mbed_error_printf("Unlocking sleep for driver that was not previously locked: %s, ln: %i\r\n", filename, line); 00177 return; 00178 } 00179 00180 core_util_atomic_decr_u8(&stat->count, 1); 00181 00182 mbed_error_printf("UNLOCK: %s, ln: %i, lock count: %u\r\n", filename, line, deep_sleep_lock); 00183 } 00184 00185 #endif // MBED_SLEEP_TRACING_ENABLED 00186 00187 void sleep_manager_lock_deep_sleep_internal(void) 00188 { 00189 if (core_util_atomic_incr_u16 (&deep_sleep_lock, 1) == 0) { 00190 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_OVERFLOW), "DeepSleepLock overflow (> 0xFFFF)", deep_sleep_lock); 00191 } 00192 } 00193 00194 void sleep_manager_unlock_deep_sleep_internal(void) 00195 { 00196 if (core_util_atomic_decr_u16 (&deep_sleep_lock, 1) == 0xFFFF) { 00197 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", deep_sleep_lock); 00198 } 00199 } 00200 00201 bool sleep_manager_can_deep_sleep(void) 00202 { 00203 return core_util_atomic_load_u16 (&deep_sleep_lock) == 0; 00204 } 00205 00206 bool sleep_manager_can_deep_sleep_test_check() 00207 { 00208 uint32_t check_time_ns = 2000000; 00209 00210 while (check_time_ns) { 00211 if (sleep_manager_can_deep_sleep()) { 00212 return true; 00213 } 00214 00215 wait_ns(100000); // 100 us 00216 check_time_ns -= 100000; 00217 } 00218 return false; 00219 } 00220 00221 void sleep_manager_sleep_auto(void) 00222 { 00223 #ifdef MBED_SLEEP_TRACING_ENABLED 00224 sleep_tracker_print_stats(); 00225 #endif 00226 core_util_critical_section_enter(); 00227 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER 00228 us_timestamp_t start = read_us(); 00229 bool deep = false; 00230 #endif 00231 00232 // debug profile should keep debuggers attached, no deep sleep allowed 00233 #ifdef MBED_DEBUG 00234 hal_sleep(); 00235 #else 00236 if (sleep_manager_can_deep_sleep()) { 00237 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER 00238 deep = true; 00239 #endif 00240 hal_deepsleep(); 00241 } else { 00242 hal_sleep(); 00243 } 00244 #endif 00245 00246 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER 00247 us_timestamp_t end = read_us(); 00248 if (true == deep) { 00249 deep_sleep_time += end - start; 00250 } else { 00251 sleep_time += end - start; 00252 } 00253 #endif 00254 core_util_critical_section_exit(); 00255 } 00256 00257 #else 00258 00259 // locking is valid only if DEVICE_SLEEP is defined 00260 // we provide empty implementation 00261 00262 void sleep_manager_lock_deep_sleep_internal(void) 00263 { 00264 00265 } 00266 00267 void sleep_manager_unlock_deep_sleep_internal(void) 00268 { 00269 00270 } 00271 00272 bool sleep_manager_can_deep_sleep(void) 00273 { 00274 // no sleep implemented 00275 return false; 00276 } 00277 00278 #endif
Generated on Tue Jul 12 2022 13:54:33 by
