mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_sleep_manager.c Source File

mbed_sleep_manager.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 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 "mbed_power_mgmt.h"
00019 #include "mbed_interface.h"
00020 #include "mbed_critical.h"
00021 #include "mbed_assert.h"
00022 #include "mbed_error.h"
00023 #include "mbed_stats.h"
00024 
00025 #include "hal/us_ticker_api.h"
00026 #include "hal/lp_ticker_api.h"
00027 
00028 #include <limits.h>
00029 #include <stdio.h>
00030 
00031 #if DEVICE_SLEEP
00032 
00033 // deep sleep locking counter. A target is allowed to deep sleep if counter == 0
00034 static uint16_t deep_sleep_lock = 0U;
00035 static us_timestamp_t sleep_time = 0;
00036 static us_timestamp_t deep_sleep_time = 0;
00037 
00038 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER
00039 static ticker_data_t *sleep_ticker = NULL;
00040 #endif
00041 
00042 static inline us_timestamp_t read_us(void)
00043 {
00044 #if defined(MBED_CPU_STATS_ENABLED) && DEVICE_LPTICKER
00045     if (NULL == sleep_ticker) {
00046         sleep_ticker = (ticker_data_t *)get_lp_ticker_data();
00047     }
00048     return ticker_read_us(sleep_ticker);
00049 #else
00050     return 0;
00051 #endif
00052 }
00053 
00054 us_timestamp_t mbed_time_idle(void)
00055 {
00056     return (sleep_time + deep_sleep_time);
00057 }
00058 
00059 us_timestamp_t mbed_uptime(void)
00060 {
00061     return read_us();
00062 }
00063 
00064 us_timestamp_t mbed_time_sleep(void)
00065 {
00066     return sleep_time;
00067 }
00068 
00069 us_timestamp_t mbed_time_deepsleep(void)
00070 {
00071     return deep_sleep_time;
00072 }
00073 
00074 #ifdef MBED_SLEEP_TRACING_ENABLED
00075 
00076 // Number of drivers that can be stored in the structure
00077 #define STATISTIC_COUNT  10
00078 
00079 typedef struct sleep_statistic {
00080     const char *identifier;
00081     uint8_t count;
00082 } sleep_statistic_t;
00083 
00084 static sleep_statistic_t sleep_stats[STATISTIC_COUNT];
00085 
00086 static sleep_statistic_t *sleep_tracker_find(const char *const filename)
00087 {
00088     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00089         if (sleep_stats[i].identifier == filename) {
00090             return &sleep_stats[i];
00091         }
00092     }
00093 
00094     return NULL;
00095 }
00096 
00097 static sleep_statistic_t *sleep_tracker_add(const char *const filename)
00098 {
00099     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00100         if (sleep_stats[i].identifier == NULL) {
00101             sleep_stats[i].identifier = filename;
00102 
00103             return &sleep_stats[i];
00104         }
00105     }
00106 
00107     mbed_error_printf("No free indexes left to use in mbed sleep tracker.\r\n");
00108 
00109     return NULL;
00110 }
00111 
00112 static void sleep_tracker_print_stats(void)
00113 {
00114     mbed_error_printf("Sleep locks held:\r\n");
00115     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00116         if (sleep_stats[i].count == 0) {
00117             continue;
00118         }
00119 
00120         if (sleep_stats[i].identifier == NULL) {
00121             return;
00122         }
00123 
00124         mbed_error_printf("[id: %s, count: %u]\r\n", sleep_stats[i].identifier,
00125                           sleep_stats[i].count);
00126     }
00127 }
00128 
00129 void sleep_tracker_lock(const char *const filename, int line)
00130 {
00131     sleep_statistic_t *stat = sleep_tracker_find(filename);
00132 
00133     // Entry for this driver does not exist, create one.
00134     if (stat == NULL) {
00135         stat = sleep_tracker_add(filename);
00136     }
00137 
00138     core_util_atomic_incr_u8(&stat->count, 1);
00139 
00140     mbed_error_printf("LOCK: %s, ln: %i, lock count: %u\r\n", filename, line, deep_sleep_lock);
00141 }
00142 
00143 void sleep_tracker_unlock(const char *const filename, int line)
00144 {
00145     sleep_statistic_t *stat = sleep_tracker_find(filename);
00146 
00147     // Entry for this driver does not exist, something went wrong.
00148     if (stat == NULL) {
00149         mbed_error_printf("Unlocking sleep for driver that was not previously locked: %s, ln: %i\r\n", filename, line);
00150         return;
00151     }
00152 
00153     core_util_atomic_decr_u8(&stat->count, 1);
00154 
00155     mbed_error_printf("UNLOCK: %s, ln: %i, lock count: %u\r\n", filename, line, deep_sleep_lock);
00156 }
00157 
00158 #endif // MBED_SLEEP_TRACING_ENABLED
00159 
00160 void sleep_manager_lock_deep_sleep_internal(void)
00161 {
00162     core_util_critical_section_enter();
00163     if (deep_sleep_lock == USHRT_MAX) {
00164         core_util_critical_section_exit();
00165         MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_OVERFLOW), "DeepSleepLock overflow (> USHRT_MAX)", deep_sleep_lock);
00166     }
00167     core_util_atomic_incr_u16(&deep_sleep_lock, 1);
00168     core_util_critical_section_exit();
00169 }
00170 
00171 void sleep_manager_unlock_deep_sleep_internal(void)
00172 {
00173     core_util_critical_section_enter();
00174     if (deep_sleep_lock == 0) {
00175         core_util_critical_section_exit();
00176         MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", deep_sleep_lock);
00177     }
00178     core_util_atomic_decr_u16(&deep_sleep_lock, 1);
00179     core_util_critical_section_exit();
00180 }
00181 
00182 bool sleep_manager_can_deep_sleep(void)
00183 {
00184     return deep_sleep_lock == 0 ? true : false;
00185 }
00186 
00187 bool sleep_manager_can_deep_sleep_test_check()
00188 {
00189     const uint32_t check_time_us = 2000;
00190     const ticker_data_t *const ticker = get_us_ticker_data();
00191     uint32_t start = ticker_read(ticker);
00192     while ((ticker_read(ticker) - start) < check_time_us) {
00193         if (sleep_manager_can_deep_sleep()) {
00194             return true;
00195         }
00196     }
00197     return false;
00198 }
00199 
00200 void sleep_manager_sleep_auto(void)
00201 {
00202 #ifdef MBED_SLEEP_TRACING_ENABLED
00203     sleep_tracker_print_stats();
00204 #endif
00205     core_util_critical_section_enter();
00206     us_timestamp_t start = read_us();
00207     bool deep = false;
00208 
00209 // debug profile should keep debuggers attached, no deep sleep allowed
00210 #ifdef MBED_DEBUG
00211     hal_sleep();
00212 #else
00213     if (sleep_manager_can_deep_sleep()) {
00214         deep = true;
00215         hal_deepsleep();
00216     } else {
00217         hal_sleep();
00218     }
00219 #endif
00220 
00221     us_timestamp_t end = read_us();
00222     if (true == deep) {
00223         deep_sleep_time += end - start;
00224     } else {
00225         sleep_time += end - start;
00226     }
00227     core_util_critical_section_exit();
00228 }
00229 
00230 #else
00231 
00232 // locking is valid only if DEVICE_SLEEP is defined
00233 // we provide empty implementation
00234 
00235 void sleep_manager_lock_deep_sleep_internal(void)
00236 {
00237 
00238 }
00239 
00240 void sleep_manager_unlock_deep_sleep_internal(void)
00241 {
00242 
00243 }
00244 
00245 bool sleep_manager_can_deep_sleep(void)
00246 {
00247     // no sleep implemented
00248     return false;
00249 }
00250 
00251 #endif