RTC auf true

Revision:
0:38ceb79fef03
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hal/LowPowerTickerWrapper.cpp	Wed Nov 28 15:10:15 2018 +0000
@@ -0,0 +1,310 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "hal/LowPowerTickerWrapper.h"
+#include "platform/Callback.h"
+
+LowPowerTickerWrapper::LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match)
+    : _intf(data->interface), _min_count_between_writes(min_cycles_between_writes + 1), _min_count_until_match(min_cycles_until_match + 1), _suspended(false)
+{
+    core_util_critical_section_enter();
+
+    this->data.interface = interface;
+    this->data.queue = data->queue;
+    _reset();
+
+    core_util_critical_section_exit();
+}
+
+void LowPowerTickerWrapper::irq_handler(ticker_irq_handler_type handler)
+{
+    core_util_critical_section_enter();
+
+    if (_pending_fire_now || _match_check(_intf->read()) || _suspended) {
+        _timeout.detach();
+        _pending_timeout = false;
+        _pending_match = false;
+        _pending_fire_now = false;
+        if (handler) {
+            handler(&data);
+        }
+    } else {
+        // Spurious interrupt
+        _intf->clear_interrupt();
+    }
+
+    core_util_critical_section_exit();
+}
+
+void LowPowerTickerWrapper::suspend()
+{
+    core_util_critical_section_enter();
+
+    // Wait until rescheduling is allowed
+    while (!_set_interrupt_allowed) {
+        timestamp_t current = _intf->read();
+        if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) {
+            _set_interrupt_allowed  = true;
+        }
+    }
+
+    _reset();
+    _suspended = true;
+
+    core_util_critical_section_exit();
+}
+
+void LowPowerTickerWrapper::resume()
+{
+    core_util_critical_section_enter();
+
+    // Wait until rescheduling is allowed
+    while (!_set_interrupt_allowed) {
+        timestamp_t current = _intf->read();
+        if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) {
+            _set_interrupt_allowed  = true;
+        }
+    }
+
+    _suspended = false;
+
+    core_util_critical_section_exit();
+}
+
+bool LowPowerTickerWrapper::timeout_pending()
+{
+    core_util_critical_section_enter();
+
+    bool pending = _pending_timeout;
+
+    core_util_critical_section_exit();
+    return pending;
+}
+
+void LowPowerTickerWrapper::init()
+{
+    core_util_critical_section_enter();
+
+    _reset();
+    _intf->init();
+
+    core_util_critical_section_exit();
+}
+
+void LowPowerTickerWrapper::free()
+{
+    core_util_critical_section_enter();
+
+    _reset();
+    _intf->free();
+
+    core_util_critical_section_exit();
+}
+
+uint32_t LowPowerTickerWrapper::read()
+{
+    core_util_critical_section_enter();
+
+    timestamp_t current = _intf->read();
+    if (!_suspended && _match_check(current)) {
+        _intf->fire_interrupt();
+    }
+
+    core_util_critical_section_exit();
+    return current;
+}
+
+void LowPowerTickerWrapper::set_interrupt(timestamp_t timestamp)
+{
+    core_util_critical_section_enter();
+
+    _last_set_interrupt = _intf->read();
+    _cur_match_time = timestamp;
+    _pending_match = true;
+    if (!_suspended) {
+        _schedule_match(_last_set_interrupt);
+    } else {
+        _intf->set_interrupt(timestamp);
+        _last_actual_set_interrupt = _last_set_interrupt;
+        _set_interrupt_allowed = false;
+    }
+
+    core_util_critical_section_exit();
+}
+
+void LowPowerTickerWrapper::disable_interrupt()
+{
+    core_util_critical_section_enter();
+
+    _intf->disable_interrupt();
+
+    core_util_critical_section_exit();
+}
+
+void LowPowerTickerWrapper::clear_interrupt()
+{
+    core_util_critical_section_enter();
+
+    _intf->clear_interrupt();
+
+    core_util_critical_section_exit();
+}
+
+void LowPowerTickerWrapper::fire_interrupt()
+{
+    core_util_critical_section_enter();
+
+    _pending_fire_now = 1;
+    _intf->fire_interrupt();
+
+    core_util_critical_section_exit();
+}
+
+const ticker_info_t *LowPowerTickerWrapper::get_info()
+{
+
+    core_util_critical_section_enter();
+
+    const ticker_info_t *info = _intf->get_info();
+
+    core_util_critical_section_exit();
+    return info;
+}
+
+void LowPowerTickerWrapper::_reset()
+{
+    MBED_ASSERT(core_util_in_critical_section());
+
+    _timeout.detach();
+    _pending_timeout = false;
+    _pending_match = false;
+    _pending_fire_now = false;
+    _set_interrupt_allowed = true;
+    _cur_match_time = 0;
+    _last_set_interrupt = 0;
+    _last_actual_set_interrupt = 0;
+
+    const ticker_info_t *info = _intf->get_info();
+    if (info->bits >= 32) {
+        _mask = 0xffffffff;
+    } else {
+        _mask = ((uint64_t)1 << info->bits) - 1;
+    }
+
+    // Round us_per_tick up
+    _us_per_tick = (1000000 + info->frequency - 1) / info->frequency;
+}
+
+void LowPowerTickerWrapper::_timeout_handler()
+{
+    core_util_critical_section_enter();
+    _pending_timeout = false;
+
+    timestamp_t current = _intf->read();
+    /* Add extra check for '_last_set_interrupt == _cur_match_time'
+     * 
+     * When '_last_set_interrupt == _cur_match_time', _ticker_match_interval_passed sees it as
+     * one-round interval rather than just-pass, so add extra check for it. In rare cases, we
+     * may trap in _timeout_handler/_schedule_match loop. This check can break it.
+     */
+    if ((_last_set_interrupt == _cur_match_time) ||
+        _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time)) {
+        _intf->fire_interrupt();
+    } else {
+        _schedule_match(current);
+    }
+
+    core_util_critical_section_exit();
+}
+
+bool LowPowerTickerWrapper::_match_check(timestamp_t current)
+{
+    MBED_ASSERT(core_util_in_critical_section());
+
+    if (!_pending_match) {
+        return false;
+    }
+    /* Add extra check for '_last_set_interrupt == _cur_match_time' as above */
+    return (_last_set_interrupt == _cur_match_time) ||
+        _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time);
+}
+
+uint32_t LowPowerTickerWrapper::_lp_ticks_to_us(uint32_t ticks)
+{
+    MBED_ASSERT(core_util_in_critical_section());
+
+    // Add 4 microseconds to round up the micro second ticker time (which has a frequency of at least 250KHz - 4us period)
+    return _us_per_tick * ticks + 4;
+}
+
+void LowPowerTickerWrapper::_schedule_match(timestamp_t current)
+{
+    MBED_ASSERT(core_util_in_critical_section());
+
+    // Check if _intf->set_interrupt is allowed
+    if (!_set_interrupt_allowed) {
+        if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) {
+            _set_interrupt_allowed  = true;
+        }
+    }
+
+    uint32_t cycles_until_match = (_cur_match_time - current) & _mask;
+    bool too_close = cycles_until_match < _min_count_until_match;
+
+    if (!_set_interrupt_allowed) {
+
+        // Can't use _intf->set_interrupt so use microsecond Timeout instead
+
+        // Speed optimization - if a timer has already been scheduled
+        // then don't schedule it again.
+        if (!_pending_timeout) {
+            uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match;
+            _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks));
+            _pending_timeout = true;
+        }
+        return;
+    }
+
+    if (!too_close) {
+
+        // Schedule LP ticker
+        _intf->set_interrupt(_cur_match_time);
+        current = _intf->read();
+        _last_actual_set_interrupt = current;
+        _set_interrupt_allowed = false;
+
+        // Check for overflow
+        uint32_t new_cycles_until_match = (_cur_match_time - current) & _mask;
+        if (new_cycles_until_match > cycles_until_match) {
+            // Overflow so fire now
+            _intf->fire_interrupt();
+            return;
+        }
+
+        // Update variables with new time
+        cycles_until_match = new_cycles_until_match;
+        too_close = cycles_until_match < _min_count_until_match;
+    }
+
+    if (too_close) {
+
+        // Low power ticker incremented to less than _min_count_until_match
+        // so low power ticker may not fire. Use Timeout to ensure it does fire.
+        uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match;
+        _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks));
+        _pending_timeout = true;
+        return;
+    }
+}