mbed library sources. Supersedes mbed-src.

Fork of mbed-dev by mbed official

Committer:
pmcorreia
Date:
Tue Oct 09 14:42:37 2018 +0000
Revision:
187:fa51feb62426
Parent:
186:707f6e361f3e
Updated version to work with F446RE

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Anna Bridge 186:707f6e361f3e 1 /* mbed Microcontroller Library
Anna Bridge 186:707f6e361f3e 2 * Copyright (c) 2018 ARM Limited
Anna Bridge 186:707f6e361f3e 3 *
Anna Bridge 186:707f6e361f3e 4 * Licensed under the Apache License, Version 2.0 (the "License");
Anna Bridge 186:707f6e361f3e 5 * you may not use this file except in compliance with the License.
Anna Bridge 186:707f6e361f3e 6 * You may obtain a copy of the License at
Anna Bridge 186:707f6e361f3e 7 *
Anna Bridge 186:707f6e361f3e 8 * http://www.apache.org/licenses/LICENSE-2.0
Anna Bridge 186:707f6e361f3e 9 *
Anna Bridge 186:707f6e361f3e 10 * Unless required by applicable law or agreed to in writing, software
Anna Bridge 186:707f6e361f3e 11 * distributed under the License is distributed on an "AS IS" BASIS,
Anna Bridge 186:707f6e361f3e 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Anna Bridge 186:707f6e361f3e 13 * See the License for the specific language governing permissions and
Anna Bridge 186:707f6e361f3e 14 * limitations under the License.
Anna Bridge 186:707f6e361f3e 15 */
Anna Bridge 186:707f6e361f3e 16 #include "hal/lp_ticker_api.h"
Anna Bridge 186:707f6e361f3e 17
Anna Bridge 186:707f6e361f3e 18 #if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0)
Anna Bridge 186:707f6e361f3e 19
Anna Bridge 186:707f6e361f3e 20 #include "Timeout.h"
Anna Bridge 186:707f6e361f3e 21 #include "mbed_critical.h"
Anna Bridge 186:707f6e361f3e 22
Anna Bridge 186:707f6e361f3e 23 static const timestamp_t min_delta = LPTICKER_DELAY_TICKS;
Anna Bridge 186:707f6e361f3e 24
Anna Bridge 186:707f6e361f3e 25 static bool init = false;
Anna Bridge 186:707f6e361f3e 26 static bool pending = false;
Anna Bridge 186:707f6e361f3e 27 static bool timeout_pending = false;
Anna Bridge 186:707f6e361f3e 28 static timestamp_t last_set_interrupt = 0;
Anna Bridge 186:707f6e361f3e 29 static timestamp_t last_request = 0;
Anna Bridge 186:707f6e361f3e 30 static timestamp_t next = 0;
Anna Bridge 186:707f6e361f3e 31
Anna Bridge 186:707f6e361f3e 32 static timestamp_t mask;
Anna Bridge 186:707f6e361f3e 33 static timestamp_t reschedule_us;
Anna Bridge 186:707f6e361f3e 34
Anna Bridge 186:707f6e361f3e 35 // Do not use SingletonPtr since this must be initialized in a critical section
Anna Bridge 186:707f6e361f3e 36 static mbed::Timeout *timeout;
Anna Bridge 186:707f6e361f3e 37 static uint64_t timeout_data[sizeof(mbed::Timeout) / 8];
Anna Bridge 186:707f6e361f3e 38
Anna Bridge 186:707f6e361f3e 39 /**
Anna Bridge 186:707f6e361f3e 40 * Initialize variables
Anna Bridge 186:707f6e361f3e 41 */
Anna Bridge 186:707f6e361f3e 42 static void init_local()
Anna Bridge 186:707f6e361f3e 43 {
Anna Bridge 186:707f6e361f3e 44 MBED_ASSERT(core_util_in_critical_section());
Anna Bridge 186:707f6e361f3e 45
Anna Bridge 186:707f6e361f3e 46 const ticker_info_t* info = lp_ticker_get_info();
Anna Bridge 186:707f6e361f3e 47 if (info->bits >= 32) {
Anna Bridge 186:707f6e361f3e 48 mask = 0xffffffff;
Anna Bridge 186:707f6e361f3e 49 } else {
Anna Bridge 186:707f6e361f3e 50 mask = ((uint64_t)1 << info->bits) - 1;
Anna Bridge 186:707f6e361f3e 51 }
Anna Bridge 186:707f6e361f3e 52
Anna Bridge 186:707f6e361f3e 53 // Round us_per_tick up
Anna Bridge 186:707f6e361f3e 54 timestamp_t us_per_tick = (1000000 + info->frequency - 1) / info->frequency;
Anna Bridge 186:707f6e361f3e 55
Anna Bridge 186:707f6e361f3e 56 // Add 1 tick to the min delta for the case where the clock transitions after you read it
Anna Bridge 186:707f6e361f3e 57 // Add 4 microseconds to round up the micro second ticker time (which has a frequency of at least 250KHz - 4us period)
Anna Bridge 186:707f6e361f3e 58 reschedule_us = (min_delta + 1) * us_per_tick + 4;
Anna Bridge 186:707f6e361f3e 59
Anna Bridge 186:707f6e361f3e 60 timeout = new (timeout_data) mbed::Timeout();
Anna Bridge 186:707f6e361f3e 61 }
Anna Bridge 186:707f6e361f3e 62
Anna Bridge 186:707f6e361f3e 63 /**
Anna Bridge 186:707f6e361f3e 64 * Call lp_ticker_set_interrupt with a value that is guaranteed to fire
Anna Bridge 186:707f6e361f3e 65 *
Anna Bridge 186:707f6e361f3e 66 * Assumptions
Anna Bridge 186:707f6e361f3e 67 * -Only one low power clock tick can pass from the last read (last_read)
Anna Bridge 186:707f6e361f3e 68 * -The closest an interrupt can fire is max_delta + 1
Anna Bridge 186:707f6e361f3e 69 *
Anna Bridge 186:707f6e361f3e 70 * @param last_read The last value read from lp_ticker_read
Anna Bridge 186:707f6e361f3e 71 * @param timestamp The timestamp to trigger the interrupt at
Anna Bridge 186:707f6e361f3e 72 */
Anna Bridge 186:707f6e361f3e 73 static void set_interrupt_safe(timestamp_t last_read, timestamp_t timestamp)
Anna Bridge 186:707f6e361f3e 74 {
Anna Bridge 186:707f6e361f3e 75 MBED_ASSERT(core_util_in_critical_section());
Anna Bridge 186:707f6e361f3e 76 uint32_t delta = (timestamp - last_read) & mask;
Anna Bridge 186:707f6e361f3e 77 if (delta < min_delta + 2) {
Anna Bridge 186:707f6e361f3e 78 timestamp = (last_read + min_delta + 2) & mask;
Anna Bridge 186:707f6e361f3e 79 }
Anna Bridge 186:707f6e361f3e 80 lp_ticker_set_interrupt(timestamp);
Anna Bridge 186:707f6e361f3e 81 }
Anna Bridge 186:707f6e361f3e 82
Anna Bridge 186:707f6e361f3e 83 /**
Anna Bridge 186:707f6e361f3e 84 * Set the low power ticker match time when hardware is ready
Anna Bridge 186:707f6e361f3e 85 *
Anna Bridge 186:707f6e361f3e 86 * This event is scheduled to set the lp timer after the previous write
Anna Bridge 186:707f6e361f3e 87 * has taken effect and it is safe to write a new value without blocking.
Anna Bridge 186:707f6e361f3e 88 * If the time has already passed then this function fires and interrupt
Anna Bridge 186:707f6e361f3e 89 * immediately.
Anna Bridge 186:707f6e361f3e 90 */
Anna Bridge 186:707f6e361f3e 91 static void set_interrupt_later()
Anna Bridge 186:707f6e361f3e 92 {
Anna Bridge 186:707f6e361f3e 93 core_util_critical_section_enter();
Anna Bridge 186:707f6e361f3e 94
Anna Bridge 186:707f6e361f3e 95 timestamp_t current = lp_ticker_read();
Anna Bridge 186:707f6e361f3e 96 if (_ticker_match_interval_passed(last_request, current, next)) {
Anna Bridge 186:707f6e361f3e 97 lp_ticker_fire_interrupt();
Anna Bridge 186:707f6e361f3e 98 } else {
Anna Bridge 186:707f6e361f3e 99 set_interrupt_safe(current, next);
Anna Bridge 186:707f6e361f3e 100 last_set_interrupt = lp_ticker_read();
Anna Bridge 186:707f6e361f3e 101 }
Anna Bridge 186:707f6e361f3e 102 timeout_pending = false;
Anna Bridge 186:707f6e361f3e 103
Anna Bridge 186:707f6e361f3e 104 core_util_critical_section_exit();
Anna Bridge 186:707f6e361f3e 105 }
Anna Bridge 186:707f6e361f3e 106
Anna Bridge 186:707f6e361f3e 107 /**
Anna Bridge 186:707f6e361f3e 108 * Wrapper around lp_ticker_set_interrupt to prevent blocking
Anna Bridge 186:707f6e361f3e 109 *
Anna Bridge 186:707f6e361f3e 110 * Problems this function is solving:
Anna Bridge 186:707f6e361f3e 111 * 1. Interrupt may not fire if set earlier than LPTICKER_DELAY_TICKS low power clock cycles
Anna Bridge 186:707f6e361f3e 112 * 2. Setting the interrupt back-to-back will block
Anna Bridge 186:707f6e361f3e 113 *
Anna Bridge 186:707f6e361f3e 114 * This wrapper function prevents lp_ticker_set_interrupt from being called
Anna Bridge 186:707f6e361f3e 115 * back-to-back and blocking while the first write is in progress. This function
Anna Bridge 186:707f6e361f3e 116 * avoids that problem by scheduling a timeout event if the lp ticker is in the
Anna Bridge 186:707f6e361f3e 117 * middle of a write operation.
Anna Bridge 186:707f6e361f3e 118 *
Anna Bridge 186:707f6e361f3e 119 * @param timestamp Time to call ticker irq
Anna Bridge 186:707f6e361f3e 120 * @note this is a utility function and it's not required part of HAL implementation
Anna Bridge 186:707f6e361f3e 121 */
Anna Bridge 186:707f6e361f3e 122 extern "C" void lp_ticker_set_interrupt_wrapper(timestamp_t timestamp)
Anna Bridge 186:707f6e361f3e 123 {
Anna Bridge 186:707f6e361f3e 124 core_util_critical_section_enter();
Anna Bridge 186:707f6e361f3e 125
Anna Bridge 186:707f6e361f3e 126 if (!init) {
Anna Bridge 186:707f6e361f3e 127 init_local();
Anna Bridge 186:707f6e361f3e 128 init = true;
Anna Bridge 186:707f6e361f3e 129 }
Anna Bridge 186:707f6e361f3e 130
Anna Bridge 186:707f6e361f3e 131 timestamp_t current = lp_ticker_read();
Anna Bridge 186:707f6e361f3e 132 if (pending) {
Anna Bridge 186:707f6e361f3e 133 // Check if pending should be cleared
Anna Bridge 186:707f6e361f3e 134 if (((current - last_set_interrupt) & mask) >= min_delta) {
Anna Bridge 186:707f6e361f3e 135 pending = false;
Anna Bridge 186:707f6e361f3e 136 }
Anna Bridge 186:707f6e361f3e 137 }
Anna Bridge 186:707f6e361f3e 138
Anna Bridge 186:707f6e361f3e 139 if (pending || timeout_pending) {
Anna Bridge 186:707f6e361f3e 140 next = timestamp;
Anna Bridge 186:707f6e361f3e 141 last_request = current;
Anna Bridge 186:707f6e361f3e 142 if (!timeout_pending) {
Anna Bridge 186:707f6e361f3e 143 timeout->attach_us(set_interrupt_later, reschedule_us);
Anna Bridge 186:707f6e361f3e 144 timeout_pending = true;
Anna Bridge 186:707f6e361f3e 145 }
Anna Bridge 186:707f6e361f3e 146 } else {
Anna Bridge 186:707f6e361f3e 147 // Schedule immediately if nothing is pending
Anna Bridge 186:707f6e361f3e 148 set_interrupt_safe(current, timestamp);
Anna Bridge 186:707f6e361f3e 149 last_set_interrupt = lp_ticker_read();
Anna Bridge 186:707f6e361f3e 150 pending = true;
Anna Bridge 186:707f6e361f3e 151 }
Anna Bridge 186:707f6e361f3e 152
Anna Bridge 186:707f6e361f3e 153 core_util_critical_section_exit();
Anna Bridge 186:707f6e361f3e 154 }
Anna Bridge 186:707f6e361f3e 155
Anna Bridge 186:707f6e361f3e 156 #endif