Skip to content

Commit 85c477c

Browse files
authored
Merge pull request #10609 from kjbracey-arm/us_ticker_optimise
wait_us optimization
2 parents dfdf70b + c5b9779 commit 85c477c

File tree

36 files changed

+555
-54
lines changed

36 files changed

+555
-54
lines changed

TESTS/mbed_hal/us_ticker/main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ void us_ticker_info_test()
3434
TEST_ASSERT(p_ticker_info->frequency >= 250000);
3535
TEST_ASSERT(p_ticker_info->frequency <= 8000000);
3636
TEST_ASSERT(p_ticker_info->bits >= 16);
37+
38+
#ifdef US_TICKER_PERIOD_NUM
39+
TEST_ASSERT_UINT32_WITHIN(1, 1000000 * US_TICKER_PERIOD_DEN / US_TICKER_PERIOD_NUM, p_ticker_info->frequency);
40+
TEST_ASSERT_EQUAL_UINT32(US_TICKER_MASK, ((uint64_t)1 << p_ticker_info->bits) - 1);
41+
#endif
3742
}
3843

3944
utest::v1::status_t test_setup(const size_t number_of_cases)

components/TARGET_PSA/services/storage/common/psa_storage_common_impl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ static psa_status_t convert_status(int status)
127127
* \param n[in] number of bits to shift right
128128
* \return the result
129129
*/
130-
MBED_FORCEINLINE uint32_t lsr32(uint32_t x, uint32_t n)
130+
static MBED_FORCEINLINE uint32_t lsr32(uint32_t x, uint32_t n)
131131
{
132132
return x >> n;
133133
}
@@ -140,7 +140,7 @@ MBED_FORCEINLINE uint32_t lsr32(uint32_t x, uint32_t n)
140140
* \param n[in] number of bits to shift right
141141
* \return the result
142142
*/
143-
MBED_FORCEINLINE uint64_t lsr64(uint64_t x, uint32_t n)
143+
static MBED_FORCEINLINE uint64_t lsr64(uint64_t x, uint32_t n)
144144
{
145145
return x >> n;
146146
}

hal/mbed_us_ticker_api.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
#include <stddef.h>
19+
#include "platform/mbed_atomic.h"
1920
#include "hal/us_ticker_api.h"
2021

2122
#if DEVICE_USTICKER
@@ -24,15 +25,54 @@ static ticker_event_queue_t events = { 0 };
2425

2526
static ticker_irq_handler_type irq_handler = ticker_irq_handler;
2627

28+
#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
29+
30+
// If we are initializing at boot, we want the timer to be
31+
// always-on, so we block any attempt to free it. We do need
32+
// to pass through init(), as that needs to reset pending
33+
// interrupts.
34+
static void block_us_ticker_free()
35+
{
36+
}
37+
38+
#else // MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
39+
40+
bool _us_ticker_initialized;
41+
42+
// If we are not initializing at boot, we want to track
43+
// whether the timer has been initialized. This permits
44+
// a fast path for wait_us.
45+
static void note_us_ticker_init()
46+
{
47+
us_ticker_init();
48+
core_util_atomic_store_bool(&_us_ticker_initialized, true);
49+
}
50+
51+
static void note_us_ticker_free()
52+
{
53+
core_util_atomic_store_bool(&_us_ticker_initialized, false);
54+
us_ticker_free();
55+
}
56+
57+
#endif // MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
58+
2759
static const ticker_interface_t us_interface = {
60+
#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
2861
.init = us_ticker_init,
62+
#else
63+
.init = note_us_ticker_init,
64+
#endif
2965
.read = us_ticker_read,
3066
.disable_interrupt = us_ticker_disable_interrupt,
3167
.clear_interrupt = us_ticker_clear_interrupt,
3268
.set_interrupt = us_ticker_set_interrupt,
3369
.fire_interrupt = us_ticker_fire_interrupt,
3470
.get_info = us_ticker_get_info,
35-
.free = us_ticker_free,
71+
#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
72+
.free = block_us_ticker_free,
73+
#else
74+
.free = note_us_ticker_free,
75+
#endif
3676
.runs_in_deep_sleep = false,
3777
};
3878

