Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_power_mgmt.c Source File

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