mbed-os
Dependents: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
rtos/TARGET_CORTEX/mbed_rtx_idle.cpp@0:b74591d5ab33, 2017-12-11 (annotated)
- Committer:
- be_bryan
- Date:
- Mon Dec 11 17:54:04 2017 +0000
- Revision:
- 0:b74591d5ab33
motor ++
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
be_bryan | 0:b74591d5ab33 | 1 | /* mbed Microcontroller Library |
be_bryan | 0:b74591d5ab33 | 2 | * Copyright (c) 2006-2012 ARM Limited |
be_bryan | 0:b74591d5ab33 | 3 | * |
be_bryan | 0:b74591d5ab33 | 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
be_bryan | 0:b74591d5ab33 | 5 | * of this software and associated documentation files (the "Software"), to deal |
be_bryan | 0:b74591d5ab33 | 6 | * in the Software without restriction, including without limitation the rights |
be_bryan | 0:b74591d5ab33 | 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
be_bryan | 0:b74591d5ab33 | 8 | * copies of the Software, and to permit persons to whom the Software is |
be_bryan | 0:b74591d5ab33 | 9 | * furnished to do so, subject to the following conditions: |
be_bryan | 0:b74591d5ab33 | 10 | * |
be_bryan | 0:b74591d5ab33 | 11 | * The above copyright notice and this permission notice shall be included in |
be_bryan | 0:b74591d5ab33 | 12 | * all copies or substantial portions of the Software. |
be_bryan | 0:b74591d5ab33 | 13 | * |
be_bryan | 0:b74591d5ab33 | 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
be_bryan | 0:b74591d5ab33 | 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
be_bryan | 0:b74591d5ab33 | 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
be_bryan | 0:b74591d5ab33 | 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
be_bryan | 0:b74591d5ab33 | 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
be_bryan | 0:b74591d5ab33 | 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
be_bryan | 0:b74591d5ab33 | 20 | * SOFTWARE. |
be_bryan | 0:b74591d5ab33 | 21 | */ |
be_bryan | 0:b74591d5ab33 | 22 | |
be_bryan | 0:b74591d5ab33 | 23 | #include "rtos/rtos_idle.h" |
be_bryan | 0:b74591d5ab33 | 24 | #include "platform/mbed_sleep.h" |
be_bryan | 0:b74591d5ab33 | 25 | #include "TimerEvent.h" |
be_bryan | 0:b74591d5ab33 | 26 | #include "lp_ticker_api.h" |
be_bryan | 0:b74591d5ab33 | 27 | #include "rtx_core_cm.h" |
be_bryan | 0:b74591d5ab33 | 28 | #include "mbed_critical.h" |
be_bryan | 0:b74591d5ab33 | 29 | #include "mbed_assert.h" |
be_bryan | 0:b74591d5ab33 | 30 | #include <new> |
be_bryan | 0:b74591d5ab33 | 31 | #include "rtx_os.h" |
be_bryan | 0:b74591d5ab33 | 32 | extern "C" { |
be_bryan | 0:b74591d5ab33 | 33 | #include "rtx_lib.h" |
be_bryan | 0:b74591d5ab33 | 34 | } |
be_bryan | 0:b74591d5ab33 | 35 | |
be_bryan | 0:b74591d5ab33 | 36 | using namespace mbed; |
be_bryan | 0:b74591d5ab33 | 37 | |
be_bryan | 0:b74591d5ab33 | 38 | #ifdef MBED_TICKLESS |
be_bryan | 0:b74591d5ab33 | 39 | |
be_bryan | 0:b74591d5ab33 | 40 | #if (defined(NO_SYSTICK)) |
be_bryan | 0:b74591d5ab33 | 41 | /** |
be_bryan | 0:b74591d5ab33 | 42 | * Return an IRQ number that can be used in the absence of SysTick |
be_bryan | 0:b74591d5ab33 | 43 | * |
be_bryan | 0:b74591d5ab33 | 44 | * @return Free IRQ number that can be used |
be_bryan | 0:b74591d5ab33 | 45 | */ |
be_bryan | 0:b74591d5ab33 | 46 | extern "C" IRQn_Type mbed_get_m0_tick_irqn(void); |
be_bryan | 0:b74591d5ab33 | 47 | #endif |
be_bryan | 0:b74591d5ab33 | 48 | |
be_bryan | 0:b74591d5ab33 | 49 | class RtosTimer : private TimerEvent { |
be_bryan | 0:b74591d5ab33 | 50 | public: |
be_bryan | 0:b74591d5ab33 | 51 | RtosTimer(): TimerEvent(get_lp_ticker_data()), _start_time(0), _tick(0) { |
be_bryan | 0:b74591d5ab33 | 52 | _start_time = ticker_read_us(_ticker_data); |
be_bryan | 0:b74591d5ab33 | 53 | #if (defined(NO_SYSTICK)) |
be_bryan | 0:b74591d5ab33 | 54 | NVIC_SetVector(mbed_get_m0_tick_irqn(), (uint32_t)SysTick_Handler); |
be_bryan | 0:b74591d5ab33 | 55 | NVIC_SetPriority(mbed_get_m0_tick_irqn(), 0xFF); /* RTOS requires lowest priority */ |
be_bryan | 0:b74591d5ab33 | 56 | NVIC_EnableIRQ(mbed_get_m0_tick_irqn()); |
be_bryan | 0:b74591d5ab33 | 57 | #else |
be_bryan | 0:b74591d5ab33 | 58 | // Ensure SysTick has the correct priority as it is still used |
be_bryan | 0:b74591d5ab33 | 59 | // to trigger software interrupts on each tick. The period does |
be_bryan | 0:b74591d5ab33 | 60 | // not matter since it will never start counting. |
be_bryan | 0:b74591d5ab33 | 61 | OS_Tick_Setup(osRtxConfig.tick_freq, OS_TICK_HANDLER); |
be_bryan | 0:b74591d5ab33 | 62 | #endif |
be_bryan | 0:b74591d5ab33 | 63 | }; |
be_bryan | 0:b74591d5ab33 | 64 | |
be_bryan | 0:b74591d5ab33 | 65 | /** |
be_bryan | 0:b74591d5ab33 | 66 | * Schedule an os tick to fire |
be_bryan | 0:b74591d5ab33 | 67 | * |
be_bryan | 0:b74591d5ab33 | 68 | * @param delta Tick to fire at relative to current tick |
be_bryan | 0:b74591d5ab33 | 69 | */ |
be_bryan | 0:b74591d5ab33 | 70 | void schedule_tick(uint32_t delta=1) { |
be_bryan | 0:b74591d5ab33 | 71 | insert_absolute(_start_time + (_tick + delta) * 1000000 / OS_TICK_FREQ); |
be_bryan | 0:b74591d5ab33 | 72 | } |
be_bryan | 0:b74591d5ab33 | 73 | |
be_bryan | 0:b74591d5ab33 | 74 | |
be_bryan | 0:b74591d5ab33 | 75 | /** |
be_bryan | 0:b74591d5ab33 | 76 | * Prevent any scheduled ticks from triggering |
be_bryan | 0:b74591d5ab33 | 77 | */ |
be_bryan | 0:b74591d5ab33 | 78 | void cancel_tick() { |
be_bryan | 0:b74591d5ab33 | 79 | remove(); |
be_bryan | 0:b74591d5ab33 | 80 | } |
be_bryan | 0:b74591d5ab33 | 81 | |
be_bryan | 0:b74591d5ab33 | 82 | /** |
be_bryan | 0:b74591d5ab33 | 83 | * Get the current tick count |
be_bryan | 0:b74591d5ab33 | 84 | * |
be_bryan | 0:b74591d5ab33 | 85 | * @return The number of ticks since boot. This should match RTX's tick count |
be_bryan | 0:b74591d5ab33 | 86 | */ |
be_bryan | 0:b74591d5ab33 | 87 | uint32_t get_tick() { |
be_bryan | 0:b74591d5ab33 | 88 | return _tick & 0xFFFFFFFF; |
be_bryan | 0:b74591d5ab33 | 89 | } |
be_bryan | 0:b74591d5ab33 | 90 | |
be_bryan | 0:b74591d5ab33 | 91 | /** |
be_bryan | 0:b74591d5ab33 | 92 | * Update the internal tick count |
be_bryan | 0:b74591d5ab33 | 93 | * |
be_bryan | 0:b74591d5ab33 | 94 | * @return The number of ticks incremented |
be_bryan | 0:b74591d5ab33 | 95 | */ |
be_bryan | 0:b74591d5ab33 | 96 | uint32_t update_tick() { |
be_bryan | 0:b74591d5ab33 | 97 | uint64_t new_tick = ticker_read_us(_ticker_data) * OS_TICK_FREQ / 1000000; |
be_bryan | 0:b74591d5ab33 | 98 | if (new_tick > _tick) { |
be_bryan | 0:b74591d5ab33 | 99 | // Don't update to the current tick. Instead, update to the |
be_bryan | 0:b74591d5ab33 | 100 | // previous tick and let the SysTick handler increment it |
be_bryan | 0:b74591d5ab33 | 101 | // to the current value. This allows scheduling restart |
be_bryan | 0:b74591d5ab33 | 102 | // successfully after the OS is resumed. |
be_bryan | 0:b74591d5ab33 | 103 | new_tick--; |
be_bryan | 0:b74591d5ab33 | 104 | } |
be_bryan | 0:b74591d5ab33 | 105 | uint32_t elapsed_ticks = new_tick - _tick; |
be_bryan | 0:b74591d5ab33 | 106 | _tick = new_tick; |
be_bryan | 0:b74591d5ab33 | 107 | return elapsed_ticks; |
be_bryan | 0:b74591d5ab33 | 108 | } |
be_bryan | 0:b74591d5ab33 | 109 | |
be_bryan | 0:b74591d5ab33 | 110 | /** |
be_bryan | 0:b74591d5ab33 | 111 | * Get the time |
be_bryan | 0:b74591d5ab33 | 112 | * |
be_bryan | 0:b74591d5ab33 | 113 | * @return Current time in microseconds |
be_bryan | 0:b74591d5ab33 | 114 | */ |
be_bryan | 0:b74591d5ab33 | 115 | us_timestamp_t get_time() { |
be_bryan | 0:b74591d5ab33 | 116 | return ticker_read_us(_ticker_data); |
be_bryan | 0:b74591d5ab33 | 117 | } |
be_bryan | 0:b74591d5ab33 | 118 | |
be_bryan | 0:b74591d5ab33 | 119 | ~RtosTimer() { |
be_bryan | 0:b74591d5ab33 | 120 | |
be_bryan | 0:b74591d5ab33 | 121 | }; |
be_bryan | 0:b74591d5ab33 | 122 | |
be_bryan | 0:b74591d5ab33 | 123 | protected: |
be_bryan | 0:b74591d5ab33 | 124 | |
be_bryan | 0:b74591d5ab33 | 125 | void handler() { |
be_bryan | 0:b74591d5ab33 | 126 | #if (defined(NO_SYSTICK)) |
be_bryan | 0:b74591d5ab33 | 127 | NVIC_SetPendingIRQ(mbed_get_m0_tick_irqn()); |
be_bryan | 0:b74591d5ab33 | 128 | #else |
be_bryan | 0:b74591d5ab33 | 129 | SCB->ICSR = SCB_ICSR_PENDSTSET_Msk; |
be_bryan | 0:b74591d5ab33 | 130 | #endif |
be_bryan | 0:b74591d5ab33 | 131 | _tick++; |
be_bryan | 0:b74591d5ab33 | 132 | } |
be_bryan | 0:b74591d5ab33 | 133 | |
be_bryan | 0:b74591d5ab33 | 134 | us_timestamp_t _start_time; |
be_bryan | 0:b74591d5ab33 | 135 | uint64_t _tick; |
be_bryan | 0:b74591d5ab33 | 136 | }; |
be_bryan | 0:b74591d5ab33 | 137 | |
be_bryan | 0:b74591d5ab33 | 138 | static RtosTimer *os_timer; |
be_bryan | 0:b74591d5ab33 | 139 | static uint64_t os_timer_data[sizeof(RtosTimer) / 8]; |
be_bryan | 0:b74591d5ab33 | 140 | |
be_bryan | 0:b74591d5ab33 | 141 | /// Enable System Timer. |
be_bryan | 0:b74591d5ab33 | 142 | int32_t OS_Tick_Enable (void) |
be_bryan | 0:b74591d5ab33 | 143 | { |
be_bryan | 0:b74591d5ab33 | 144 | // Do not use SingletonPtr since this relies on the RTOS |
be_bryan | 0:b74591d5ab33 | 145 | if (NULL == os_timer) { |
be_bryan | 0:b74591d5ab33 | 146 | os_timer = new (os_timer_data) RtosTimer(); |
be_bryan | 0:b74591d5ab33 | 147 | } |
be_bryan | 0:b74591d5ab33 | 148 | |
be_bryan | 0:b74591d5ab33 | 149 | // set to fire interrupt on next tick |
be_bryan | 0:b74591d5ab33 | 150 | os_timer->schedule_tick(); |
be_bryan | 0:b74591d5ab33 | 151 | |
be_bryan | 0:b74591d5ab33 | 152 | return 0; |
be_bryan | 0:b74591d5ab33 | 153 | } |
be_bryan | 0:b74591d5ab33 | 154 | |
be_bryan | 0:b74591d5ab33 | 155 | /// Disable System Timer. |
be_bryan | 0:b74591d5ab33 | 156 | int32_t OS_Tick_Disable (void) |
be_bryan | 0:b74591d5ab33 | 157 | { |
be_bryan | 0:b74591d5ab33 | 158 | os_timer->cancel_tick(); |
be_bryan | 0:b74591d5ab33 | 159 | |
be_bryan | 0:b74591d5ab33 | 160 | return 0; |
be_bryan | 0:b74591d5ab33 | 161 | } |
be_bryan | 0:b74591d5ab33 | 162 | |
be_bryan | 0:b74591d5ab33 | 163 | /// Acknowledge System Timer IRQ. |
be_bryan | 0:b74591d5ab33 | 164 | int32_t OS_Tick_AcknowledgeIRQ (void) |
be_bryan | 0:b74591d5ab33 | 165 | { |
be_bryan | 0:b74591d5ab33 | 166 | os_timer->schedule_tick(); |
be_bryan | 0:b74591d5ab33 | 167 | |
be_bryan | 0:b74591d5ab33 | 168 | return 0; |
be_bryan | 0:b74591d5ab33 | 169 | } |
be_bryan | 0:b74591d5ab33 | 170 | |
be_bryan | 0:b74591d5ab33 | 171 | /// Get System Timer count. |
be_bryan | 0:b74591d5ab33 | 172 | uint32_t OS_Tick_GetCount (void) |
be_bryan | 0:b74591d5ab33 | 173 | { |
be_bryan | 0:b74591d5ab33 | 174 | return os_timer->get_time() & 0xFFFFFFFF; |
be_bryan | 0:b74591d5ab33 | 175 | } |
be_bryan | 0:b74591d5ab33 | 176 | |
be_bryan | 0:b74591d5ab33 | 177 | // Get OS Tick IRQ number. |
be_bryan | 0:b74591d5ab33 | 178 | int32_t OS_Tick_GetIRQn (void) { |
be_bryan | 0:b74591d5ab33 | 179 | return -1; |
be_bryan | 0:b74591d5ab33 | 180 | } |
be_bryan | 0:b74591d5ab33 | 181 | |
be_bryan | 0:b74591d5ab33 | 182 | // Get OS Tick overflow status. |
be_bryan | 0:b74591d5ab33 | 183 | uint32_t OS_Tick_GetOverflow (void) { |
be_bryan | 0:b74591d5ab33 | 184 | return 0; |
be_bryan | 0:b74591d5ab33 | 185 | } |
be_bryan | 0:b74591d5ab33 | 186 | |
be_bryan | 0:b74591d5ab33 | 187 | // Get OS Tick interval. |
be_bryan | 0:b74591d5ab33 | 188 | uint32_t OS_Tick_GetInterval (void) { |
be_bryan | 0:b74591d5ab33 | 189 | return 1000; |
be_bryan | 0:b74591d5ab33 | 190 | } |
be_bryan | 0:b74591d5ab33 | 191 | |
be_bryan | 0:b74591d5ab33 | 192 | static void default_idle_hook(void) |
be_bryan | 0:b74591d5ab33 | 193 | { |
be_bryan | 0:b74591d5ab33 | 194 | uint32_t elapsed_ticks = 0; |
be_bryan | 0:b74591d5ab33 | 195 | |
be_bryan | 0:b74591d5ab33 | 196 | core_util_critical_section_enter(); |
be_bryan | 0:b74591d5ab33 | 197 | uint32_t ticks_to_sleep = svcRtxKernelSuspend(); |
be_bryan | 0:b74591d5ab33 | 198 | MBED_ASSERT(os_timer->get_tick() == svcRtxKernelGetTickCount()); |
be_bryan | 0:b74591d5ab33 | 199 | if (ticks_to_sleep) { |
be_bryan | 0:b74591d5ab33 | 200 | os_timer->schedule_tick(ticks_to_sleep); |
be_bryan | 0:b74591d5ab33 | 201 | |
be_bryan | 0:b74591d5ab33 | 202 | sleep_manager_lock_deep_sleep(); |
be_bryan | 0:b74591d5ab33 | 203 | sleep(); |
be_bryan | 0:b74591d5ab33 | 204 | sleep_manager_unlock_deep_sleep(); |
be_bryan | 0:b74591d5ab33 | 205 | |
be_bryan | 0:b74591d5ab33 | 206 | os_timer->cancel_tick(); |
be_bryan | 0:b74591d5ab33 | 207 | // calculate how long we slept |
be_bryan | 0:b74591d5ab33 | 208 | elapsed_ticks = os_timer->update_tick(); |
be_bryan | 0:b74591d5ab33 | 209 | } |
be_bryan | 0:b74591d5ab33 | 210 | svcRtxKernelResume(elapsed_ticks); |
be_bryan | 0:b74591d5ab33 | 211 | core_util_critical_section_exit(); |
be_bryan | 0:b74591d5ab33 | 212 | } |
be_bryan | 0:b74591d5ab33 | 213 | |
be_bryan | 0:b74591d5ab33 | 214 | #elif defined(FEATURE_UVISOR) |
be_bryan | 0:b74591d5ab33 | 215 | |
be_bryan | 0:b74591d5ab33 | 216 | static void default_idle_hook(void) |
be_bryan | 0:b74591d5ab33 | 217 | { |
be_bryan | 0:b74591d5ab33 | 218 | /* uVisor can't sleep. See <https://github.com/ARMmbed/uvisor/issues/420> |
be_bryan | 0:b74591d5ab33 | 219 | * for details. */ |
be_bryan | 0:b74591d5ab33 | 220 | } |
be_bryan | 0:b74591d5ab33 | 221 | |
be_bryan | 0:b74591d5ab33 | 222 | #else |
be_bryan | 0:b74591d5ab33 | 223 | |
be_bryan | 0:b74591d5ab33 | 224 | static void default_idle_hook(void) |
be_bryan | 0:b74591d5ab33 | 225 | { |
be_bryan | 0:b74591d5ab33 | 226 | // critical section to complete sleep with locked deepsleep |
be_bryan | 0:b74591d5ab33 | 227 | core_util_critical_section_enter(); |
be_bryan | 0:b74591d5ab33 | 228 | sleep_manager_lock_deep_sleep(); |
be_bryan | 0:b74591d5ab33 | 229 | sleep(); |
be_bryan | 0:b74591d5ab33 | 230 | sleep_manager_unlock_deep_sleep(); |
be_bryan | 0:b74591d5ab33 | 231 | core_util_critical_section_exit(); |
be_bryan | 0:b74591d5ab33 | 232 | } |
be_bryan | 0:b74591d5ab33 | 233 | |
be_bryan | 0:b74591d5ab33 | 234 | #endif // MBED_TICKLESS |
be_bryan | 0:b74591d5ab33 | 235 | |
be_bryan | 0:b74591d5ab33 | 236 | static void (*idle_hook_fptr)(void) = &default_idle_hook; |
be_bryan | 0:b74591d5ab33 | 237 | |
be_bryan | 0:b74591d5ab33 | 238 | void rtos_attach_idle_hook(void (*fptr)(void)) |
be_bryan | 0:b74591d5ab33 | 239 | { |
be_bryan | 0:b74591d5ab33 | 240 | //Attach the specified idle hook, or the default idle hook in case of a NULL pointer |
be_bryan | 0:b74591d5ab33 | 241 | if (fptr != NULL) { |
be_bryan | 0:b74591d5ab33 | 242 | idle_hook_fptr = fptr; |
be_bryan | 0:b74591d5ab33 | 243 | } else { |
be_bryan | 0:b74591d5ab33 | 244 | idle_hook_fptr = default_idle_hook; |
be_bryan | 0:b74591d5ab33 | 245 | } |
be_bryan | 0:b74591d5ab33 | 246 | } |
be_bryan | 0:b74591d5ab33 | 247 | |
be_bryan | 0:b74591d5ab33 | 248 | extern "C" void rtos_idle_loop(void) |
be_bryan | 0:b74591d5ab33 | 249 | { |
be_bryan | 0:b74591d5ab33 | 250 | //Continuously call the idle hook function pointer |
be_bryan | 0:b74591d5ab33 | 251 | while (1) { |
be_bryan | 0:b74591d5ab33 | 252 | idle_hook_fptr(); |
be_bryan | 0:b74591d5ab33 | 253 | } |
be_bryan | 0:b74591d5ab33 | 254 | } |