Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_hal_timer.cpp Source File

arm_hal_timer.cpp

00001 /*
00002  * Copyright (c) 2016-2018, Arm Limited and affiliates.
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 before mbed.h to properly get UINT*_C()
00019 #include "ns_types.h"
00020 
00021 #include "platform/SingletonPtr.h"
00022 #include "platform/arm_hal_timer.h"
00023 #include "platform/arm_hal_interrupt.h"
00024 #include "platform/mbed_assert.h"
00025 #include "Timeout.h"
00026 #include "Timer.h"
00027 #include "Ticker.h"
00028 #include "events/Event.h"
00029 #include "events/mbed_shared_queues.h"
00030 
00031 using namespace mbed;
00032 using namespace events;
00033 
00034 static SingletonPtr<Timer> timer;
00035 static SingletonPtr<Timeout>  timeout;
00036 
00037 // If critical sections are implemented using mutexes, timers must be called in thread context, and
00038 // we use the high-priority event queue for this.
00039 // If critical sections disable interrupts, we can call timers directly from interrupt. Avoiding the
00040 // event queue can save ~1600B of RAM if the rest of the system is not using the event queue either.
00041 // Caveats of this tunable are listed on arm_hal_interrupt.c.
00042 #if !MBED_CONF_NANOSTACK_HAL_CRITICAL_SECTION_USABLE_FROM_INTERRUPT
00043 static EventQueue *equeue;
00044 #endif
00045 
00046 static uint32_t due;
00047 static void (*arm_hal_callback)(void);
00048 
00049 #if defined(NS_EVENTLOOP_USE_TICK_TIMER)
00050 
00051 #if MBED_CONF_NANOSTACK_HAL_CRITICAL_SECTION_USABLE_FROM_INTERRUPT
00052 static SingletonPtr<Ticker> tick_ticker;
00053 #endif
00054 
00055 static int tick_timer_id;
00056 static void (*tick_timer_cb)(void);
00057 
00058 int8_t platform_tick_timer_register(void (*tick_timer_cb_handler)(void))
00059 {
00060 #if !MBED_CONF_NANOSTACK_HAL_CRITICAL_SECTION_USABLE_FROM_INTERRUPT
00061     equeue = mbed_highprio_event_queue();
00062     MBED_ASSERT(equeue != NULL);
00063 #endif
00064 
00065     tick_timer_cb = tick_timer_cb_handler;
00066     return 0;
00067 }
00068 
00069 int8_t platform_tick_timer_start(uint32_t period_ms)
00070 {
00071     int8_t retval = -1;
00072     if (tick_timer_cb && tick_timer_id == 0) {
00073 #if !MBED_CONF_NANOSTACK_HAL_CRITICAL_SECTION_USABLE_FROM_INTERRUPT
00074         tick_timer_id = equeue->call_every(period_ms, tick_timer_cb);
00075         if (tick_timer_id != 0) {
00076             retval = 0;
00077         }
00078 #else
00079         tick_ticker->attach_us(tick_timer_cb, period_ms * 1000);
00080         tick_timer_id = 1;
00081         retval = 0;
00082 #endif
00083     }
00084     return retval;
00085 }
00086 
00087 int8_t platform_tick_timer_stop(void)
00088 {
00089     int8_t retval = -1;
00090     if (tick_timer_id != 0) {
00091 #if !MBED_CONF_NANOSTACK_HAL_CRITICAL_SECTION_USABLE_FROM_INTERRUPT
00092         equeue->cancel(tick_timer_id);
00093 #else
00094         tick_ticker->detach();
00095 #endif
00096         tick_timer_id = 0;
00097         retval = 0;
00098     }
00099     return retval;
00100 }
00101 #endif // NS_EVENTLOOP_USE_TICK_TIMER
00102 
00103 
00104 // Called once at boot
00105 void platform_timer_enable(void)
00106 {
00107 #if !MBED_CONF_NANOSTACK_HAL_CRITICAL_SECTION_USABLE_FROM_INTERRUPT
00108     equeue = mbed_highprio_event_queue();
00109     MBED_ASSERT(equeue != NULL);
00110 #endif
00111     timer->start();
00112     // Prime the SingletonPtr - can't construct from IRQ/critical section
00113     timeout.get();
00114 }
00115 
00116 // Actually cancels a timer, not the opposite of enable
00117 void platform_timer_disable(void)
00118 {
00119     timeout->detach();
00120 }
00121 
00122 // Not called while running, fortunately
00123 void platform_timer_set_cb(void (*new_fp)(void))
00124 {
00125     arm_hal_callback = new_fp;
00126 }
00127 
00128 static void timer_callback(void)
00129 {
00130     due = 0;
00131 
00132 #if MBED_CONF_NANOSTACK_HAL_CRITICAL_SECTION_USABLE_FROM_INTERRUPT
00133     // Callback is interrupt safe so it can be called directly without
00134     // bouncing via event queue thread.
00135     arm_hal_callback();
00136 #else
00137     equeue->call(arm_hal_callback);
00138 #endif
00139 }
00140 
00141 // This is called from inside platform_enter_critical - IRQs can't happen
00142 void platform_timer_start(uint16_t slots)
00143 {
00144     timer->reset();
00145     due = slots * UINT32_C(50);
00146     timeout->attach_us(timer_callback, due);
00147 }
00148 
00149 // This is called from inside platform_enter_critical - IRQs can't happen
00150 uint16_t platform_timer_get_remaining_slots(void)
00151 {
00152     uint32_t elapsed = timer->read_us();
00153     if (elapsed < due) {
00154         return (uint16_t)((due - elapsed) / 50);
00155     } else {
00156         return 0;
00157     }
00158 }
00159