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_wait_api_no_rtos.c Source File

mbed_wait_api_no_rtos.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 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 "cmsis.h"
00019 #include "platform/mbed_toolchain.h"
00020 #include "platform/mbed_wait_api.h"
00021 
00022 #include "hal/lp_ticker_api.h"
00023 #include "hal/us_ticker_api.h"
00024 #include "hal/ticker_api.h"
00025 
00026 // This implementation of the wait functions will be compiled only
00027 // if the RTOS is not present.
00028 #ifndef MBED_CONF_RTOS_PRESENT
00029 
00030 void wait(float s)
00031 {
00032     wait_ms(s * 1000.0f);
00033 }
00034 
00035 void wait_ms(int ms)
00036 {
00037 #if DEVICE_LPTICKER
00038     const ticker_data_t *const ticker = get_lp_ticker_data();
00039     uint32_t start = ticker_read(ticker);
00040     while ((ticker_read(ticker) - start) < (uint32_t)(ms * 1000));
00041 #else
00042     wait_us(ms * 1000);
00043 #endif
00044 }
00045 
00046 #endif // #ifndef MBED_CONF_RTOS_PRESENT
00047 
00048 // This wait_us is used by both RTOS and non-RTOS builds
00049 /*  The actual time delay may be 1 less usec */
00050 
00051 #if DEVICE_USTICKER
00052 
00053 #if defined US_TICKER_PERIOD_NUM
00054 /* Real definition for binary compatibility with binaries not using the new macro */
00055 void (wait_us)(int us)
00056 {
00057     wait_us(us);
00058 }
00059 
00060 /* External definition for the inline function */
00061 extern void _wait_us_inline(unsigned int us);
00062 
00063 void _wait_us_ticks(uint32_t ticks)
00064 {
00065     const uint32_t start = us_ticker_read();
00066     while (((us_ticker_read() - start) & US_TICKER_MASK) < ticks);
00067 }
00068 
00069 void _wait_us_generic(unsigned int us)
00070 #else
00071 void wait_us(int us)
00072 #endif
00073 {
00074     // Generic version using full ticker, allowing for initialization, scaling and widening of timer
00075     const ticker_data_t *const ticker = get_us_ticker_data();
00076     const uint32_t start = ticker_read(ticker);
00077     while ((ticker_read(ticker) - start) < (uint32_t)us);
00078 }
00079 
00080 #else // DEVICE_USTICKER
00081 
00082 // fallback to wait_ns for targets without usticker
00083 void wait_us(int us)
00084 {
00085     while (us > 1024) {
00086         us -= 1024;
00087         wait_ns(1024000);
00088     }
00089     if (us > 0) {
00090         wait_ns(us * 1000);
00091     }
00092 }
00093 
00094 #endif // DEVICE_USTICKER
00095 
00096 // This wait_ns is used by both RTOS and non-RTOS builds
00097 
00098 #ifdef __CORTEX_M
00099 #if (__CORTEX_M == 0 && !defined __CM0PLUS_REV) || __CORTEX_M == 1
00100 // Cortex-M0 and Cortex-M1 take 6 cycles per iteration - SUBS = 1, 2xNOP = 2, BCS = 3
00101 #define LOOP_SCALER 6000
00102 #elif (__CORTEX_M == 0 && defined __CM0PLUS_REV) || __CORTEX_M == 3 || __CORTEX_M == 4 || \
00103       __CORTEX_M == 23
00104 // Cortex-M0+, M3, M4 and M23 take 5 cycles per iteration - SUBS = 1, 2xNOP = 2, BCS = 2
00105 #define LOOP_SCALER 5000
00106 #elif __CORTEX_M == 33
00107 // Cortex-M33 can dual issue for 3 cycles per iteration (SUB,NOP) = 1, (NOP,BCS) = 2
00108 #define LOOP_SCALER 3000
00109 #elif __CORTEX_M == 7
00110 // Cortex-M7 manages to dual-issue for 2 cycles per iteration (SUB,NOP) = 1, (NOP,BCS) = 1
00111 // (The NOPs were added to stabilise this - with just the SUB and BCS, it seems that the
00112 // M7 sometimes takes 1 cycle, sometimes 2, possibly depending on alignment)
00113 #define LOOP_SCALER 2000
00114 #endif
00115 #elif defined __CORTEX_A
00116 #if __CORTEX_A == 9
00117 // Cortex-A9 can dual issue for 3 cycles per iteration (SUB,NOP) = 1, (NOP,BCS) = 2
00118 #define LOOP_SCALER 3000
00119 #endif
00120 #endif
00121 
00122 /* We only define the function if we've identified the CPU. If we haven't,
00123  * rather than a compile-time error, leave it undefined, rather than faulting
00124  * with an immediate #error. This leaves the door open to non-ARM
00125  * builds with or people providing substitutes for other CPUs, and only if
00126  * needed.
00127  */
00128 #ifdef LOOP_SCALER
00129 
00130 /* Timing seems to depend on alignment, and toolchains do not support aligning
00131  * functions well. So sidestep that by hand-assembling the code. Also avoids
00132  * the hassle of handling multiple toolchains with different assembler
00133  * syntax.
00134  */
00135 MBED_ALIGN(16)
00136 static const uint16_t delay_loop_code[] = {
00137     0x1E40, // SUBS R0,R0,#1
00138     0xBF00, // NOP
00139     0xBF00, // NOP
00140     0xD2FB, // BCS .-3        (0x00 would be .+2, so 0xFB = -5 = .-3)
00141     0x4770  // BX LR
00142 };
00143 
00144 /* Take the address of the code, set LSB to indicate Thumb, and cast to void() function pointer */
00145 #define delay_loop ((void(*)()) ((uintptr_t) delay_loop_code + 1))
00146 
00147 /* Some targets may not provide zero-wait-state flash performance. Export this function
00148  * to be overridable for targets to provide more accurate implementation like locating
00149  * 'delay_loop_code' in SRAM. */
00150 MBED_WEAK void wait_ns(unsigned int ns)
00151 {
00152     uint32_t cycles_per_us = SystemCoreClock / 1000000;
00153     // Note that this very calculation, plus call overhead, will take multiple
00154     // cycles. Could well be 100ns on its own... So round down here, startup is
00155     // worth at least one loop iteration.
00156     uint32_t count = (cycles_per_us * ns) / LOOP_SCALER;
00157 
00158     delay_loop(count);
00159 }
00160 #endif // LOOP_SCALER