hal/us_ticker_api.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,21 @@ extern "C" {
4141
*
4242
* @see hal_us_ticker_tests
4343
*
44+
* # Compile-time optimization macros
45+
*
46+
* To permit compile-time optimization, particularly of wait_us, the following macros should
47+
* be defined by a target's device.h:
48+
*
49+
* US_TICKER_PERIOD_NUM, US_TICKER_PERIOD_DEN: These denote the ratio (numerator, denominator)
50+
* of the ticker period to a microsecond. For example, an 8MHz ticker would have NUM = 1, DEN = 8;
51+
* a 1MHz ticker would have NUM = 1, DEN = 1; a 250kHz ticker would have NUM = 4, DEN = 1.
52+
* Both numerator and denominator must be 16 bits or less.
53+
*
54+
* US_TICKER_MASK: The value mask for the ticker - eg 0x07FFFFFF for a 27-bit ticker.
55+
*
56+
* If any are defined, all 3 must be defined, and the macros are checked for consistency with
57+
* us_ticker_get_info by test ::us_ticker_info_test.
58+
4459
* @{
4560
*/
4661

@@ -74,6 +89,7 @@ extern "C" {
7489
* Verified by ::ticker_fire_now_test
7590
* * The ticker operations ticker_read, ticker_clear_interrupt, ticker_set_interrupt and ticker_fire_interrupt
7691
* take less than 20us to complete - Verified by ::ticker_speed_test
92+
* * The ticker operations ticker_init and ticker_read are atomic.
7793
*
7894
* # Undefined behavior
7995
* * Calling any function other than ticker_init before the initialization of the ticker
@@ -210,7 +226,7 @@ void us_ticker_free(void);
210226
* }
211227
* @endcode
212228
*/
213-
uint32_t us_ticker_read(void);
229+
uint32_t (us_ticker_read)(void);
214230

215231
/** Set interrupt for specified timestamp
216232
*

platform/mbed_retarget.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,9 @@ extern "C" FILEHANDLE PREFIX(_open)(const char *name, int openflags)
483483
if (!mbed_sdk_inited) {
484484
mbed_copy_nvic();
485485
mbed_sdk_init();
486+
#if DEVICE_USTICKER && MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
487+
us_ticker_init();
488+
#endif
486489
mbed_sdk_inited = 1;
487490
}
488491
#endif

platform/mbed_sdk_boot.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <stdlib.h>
2020
#include <stdint.h>
2121
#include "cmsis.h"
22+
#include "hal/us_ticker_api.h"
2223

2324
/* This startup is for mbed 2 baremetal. There is no config for RTOS for mbed 2,
2425
* therefore we protect this file with MBED_CONF_RTOS_PRESENT
@@ -82,6 +83,9 @@ void _platform_post_stackheap_init(void)
8283
{
8384
mbed_copy_nvic();
8485
mbed_sdk_init();
86+
#if DEVICE_USTICKER && MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
87+
us_ticker_init();
88+
#endif
8589
}
8690

8791
#elif defined (__GNUC__)
@@ -92,6 +96,9 @@ void software_init_hook(void)
9296
{
9397
mbed_copy_nvic();
9498
mbed_sdk_init();
99+
#if DEVICE_USTICKER && MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
100+
us_ticker_init();
101+
#endif
95102
software_init_hook_rtos();
96103
}
97104

@@ -107,6 +114,9 @@ int __wrap_main(void)
107114
int __low_level_init(void)
108115
{
109116
mbed_copy_nvic();
117+
#if DEVICE_USTICKER && MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
118+
us_ticker_init();
119+
#endif
110120
return 1;
111121
}
112122

platform/mbed_toolchain.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,11 @@
277277
*/
278278
#ifndef MBED_FORCEINLINE
279279
#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM)
280-
#define MBED_FORCEINLINE static inline __attribute__((always_inline))
280+
#define MBED_FORCEINLINE inline __attribute__((always_inline))
281281
#elif defined(__ICCARM__)
282-
#define MBED_FORCEINLINE _Pragma("inline=forced") static
282+
#define MBED_FORCEINLINE _Pragma("inline=forced")
283283
#else
284-
#define MBED_FORCEINLINE static inline
284+
#define MBED_FORCEINLINE inline
285285
#endif
286286
#endif
287287

platform/mbed_wait_api.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
#ifndef MBED_WAIT_API_H
2626
#define MBED_WAIT_API_H
2727

28+
#include "platform/mbed_atomic.h"
29+
#include "device.h"
30+
2831
#ifdef __cplusplus
2932
extern "C" {
3033
#endif
@@ -115,6 +118,48 @@ void wait_us(int us);
115118
*/
116119
void wait_ns(unsigned int ns);
117120

121+
/* Optimize if we know the rate */
122+
#if DEVICE_USTICKER && defined US_TICKER_PERIOD_NUM
123+
void _wait_us_ticks(uint32_t ticks);
124+
void _wait_us_generic(unsigned int us);
125+
126+
/* Further optimization if we know us_ticker is always running */
127+
#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
128+
#define _us_ticker_is_initialized true
129+
#else
130+
extern bool _us_ticker_initialized;
131+
#define _us_ticker_is_initialized core_util_atomic_load_bool(&_us_ticker_initialized)
132+
#endif
133+
134+
#if US_TICKER_PERIOD_DEN == 1 && (US_TICKER_MASK * US_TICKER_PERIOD_NUM) >= 0xFFFFFFFF
135+
/* Ticker is wide and slow enough to have full 32-bit range - can always use it directly */
136+
#define _us_is_small_enough(us) true
137+
#else
138+
/* Threshold is determined by specification of us_ticker_api.h - smallest possible
139+
* time range for the us_ticker is 16-bit 8MHz, which gives 8192us. This also leaves
140+
* headroom for the multiplication in 32 bits.
141+
*/
142+
#define _us_is_small_enough(us) ((us) < 8192)
143+
#endif
144+
145+
/* Speed optimisation for small wait_us. Care taken to preserve binary compatibility */
146+
inline void _wait_us_inline(unsigned int us)
147+
{
148+
/* Threshold is determined by specification of us_ticker_api.h - smallest possible
149+
* time range for the us_ticker is 16-bit 8MHz, which gives 8192us. This also leaves
150+
* headroom for the multiplication in 32 bits.
151+
*/
152+
if (_us_is_small_enough(us) && _us_ticker_is_initialized) {
153+
const uint32_t ticks = ((us * US_TICKER_PERIOD_DEN) + US_TICKER_PERIOD_NUM - 1) / US_TICKER_PERIOD_NUM;
154+
_wait_us_ticks(ticks);
155+
} else {
156+
_wait_us_generic(us);
157+
}
158+
}
159+
160+
#define wait_us(us) _wait_us_inline(us)
161+
#endif // Known-rate, initialised timer
162+
118163
#ifdef __cplusplus
119164
}
120165
#endif

platform/mbed_wait_api_no_rtos.c

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
#include "platform/mbed_toolchain.h"
2020
#include "platform/mbed_wait_api.h"
2121

22+
#include "hal/lp_ticker_api.h"
23+
#include "hal/us_ticker_api.h"
24+
#include "hal/ticker_api.h"
25+
2226
// This implementation of the wait functions will be compiled only
2327
// if the RTOS is not present.
2428
#ifndef MBED_CONF_RTOS_PRESENT
2529

26-
#include "hal/lp_ticker_api.h"
27-
#include "hal/us_ticker_api.h"
28-
2930
void wait(float s)
3031
{
3132
wait_ms(s * 1000.0f);
@@ -42,24 +43,55 @@ void wait_ms(int ms)
4243
#endif
4344
}
4445

46+
#endif // #ifndef MBED_CONF_RTOS_PRESENT
47+
48+
// This wait_us is used by both RTOS and non-RTOS builds
49+
/* The actual time delay may be 1 less usec */
50+
51+
#if DEVICE_USTICKER
52+
53+
#if defined US_TICKER_PERIOD_NUM
54+
/* Real definition for binary compatibility with binaries not using the new macro */
55+
void (wait_us)(int us)
56+
{
57+
wait_us(us);
58+
}
59+
60+
/* External definition for the inline function */
61+
extern void _wait_us_inline(unsigned int us);
62+
63+
void _wait_us_ticks(uint32_t ticks)
64+
{
65+
const uint32_t start = us_ticker_read();
66+
while (((us_ticker_read() - start) & US_TICKER_MASK) < ticks);
67+
}
68+
69+
void _wait_us_generic(unsigned int us)
70+
#else
4571
void wait_us(int us)
72+
#endif
4673
{
47-
#if DEVICE_USTICKER
74+
// Generic version using full ticker, allowing for initialization, scaling and widening of timer
4875
const ticker_data_t *const ticker = get_us_ticker_data();
49-
uint32_t start = ticker_read(ticker);
76+
const uint32_t start = ticker_read(ticker);
5077
while ((ticker_read(ticker) - start) < (uint32_t)us);
51-
#else // fallback to wait_ns for targets without usticker
52-
while (us > 1000) {
53-
us -= 1000;
54-
wait_ns(1000000);
78+
}
79+
80+
#else // DEVICE_USTICKER
81+
82+
// fallback to wait_ns for targets without usticker
83+
void wait_us(int us)
84+
{
85+
while (us > 1024) {
86+
us -= 1024;
87+
wait_ns(1024000);
5588
}
5689
if (us > 0) {
5790
wait_ns(us * 1000);
5891
}
59-
#endif // DEVICE_USTICKER
6092
}
6193

62-
#endif // #ifndef MBED_CONF_RTOS_PRESENT
94+
#endif // DEVICE_USTICKER
6395

6496
// This wait_ns is used by both RTOS and non-RTOS builds
6597

@@ -110,7 +142,7 @@ static const uint16_t delay_loop_code[] = {
110142
};
111143

112144
/* Take the address of the code, set LSB to indicate Thumb, and cast to void() function pointer */
113-
#define delay_loop ((void(*)()) ((uintptr_t) delay_loop_code | 1))
145+
#define delay_loop ((void(*)()) ((uintptr_t) delay_loop_code + 1))
114146

115147
/* Some targets may not provide zero-wait-state flash performance. Export this function
116148
* to be overridable for targets to provide more accurate implementation like locating

platform/mbed_wait_api_rtos.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,5 @@ void wait_ms(int ms)
6363
}
6464
}
6565

66-
/* The actual time delay may be 1 less usec */
67-
void wait_us(int us)
68-
{
69-
if (us > 10000) {
70-
MBED_WARNING(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_UNKNOWN),
71-
"wait_us blocks deep sleep, wait_ms recommended for long delays\n");
72-
}
73-
const ticker_data_t *const ticker = get_us_ticker_data();
74-
uint32_t start = ticker_read(ticker);
75-
while ((ticker_read(ticker) - start) < (uint32_t)us);
76-
}
77-
7866
#endif // #if MBED_CONF_RTOS_PRESENT
7967

rtos/TARGET_CORTEX/mbed_boot.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include <stdlib.h>
5959

6060
#include "cmsis.h"
61+
#include "hal/us_ticker_api.h"
6162
#include "mbed_toolchain.h"
6263
#include "mbed_boot.h"
6364
#include "mbed_error.h"
@@ -75,6 +76,9 @@ void mbed_init(void)
7576
mbed_mpu_manager_init();
7677
mbed_cpy_nvic();
7778
mbed_sdk_init();
79+
#if DEVICE_USTICKER && MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT
80+
us_ticker_init();
81+
#endif
7882
mbed_rtos_init();
7983
}
8084

0 commit comments

Comments
 (0)