mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #10857 from ARMmbed/feature-watchdog
Add Watchdog and ResetReasonpull/10873/head
commit
ccb63d771e
|
@ -0,0 +1,163 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
from mbed_host_tests import BaseHostTest
|
||||||
|
from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector
|
||||||
|
|
||||||
|
DEFAULT_SYNC_DELAY = 4.0
|
||||||
|
|
||||||
|
MSG_VALUE_WATCHDOG_PRESENT = 'wdg_present'
|
||||||
|
MSG_VALUE_DUMMY = '0'
|
||||||
|
MSG_VALUE_RESET_REASON_GET = 'get'
|
||||||
|
MSG_VALUE_RESET_REASON_CLEAR = 'clear'
|
||||||
|
MSG_VALUE_DEVICE_RESET_NVIC = 'nvic'
|
||||||
|
MSG_VALUE_DEVICE_RESET_WATCHDOG = 'watchdog'
|
||||||
|
|
||||||
|
MSG_KEY_DEVICE_READY = 'ready'
|
||||||
|
MSG_KEY_RESET_REASON_RAW = 'reason_raw'
|
||||||
|
MSG_KEY_RESET_REASON = 'reason'
|
||||||
|
MSG_KEY_DEVICE_RESET = 'reset'
|
||||||
|
MSG_KEY_SYNC = '__sync'
|
||||||
|
|
||||||
|
RESET_REASONS = {
|
||||||
|
'POWER_ON': '0',
|
||||||
|
'PIN_RESET': '1',
|
||||||
|
'BROWN_OUT': '2',
|
||||||
|
'SOFTWARE': '3',
|
||||||
|
'WATCHDOG': '4',
|
||||||
|
'LOCKUP': '5',
|
||||||
|
'WAKE_LOW_POWER': '6',
|
||||||
|
'ACCESS_ERROR': '7',
|
||||||
|
'BOOT_ERROR': '8',
|
||||||
|
'MULTIPLE': '9',
|
||||||
|
'PLATFORM': '10',
|
||||||
|
'UNKNOWN': '11'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def raise_if_different(expected, actual, text=''):
|
||||||
|
"""Raise a RuntimeError if actual is different than expected."""
|
||||||
|
if expected != actual:
|
||||||
|
raise RuntimeError('{}Got {!r}, expected {!r}'
|
||||||
|
.format(text, actual, expected))
|
||||||
|
|
||||||
|
|
||||||
|
class ResetReasonTest(BaseHostTest):
|
||||||
|
"""Test for the Reset Reason HAL API.
|
||||||
|
|
||||||
|
Given a device supporting a Reset Reason API.
|
||||||
|
When the device is restarted using various methods.
|
||||||
|
Then the device returns a correct reset reason for every restart.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(ResetReasonTest, self).__init__()
|
||||||
|
self.device_has_watchdog = None
|
||||||
|
self.raw_reset_reasons = set()
|
||||||
|
self.sync_delay = DEFAULT_SYNC_DELAY
|
||||||
|
self.test_steps_sequence = self.test_steps()
|
||||||
|
# Advance the coroutine to it's first yield statement.
|
||||||
|
self.test_steps_sequence.send(None)
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
sync_delay = self.get_config_item('forced_reset_timeout')
|
||||||
|
self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready)
|
||||||
|
self.register_callback(MSG_KEY_RESET_REASON_RAW, self.cb_reset_reason_raw)
|
||||||
|
self.register_callback(MSG_KEY_RESET_REASON, self.cb_reset_reason)
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_reset_reason)
|
||||||
|
|
||||||
|
def cb_device_ready(self, key, value, timestamp):
|
||||||
|
"""Request a raw value of the reset_reason register.
|
||||||
|
|
||||||
|
Additionally, save the device's watchdog status on the first call.
|
||||||
|
"""
|
||||||
|
if self.device_has_watchdog is None:
|
||||||
|
self.device_has_watchdog = (value == MSG_VALUE_WATCHDOG_PRESENT)
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON_RAW, MSG_VALUE_RESET_REASON_GET)
|
||||||
|
|
||||||
|
def cb_reset_reason_raw(self, key, value, timestamp):
|
||||||
|
"""Verify that the raw reset_reason register value is unique.
|
||||||
|
|
||||||
|
Fail the test suite if the raw reset_reason value is not unique.
|
||||||
|
Request a platform independent reset_reason otherwise.
|
||||||
|
"""
|
||||||
|
if value in self.raw_reset_reasons:
|
||||||
|
self.log('TEST FAILED: The raw reset reason is not unique. '
|
||||||
|
'{!r} is already present in {!r}.'
|
||||||
|
.format(value, self.raw_reset_reasons))
|
||||||
|
self.notify_complete(False)
|
||||||
|
else:
|
||||||
|
self.raw_reset_reasons.add(value)
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_GET)
|
||||||
|
|
||||||
|
def cb_reset_reason(self, key, value, timestamp):
|
||||||
|
"""Feed the test_steps coroutine with reset_reason value.
|
||||||
|
|
||||||
|
Pass the test suite if the coroutine yields True.
|
||||||
|
Fail the test suite if the iterator stops or raises a RuntimeError.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if self.test_steps_sequence.send(value):
|
||||||
|
self.notify_complete(True)
|
||||||
|
except (StopIteration, RuntimeError) as exc:
|
||||||
|
self.log('TEST FAILED: {}'.format(exc))
|
||||||
|
self.notify_complete(False)
|
||||||
|
|
||||||
|
def test_steps(self):
|
||||||
|
"""Generate a sequence of test steps.
|
||||||
|
|
||||||
|
This coroutine calls yield to wait for the input from the device
|
||||||
|
(the reset_reason). If the device gives the wrong response, the
|
||||||
|
generator raises a RuntimeError exception and fails the test.
|
||||||
|
"""
|
||||||
|
# Ignore the first reason.
|
||||||
|
__ignored_reset_reason = yield
|
||||||
|
self.raw_reset_reasons.clear()
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR)
|
||||||
|
__ignored_clear_ack = yield
|
||||||
|
|
||||||
|
# Request a NVIC_SystemReset() call.
|
||||||
|
self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_NVIC)
|
||||||
|
__ignored_reset_ack = yield
|
||||||
|
time.sleep(self.sync_delay)
|
||||||
|
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
||||||
|
reset_reason = yield
|
||||||
|
raise_if_different(RESET_REASONS['SOFTWARE'], reset_reason, 'Wrong reset reason. ')
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR)
|
||||||
|
__ignored_clear_ack = yield
|
||||||
|
|
||||||
|
# Reset the device using DAP.
|
||||||
|
self.reset_dut(DefaultTestSelector.RESET_TYPE_SW_RST)
|
||||||
|
reset_reason = yield
|
||||||
|
raise_if_different(RESET_REASONS['PIN_RESET'], reset_reason, 'Wrong reset reason. ')
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR)
|
||||||
|
__ignored_clear_ack = yield
|
||||||
|
|
||||||
|
# Start a watchdog timer and wait for it to reset the device.
|
||||||
|
if not self.device_has_watchdog:
|
||||||
|
self.log('DUT does not have a watchdog. Skipping this reset reason.')
|
||||||
|
else:
|
||||||
|
self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_WATCHDOG)
|
||||||
|
__ignored_reset_ack = yield
|
||||||
|
time.sleep(self.sync_delay)
|
||||||
|
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
||||||
|
reset_reason = yield
|
||||||
|
raise_if_different(RESET_REASONS['WATCHDOG'], reset_reason, 'Wrong reset reason. ')
|
||||||
|
|
||||||
|
# The sequence is correct -- test passed.
|
||||||
|
yield True
|
|
@ -0,0 +1,74 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
from mbed_host_tests import BaseHostTest
|
||||||
|
|
||||||
|
DEFAULT_SYNC_DELAY = 4.0
|
||||||
|
|
||||||
|
MSG_VALUE_DUMMY = '0'
|
||||||
|
MSG_KEY_DEVICE_READY = 'ready'
|
||||||
|
MSG_KEY_START_CASE = 'start_case'
|
||||||
|
MSG_KEY_DEVICE_RESET = 'reset_on_case_teardown'
|
||||||
|
MSG_KEY_SYNC = '__sync'
|
||||||
|
|
||||||
|
|
||||||
|
class SyncOnReset(BaseHostTest):
|
||||||
|
"""Host side test that handles device reset during case teardown.
|
||||||
|
|
||||||
|
Given a device that performs a reset during a test case teardown.
|
||||||
|
When the device notifies the host about the reset.
|
||||||
|
Then the host:
|
||||||
|
* keeps track of the test case index of the current test suite,
|
||||||
|
* performs a dev-host handshake,
|
||||||
|
* advances the test suite to next test case.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Developed for a watchdog test, so that it can be run on devices that
|
||||||
|
do not support watchdog timeout updates after the initial setup.
|
||||||
|
As a solution, after testing watchdog with one set of settings, the
|
||||||
|
device performs a reset and notifies the host with the test case number,
|
||||||
|
so that the test suite may be advanced once the device boots again.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(SyncOnReset, self).__init__()
|
||||||
|
self.test_case_num = 0
|
||||||
|
self.sync_delay = DEFAULT_SYNC_DELAY
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
sync_delay = self.get_config_item('forced_reset_timeout')
|
||||||
|
self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready)
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset)
|
||||||
|
|
||||||
|
def cb_device_ready(self, key, value, timestamp):
|
||||||
|
"""Advance the device test suite to the next test case."""
|
||||||
|
self.send_kv(MSG_KEY_START_CASE, self.test_case_num)
|
||||||
|
|
||||||
|
def cb_device_reset(self, key, value, timestamp):
|
||||||
|
"""Wait for the device to boot and perform a handshake.
|
||||||
|
|
||||||
|
Additionally, keep track of the last test case number.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.test_case_num = int(value)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
self.test_case_num += 1
|
||||||
|
time.sleep(self.sync_delay)
|
||||||
|
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
|
@ -0,0 +1,145 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
import collections
|
||||||
|
import threading
|
||||||
|
from mbed_host_tests import BaseHostTest
|
||||||
|
|
||||||
|
TestCaseData = collections.namedtuple('TestCaseData', ['index', 'data_to_send'])
|
||||||
|
|
||||||
|
DEFAULT_SYNC_DELAY = 4.0
|
||||||
|
MAX_HB_PERIOD = 2.5 # [s] Max expected heartbeat period.
|
||||||
|
|
||||||
|
MSG_VALUE_DUMMY = '0'
|
||||||
|
CASE_DATA_INVALID = 0xffffffff
|
||||||
|
CASE_DATA_PHASE2_OK = 0xfffffffe
|
||||||
|
CASE_DATA_INSUFF_HB = 0x0
|
||||||
|
|
||||||
|
MSG_KEY_SYNC = '__sync'
|
||||||
|
MSG_KEY_DEVICE_READY = 'ready'
|
||||||
|
MSG_KEY_START_CASE = 'start_case'
|
||||||
|
MSG_KEY_DEVICE_RESET = 'dev_reset'
|
||||||
|
MSG_KEY_HEARTBEAT = 'hb'
|
||||||
|
|
||||||
|
|
||||||
|
class WatchdogReset(BaseHostTest):
|
||||||
|
"""Host side test that handles device reset.
|
||||||
|
|
||||||
|
Given a device with a watchdog timer started.
|
||||||
|
When the device notifies the host about an incoming reset.
|
||||||
|
Then the host:
|
||||||
|
* keeps track of the test case index of the current test suite,
|
||||||
|
* performs a dev-host handshake.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(WatchdogReset, self).__init__()
|
||||||
|
self.current_case = TestCaseData(0, CASE_DATA_INVALID)
|
||||||
|
self.__handshake_timer = None
|
||||||
|
self.sync_delay = DEFAULT_SYNC_DELAY
|
||||||
|
self.drop_heartbeat_messages = True
|
||||||
|
self.hb_timestamps_us = []
|
||||||
|
|
||||||
|
def handshake_timer_start(self, seconds=1.0, pre_sync_fun=None):
|
||||||
|
"""Start a new handshake timer."""
|
||||||
|
|
||||||
|
def timer_handler():
|
||||||
|
"""Perform a dev-host handshake by sending a sync message."""
|
||||||
|
if pre_sync_fun is not None:
|
||||||
|
pre_sync_fun()
|
||||||
|
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
||||||
|
|
||||||
|
self.__handshake_timer = threading.Timer(seconds, timer_handler)
|
||||||
|
self.__handshake_timer.start()
|
||||||
|
|
||||||
|
def handshake_timer_cancel(self):
|
||||||
|
"""Cancel the current handshake timer."""
|
||||||
|
try:
|
||||||
|
self.__handshake_timer.cancel()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
self.__handshake_timer = None
|
||||||
|
|
||||||
|
def heartbeat_timeout_handler(self):
|
||||||
|
"""Handler for the heartbeat timeout.
|
||||||
|
|
||||||
|
Compute the time span of the last heartbeat sequence.
|
||||||
|
Set self.current_case.data_to_send to CASE_DATA_INVALID if no heartbeat was received.
|
||||||
|
Set self.current_case.data_to_send to CASE_DATA_INSUFF_HB if only one heartbeat was
|
||||||
|
received.
|
||||||
|
"""
|
||||||
|
self.drop_heartbeat_messages = True
|
||||||
|
dev_data = CASE_DATA_INVALID
|
||||||
|
if len(self.hb_timestamps_us) == 1:
|
||||||
|
dev_data = CASE_DATA_INSUFF_HB
|
||||||
|
self.log('Not enough heartbeats received.')
|
||||||
|
elif len(self.hb_timestamps_us) >= 2:
|
||||||
|
dev_data = int(round(0.001 * (self.hb_timestamps_us[-1] - self.hb_timestamps_us[0])))
|
||||||
|
self.log('Heartbeat time span was {} ms.'.format(dev_data))
|
||||||
|
self.current_case = TestCaseData(self.current_case.index, dev_data)
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
sync_delay = self.get_config_item('forced_reset_timeout')
|
||||||
|
self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready)
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset)
|
||||||
|
self.register_callback(MSG_KEY_HEARTBEAT, self.cb_heartbeat)
|
||||||
|
|
||||||
|
def teardown(self):
|
||||||
|
self.handshake_timer_cancel()
|
||||||
|
|
||||||
|
def cb_device_ready(self, key, value, timestamp):
|
||||||
|
"""Advance the device test suite to a proper test case.
|
||||||
|
|
||||||
|
Additionally, send test case data to the device.
|
||||||
|
"""
|
||||||
|
self.handshake_timer_cancel()
|
||||||
|
msg_value = '{0.index:02x},{0.data_to_send:08x}'.format(self.current_case)
|
||||||
|
self.send_kv(MSG_KEY_START_CASE, msg_value)
|
||||||
|
self.drop_heartbeat_messages = False
|
||||||
|
self.hb_timestamps_us = []
|
||||||
|
|
||||||
|
def cb_device_reset(self, key, value, timestamp):
|
||||||
|
"""Keep track of the test case number.
|
||||||
|
|
||||||
|
Also set a new handshake timeout, so when the device gets
|
||||||
|
restarted by the watchdog, the communication will be restored
|
||||||
|
by the __handshake_timer.
|
||||||
|
"""
|
||||||
|
self.handshake_timer_cancel()
|
||||||
|
case_num, dev_reset_delay_ms = (int(i, base=16) for i in value.split(','))
|
||||||
|
self.current_case = TestCaseData(case_num, CASE_DATA_PHASE2_OK)
|
||||||
|
self.handshake_timer_start(self.sync_delay + dev_reset_delay_ms / 1000.0)
|
||||||
|
|
||||||
|
def cb_heartbeat(self, key, value, timestamp):
|
||||||
|
"""Save the timestamp of a heartbeat message.
|
||||||
|
|
||||||
|
Additionally, keep track of the test case number.
|
||||||
|
|
||||||
|
Also each heartbeat sets a new timeout, so when the device gets
|
||||||
|
restarted by the watchdog, the communication will be restored
|
||||||
|
by the __handshake_timer.
|
||||||
|
"""
|
||||||
|
if self.drop_heartbeat_messages:
|
||||||
|
return
|
||||||
|
self.handshake_timer_cancel()
|
||||||
|
case_num, timestamp_us = (int(i, base=16) for i in value.split(','))
|
||||||
|
self.current_case = TestCaseData(case_num, CASE_DATA_INVALID)
|
||||||
|
self.hb_timestamps_us.append(timestamp_us)
|
||||||
|
self.handshake_timer_start(
|
||||||
|
seconds=(MAX_HB_PERIOD + self.sync_delay),
|
||||||
|
pre_sync_fun=self.heartbeat_timeout_handler)
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_DRIVERS_RESET_REASON_TESTS_H
|
||||||
|
#define MBED_DRIVERS_RESET_REASON_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
/** Test the ResetReason driver API
|
||||||
|
*
|
||||||
|
* Given a device supporting a ResetReason API,
|
||||||
|
* when the device is restarted,
|
||||||
|
* then the device returns a correct reset reason for every restart.
|
||||||
|
*/
|
||||||
|
void test_reset_reason();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_RESET_REASON
|
||||||
|
#error [NOT_SUPPORTED] Reset reason API not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "drivers/ResetReason.h"
|
||||||
|
#include "ResetReason_tests.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
|
||||||
|
#define MSG_VALUE_WATCHDOG_STATUS "wdg_present"
|
||||||
|
#define WDG_TIMEOUT_MS 50UL
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define MSG_VALUE_WATCHDOG_STATUS "no_wdg"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define MSG_VALUE_RESET_REASON_GET "get"
|
||||||
|
#define MSG_VALUE_RESET_REASON_CLEAR "clear"
|
||||||
|
#define MSG_VALUE_RESET_REASON_CLEAR_ACK "cleared"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_ACK "ack"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_NVIC "nvic"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_WATCHDOG "watchdog"
|
||||||
|
#define MSG_VALUE_LEN 16
|
||||||
|
#define MSG_KEY_LEN 16
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_RESET_REASON_RAW "reason_raw"
|
||||||
|
#define MSG_KEY_RESET_REASON "reason"
|
||||||
|
#define MSG_KEY_DEVICE_RESET "reset"
|
||||||
|
|
||||||
|
#define SERIAL_FLUSH_TIME_MS 20
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CMD_STATUS_CONTINUE,
|
||||||
|
CMD_STATUS_ERROR
|
||||||
|
} cmd_status_t;
|
||||||
|
|
||||||
|
static cmd_status_t handle_command(const char *key, const char *value)
|
||||||
|
{
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON_RAW) == 0) {
|
||||||
|
uint32_t raw_reason = ResetReason::get_raw();
|
||||||
|
char raw_reason_hex_str[9] = { };
|
||||||
|
int raw_reason_hex_str_len = snprintf(raw_reason_hex_str,
|
||||||
|
sizeof raw_reason_hex_str, "%08lx", raw_reason);
|
||||||
|
|
||||||
|
if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON_RAW, raw_reason_hex_str);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_GET) == 0) {
|
||||||
|
int reason = (int) ResetReason::get();
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON, reason);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_CLEAR) == 0) {
|
||||||
|
/* In order to keep this code compatible with a host script common for
|
||||||
|
* both HAL API tests and driver API tests, ignore the 'clear' command
|
||||||
|
* received from host.
|
||||||
|
*
|
||||||
|
* The driver API does not provide clear() function directly.
|
||||||
|
*/
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR_ACK);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) {
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK);
|
||||||
|
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
|
||||||
|
NVIC_SystemReset();
|
||||||
|
TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) {
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK);
|
||||||
|
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
|
||||||
|
watchdog_config_t config = { .timeout_ms = WDG_TIMEOUT_MS };
|
||||||
|
if (hal_watchdog_init(&config) != WATCHDOG_STATUS_OK) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Invalid message key.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_reset_reason()
|
||||||
|
{
|
||||||
|
// Report readiness and watchdog status.
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_WATCHDOG_STATUS);
|
||||||
|
|
||||||
|
cmd_status_t cmd_status = CMD_STATUS_CONTINUE;
|
||||||
|
static char _key[MSG_KEY_LEN + 1] = { };
|
||||||
|
static char _value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
// Let the host side decide what to do and just handle the commands.
|
||||||
|
while (CMD_STATUS_CONTINUE == cmd_status) {
|
||||||
|
memset(_key, 0, sizeof _key);
|
||||||
|
memset(_value, 0, sizeof _value);
|
||||||
|
greentea_parse_kv(_key, _value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
cmd_status = handle_command(_key, _value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(60, "reset_reason");
|
||||||
|
test_reset_reason(); // The result of this test suite is reported by the host side.
|
||||||
|
GREENTEA_TESTSUITE_RESULT(0); // Fail on any error.
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_DRIVERS_WATCHDOG_TESTS_H
|
||||||
|
#define MBED_DRIVERS_WATCHDOG_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
/** Test Watchdog max_timeout validity
|
||||||
|
*
|
||||||
|
* Given a device supporting Watchdog driver API,
|
||||||
|
* when @a Watchdog::get_max_timeout() is called,
|
||||||
|
* then the returned value is greater than 1.
|
||||||
|
*/
|
||||||
|
void test_max_timeout_is_valid();
|
||||||
|
|
||||||
|
/** Test Watchdog stop
|
||||||
|
*
|
||||||
|
* Given a device without a support for the @a disable_watchdog feature,
|
||||||
|
* when @a Watchdog::stop() is called,
|
||||||
|
* then false is returned.
|
||||||
|
*
|
||||||
|
* Otherwise, given the device with @a disable_watchdog feature support:
|
||||||
|
*
|
||||||
|
* Given the Watchdog is *NOT* running,
|
||||||
|
* when @a Watchdog::stop() is called,
|
||||||
|
* then false is returned.
|
||||||
|
*
|
||||||
|
* Given the Watchdog is running,
|
||||||
|
* when @a Watchdog::stop() is called before the timeout expires,
|
||||||
|
* then true is returned and the device is not restarted.
|
||||||
|
*
|
||||||
|
* Given the Watchdog is *NOT* running (it has already been stopped),
|
||||||
|
* when @a Watchdog::stop() is called,
|
||||||
|
* then false is returned.
|
||||||
|
*/
|
||||||
|
void test_stop();
|
||||||
|
|
||||||
|
/** Test Watchdog start multiple times
|
||||||
|
*
|
||||||
|
* Given a set of unique timeout values,
|
||||||
|
* when Watchdog::start(T) is called for each value T,
|
||||||
|
* then, for every T, Watchdog::start() returns true
|
||||||
|
* and Watchdog::get_timeout() returns an actual timeout value R
|
||||||
|
* and T <= R < 2 * T.
|
||||||
|
*/
|
||||||
|
void test_restart();
|
||||||
|
|
||||||
|
/** Test Watchdog start with a valid config
|
||||||
|
*
|
||||||
|
* Given a value of T ms which is within supported Watchdog timeout range,
|
||||||
|
* when Watchdog::start(T) is called,
|
||||||
|
* then true is returned
|
||||||
|
* and Watchdog::get_timeout() returns an actual timeout value R
|
||||||
|
* and T <= R < 2 * T.
|
||||||
|
*/
|
||||||
|
template<uint32_t timeout_ms>
|
||||||
|
void test_start();
|
||||||
|
|
||||||
|
/** Test Watchdog start with max_timeout
|
||||||
|
*
|
||||||
|
* Given max_timeout value returned by @a Watchdog::get_max_timeout(),
|
||||||
|
* when @a Watchdog::start(max_timeout) is called,
|
||||||
|
* then true is returned
|
||||||
|
* and @a Watchdog::get_timeout() returns max_timeout.
|
||||||
|
*/
|
||||||
|
void test_start_max_timeout();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,284 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_WATCHDOG
|
||||||
|
#error [NOT_SUPPORTED] Watchdog not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
#include "drivers/Watchdog.h"
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
#include "Watchdog_tests.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* The shortest timeout value, this test suite is able to handle correctly. */
|
||||||
|
#define WDG_MIN_TIMEOUT_MS 50UL
|
||||||
|
|
||||||
|
// Do not set watchdog timeout shorter than WDG_MIN_TIMEOUT_MS, as it may
|
||||||
|
// cause the host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS'
|
||||||
|
// if watchdog performs reset during test suite teardown.
|
||||||
|
#define WDG_TIMEOUT_MS 100UL
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define MSG_VALUE_LEN 24
|
||||||
|
#define MSG_KEY_LEN 24
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_START_CASE "start_case"
|
||||||
|
#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown"
|
||||||
|
|
||||||
|
/* To prevent a loss of Greentea data, the serial buffers have to be flushed
|
||||||
|
* before the UART peripheral shutdown. The UART shutdown happens when the
|
||||||
|
* device is entering the deepsleep mode or performing a reset.
|
||||||
|
*
|
||||||
|
* With the current API, it is not possible to check if the hardware buffers
|
||||||
|
* are empty. However, it is possible to determine the time required for the
|
||||||
|
* buffers to flush.
|
||||||
|
*
|
||||||
|
* Take NUMAKER_PFM_NUC472 as an example:
|
||||||
|
* The UART peripheral has 16-byte Tx FIFO. With a baud rate set to 9600,
|
||||||
|
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
|
||||||
|
* To be on the safe side, set the wait time to 20 ms.
|
||||||
|
*/
|
||||||
|
#define SERIAL_FLUSH_TIME_MS 20
|
||||||
|
|
||||||
|
int CASE_INDEX_START;
|
||||||
|
int CASE_INDEX_CURRENT;
|
||||||
|
bool CASE_IGNORED = false;
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
using utest::v1::Specification;
|
||||||
|
using utest::v1::Harness;
|
||||||
|
|
||||||
|
using namespace mbed;
|
||||||
|
|
||||||
|
Thread wdg_kicking_thread;
|
||||||
|
Semaphore kick_wdg_during_test_teardown(0, 1);
|
||||||
|
|
||||||
|
void wdg_kicking_thread_fun()
|
||||||
|
{
|
||||||
|
kick_wdg_during_test_teardown.wait();
|
||||||
|
while (true) {
|
||||||
|
hal_watchdog_kick();
|
||||||
|
wait_ms(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_max_timeout_is_valid()
|
||||||
|
{
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
TEST_ASSERT(watchdog.get_max_timeout() > 1UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_stop()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
if (!features.disable_watchdog) {
|
||||||
|
TEST_ASSERT_FALSE(watchdog.stop());
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
TEST_ASSERT_FALSE(watchdog.stop());
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(WDG_TIMEOUT_MS));
|
||||||
|
TEST_ASSERT_TRUE(watchdog.is_running());
|
||||||
|
TEST_ASSERT_TRUE(watchdog.stop());
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
// Make sure that a disabled watchdog does not reset the core.
|
||||||
|
wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value.
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(watchdog.stop());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void test_restart()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.update_config) {
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!features.disable_watchdog) {
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
uint32_t max_timeout = watchdog.get_max_timeout();
|
||||||
|
uint32_t timeouts[] = {
|
||||||
|
max_timeout / 4,
|
||||||
|
max_timeout / 8,
|
||||||
|
max_timeout / 16
|
||||||
|
};
|
||||||
|
int num_timeouts = sizeof timeouts / sizeof timeouts[0];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_timeouts; i++) {
|
||||||
|
if (timeouts[i] < WDG_MIN_TIMEOUT_MS) {
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(timeouts[i]));
|
||||||
|
TEST_ASSERT_TRUE(watchdog.is_running());
|
||||||
|
uint32_t actual_timeout = watchdog.get_timeout();
|
||||||
|
TEST_ASSERT_TRUE(watchdog.stop());
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
// The watchdog should trigger at, or after the timeout value.
|
||||||
|
TEST_ASSERT(actual_timeout >= timeouts[i]);
|
||||||
|
// The watchdog should trigger before twice the timeout value.
|
||||||
|
TEST_ASSERT(actual_timeout < 2 * timeouts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
CASE_INDEX_CURRENT = index_of_case;
|
||||||
|
CASE_IGNORED = false;
|
||||||
|
return utest::v1::greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_teardown_sync_on_reset(const Case *const source, const size_t passed, const size_t failed,
|
||||||
|
const utest::v1::failure_t failure)
|
||||||
|
{
|
||||||
|
if (CASE_IGNORED) {
|
||||||
|
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
// Unlock kicking the watchdog during teardown.
|
||||||
|
kick_wdg_during_test_teardown.release();
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
if (failed) {
|
||||||
|
/* Return immediately and skip the device reset, if the test case failed.
|
||||||
|
* Provided that the device won't be restarted by other means (i.e. watchdog timer),
|
||||||
|
* this should allow the test suite to finish in a defined manner
|
||||||
|
* and report failure to host.
|
||||||
|
* In case of watchdog reset during test suite teardown, the loss of serial
|
||||||
|
* connection is possible, so the host-test-runner may return 'TIMEOUT'
|
||||||
|
* instead of 'FAIL'.
|
||||||
|
*/
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT);
|
||||||
|
utest_printf("The device will now restart.\n");
|
||||||
|
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
|
||||||
|
NVIC_SystemReset();
|
||||||
|
return status; // Reset is instant so this line won't be reached.
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case *const source, const size_t passed, const size_t failed,
|
||||||
|
const utest::v1::failure_t failure)
|
||||||
|
{
|
||||||
|
if (CASE_IGNORED) {
|
||||||
|
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (features.disable_watchdog) {
|
||||||
|
hal_watchdog_stop();
|
||||||
|
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
return case_teardown_sync_on_reset(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<uint32_t timeout_ms>
|
||||||
|
void test_start()
|
||||||
|
{
|
||||||
|
if (timeout_ms < WDG_MIN_TIMEOUT_MS) {
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(timeout_ms));
|
||||||
|
uint32_t actual_timeout = watchdog.get_timeout();
|
||||||
|
// The watchdog should trigger at, or after the timeout value.
|
||||||
|
TEST_ASSERT(actual_timeout >= timeout_ms);
|
||||||
|
// The watchdog should trigger before twice the timeout value.
|
||||||
|
TEST_ASSERT(actual_timeout < 2 * timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_start_max_timeout()
|
||||||
|
{
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
uint32_t max_timeout = watchdog.get_max_timeout();
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(max_timeout));
|
||||||
|
// The watchdog should trigger at, or after the timeout value.
|
||||||
|
TEST_ASSERT(watchdog.get_timeout() >= max_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int testsuite_setup_sync_on_reset(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(45, "sync_on_reset");
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
|
if (status != utest::v1::STATUS_CONTINUE) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
|
||||||
|
utest_printf("Invalid message key.\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tailptr = NULL;
|
||||||
|
CASE_INDEX_START = (int) strtol(value, &tailptr, 10);
|
||||||
|
if (*tailptr != '\0' || CASE_INDEX_START < 0) {
|
||||||
|
utest_printf("Invalid start case index received from host\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The thread is started here, but feeding the watchdog will start
|
||||||
|
// when the semaphore is released during a test case teardown.
|
||||||
|
wdg_kicking_thread.start(mbed::callback(wdg_kicking_thread_fun));
|
||||||
|
|
||||||
|
utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases);
|
||||||
|
return CASE_INDEX_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("max_timeout is valid", test_max_timeout_is_valid),
|
||||||
|
Case("Stop", test_stop),
|
||||||
|
Case("Restart multiple times",
|
||||||
|
(utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_restart, (utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset),
|
||||||
|
Case("Start, 100 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_start<100UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
|
||||||
|
Case("Start, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_start_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Harness will start with a test case index provided by host script.
|
||||||
|
return !Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_DRIVERS_WATCHDOG_RESET_TESTS_H
|
||||||
|
#define MBED_DRIVERS_WATCHDOG_RESET_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
/** Test Watchdog reset
|
||||||
|
*
|
||||||
|
* Given a device with a Watchdog started,
|
||||||
|
* when a Watchdog timeout expires,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_simple_reset();
|
||||||
|
|
||||||
|
/** Test Watchdog reset in sleep mode
|
||||||
|
*
|
||||||
|
* Given a device with a Watchdog started,
|
||||||
|
* when the Watchdog timeout expires while the device is in sleep mode,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_sleep_reset();
|
||||||
|
|
||||||
|
/** Test Watchdog reset in deepsleep mode
|
||||||
|
*
|
||||||
|
* Given a device with a Watchdog started,
|
||||||
|
* when the Watchdog timeout expires while the device is in deepsleep mode,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_deepsleep_reset();
|
||||||
|
|
||||||
|
/** Test Watchdog reset after Watchdog restart
|
||||||
|
*
|
||||||
|
* Given a device with a Watchdog started,
|
||||||
|
* when the Watchdog is stopped before its timeout expires,
|
||||||
|
* then the device is not restarted.
|
||||||
|
* When the Watchdog is started again and its timeout expires,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_restart_reset();
|
||||||
|
|
||||||
|
/** Test Watchdog kick
|
||||||
|
*
|
||||||
|
* Given a device with a Watchdog started,
|
||||||
|
* when the Watchdog is kicked before its timeout expires,
|
||||||
|
* then the device restart is prevented.
|
||||||
|
* When the Watchdog is *NOT* kicked again before next timeout expires,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_kick_reset();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,321 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_WATCHDOG
|
||||||
|
#error [NOT_SUPPORTED] Watchdog not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "drivers/Watchdog.h"
|
||||||
|
#include "Watchdog_reset_tests.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#define TIMEOUT_MS 100UL
|
||||||
|
#define KICK_ADVANCE_MS 10UL
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define CASE_DATA_INVALID 0xffffffffUL
|
||||||
|
#define CASE_DATA_PHASE2_OK 0xfffffffeUL
|
||||||
|
|
||||||
|
#define MSG_VALUE_LEN 24
|
||||||
|
#define MSG_KEY_LEN 24
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_START_CASE "start_case"
|
||||||
|
#define MSG_KEY_DEVICE_RESET "dev_reset"
|
||||||
|
|
||||||
|
/* To prevent a loss of Greentea data, the serial buffers have to be flushed
|
||||||
|
* before the UART peripheral shutdown. The UART shutdown happens when the
|
||||||
|
* device is entering the deepsleep mode or performing a reset.
|
||||||
|
*
|
||||||
|
* With the current API, it is not possible to check if the hardware buffers
|
||||||
|
* are empty. However, it is possible to determine the time required for the
|
||||||
|
* buffers to flush.
|
||||||
|
*
|
||||||
|
* Take NUMAKER_PFM_NUC472 as an example:
|
||||||
|
* The UART peripheral has 16-byte Tx FIFO. With a baud rate set to 9600,
|
||||||
|
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
|
||||||
|
* To be on the safe side, set the wait time to 20 ms.
|
||||||
|
*/
|
||||||
|
#define SERIAL_FLUSH_TIME_MS 20
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
using utest::v1::Specification;
|
||||||
|
using utest::v1::Harness;
|
||||||
|
|
||||||
|
using namespace mbed;
|
||||||
|
|
||||||
|
struct testcase_data {
|
||||||
|
int index;
|
||||||
|
int start_index;
|
||||||
|
uint32_t received_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void release_sem(Semaphore *sem)
|
||||||
|
{
|
||||||
|
sem->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
testcase_data current_case;
|
||||||
|
|
||||||
|
bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms)
|
||||||
|
{
|
||||||
|
char msg_value[12];
|
||||||
|
int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms);
|
||||||
|
if (str_len != (sizeof msg_value) - 1) {
|
||||||
|
utest_printf("Failed to compose a value string to be sent to host.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_simple_reset()
|
||||||
|
{
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
// Verify if this test case passed based on data received from host.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
// Init the watchdog and wait for a device reset.
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
|
||||||
|
TEST_ASSERT_TRUE(watchdog.is_running());
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during wait_ms() above;
|
||||||
|
|
||||||
|
watchdog.kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEVICE_SLEEP
|
||||||
|
void test_sleep_reset()
|
||||||
|
{
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
Semaphore sem(0, 1);
|
||||||
|
Timeout timeout;
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
|
||||||
|
TEST_ASSERT_TRUE(watchdog.is_running());
|
||||||
|
sleep_manager_lock_deep_sleep();
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS));
|
||||||
|
if (sleep_manager_can_deep_sleep()) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sem.wait(); // Device reset expected.
|
||||||
|
sleep_manager_unlock_deep_sleep();
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during sem.wait() (sleep) above;
|
||||||
|
|
||||||
|
watchdog.kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEVICE_LOWPOWERTIMER
|
||||||
|
void test_deepsleep_reset()
|
||||||
|
{
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
Semaphore sem(0, 1);
|
||||||
|
LowPowerTimeout lp_timeout;
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
|
||||||
|
TEST_ASSERT_TRUE(watchdog.is_running());
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS));
|
||||||
|
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
|
||||||
|
if (!sleep_manager_can_deep_sleep()) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed.");
|
||||||
|
}
|
||||||
|
sem.wait(); // Device reset expected.
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during sem.wait() (deepsleep) above;
|
||||||
|
|
||||||
|
watchdog.kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void test_restart_reset()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.disable_watchdog) {
|
||||||
|
TEST_IGNORE_MESSAGE("Disabling Watchdog not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
|
||||||
|
TEST_ASSERT_TRUE(watchdog.is_running());
|
||||||
|
wait_ms(TIMEOUT_MS / 2UL);
|
||||||
|
TEST_ASSERT_TRUE(watchdog.stop());
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
// Check that stopping the Watchdog prevents a device reset.
|
||||||
|
// The watchdog should trigger at, or after the timeout value.
|
||||||
|
// The watchdog should trigger before twice the timeout value.
|
||||||
|
wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_MS);
|
||||||
|
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
|
||||||
|
TEST_ASSERT_TRUE(watchdog.is_running());
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during that wait() above;
|
||||||
|
|
||||||
|
watchdog.kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_kick_reset()
|
||||||
|
{
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
TEST_ASSERT_FALSE(watchdog.is_running());
|
||||||
|
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
|
||||||
|
TEST_ASSERT_TRUE(watchdog.is_running());
|
||||||
|
for (int i = 3; i; i--) {
|
||||||
|
// The reset is prevented as long as the watchdog is kicked
|
||||||
|
// anytime before the timeout.
|
||||||
|
wait_ms(TIMEOUT_MS - KICK_ADVANCE_MS);
|
||||||
|
watchdog.kick();
|
||||||
|
}
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during that wait() above;
|
||||||
|
|
||||||
|
watchdog.kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
current_case.index = index_of_case;
|
||||||
|
return utest::v1::greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
int testsuite_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(90, "watchdog_reset");
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
|
if (status != utest::v1::STATUS_CONTINUE) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
|
||||||
|
utest_printf("Invalid message key.\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data));
|
||||||
|
if (num_args == 0 || num_args == EOF) {
|
||||||
|
utest_printf("Invalid data received from host\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases,
|
||||||
|
current_case.start_index);
|
||||||
|
return current_case.start_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Watchdog reset", case_setup, test_simple_reset),
|
||||||
|
#if DEVICE_SLEEP
|
||||||
|
Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset),
|
||||||
|
#if DEVICE_LOWPOWERTIMER
|
||||||
|
Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset),
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
Case("Watchdog started again", case_setup, test_restart_reset),
|
||||||
|
Case("Kicking the Watchdog prevents reset", case_setup, test_kick_reset),
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Harness will start with a test case index provided by host script.
|
||||||
|
return !Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_RESET_REASON
|
||||||
|
#error [NOT_SUPPORTED] Reset reason API not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "hal/reset_reason_api.h"
|
||||||
|
#include "reset_reason_api_tests.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
|
||||||
|
#define MSG_VALUE_WATCHDOG_STATUS "wdg_present"
|
||||||
|
#define WDG_TIMEOUT_MS 50UL
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define MSG_VALUE_WATCHDOG_STATUS "no_wdg"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define MSG_VALUE_RESET_REASON_GET "get"
|
||||||
|
#define MSG_VALUE_RESET_REASON_CLEAR "clear"
|
||||||
|
#define MSG_VALUE_RESET_REASON_CLEAR_ACK "cleared"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_ACK "ack"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_NVIC "nvic"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_WATCHDOG "watchdog"
|
||||||
|
#define MSG_VALUE_LEN 16
|
||||||
|
#define MSG_KEY_LEN 16
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_RESET_REASON_RAW "reason_raw"
|
||||||
|
#define MSG_KEY_RESET_REASON "reason"
|
||||||
|
#define MSG_KEY_DEVICE_RESET "reset"
|
||||||
|
|
||||||
|
/* To prevent loss of Greentea data, flush serial buffers before the UART peripheral shutdown. The UART shutdown happens when the
|
||||||
|
* device is entering the deepsleep mode or performing a reset.
|
||||||
|
*
|
||||||
|
* With the current API, it is not possible to check if the hardware buffers
|
||||||
|
* are empty. However, you can determine the amount of time required for the
|
||||||
|
* buffers to flush.
|
||||||
|
*
|
||||||
|
* For example, NUMAKER_PFM_NUC472:
|
||||||
|
* The UART peripheral has 16-byte Tx FIFO. With a baud rate of 9600,
|
||||||
|
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
|
||||||
|
* To be on the safe side, set the wait time to 20 ms.
|
||||||
|
*/
|
||||||
|
#define SERIAL_FLUSH_TIME_MS 20
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CMD_STATUS_CONTINUE,
|
||||||
|
CMD_STATUS_ERROR
|
||||||
|
} cmd_status_t;
|
||||||
|
|
||||||
|
static cmd_status_t handle_command(const char *key, const char *value)
|
||||||
|
{
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON_RAW) == 0) {
|
||||||
|
uint32_t raw_reason = hal_reset_reason_get_raw();
|
||||||
|
char raw_reason_hex_str[9] = { };
|
||||||
|
int raw_reason_hex_str_len = snprintf(raw_reason_hex_str,
|
||||||
|
sizeof raw_reason_hex_str, "%08lx", raw_reason);
|
||||||
|
|
||||||
|
if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON_RAW, raw_reason_hex_str);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_GET) == 0) {
|
||||||
|
int reason = (int) hal_reset_reason_get();
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON, reason);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_CLEAR) == 0) {
|
||||||
|
hal_reset_reason_clear();
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR_ACK);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) {
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK);
|
||||||
|
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
|
||||||
|
NVIC_SystemReset();
|
||||||
|
TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) {
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK);
|
||||||
|
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
|
||||||
|
watchdog_config_t config = { .timeout_ms = WDG_TIMEOUT_MS };
|
||||||
|
if (hal_watchdog_init(&config) != WATCHDOG_STATUS_OK) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Invalid message key.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_reset_reason()
|
||||||
|
{
|
||||||
|
// Report readiness and watchdog status.
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_WATCHDOG_STATUS);
|
||||||
|
|
||||||
|
cmd_status_t cmd_status = CMD_STATUS_CONTINUE;
|
||||||
|
static char _key[MSG_KEY_LEN + 1] = { };
|
||||||
|
static char _value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
// Let the host side decide what to do and just handle the commands.
|
||||||
|
while (CMD_STATUS_CONTINUE == cmd_status) {
|
||||||
|
memset(_key, 0, sizeof _key);
|
||||||
|
memset(_value, 0, sizeof _value);
|
||||||
|
greentea_parse_kv(_key, _value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
cmd_status = handle_command(_key, _value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(60, "reset_reason");
|
||||||
|
test_reset_reason(); // The result of this test suite is reported by the host side.
|
||||||
|
GREENTEA_TESTSUITE_RESULT(0); // Fail on any error.
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup hal_reset_reason_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_HAL_RESET_REASON_API_TESTS_H
|
||||||
|
#define MBED_HAL_RESET_REASON_API_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Test the Reset Reason HAL API
|
||||||
|
*
|
||||||
|
* Given a device supporting a Reset Reason API,
|
||||||
|
* when the device is restarted,
|
||||||
|
* then the device returns a correct reset reason for every restart.
|
||||||
|
*/
|
||||||
|
void test_reset_reason();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_WATCHDOG
|
||||||
|
#error [NOT_SUPPORTED] Watchdog not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
#include "mbed_wait_api.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "watchdog_api_tests.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* The shortest timeout value, this test suite is able to handle correctly. */
|
||||||
|
#define WDG_MIN_TIMEOUT_MS 50UL
|
||||||
|
|
||||||
|
// Do not set watchdog timeout shorter than WDG_MIN_TIMEOUT_MS, as it may
|
||||||
|
// cause the host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS'
|
||||||
|
// if watchdog performs reset during test suite teardown.
|
||||||
|
#define WDG_TIMEOUT_MS 100UL
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define MSG_VALUE_LEN 24
|
||||||
|
#define MSG_KEY_LEN 24
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_START_CASE "start_case"
|
||||||
|
#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown"
|
||||||
|
|
||||||
|
/* To prevent a loss of Greentea data, the serial buffers have to be flushed
|
||||||
|
* before the UART peripheral shutdown. The UART shutdown happens when the
|
||||||
|
* device is entering the deepsleep mode or performing a reset.
|
||||||
|
*
|
||||||
|
* With the current API, it is not possible to check if the hardware buffers
|
||||||
|
* are empty. However, it is possible to determine the time required for the
|
||||||
|
* buffers to flush.
|
||||||
|
*
|
||||||
|
* Take NUMAKER_PFM_NUC472 as an example:
|
||||||
|
* The UART peripheral has 16-byte Tx FIFO. With a baud rate set to 9600,
|
||||||
|
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
|
||||||
|
* To be on the safe side, set the wait time to 20 ms.
|
||||||
|
*/
|
||||||
|
#define SERIAL_FLUSH_TIME_MS 20
|
||||||
|
|
||||||
|
int CASE_INDEX_START;
|
||||||
|
int CASE_INDEX_CURRENT;
|
||||||
|
bool CASE_IGNORED = false;
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
using utest::v1::Specification;
|
||||||
|
using utest::v1::Harness;
|
||||||
|
|
||||||
|
const watchdog_config_t WDG_CONFIG_DEFAULT = { .timeout_ms = WDG_TIMEOUT_MS };
|
||||||
|
|
||||||
|
Thread wdg_kicking_thread;
|
||||||
|
Semaphore kick_wdg_during_test_teardown(0, 1);
|
||||||
|
|
||||||
|
void wdg_kicking_thread_fun()
|
||||||
|
{
|
||||||
|
kick_wdg_during_test_teardown.wait();
|
||||||
|
while (true) {
|
||||||
|
hal_watchdog_kick();
|
||||||
|
wait_ms(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_max_timeout_is_valid()
|
||||||
|
{
|
||||||
|
TEST_ASSERT(hal_watchdog_get_platform_features().max_timeout > 1UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_restart_is_possible()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.disable_watchdog) {
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TEST_ASSERT(features.update_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_stop()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.disable_watchdog) {
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_NOT_SUPPORTED, hal_watchdog_stop());
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&WDG_CONFIG_DEFAULT));
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
|
||||||
|
// Make sure that a disabled watchdog does not reset the core.
|
||||||
|
wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value.
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_update_config()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.update_config) {
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_config_t config = WDG_CONFIG_DEFAULT;
|
||||||
|
uint32_t timeouts[] = {
|
||||||
|
features.max_timeout / 4,
|
||||||
|
features.max_timeout / 8,
|
||||||
|
features.max_timeout / 16
|
||||||
|
};
|
||||||
|
int num_timeouts = sizeof timeouts / sizeof timeouts[0];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_timeouts; i++) {
|
||||||
|
if (timeouts[i] < WDG_MIN_TIMEOUT_MS) {
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.timeout_ms = timeouts[i];
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
uint32_t reload_value = hal_watchdog_get_reload_value();
|
||||||
|
// The watchdog should trigger at, or after the timeout value.
|
||||||
|
TEST_ASSERT(reload_value >= timeouts[i]);
|
||||||
|
// The watchdog should trigger before twice the timeout value.
|
||||||
|
TEST_ASSERT(reload_value < 2 * timeouts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
CASE_INDEX_CURRENT = index_of_case;
|
||||||
|
CASE_IGNORED = false;
|
||||||
|
return utest::v1::greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_teardown_sync_on_reset(const Case *const source, const size_t passed, const size_t failed,
|
||||||
|
const utest::v1::failure_t failure)
|
||||||
|
{
|
||||||
|
if (CASE_IGNORED) {
|
||||||
|
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
// Unlock kicking the watchdog during teardown.
|
||||||
|
kick_wdg_during_test_teardown.release();
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
if (failed) {
|
||||||
|
/* Return immediately and skip the device reset, if the test case failed.
|
||||||
|
* Provided that the device won't be restarted by other means (i.e. watchdog timer),
|
||||||
|
* this should allow the test suite to finish in a defined manner
|
||||||
|
* and report failure to host.
|
||||||
|
* In case of watchdog reset during test suite teardown, the loss of serial
|
||||||
|
* connection is possible, so the host-test-runner may return 'TIMEOUT'
|
||||||
|
* instead of 'FAIL'.
|
||||||
|
*/
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT);
|
||||||
|
utest_printf("The device will now restart.\n");
|
||||||
|
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
|
||||||
|
NVIC_SystemReset();
|
||||||
|
return status; // Reset is instant so this line won't be reached.
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case *const source, const size_t passed, const size_t failed,
|
||||||
|
const utest::v1::failure_t failure)
|
||||||
|
{
|
||||||
|
if (CASE_IGNORED) {
|
||||||
|
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (features.disable_watchdog) {
|
||||||
|
hal_watchdog_stop();
|
||||||
|
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
return case_teardown_sync_on_reset(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<uint32_t timeout_ms>
|
||||||
|
void test_init()
|
||||||
|
{
|
||||||
|
if (timeout_ms < WDG_MIN_TIMEOUT_MS) {
|
||||||
|
CASE_IGNORED = true;
|
||||||
|
TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
watchdog_config_t config = { .timeout_ms = timeout_ms };
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
uint32_t reload_value = hal_watchdog_get_reload_value();
|
||||||
|
// The watchdog should trigger at, or after the timeout value.
|
||||||
|
TEST_ASSERT(reload_value >= timeout_ms);
|
||||||
|
// The watchdog should trigger before twice the timeout value.
|
||||||
|
TEST_ASSERT(reload_value < 2 * timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_init_max_timeout()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
watchdog_config_t config = { .timeout_ms = features.max_timeout };
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
// The watchdog should trigger at, or after the timeout value.
|
||||||
|
TEST_ASSERT(hal_watchdog_get_reload_value() >= features.max_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int testsuite_setup_sync_on_reset(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(45, "sync_on_reset");
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
|
if (status != utest::v1::STATUS_CONTINUE) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
|
||||||
|
utest_printf("Invalid message key.\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tailptr = NULL;
|
||||||
|
CASE_INDEX_START = (int) strtol(value, &tailptr, 10);
|
||||||
|
if (*tailptr != '\0' || CASE_INDEX_START < 0) {
|
||||||
|
utest_printf("Invalid start case index received from host\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The thread is started here, but feeding the watchdog will start
|
||||||
|
// when the semaphore is released during a test case teardown.
|
||||||
|
wdg_kicking_thread.start(mbed::callback(wdg_kicking_thread_fun));
|
||||||
|
|
||||||
|
utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases);
|
||||||
|
return CASE_INDEX_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Platform feature max_timeout is valid", test_max_timeout_is_valid),
|
||||||
|
Case("Stopped watchdog can be started again", test_restart_is_possible),
|
||||||
|
Case("Watchdog can be stopped", test_stop),
|
||||||
|
|
||||||
|
Case("Update config with multiple init calls",
|
||||||
|
(utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_update_config,
|
||||||
|
(utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset),
|
||||||
|
|
||||||
|
Case("Init, 100 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_init<100UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
|
||||||
|
Case("Init, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_init_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Harness will start with a test case index provided by host script.
|
||||||
|
return !Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup hal_watchdog_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_HAL_WATCHDOG_API_TESTS_H
|
||||||
|
#define MBED_HAL_WATCHDOG_API_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
/** Test max_timeout validity
|
||||||
|
*
|
||||||
|
* Given a device supporting Watchdog HAL API,
|
||||||
|
* when @a hal_watchdog_get_platform_features() is called,
|
||||||
|
* then max_timeout member of returned watchdog_features_t struct is greater than 1.
|
||||||
|
*/
|
||||||
|
void test_max_timeout_is_valid();
|
||||||
|
|
||||||
|
/** Test Watchdog features if a stopped Watchdog can be started again
|
||||||
|
*
|
||||||
|
* Given a device supporting Watchdog HAL API,
|
||||||
|
* when the device supports the @a disable_watchdog feature,
|
||||||
|
* then the device also supports @a update_config feature.
|
||||||
|
*/
|
||||||
|
void test_restart_is_possible();
|
||||||
|
|
||||||
|
/** Test Watchdog stop
|
||||||
|
*
|
||||||
|
* Given a device without a support for the @a disable_watchdog feature,
|
||||||
|
* when @a hal_watchdog_stop() is called,
|
||||||
|
* then WATCHDOG_STATUS_NOT_SUPPORTED is returned.
|
||||||
|
*
|
||||||
|
* Otherwise, given the device with @a disable_watchdog feature support:
|
||||||
|
*
|
||||||
|
* Given the Watchdog is *NOT* running,
|
||||||
|
* when @a hal_watchdog_stop() is called,
|
||||||
|
* then WATCHDOG_STATUS_OK is returned.
|
||||||
|
*
|
||||||
|
* Given the Watchdog is running,
|
||||||
|
* when @a hal_watchdog_stop() is called before the timeout expires,
|
||||||
|
* then WATCHDOG_STATUS_OK is returned and the device is not restarted.
|
||||||
|
*
|
||||||
|
* Given the Watchdog is *NOT* running (it has already been stopped),
|
||||||
|
* when @a hal_watchdog_stop() is called,
|
||||||
|
* then WATCHDOG_STATUS_OK is returned.
|
||||||
|
*/
|
||||||
|
void test_stop();
|
||||||
|
|
||||||
|
/** Test Watchdog init multiple times
|
||||||
|
*
|
||||||
|
* Given a set of unique timeout values,
|
||||||
|
* when @a config.timeout_ms is set to each of these values (T),
|
||||||
|
* then, for every value T, @a hal_watchdog_init() returns @a WATCHDOG_STATUS_OK
|
||||||
|
* and @a hal_watchdog_get_reload_value() returns a reload value R
|
||||||
|
* and T <= R < 2 * T.
|
||||||
|
*/
|
||||||
|
void test_update_config();
|
||||||
|
|
||||||
|
/** Test Watchdog init with a valid config
|
||||||
|
*
|
||||||
|
* Given @a config.timeout_ms is set to T ms,
|
||||||
|
* which is within supported Watchdog timeout range,
|
||||||
|
* when @a hal_watchdog_init() is called,
|
||||||
|
* then @a WATCHDOG_STATUS_OK is returned
|
||||||
|
* and @a hal_watchdog_get_reload_value() returns a reload value R
|
||||||
|
* and T <= R < 2 * T.
|
||||||
|
*/
|
||||||
|
template<uint32_t timeout_ms>
|
||||||
|
void test_init();
|
||||||
|
|
||||||
|
/** Test Watchdog init with a max_timeout
|
||||||
|
*
|
||||||
|
* Given @a config.timeout_ms is set to max_timeout,
|
||||||
|
* which is a value returned by @a hal_watchdog_get_platform_features(),
|
||||||
|
* when @a hal_watchdog_init() is called,
|
||||||
|
* then @a WATCHDOG_STATUS_OK is returned
|
||||||
|
* and @a hal_watchdog_get_reload_value() returns max_timeout.
|
||||||
|
*/
|
||||||
|
void test_init_max_timeout();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
|
|
|
@ -0,0 +1,307 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_WATCHDOG
|
||||||
|
#error [NOT_SUPPORTED] Watchdog not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
#include "watchdog_reset_tests.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#define TIMEOUT_MS 100UL
|
||||||
|
#define KICK_ADVANCE_MS 10UL
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define CASE_DATA_INVALID 0xffffffffUL
|
||||||
|
#define CASE_DATA_PHASE2_OK 0xfffffffeUL
|
||||||
|
|
||||||
|
#define MSG_VALUE_LEN 24
|
||||||
|
#define MSG_KEY_LEN 24
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_START_CASE "start_case"
|
||||||
|
#define MSG_KEY_DEVICE_RESET "dev_reset"
|
||||||
|
|
||||||
|
/* To prevent a loss of Greentea data, the serial buffers have to be flushed
|
||||||
|
* before the UART peripheral shutdown. The UART shutdown happens when the
|
||||||
|
* device is entering the deepsleep mode or performing a reset.
|
||||||
|
*
|
||||||
|
* With the current API, it is not possible to check if the hardware buffers
|
||||||
|
* are empty. However, it is possible to determine the time required for the
|
||||||
|
* buffers to flush.
|
||||||
|
*
|
||||||
|
* Take NUMAKER_PFM_NUC472 as an example:
|
||||||
|
* The UART peripheral has 16-byte Tx FIFO. With a baud rate set to 9600,
|
||||||
|
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
|
||||||
|
* To be on the safe side, set the wait time to 20 ms.
|
||||||
|
*/
|
||||||
|
#define SERIAL_FLUSH_TIME_MS 20
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
using utest::v1::Specification;
|
||||||
|
using utest::v1::Harness;
|
||||||
|
|
||||||
|
struct testcase_data {
|
||||||
|
int index;
|
||||||
|
int start_index;
|
||||||
|
uint32_t received_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void release_sem(Semaphore *sem)
|
||||||
|
{
|
||||||
|
sem->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
testcase_data current_case;
|
||||||
|
|
||||||
|
bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms)
|
||||||
|
{
|
||||||
|
char msg_value[12];
|
||||||
|
int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms);
|
||||||
|
if (str_len != (sizeof msg_value) - 1) {
|
||||||
|
utest_printf("Failed to compose a value string to be sent to host.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_simple_reset()
|
||||||
|
{
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
// Verify if this test case passed based on data received from host.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
// Init the watchdog and wait for a device reset.
|
||||||
|
watchdog_config_t config = { TIMEOUT_MS };
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during wait_ms() above;
|
||||||
|
|
||||||
|
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEVICE_SLEEP
|
||||||
|
void test_sleep_reset()
|
||||||
|
{
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
watchdog_config_t config = { TIMEOUT_MS };
|
||||||
|
Semaphore sem(0, 1);
|
||||||
|
Timeout timeout;
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
sleep_manager_lock_deep_sleep();
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS));
|
||||||
|
if (sleep_manager_can_deep_sleep()) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sem.wait(); // Device reset expected.
|
||||||
|
sleep_manager_unlock_deep_sleep();
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during sem.wait() (sleep) above;
|
||||||
|
|
||||||
|
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEVICE_LOWPOWERTIMER
|
||||||
|
void test_deepsleep_reset()
|
||||||
|
{
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
watchdog_config_t config = { TIMEOUT_MS };
|
||||||
|
Semaphore sem(0, 1);
|
||||||
|
LowPowerTimeout lp_timeout;
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS));
|
||||||
|
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
|
||||||
|
if (!sleep_manager_can_deep_sleep()) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed.");
|
||||||
|
}
|
||||||
|
sem.wait(); // Device reset expected.
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during sem.wait() (deepsleep) above;
|
||||||
|
|
||||||
|
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void test_restart_reset()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.disable_watchdog) {
|
||||||
|
TEST_IGNORE_MESSAGE("Disabling Watchdog not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
watchdog_config_t config = { TIMEOUT_MS };
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
wait_ms(TIMEOUT_MS / 2UL);
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
|
||||||
|
// Check that stopping the Watchdog prevents a device reset.
|
||||||
|
// The watchdog should trigger at, or after the timeout value.
|
||||||
|
// The watchdog should trigger before twice the timeout value.
|
||||||
|
wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_MS);
|
||||||
|
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during that wait() above;
|
||||||
|
|
||||||
|
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_kick_reset()
|
||||||
|
{
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
watchdog_config_t config = { TIMEOUT_MS };
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
for (int i = 3; i; i--) {
|
||||||
|
// The reset is prevented as long as the watchdog is kicked
|
||||||
|
// anytime before the timeout.
|
||||||
|
wait_ms(TIMEOUT_MS - KICK_ADVANCE_MS);
|
||||||
|
hal_watchdog_kick();
|
||||||
|
}
|
||||||
|
if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Watchdog should fire before twice the timeout value.
|
||||||
|
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
|
||||||
|
|
||||||
|
// Watchdog reset should have occurred during that wait() above;
|
||||||
|
|
||||||
|
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
current_case.index = index_of_case;
|
||||||
|
return utest::v1::greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
int testsuite_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(90, "watchdog_reset");
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
|
if (status != utest::v1::STATUS_CONTINUE) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
|
||||||
|
utest_printf("Invalid message key.\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data));
|
||||||
|
if (num_args == 0 || num_args == EOF) {
|
||||||
|
utest_printf("Invalid data received from host\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases,
|
||||||
|
current_case.start_index);
|
||||||
|
return current_case.start_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Watchdog reset", case_setup, test_simple_reset),
|
||||||
|
#if DEVICE_SLEEP
|
||||||
|
Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset),
|
||||||
|
#if DEVICE_LOWPOWERTIMER
|
||||||
|
Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset),
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
Case("Watchdog started again", case_setup, test_restart_reset),
|
||||||
|
Case("Kicking the Watchdog prevents reset", case_setup, test_kick_reset),
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Harness will start with a test case index provided by host script.
|
||||||
|
return !Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup hal_watchdog_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_HAL_WATCHDOG_RESET_TESTS_H
|
||||||
|
#define MBED_HAL_WATCHDOG_RESET_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
/** Test watchdog reset
|
||||||
|
*
|
||||||
|
* Given a device with a watchdog started,
|
||||||
|
* when a watchdog timeout expires,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_simple_reset();
|
||||||
|
|
||||||
|
/** Test watchdog reset in sleep mode
|
||||||
|
*
|
||||||
|
* Given a device with a watchdog started,
|
||||||
|
* when the watchdog timeout expires while the device is in sleep mode,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_sleep_reset();
|
||||||
|
|
||||||
|
/** Test watchdog reset in deepsleep mode
|
||||||
|
*
|
||||||
|
* Given a device with a watchdog started,
|
||||||
|
* when the watchdog timeout expires while the device is in deepsleep mode,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_deepsleep_reset();
|
||||||
|
|
||||||
|
/** Test watchdog reset after watchdog restart
|
||||||
|
*
|
||||||
|
* Given a device with a watchdog started,
|
||||||
|
* when the watchdog is stopped before its timeout expires,
|
||||||
|
* then the device is not restarted.
|
||||||
|
* When the watchdog is started again and its timeout expires,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_restart_reset();
|
||||||
|
|
||||||
|
/** Test watchdog kick
|
||||||
|
*
|
||||||
|
* Given a device with a watchdog started,
|
||||||
|
* when the watchdog is kicked before its timeout expires,
|
||||||
|
* then the device restart is prevented.
|
||||||
|
* When the watchdog is *NOT* kicked again before next timeout expires,
|
||||||
|
* then the device is restarted.
|
||||||
|
*/
|
||||||
|
void test_kick_reset();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_WATCHDOG
|
||||||
|
#error [NOT_SUPPORTED] Watchdog not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "us_ticker_api.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "watchdog_timing_tests.h"
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define CASE_DATA_INVALID 0xffffffffUL
|
||||||
|
|
||||||
|
#define MSG_VALUE_LEN 24
|
||||||
|
#define MSG_KEY_LEN 24
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_START_CASE "start_case"
|
||||||
|
#define MSG_KEY_HEARTBEAT "hb"
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
using utest::v1::Specification;
|
||||||
|
using utest::v1::Harness;
|
||||||
|
|
||||||
|
struct testcase_data {
|
||||||
|
int index;
|
||||||
|
int start_index;
|
||||||
|
uint32_t received_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase_data current_case;
|
||||||
|
|
||||||
|
template<uint32_t timeout_ms>
|
||||||
|
void test_timing()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (timeout_ms > features.max_timeout) {
|
||||||
|
TEST_IGNORE_MESSAGE("Requested timeout value not supported for this target -- ignoring test case.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2. -- verify the test results.
|
||||||
|
// Verify the heartbeat time span sent by host is within given range:
|
||||||
|
// 1. The watchdog should trigger at, or after the timeout value.
|
||||||
|
// 2. The watchdog should trigger before twice the timeout value.
|
||||||
|
if (current_case.received_data != CASE_DATA_INVALID) {
|
||||||
|
// Provided the watchdog works as expected, the last timestamp received
|
||||||
|
// by the host will always be before the expected reset time. Because
|
||||||
|
// of that, the constraint no 1. is not verified.
|
||||||
|
TEST_ASSERT(current_case.received_data > 0);
|
||||||
|
TEST_ASSERT(current_case.received_data < 2 * timeout_ms);
|
||||||
|
current_case.received_data = CASE_DATA_INVALID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1. -- run the test code.
|
||||||
|
// Send heartbeat messages to host until the watchdeg resets the device.
|
||||||
|
const ticker_data_t *const us_ticker = get_us_ticker_data();
|
||||||
|
us_timestamp_t current_ts, next_ts, expected_reset_ts, divider, ts_increment;
|
||||||
|
char msg_value[12];
|
||||||
|
|
||||||
|
watchdog_config_t config = { timeout_ms };
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
next_ts = ticker_read_us(us_ticker);
|
||||||
|
expected_reset_ts = next_ts + 1000ULL * timeout_ms;
|
||||||
|
|
||||||
|
divider = 0x2ULL;
|
||||||
|
while (1) {
|
||||||
|
current_ts = ticker_read_us(us_ticker);
|
||||||
|
if (current_ts < next_ts) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", current_case.start_index + current_case.index,
|
||||||
|
(uint32_t) current_ts);
|
||||||
|
if (str_len != (sizeof msg_value) - 1) {
|
||||||
|
utest_printf("Failed to compose a value string to be sent to host.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
greentea_send_kv(MSG_KEY_HEARTBEAT, msg_value);
|
||||||
|
|
||||||
|
// The closer to expected reset, the smaller heartbeat time difference.
|
||||||
|
// This should reduce measurement error present for heartbeat with
|
||||||
|
// equal periods.
|
||||||
|
ts_increment = (1000ULL * timeout_ms / divider);
|
||||||
|
next_ts += ts_increment;
|
||||||
|
|
||||||
|
if (current_ts <= expected_reset_ts) {
|
||||||
|
divider <<= 1;
|
||||||
|
} else if (divider > 0x2ULL) {
|
||||||
|
divider >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
current_case.index = index_of_case;
|
||||||
|
return utest::v1::greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
int testsuite_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(90, "watchdog_reset");
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
|
if (status != utest::v1::STATUS_CONTINUE) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
|
||||||
|
utest_printf("Invalid message key.\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data));
|
||||||
|
if (num_args == 0 || num_args == EOF) {
|
||||||
|
utest_printf("Invalid data received from host\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases,
|
||||||
|
current_case.start_index);
|
||||||
|
return current_case.start_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Timing, 200 ms", case_setup, test_timing<200UL>),
|
||||||
|
Case("Timing, 500 ms", case_setup, test_timing<500UL>),
|
||||||
|
Case("Timing, 1000 ms", case_setup, test_timing<1000UL>),
|
||||||
|
Case("Timing, 3000 ms", case_setup, test_timing<3000UL>),
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Harness will start with a test case index provided by host script.
|
||||||
|
return !Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup hal_watchdog_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_HAL_WATCHDOG_TIMING_TESTS_H
|
||||||
|
#define MBED_HAL_WATCHDOG_TIMING_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
/** Test watchdog timing accuracy
|
||||||
|
*
|
||||||
|
* Phase 1.
|
||||||
|
* Given a watchdog timer started with a timeout value of X ms,
|
||||||
|
* when the time of X ms elapses,
|
||||||
|
* then the device is restarted by the watchdog.
|
||||||
|
*
|
||||||
|
* Phase 2.
|
||||||
|
* Given a device restarted by the watchdog timer,
|
||||||
|
* when the device receives time measurement T from the host,
|
||||||
|
* then X <= T < 2 * X.
|
||||||
|
*/
|
||||||
|
template<uint32_t timeout_ms, uint32_t delta_ms>
|
||||||
|
void test_timing();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
|
|
|
@ -92,6 +92,7 @@ set(unittest-includes-base
|
||||||
"${PROJECT_SOURCE_DIR}/target_h/events"
|
"${PROJECT_SOURCE_DIR}/target_h/events"
|
||||||
"${PROJECT_SOURCE_DIR}/target_h/events/equeue"
|
"${PROJECT_SOURCE_DIR}/target_h/events/equeue"
|
||||||
"${PROJECT_SOURCE_DIR}/target_h/platform"
|
"${PROJECT_SOURCE_DIR}/target_h/platform"
|
||||||
|
"${PROJECT_SOURCE_DIR}/target_h/drivers"
|
||||||
"${PROJECT_SOURCE_DIR}/stubs"
|
"${PROJECT_SOURCE_DIR}/stubs"
|
||||||
"${PROJECT_SOURCE_DIR}/.."
|
"${PROJECT_SOURCE_DIR}/.."
|
||||||
"${PROJECT_SOURCE_DIR}/../features"
|
"${PROJECT_SOURCE_DIR}/../features"
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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 "gtest/gtest.h"
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "Watchdog.h"
|
||||||
|
|
||||||
|
using namespace mbed;
|
||||||
|
extern bool testcase;
|
||||||
|
// AStyle ignored as the definition is not clear due to preprocessor usage
|
||||||
|
// *INDENT-OFF*
|
||||||
|
class TestWatchdog : public testing::Test {
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void SetUp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// *INDENT-ON*
|
||||||
|
|
||||||
|
TEST_F(TestWatchdog, test_watchdog_start_stop_get_timeout)
|
||||||
|
{
|
||||||
|
EXPECT_TRUE(Watchdog::get_instance().start(500));
|
||||||
|
EXPECT_FALSE(Watchdog::get_instance().start(2000));
|
||||||
|
EXPECT_TRUE(Watchdog::get_instance().stop());
|
||||||
|
EXPECT_FALSE(Watchdog::get_instance().stop());
|
||||||
|
EXPECT_EQ(500, Watchdog::get_instance().get_timeout());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestWatchdog, test_watchdog_get_max_timeout)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(0xFFFFFFFF, Watchdog::get_instance().get_max_timeout());
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
####################
|
||||||
|
# UNIT TESTS
|
||||||
|
####################
|
||||||
|
set(TEST_SUITE_NAME "Watchdog")
|
||||||
|
|
||||||
|
# Add test specific include paths
|
||||||
|
set(unittest-includes ${unittest-includes}
|
||||||
|
.
|
||||||
|
../hal
|
||||||
|
)
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
set(unittest-sources
|
||||||
|
../drivers/Watchdog.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test files
|
||||||
|
set(unittest-test-sources
|
||||||
|
drivers/Watchdog/test_watchdog.cpp
|
||||||
|
stubs/mbed_critical_stub.c
|
||||||
|
stubs/mbed_assert_stub.c
|
||||||
|
stubs/watchdog_api_stub.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# defines
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEVICE_WATCHDOG -DMBED_WDOG_ASSERT=1")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEVICE_WATCHDOG -DMBED_WDOG_ASSERT=1")
|
|
@ -35,6 +35,7 @@ set(unittest-test-sources
|
||||||
stubs/cipher_stub.c
|
stubs/cipher_stub.c
|
||||||
stubs/aes_stub.c
|
stubs/aes_stub.c
|
||||||
stubs/cmac_stub.c
|
stubs/cmac_stub.c
|
||||||
|
stubs/mbed_assert_stub.c
|
||||||
../features/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c
|
../features/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,4 +20,5 @@ set(unittest-test-sources
|
||||||
stubs/EventFlags_stub.cpp
|
stubs/EventFlags_stub.cpp
|
||||||
stubs/Mutex_stub.cpp
|
stubs/Mutex_stub.cpp
|
||||||
stubs/CellularContext_stub.cpp
|
stubs/CellularContext_stub.cpp
|
||||||
|
stubs/mbed_assert_stub.c
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
*
|
||||||
|
* 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 "watchdog_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
static uint32_t _timeout = 0;
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
_timeout = config->timeout_ms;
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
return _timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
watchdog_features_t features;
|
||||||
|
features.max_timeout = 0xFFFFFFFF;
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_WATCHDOG
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef MBED_LOWPOWERTICKER_H
|
||||||
|
#define MBED_LOWPOWERTICKER_H
|
||||||
|
|
||||||
|
#include "hal/ticker_api.h"
|
||||||
|
#include "Callback.h"
|
||||||
|
|
||||||
|
namespace mbed {
|
||||||
|
/** \addtogroup drivers */
|
||||||
|
|
||||||
|
/** mock Low Power Ticker
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class LowPowerTicker {
|
||||||
|
|
||||||
|
public:
|
||||||
|
LowPowerTicker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~LowPowerTicker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void attach_us(Callback<void()> func, us_timestamp_t t)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void detach()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mbed
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef MBED_TICKER_H
|
||||||
|
#define MBED_TICKER_H
|
||||||
|
#include "drivers/TimerEvent.h"
|
||||||
|
#include "platform/Callback.h"
|
||||||
|
|
||||||
|
namespace mbed {
|
||||||
|
/** \addtogroup drivers */
|
||||||
|
|
||||||
|
/** mock Ticker
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Ticker {
|
||||||
|
|
||||||
|
public:
|
||||||
|
Ticker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void attach_us(Callback<void()> func, us_timestamp_t t)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void detach()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
~Ticker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mbed
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,135 @@
|
||||||
|
|
||||||
|
/** \addtogroup platform */
|
||||||
|
/** @{*/
|
||||||
|
/**
|
||||||
|
* \defgroup platform_Assert Assert macros
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018--2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef MBED_ASSERT_H
|
||||||
|
#define MBED_ASSERT_H
|
||||||
|
|
||||||
|
#include "mbed_preprocessor.h"
|
||||||
|
#include "mbed_toolchain.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Internal mbed assert function which is invoked when MBED_ASSERT macro fails.
|
||||||
|
* This function is active only if NDEBUG is not defined prior to including this
|
||||||
|
* assert header file.
|
||||||
|
* In case of MBED_ASSERT failing condition, error() is called with the assertation message.
|
||||||
|
* @param expr Expression to be checked.
|
||||||
|
* @param file File where assertation failed.
|
||||||
|
* @param line Failing assertation line number.
|
||||||
|
*/
|
||||||
|
MBED_NORETURN void mbed_assert_internal(const char *expr, const char *file, int line);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** MBED_ASSERT
|
||||||
|
* Declare runtime assertions: results in runtime error if condition is false
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Use of MBED_ASSERT is limited to Debug and Develop builds.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
*
|
||||||
|
* int Configure(serial_t *obj) {
|
||||||
|
* MBED_ASSERT(obj);
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
#if defined( NDEBUG ) && !defined (MBED_WDOG_ASSERT)
|
||||||
|
#define MBED_ASSERT(expr) ((void)0)
|
||||||
|
#else
|
||||||
|
#define MBED_ASSERT(expr) \
|
||||||
|
do { \
|
||||||
|
if (!(expr)) { \
|
||||||
|
mbed_assert_internal(#expr, __FILE__, __LINE__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** MBED_STATIC_ASSERT
|
||||||
|
* Declare compile-time assertions, results in compile-time error if condition is false
|
||||||
|
*
|
||||||
|
* The assertion acts as a declaration that can be placed at file scope, in a
|
||||||
|
* code block (except after a label), or as a member of a C++ class/struct/union.
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Use of MBED_STATIC_ASSERT as a member of a struct/union is limited:
|
||||||
|
* - In C++, MBED_STATIC_ASSERT is valid in class/struct/union scope.
|
||||||
|
* - In C, MBED_STATIC_ASSERT is not valid in struct/union scope, and
|
||||||
|
* MBED_STRUCT_STATIC_ASSERT is provided as an alternative that is valid
|
||||||
|
* in C and C++ class/struct/union scope.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* MBED_STATIC_ASSERT(MBED_LIBRARY_VERSION >= 120,
|
||||||
|
* "The mbed library must be at least version 120");
|
||||||
|
*
|
||||||
|
* int main() {
|
||||||
|
* MBED_STATIC_ASSERT(sizeof(int) >= sizeof(char),
|
||||||
|
* "An int must be larger than a char");
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
#if defined(__cplusplus) && (__cplusplus >= 201103L || __cpp_static_assert >= 200410L)
|
||||||
|
#define MBED_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
|
||||||
|
#elif !defined(__cplusplus) && __STDC_VERSION__ >= 201112L
|
||||||
|
#define MBED_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg)
|
||||||
|
#elif defined(__cplusplus) && defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) \
|
||||||
|
&& (__GNUC__*100 + __GNUC_MINOR__) > 403L
|
||||||
|
#define MBED_STATIC_ASSERT(expr, msg) __extension__ static_assert(expr, msg)
|
||||||
|
#elif !defined(__cplusplus) && defined(__GNUC__) && !defined(__CC_ARM) \
|
||||||
|
&& (__GNUC__*100 + __GNUC_MINOR__) > 406L
|
||||||
|
#define MBED_STATIC_ASSERT(expr, msg) __extension__ _Static_assert(expr, msg)
|
||||||
|
#elif defined(__ICCARM__)
|
||||||
|
#define MBED_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
|
||||||
|
#else
|
||||||
|
#define MBED_STATIC_ASSERT(expr, msg) \
|
||||||
|
enum {MBED_CONCAT(MBED_ASSERTION_AT_, __LINE__) = sizeof(char[(expr) ? 1 : -1])}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** MBED_STRUCT_STATIC_ASSERT
|
||||||
|
* Declare compile-time assertions, results in compile-time error if condition is false
|
||||||
|
*
|
||||||
|
* Unlike MBED_STATIC_ASSERT, MBED_STRUCT_STATIC_ASSERT can and must be used
|
||||||
|
* as a member of a C/C++ class/struct/union.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* struct thing {
|
||||||
|
* MBED_STATIC_ASSERT(2 + 2 == 4,
|
||||||
|
* "Hopefully the universe is mathematically consistent");
|
||||||
|
* };
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
#define MBED_STRUCT_STATIC_ASSERT(expr, msg) int : (expr) ? 0 : -1
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
|
@ -15,3 +15,18 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Resets the processor and most of the sub-system
|
||||||
|
*
|
||||||
|
* @note Does not affect the debug sub-system
|
||||||
|
*/
|
||||||
|
#ifndef MBED_POWER_MGMT_H
|
||||||
|
#define MBED_POWER_MGMT_H
|
||||||
|
extern void mock_system_reset();
|
||||||
|
|
||||||
|
MBED_NORETURN static inline void system_reset(void)
|
||||||
|
{
|
||||||
|
mock_system_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -2089,6 +2089,7 @@ PREDEFINED = DOXYGEN_ONLY \
|
||||||
DEVICE_PORTINOUT \
|
DEVICE_PORTINOUT \
|
||||||
DEVICE_PORTOUT \
|
DEVICE_PORTOUT \
|
||||||
DEVICE_PWMOUT \
|
DEVICE_PWMOUT \
|
||||||
|
DEVICE_RESET_REASON \
|
||||||
DEVICE_RTC \
|
DEVICE_RTC \
|
||||||
DEVICE_TRNG \
|
DEVICE_TRNG \
|
||||||
DEVICE_SERIAL \
|
DEVICE_SERIAL \
|
||||||
|
@ -2100,6 +2101,7 @@ PREDEFINED = DOXYGEN_ONLY \
|
||||||
DEVICE_SPISLAVE \
|
DEVICE_SPISLAVE \
|
||||||
DEVICE_QSPI \
|
DEVICE_QSPI \
|
||||||
DEVICE_STORAGE \
|
DEVICE_STORAGE \
|
||||||
|
DEVICE_WATCHDOG \
|
||||||
COMPONENT_SPE \
|
COMPONENT_SPE \
|
||||||
COMPONENT_SPM_MAILBOX \
|
COMPONENT_SPM_MAILBOX \
|
||||||
"TFM_LVL=1" \
|
"TFM_LVL=1" \
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"SEARCH_INCLUDES": "YES",
|
"SEARCH_INCLUDES": "YES",
|
||||||
"INCLUDE_PATH": "",
|
"INCLUDE_PATH": "",
|
||||||
"INCLUDE_FILE_PATTERNS": "",
|
"INCLUDE_FILE_PATTERNS": "",
|
||||||
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE COMPONENT_SPE COMPONENT_SPM_MAILBOX \"TFM_LVL=1\" \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\" \"BLE_ROLE_OBSERVER=1\" \"BLE_ROLE_BROADCASTER=1\" \"BLE_ROLE_PERIPHERAL=1\" \"BLE_ROLE_CENTRAL=1\" \"BLE_FEATURE_GATT_CLIENT=1\" \"BLE_FEATURE_GATT_SERVER=1\" \"BLE_FEATURE_SECURITY=1\" \"BLE_FEATURE_SECURE_CONNECTIONS=1\" \"BLE_FEATURE_SIGNING=1\" \"BLE_FEATURE_PHY_MANAGEMENT=1\" \"BLE_FEATURE_WHITELIST=1\" \"BLE_FEATURE_PRIVACY=1\" \"BLE_FEATURE_PERIODIC_ADVERTISING=1\" \"BLE_FEATURE_EXTENDED_ADVERTISING=1\"",
|
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE DEVICE_WATCHDOG COMPONENT_SPE COMPONENT_SPM_MAILBOX \"TFM_LVL=1\" \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\" \"BLE_ROLE_OBSERVER=1\" \"BLE_ROLE_BROADCASTER=1\" \"BLE_ROLE_PERIPHERAL=1\" \"BLE_ROLE_CENTRAL=1\" \"BLE_FEATURE_GATT_CLIENT=1\" \"BLE_FEATURE_GATT_SERVER=1\" \"BLE_FEATURE_SECURITY=1\" \"BLE_FEATURE_SECURE_CONNECTIONS=1\" \"BLE_FEATURE_SIGNING=1\" \"BLE_FEATURE_PHY_MANAGEMENT=1\" \"BLE_FEATURE_WHITELIST=1\" \"BLE_FEATURE_PRIVACY=1\" \"BLE_FEATURE_PERIODIC_ADVERTISING=1\" \"BLE_FEATURE_EXTENDED_ADVERTISING=1\"",
|
||||||
"EXPAND_AS_DEFINED": "",
|
"EXPAND_AS_DEFINED": "",
|
||||||
"SKIP_FUNCTION_MACROS": "NO",
|
"SKIP_FUNCTION_MACROS": "NO",
|
||||||
"STRIP_CODE_COMMENTS": "NO",
|
"STRIP_CODE_COMMENTS": "NO",
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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 "ResetReason.h"
|
||||||
|
|
||||||
|
#ifdef DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
namespace mbed {
|
||||||
|
|
||||||
|
reset_reason_t ResetReason::get()
|
||||||
|
{
|
||||||
|
// Store the reason statically so it can be accessed after the first call to
|
||||||
|
// this function resets it.
|
||||||
|
const static reset_reason_t reason = hal_reset_reason_get();
|
||||||
|
|
||||||
|
// Call get raw to cache the reset reason before clearing the registers.
|
||||||
|
ResetReason::get_raw();
|
||||||
|
|
||||||
|
hal_reset_reason_clear();
|
||||||
|
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ResetReason::get_raw()
|
||||||
|
{
|
||||||
|
const static uint32_t reason = hal_reset_reason_get_raw();
|
||||||
|
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mbed
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef MBED_RESET_REASON_H
|
||||||
|
#define MBED_RESET_REASON_H
|
||||||
|
|
||||||
|
#ifdef DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "reset_reason_api.h"
|
||||||
|
|
||||||
|
namespace mbed {
|
||||||
|
/** \addtogroup drivers */
|
||||||
|
/** A platform-independent method of checking the cause of the last system reset.
|
||||||
|
*
|
||||||
|
* When the system restarts, the reason for the restart is contained in
|
||||||
|
* the system registers at boot time in a platform specific manner.
|
||||||
|
* This API provides a generic method of fetching the reason for the restart.
|
||||||
|
*
|
||||||
|
* @ingroup drivers
|
||||||
|
*/
|
||||||
|
class ResetReason {
|
||||||
|
public:
|
||||||
|
/** Get the platform independent reason code for the last system reset.
|
||||||
|
*
|
||||||
|
* @return enum containing the last reset reason for the board.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* const reset_reason_t reason = ResetReason::get();
|
||||||
|
*
|
||||||
|
* if (reason == RESET_REASON_WATCHDOG) {
|
||||||
|
* printf("Watchdog reset\n");
|
||||||
|
* rollback();
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
static reset_reason_t get();
|
||||||
|
|
||||||
|
/** Get the platform specific reason code for the last system reset.
|
||||||
|
*
|
||||||
|
* Platform specific reasons that are not covered by the ::reset_reason_t enum
|
||||||
|
* will cause the ResetReason::get() function to return
|
||||||
|
* ::RESET_REASON_PLATFORM. In order to get the actual reason the register
|
||||||
|
* value must be fetched directly using this function and interpreted in a
|
||||||
|
* platform specific manner.
|
||||||
|
*
|
||||||
|
* @return value containing the reset reason register for the given platform.
|
||||||
|
* If the platform contains reset reasons across multiple registers they
|
||||||
|
* will be concatenated here.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* if (ResetReason::get() == RESET_REASON_PLATFORM) {
|
||||||
|
* const uint32_t platform_reason = ResetReason::get_raw();
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
static uint32_t get_raw();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mbed
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
||||||
|
#endif // MBED_RESET_REASON_H
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifdef DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "drivers/Watchdog.h"
|
||||||
|
|
||||||
|
namespace mbed {
|
||||||
|
|
||||||
|
Watchdog::Watchdog() : _running(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Watchdog::~Watchdog()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watchdog::start(uint32_t timeout)
|
||||||
|
{
|
||||||
|
MBED_ASSERT(timeout <= get_max_timeout());
|
||||||
|
MBED_ASSERT(timeout > 0);
|
||||||
|
|
||||||
|
core_util_critical_section_enter();
|
||||||
|
if (_running) {
|
||||||
|
core_util_critical_section_exit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
watchdog_config_t config;
|
||||||
|
config.timeout_ms = timeout;
|
||||||
|
watchdog_status_t sts = hal_watchdog_init(&config);
|
||||||
|
if (sts == WATCHDOG_STATUS_OK) {
|
||||||
|
_running = true;
|
||||||
|
}
|
||||||
|
core_util_critical_section_exit();
|
||||||
|
return _running;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watchdog::start()
|
||||||
|
{
|
||||||
|
|
||||||
|
return start(get_max_timeout());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watchdog::stop()
|
||||||
|
{
|
||||||
|
watchdog_status_t sts;
|
||||||
|
bool msts = true;
|
||||||
|
core_util_critical_section_enter();
|
||||||
|
if (_running) {
|
||||||
|
sts = hal_watchdog_stop();
|
||||||
|
if (sts != WATCHDOG_STATUS_OK) {
|
||||||
|
msts = false;
|
||||||
|
} else {
|
||||||
|
_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
msts = false;
|
||||||
|
}
|
||||||
|
core_util_critical_section_exit();
|
||||||
|
return msts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watchdog::kick()
|
||||||
|
{
|
||||||
|
core_util_critical_section_enter();
|
||||||
|
hal_watchdog_kick();
|
||||||
|
core_util_critical_section_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watchdog::is_running() const
|
||||||
|
{
|
||||||
|
return _running;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Watchdog::get_timeout() const
|
||||||
|
{
|
||||||
|
return hal_watchdog_get_reload_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Watchdog::get_max_timeout() const
|
||||||
|
{
|
||||||
|
const watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
return features.max_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mbed
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DEVICE_WATCHDOG
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_WATCHDOG_H
|
||||||
|
#define MBED_WATCHDOG_H
|
||||||
|
|
||||||
|
#ifdef DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "platform/mbed_error.h"
|
||||||
|
#include "platform/mbed_assert.h"
|
||||||
|
#include "platform/mbed_critical.h"
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
#include "platform/NonCopyable.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace mbed {
|
||||||
|
|
||||||
|
/** \addtogroup drivers */
|
||||||
|
/** Hardware system timer that will reset the system in the case of system failures or
|
||||||
|
* malfunctions. There is only one instance in the system.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
*
|
||||||
|
* Watchdog &watchdog = Watchdog::get_instance();
|
||||||
|
* watchdog.start();
|
||||||
|
*
|
||||||
|
* while (true) {
|
||||||
|
// kick watchdog regularly within provided timeout
|
||||||
|
watchdog.kick();
|
||||||
|
// Application code
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @note Synchronization level: Interrupt safe
|
||||||
|
* @ingroup drivers
|
||||||
|
*/
|
||||||
|
class Watchdog : private NonCopyable<Watchdog> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** As Watchdog might not stop ever, there is just one instance - we use single instance.
|
||||||
|
* This ensures we keep Watchdog alive. To operate watchdog, use start/stop methods.
|
||||||
|
*/
|
||||||
|
static Watchdog &get_instance()
|
||||||
|
{
|
||||||
|
// Use this implementation of singleton (Meyer's) rather than the one that allocates
|
||||||
|
// the instance on the heap because it ensures destruction at program end (preventing warnings
|
||||||
|
// from memory checking tools, such as valgrind).
|
||||||
|
static Watchdog instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Start the watchdog timer with the maximum timeout available on a target
|
||||||
|
*
|
||||||
|
* Timeout is defined as get_max_timeout()
|
||||||
|
*
|
||||||
|
* @return status true if the watchdog timer was started
|
||||||
|
* successfully. assert if one of the input parameters is out of range for the current platform.
|
||||||
|
* false if watchdog timer was not started
|
||||||
|
*/
|
||||||
|
bool start();
|
||||||
|
|
||||||
|
/** Start the watchdog timer
|
||||||
|
*
|
||||||
|
* @param timeout Watchdog timeout
|
||||||
|
*
|
||||||
|
* @return status true if the watchdog timer was started
|
||||||
|
* successfully. assert if one of the input parameters is out of range for the current platform.
|
||||||
|
* false if watchdog timer was not started
|
||||||
|
*/
|
||||||
|
bool start(uint32_t timeout);
|
||||||
|
|
||||||
|
/** Stops the watchdog timer
|
||||||
|
*
|
||||||
|
* Calling this function will attempt to disable any currently running
|
||||||
|
* watchdog timers if supported by the current platform.
|
||||||
|
*
|
||||||
|
* @return Returns true if the watchdog timer was successfully
|
||||||
|
* stopped, Returns false if the watchdog cannot be disabled
|
||||||
|
* on the current platform or if the timer was never started.
|
||||||
|
*/
|
||||||
|
bool stop();
|
||||||
|
|
||||||
|
/** Get the watchdog timer refresh value
|
||||||
|
*
|
||||||
|
* This function returns the refresh timeout of the watchdog timer.
|
||||||
|
*
|
||||||
|
* @return Reload value for the watchdog timer in milliseconds.
|
||||||
|
*/
|
||||||
|
uint32_t get_timeout() const;
|
||||||
|
|
||||||
|
/** Get the maximum refresh value for the current platform in milliseconds
|
||||||
|
*
|
||||||
|
* @return Maximum refresh value supported by the watchdog for the current
|
||||||
|
* platform in milliseconds
|
||||||
|
*/
|
||||||
|
uint32_t get_max_timeout() const;
|
||||||
|
|
||||||
|
/** Check if watchdog is already running
|
||||||
|
*
|
||||||
|
* @return true if watchdog is running, false otherwise
|
||||||
|
*/
|
||||||
|
bool is_running() const;
|
||||||
|
|
||||||
|
/** Kick watchdog
|
||||||
|
*
|
||||||
|
* This method is useful to control kicking by application in ticker callback periodically
|
||||||
|
*/
|
||||||
|
void kick();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Watchdog();
|
||||||
|
~Watchdog();
|
||||||
|
|
||||||
|
bool _running;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mbed
|
||||||
|
|
||||||
|
#endif // DEVICE_WATCHDOG
|
||||||
|
#endif // MBED_WATCHDOG_H
|
|
@ -0,0 +1,150 @@
|
||||||
|
/** \addtogroup hal */
|
||||||
|
/** @{*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef MBED_RESET_REASON_API_H
|
||||||
|
#define MBED_RESET_REASON_API_H
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup hal_reset_reason ResetReason HAL API
|
||||||
|
* Low-level interface to the ResetReason of a target.
|
||||||
|
*
|
||||||
|
* This module provides a platform-independent method of checking the cause
|
||||||
|
* of the last system reset.
|
||||||
|
*
|
||||||
|
* # Defined behavior
|
||||||
|
* * The function ::hal_reset_reason_clear clears the ResetReason registers
|
||||||
|
* for the next system boot.
|
||||||
|
* * By the time the user calls ::hal_reset_reason_get to read the value,
|
||||||
|
* some other part of the application may have cleared the value. Therefore,
|
||||||
|
* though there may have been a reset reason in the registers when the system
|
||||||
|
* started, the reason may not be available when the user comes to check it.
|
||||||
|
*
|
||||||
|
* # Undefined behavior
|
||||||
|
* * There is no guarantee that the function ::hal_reset_reason_get will
|
||||||
|
* return the same value when you call it repeatedly. Store the value for later
|
||||||
|
* use instead of calling the function repeatedly.
|
||||||
|
* * The function ::hal_reset_reason_clear may not clear the ResetReason
|
||||||
|
* register in time for the next system boot.
|
||||||
|
*
|
||||||
|
* # Notes
|
||||||
|
* * The contents of the targets ResetReason register may be cleared by some
|
||||||
|
* subsystem before it first gets called. This returns a ::RESET_REASON_UNKNOWN
|
||||||
|
* value to the user. To avoid this, the user should call the ResetReason API
|
||||||
|
* as early as possible at boot time.
|
||||||
|
* * If the target doesn't support clearing reset registers,
|
||||||
|
* ::hal_reset_reason_get seems to erroneously return a reset reason even after
|
||||||
|
* clearing.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup hal_reset_reason_tests ResetReason HAL tests
|
||||||
|
* Greentea tests for the ResetReason HAL.
|
||||||
|
*
|
||||||
|
* To run the ResetReason HAL tests, use the command:
|
||||||
|
*
|
||||||
|
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-reset_reason
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Definitions of different reset reasons
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
RESET_REASON_POWER_ON, /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */
|
||||||
|
RESET_REASON_PIN_RESET, /**< Set when a reset is triggered by the hardware pin on the board */
|
||||||
|
RESET_REASON_BROWN_OUT, /**< Triggered when the voltage drops below the low voltage detect (LVD) threshold; the system is held in a reset until the voltage rises above the threshold */
|
||||||
|
RESET_REASON_SOFTWARE, /**< Set during software reset, typically triggered by writing the SYSRESETREQ bit in the Application Interrupt and Reset Control register */
|
||||||
|
RESET_REASON_WATCHDOG, /**< Set when a running watchdog timer fails to be refreshed */
|
||||||
|
RESET_REASON_LOCKUP, /**< Set when the core is locked because of an unrecoverable exception */
|
||||||
|
RESET_REASON_WAKE_LOW_POWER, /**< Set when waking from deep sleep mode */
|
||||||
|
RESET_REASON_ACCESS_ERROR, /**< Umbrella value that encompasses any access related reset */
|
||||||
|
RESET_REASON_BOOT_ERROR, /**< Umbrella value that encompasses any boot related reset */
|
||||||
|
RESET_REASON_MULTIPLE, /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */
|
||||||
|
RESET_REASON_PLATFORM, /**< Platform specific reset reason not captured in this enum */
|
||||||
|
RESET_REASON_UNKNOWN /**< Unknown or unreadable reset reason **/
|
||||||
|
} reset_reason_t;
|
||||||
|
|
||||||
|
/** Fetch the reset reason for the last system reset.
|
||||||
|
*
|
||||||
|
* This function must return the contents of the system reset reason registers
|
||||||
|
* cast to an appropriate platform independent reset reason. If multiple reset
|
||||||
|
* reasons are set, this function should return ::RESET_REASON_MULTIPLE. If the
|
||||||
|
* reset reason does not match any existing platform independent value, this
|
||||||
|
* function should return ::RESET_REASON_PLATFORM. If no reset reason can be
|
||||||
|
* determined, this function should return ::RESET_REASON_UNKNOWN.
|
||||||
|
*
|
||||||
|
* This function is not idempotent; there is no guarantee the system
|
||||||
|
* reset reason will not be cleared between calls to this function altering the
|
||||||
|
* return value between calls.
|
||||||
|
*
|
||||||
|
* Note: Some platforms contain reset reason registers that persist through
|
||||||
|
* system resets. If the registers haven't been cleared before calling this
|
||||||
|
* function, multiple reasons may be set within the registers. If multiple reset
|
||||||
|
* reasons are detected, this function returns ::RESET_REASON_MULTIPLE.
|
||||||
|
*
|
||||||
|
* @return enum containing the last reset reason for the board.
|
||||||
|
*/
|
||||||
|
reset_reason_t hal_reset_reason_get(void);
|
||||||
|
|
||||||
|
|
||||||
|
/** Fetch the raw platform specific reset reason register value.
|
||||||
|
*
|
||||||
|
* This function must return the raw contents of the system reset reason
|
||||||
|
* registers cast to a uint32_t value. If the platform contains reset reasons
|
||||||
|
* that span multiple registers/addresses, the value should be concatenated into
|
||||||
|
* the return type.
|
||||||
|
*
|
||||||
|
* This function is not idempotent; there is no guarantee the system
|
||||||
|
* reset reason will not be cleared between calls to this function altering the
|
||||||
|
* return value between calls.
|
||||||
|
*
|
||||||
|
* @return value containing the reset reason register for the given platform.
|
||||||
|
* If the platform contains reset reasons across multiple registers, they
|
||||||
|
* will be concatenated here.
|
||||||
|
*/
|
||||||
|
uint32_t hal_reset_reason_get_raw(void);
|
||||||
|
|
||||||
|
/** Clear the reset reason from registers.
|
||||||
|
*
|
||||||
|
* Reset the value of the reset status registers. The reset reason persists
|
||||||
|
* between system resets on certain platforms, so the registers should be cleared
|
||||||
|
* before the system resets. Failing to do so may make it difficult to determine
|
||||||
|
* the cause of any subsequent system resets.
|
||||||
|
*/
|
||||||
|
void hal_reset_reason_clear(void);
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#endif // MBED_RESET_REASON_API_H
|
||||||
|
|
||||||
|
/** @}*/
|
|
@ -0,0 +1,178 @@
|
||||||
|
/** \addtogroup hal */
|
||||||
|
/** @{*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_WATCHDOG_API_H
|
||||||
|
#define MBED_WATCHDOG_API_H
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup hal_watchdog Watchdog HAL API
|
||||||
|
* Low-level interface to the Independent Watchdog Timer of a target.
|
||||||
|
*
|
||||||
|
* This module provides platform independent access to the system watchdog timer
|
||||||
|
* which is an embedded peripheral that will reset the system in the case of
|
||||||
|
* system failures or malfunctions.
|
||||||
|
*
|
||||||
|
* The watchdog timer initializes a system timer with a time period specified in
|
||||||
|
* the configuration. This timer counts down and triggers a system reset when it
|
||||||
|
* wraps. To prevent the system reset the timer must be continually
|
||||||
|
* kicked/refreshed by calling ::hal_watchdog_kick which will reset the countdown
|
||||||
|
* to the user specified reset value.
|
||||||
|
*
|
||||||
|
* # Defined behavior
|
||||||
|
* * Sleep and debug modes don't stop the watchdog timer from counting down.
|
||||||
|
* * The function ::hal_watchdog_init is safe to call repeatedly. The
|
||||||
|
* function's implementation must not do anything if ::hal_watchdog_init has
|
||||||
|
* already initialized the hardware watchdog timer.
|
||||||
|
* * Maximum supported timeout is `UINT32_MAX` milliseconds; minimum timeout
|
||||||
|
* is 1 millisecond.
|
||||||
|
* * The watchdog should trigger at or after the timeout value.
|
||||||
|
* * The watchdog should trigger before twice the timeout value.
|
||||||
|
*
|
||||||
|
* # Undefined behavior
|
||||||
|
* * Calling any function other than ::hal_watchdog_init or
|
||||||
|
* ::hal_watchdog_get_platform_features before you have initialized the watchdog.
|
||||||
|
*
|
||||||
|
* # Notes
|
||||||
|
* * A software reset may not stop the watchdog timer; the behavior is platform specific.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup hal_watchdog_tests Watchdog HAL tests
|
||||||
|
* Greentea tests for the Watchdog HAL.
|
||||||
|
*
|
||||||
|
* To run the Watchdog HAL tests use the command:
|
||||||
|
*
|
||||||
|
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-watchdog*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Watchdog configuration.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Refresh value for the watchdog in milliseconds. The maximum value of this
|
||||||
|
* setting is platform dependent, to find the maximum value for the current
|
||||||
|
* platform call hal_watchdog_get_features() and check the timeout value
|
||||||
|
* member. The minimum valid value for this setting is 1. Attempting to
|
||||||
|
* initialize the watchdog with a timeout of 0 ms returns
|
||||||
|
* WATCHDOG_STATUS_INVALID_ARGUMENT.
|
||||||
|
*/
|
||||||
|
uint32_t timeout_ms;
|
||||||
|
} watchdog_config_t;
|
||||||
|
|
||||||
|
/** Watchdog features.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Maximum timeout value for the watchdog in milliseconds.
|
||||||
|
*/
|
||||||
|
uint32_t max_timeout;
|
||||||
|
/**
|
||||||
|
* You can update the watchdog configuration after the watchdog has started.
|
||||||
|
*/
|
||||||
|
bool update_config;
|
||||||
|
/**
|
||||||
|
* You can stop the watchdog after it starts without a reset.
|
||||||
|
*/
|
||||||
|
bool disable_watchdog;
|
||||||
|
} watchdog_features_t;
|
||||||
|
|
||||||
|
|
||||||
|
/** Status of a watchdog operation.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
WATCHDOG_STATUS_OK, /**< Operation successful. **/
|
||||||
|
WATCHDOG_STATUS_NOT_SUPPORTED, /**< Operation not supported. **/
|
||||||
|
WATCHDOG_STATUS_INVALID_ARGUMENT /**< Invalid argument. **/
|
||||||
|
} watchdog_status_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Initialize and start a watchdog timer with the given configuration.
|
||||||
|
*
|
||||||
|
* If the watchdog timer is configured and starts successfully, this
|
||||||
|
* function returns ::WATCHDOG_STATUS_OK.
|
||||||
|
*
|
||||||
|
* If the timeout specified is outside the range supported by the platform,
|
||||||
|
* it returns ::WATCHDOG_STATUS_INVALID_ARGUMENT.
|
||||||
|
*
|
||||||
|
* @param[in] config Configuration settings for the watchdog timer
|
||||||
|
*
|
||||||
|
* @return ::WATCHDOG_STATUS_OK if the watchdog is configured correctly and
|
||||||
|
* has started. Otherwise a status indicating the fault.
|
||||||
|
*/
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config);
|
||||||
|
|
||||||
|
/** Refreshes the watchdog timer.
|
||||||
|
*
|
||||||
|
* Call this function periodically before the watchdog times out.
|
||||||
|
* Otherwise, the system resets.
|
||||||
|
*
|
||||||
|
* If a watchdog is not running, this function does nothing.
|
||||||
|
*/
|
||||||
|
void hal_watchdog_kick(void);
|
||||||
|
|
||||||
|
/** Stops the watchdog timer.
|
||||||
|
*
|
||||||
|
* Calling this function disables any running watchdog
|
||||||
|
* timers if the current platform supports them.
|
||||||
|
*
|
||||||
|
* @return Returns ::WATCHDOG_STATUS_OK if the watchdog timer was succesfully
|
||||||
|
* stopped, or if the timer was never started. Returns
|
||||||
|
* ::WATCHDOG_STATUS_NOT_SUPPORTED if the watchdog cannot be disabled on
|
||||||
|
* the current platform.
|
||||||
|
*/
|
||||||
|
watchdog_status_t hal_watchdog_stop(void);
|
||||||
|
|
||||||
|
/** Get the watchdog timer refresh value.
|
||||||
|
*
|
||||||
|
* This function returns the configured refresh timeout of the watchdog timer.
|
||||||
|
*
|
||||||
|
* @return Reload value for the watchdog timer in milliseconds.
|
||||||
|
*/
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void);
|
||||||
|
|
||||||
|
/** Get information on the current platforms supported watchdog functionality.
|
||||||
|
*
|
||||||
|
* @return watchdog_feature_t indicating supported watchdog features on the
|
||||||
|
* current platform
|
||||||
|
*/
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void);
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#endif // MBED_WATCHDOG_API_H
|
||||||
|
|
||||||
|
/** @}*/
|
2
mbed.h
2
mbed.h
|
@ -74,8 +74,10 @@
|
||||||
#include "drivers/FlashIAP.h"
|
#include "drivers/FlashIAP.h"
|
||||||
#include "drivers/MbedCRC.h"
|
#include "drivers/MbedCRC.h"
|
||||||
#include "drivers/QSPI.h"
|
#include "drivers/QSPI.h"
|
||||||
|
#include "drivers/Watchdog.h"
|
||||||
|
|
||||||
// mbed Internal components
|
// mbed Internal components
|
||||||
|
#include "drivers/ResetReason.h"
|
||||||
#include "drivers/Timer.h"
|
#include "drivers/Timer.h"
|
||||||
#include "drivers/Ticker.h"
|
#include "drivers/Ticker.h"
|
||||||
#include "drivers/Timeout.h"
|
#include "drivers/Timeout.h"
|
||||||
|
|
|
@ -288,6 +288,7 @@ typedef enum _mbed_module_type {
|
||||||
MBED_MODULE_DRIVER_PWM,
|
MBED_MODULE_DRIVER_PWM,
|
||||||
MBED_MODULE_DRIVER_QSPI,
|
MBED_MODULE_DRIVER_QSPI,
|
||||||
MBED_MODULE_DRIVER_USB,
|
MBED_MODULE_DRIVER_USB,
|
||||||
|
MBED_MODULE_DRIVER_WATCHDOG,
|
||||||
MBED_MODULE_TARGET_SDK,
|
MBED_MODULE_TARGET_SDK,
|
||||||
MBED_MODULE_BLE,
|
MBED_MODULE_BLE,
|
||||||
MBED_MODULE_NETWORK_STATS,
|
MBED_MODULE_NETWORK_STATS,
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2006-2017 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "fsl_rcm.h"
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
const uint32_t reset_sources =
|
||||||
|
RCM_GetPreviousResetSources(RCM) & kRCM_SourceAll;
|
||||||
|
|
||||||
|
// Low power mode is exited via the RESET pin. Therefore, when this reset is
|
||||||
|
// triggered both the PIN and WAKEUP will have bits set, so check this flag
|
||||||
|
// first.
|
||||||
|
#if (defined(FSL_FEATURE_RCM_HAS_WAKEUP) && FSL_FEATURE_RCM_HAS_WAKEUP)
|
||||||
|
if ((reset_sources & kRCM_SourceWakeup) != 0) {
|
||||||
|
return RESET_REASON_PLATFORM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check POR flag first. During a POR reset there will be two reset sources
|
||||||
|
// set: POR and LVD. As during the power on phase the low voltage detector
|
||||||
|
// circuit will detect a low voltage while the voltage is initially ramping
|
||||||
|
// up and set the BROWN_OUT flag. Therefore, if LVD is set we must check the
|
||||||
|
// POR to determine what the actual cause was.
|
||||||
|
if ((reset_sources & kRCM_SourcePor) != 0) {
|
||||||
|
return RESET_REASON_POWER_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((reset_sources & kRCM_SourceLvd) != 0) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((reset_sources & kRCM_SourceWdog) != 0) {
|
||||||
|
return RESET_REASON_WATCHDOG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((reset_sources & kRCM_SourcePin) != 0) {
|
||||||
|
return RESET_REASON_PIN_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((reset_sources & kRCM_SourceSw) != 0) {
|
||||||
|
return RESET_REASON_SOFTWARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (defined(FSL_FEATURE_RCM_HAS_LOC) && FSL_FEATURE_RCM_HAS_LOC)
|
||||||
|
if ((reset_sources & kRCM_SourceLoc) != 0) {
|
||||||
|
return RESET_REASON_PLATFORM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(FSL_FEATURE_RCM_HAS_LOL) && FSL_FEATURE_RCM_HAS_LOL)
|
||||||
|
if ((reset_sources & kRCM_SourceLol) != 0) {
|
||||||
|
return RESET_REASON_PLATFORM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(FSL_FEATURE_RCM_HAS_JTAG) && FSL_FEATURE_RCM_HAS_JTAG)
|
||||||
|
if ((reset_sources & kRCM_SourceJtag) != 0) {
|
||||||
|
return RESET_REASON_PLATFORM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(FSL_FEATURE_RCM_HAS_MDM_AP) && FSL_FEATURE_RCM_HAS_MDM_AP)
|
||||||
|
if ((reset_sources & kRCM_SourceMdmap) != 0) {
|
||||||
|
return RESET_REASON_PLATFORM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(FSL_FEATURE_RCM_HAS_EZPORT) && FSL_FEATURE_RCM_HAS_EZPORT)
|
||||||
|
if ((reset_sources & kRCM_SourceEzpt) != 0) {
|
||||||
|
return RESET_REASON_PLATFORM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return RESET_REASON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
return (RCM_GetPreviousResetSources(RCM) & kRCM_SourceAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
#if (defined(FSL_FEATURE_RCM_HAS_SSRS) && FSL_FEATURE_RCM_HAS_SSRS)
|
||||||
|
RCM_ClearStickyResetSources(RCM, kRCM_SourceAll);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
|
@ -0,0 +1,130 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017 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 "watchdog_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "reset_reason_api.h"
|
||||||
|
#include "fsl_wdog.h"
|
||||||
|
#include "fsl_clock.h"
|
||||||
|
#include "platform/mbed_wait_api.h"
|
||||||
|
|
||||||
|
// Platform specific watchdog definitions
|
||||||
|
#define LPO_CLOCK_FREQUENCY 1000
|
||||||
|
#define MAX_PRESCALER 8
|
||||||
|
#define MAX_TIMEOUT 0xFFFFFFFFUL
|
||||||
|
#define WCT_IN_BUS_CYCLES 256U // Watchdog configuration time (WCT) in bus clock cycles.
|
||||||
|
|
||||||
|
// Number of decrements in the timeout register per millisecond
|
||||||
|
#define TICKS_PER_MS ((LPO_CLOCK_FREQUENCY) / 1000)
|
||||||
|
|
||||||
|
// Maximum timeout that can be specified in milliseconds
|
||||||
|
#define MAX_TIMEOUT_MS_UINT64 (1ULL * ((MAX_TIMEOUT) / (TICKS_PER_MS)) * (MAX_PRESCALER))
|
||||||
|
#if (MAX_TIMEOUT_MS_UINT64 > UINT32_MAX)
|
||||||
|
#define MAX_TIMEOUT_MS UINT32_MAX
|
||||||
|
#else
|
||||||
|
#define MAX_TIMEOUT_MS (MAX_TIMEOUT_MS_UINT64 & 0xFFFFFFFFUL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Maximum supported watchdog timeout for given prescaler value
|
||||||
|
#define CALCULATE_MAX_TIMEOUT_MS_UINT64(scale) \
|
||||||
|
(1ULL * ((MAX_TIMEOUT) / (TICKS_PER_MS)) * (scale))
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t calculate_prescaler_value(const uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
if (timeout_ms > MAX_TIMEOUT_MS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t scale = 1; scale <= MAX_PRESCALER; ++scale) {
|
||||||
|
if (timeout_ms <= CALCULATE_MAX_TIMEOUT_MS_UINT64(scale)) {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until watchdog configuration time window closes.
|
||||||
|
static inline void wait_WCT(void) {
|
||||||
|
uint32_t WCT_us = (WCT_IN_BUS_CYCLES) * 1000000UL / CLOCK_GetBusClkFreq();
|
||||||
|
wait_us(WCT_us);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
wdog_config_t cfg;
|
||||||
|
cfg.enableWdog = true;
|
||||||
|
cfg.clockSource = kWDOG_LpoClockSource;
|
||||||
|
cfg.windowValue = 0;
|
||||||
|
cfg.enableUpdate = true;
|
||||||
|
cfg.enableInterrupt = false;
|
||||||
|
cfg.enableWindowMode = false;
|
||||||
|
cfg.workMode.enableWait = true;
|
||||||
|
cfg.workMode.enableStop = false;
|
||||||
|
cfg.workMode.enableDebug = false;
|
||||||
|
|
||||||
|
const uint32_t prescaler = calculate_prescaler_value(config->timeout_ms);
|
||||||
|
|
||||||
|
if (prescaler == 0) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.prescaler = (wdog_clock_prescaler_t)(prescaler - 1);
|
||||||
|
cfg.timeoutValue = (TICKS_PER_MS * config->timeout_ms) / prescaler;
|
||||||
|
|
||||||
|
WDOG_Init(WDOG, &cfg);
|
||||||
|
wait_WCT(); // Updates in the write-once registers take effect only after the WCT window closes.
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
WDOG_Refresh(WDOG);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
WDOG_Deinit(WDOG);
|
||||||
|
wait_WCT(); // Updates in the write-once registers take effect only after the WCT window closes.
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
const uint32_t timeout =
|
||||||
|
(((WDOG->TOVALH & 0xFFFFU) << 16U) | (WDOG->TOVALL & 0xFFFFU));
|
||||||
|
|
||||||
|
const uint32_t prescaler = WDOG_PRESC_PRESCVAL(WDOG->PRESC);
|
||||||
|
|
||||||
|
return ((timeout / TICKS_PER_MS) * (prescaler + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
watchdog_features_t features;
|
||||||
|
features.max_timeout = MAX_TIMEOUT_MS;
|
||||||
|
features.update_config = true;
|
||||||
|
features.disable_watchdog = true;
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_WATCHDOG
|
|
@ -0,0 +1,106 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2018 Nuvoton
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
|
||||||
|
/* All reset source flags */
|
||||||
|
#define SYS_RSTSTS_ALLRF_Msk \
|
||||||
|
(SYS_RSTSTS_PORF_Msk | \
|
||||||
|
SYS_RSTSTS_PINRF_Msk | \
|
||||||
|
SYS_RSTSTS_WDTRF_Msk | \
|
||||||
|
SYS_RSTSTS_LVRF_Msk | \
|
||||||
|
SYS_RSTSTS_BODRF_Msk | \
|
||||||
|
SYS_RSTSTS_SYSRF_Msk | \
|
||||||
|
SYS_RSTSTS_CPURF_Msk | \
|
||||||
|
SYS_RSTSTS_CPULKRF_Msk)
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
uint32_t reset_reason_raw = hal_reset_reason_get_raw();
|
||||||
|
reset_reason_t reset_reason_cast;
|
||||||
|
uint32_t reset_reason_count = 0;
|
||||||
|
|
||||||
|
if (SYS_IS_POR_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_POWER_ON;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_RSTPIN_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PIN_RESET;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_WDT_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_WATCHDOG;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_LVR_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PLATFORM;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_BOD_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_BROWN_OUT;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This MCU supports MKROM and we need to take care of bootloader/SYSRESETREQ flow. */
|
||||||
|
if (SYS_IS_SYSTEM_RST()) {
|
||||||
|
if (reset_reason_raw & (SYS_RSTSTS_ALLRF_Msk & ~SYS_RSTSTS_SYSRF_Msk)) {
|
||||||
|
/* We may boot from bootloader which would reset to go to LDROM/APROM at its end
|
||||||
|
* through writing 1 to SYSRESETREQ bit. If there are other reset reasons, we think
|
||||||
|
* it is just the case and ignore the reset reason with SYSRESETREQ. */
|
||||||
|
} else {
|
||||||
|
reset_reason_cast = RESET_REASON_SOFTWARE;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_CPU_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PLATFORM;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset_reason_raw & SYS_RSTSTS_CPULKRF_Msk) {
|
||||||
|
reset_reason_cast = RESET_REASON_LOCKUP;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset_reason_count == 0) {
|
||||||
|
reset_reason_cast = RESET_REASON_UNKNOWN;
|
||||||
|
} else if (reset_reason_count >= 2) {
|
||||||
|
reset_reason_cast = RESET_REASON_MULTIPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reset_reason_cast;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
return (SYS->RSTSTS & SYS_RSTSTS_ALLRF_Msk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
SYS_CLEAR_RST_SOURCE(SYS->RSTSTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,206 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2018 Nuvoton
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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 "watchdog_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
|
||||||
|
/* Micro seconds per second */
|
||||||
|
#define NU_US_PER_SEC 1000000
|
||||||
|
|
||||||
|
/* Watchdog clock per second */
|
||||||
|
#define NU_WDTCLK_PER_SEC (__LIRC)
|
||||||
|
|
||||||
|
/* Convert watchdog clock to nearest ms */
|
||||||
|
#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC))
|
||||||
|
|
||||||
|
/* Convert ms to nearest watchdog clock */
|
||||||
|
#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000)
|
||||||
|
|
||||||
|
/* List of hardware-supported watchdog timeout in clocks */
|
||||||
|
#define NU_WDT_16CLK 16
|
||||||
|
#define NU_WDT_64CLK 64
|
||||||
|
#define NU_WDT_256CLK 256
|
||||||
|
#define NU_WDT_1024CLK 1024
|
||||||
|
#define NU_WDT_4096CLK 4096
|
||||||
|
#define NU_WDT_16384CLK 16384
|
||||||
|
#define NU_WDT_65536CLK 65536
|
||||||
|
#define NU_WDT_262144CLK 262144
|
||||||
|
|
||||||
|
/* Watchdog reset delay */
|
||||||
|
#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK
|
||||||
|
|
||||||
|
/* Support watchdog timeout values beyond H/W
|
||||||
|
*
|
||||||
|
* Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks.
|
||||||
|
* To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to
|
||||||
|
* reach one large timeout specified in hal_watchdog_init.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Track if WDT H/W has been initialized */
|
||||||
|
static bool wdt_hw_inited = 0;
|
||||||
|
/* Hold initially-configured timeout in hal_watchdog_init */
|
||||||
|
static uint32_t wdt_timeout_reload_ms = 0;
|
||||||
|
/* Track remaining timeout for cascading */
|
||||||
|
static uint32_t wdt_timeout_rmn_clk = 0;
|
||||||
|
|
||||||
|
static void watchdog_setup_cascade_timeout(void);
|
||||||
|
static void WDT_IRQHandler(void);
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
/* Check validity of arguments */
|
||||||
|
if (! config || ! config->timeout_ms) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdt_timeout_reload_ms = config->timeout_ms;
|
||||||
|
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||||
|
|
||||||
|
if (! wdt_hw_inited) {
|
||||||
|
wdt_hw_inited = 1;
|
||||||
|
|
||||||
|
/* Enable IP module clock */
|
||||||
|
CLK_EnableModuleClock(WDT_MODULE);
|
||||||
|
|
||||||
|
/* Select IP clock source */
|
||||||
|
CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0);
|
||||||
|
|
||||||
|
/* Set up IP interrupt */
|
||||||
|
NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler);
|
||||||
|
NVIC_EnableIRQ(WDT_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags & Disable interrupt & Disable WDT */
|
||||||
|
WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
return wdt_timeout_reload_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
watchdog_features_t wdt_feat;
|
||||||
|
|
||||||
|
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
|
||||||
|
wdt_feat.max_timeout = UINT32_MAX;
|
||||||
|
/* Support re-configuring watchdog timer */
|
||||||
|
wdt_feat.update_config = 1;
|
||||||
|
/* Support stopping watchdog timer */
|
||||||
|
wdt_feat.disable_watchdog = 1;
|
||||||
|
|
||||||
|
return wdt_feat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void watchdog_setup_cascade_timeout(void)
|
||||||
|
{
|
||||||
|
uint32_t wdt_timeout_clk_toutsel;
|
||||||
|
|
||||||
|
if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_262144CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_65536CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_16384CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_4096CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_1024CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_256CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_64CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_16CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||||
|
} else if (wdt_timeout_rmn_clk) {
|
||||||
|
wdt_timeout_rmn_clk = 0;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||||
|
} else {
|
||||||
|
/* WDT has timed-out and will restart system soon. We just disable interrupt to escape
|
||||||
|
* getting stuck in WDT ISR. */
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags & Disable interrupt */
|
||||||
|
WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Configure reset delay on timeout */
|
||||||
|
WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL;
|
||||||
|
|
||||||
|
/* Configure another piece of cascaded WDT timeout */
|
||||||
|
WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval
|
||||||
|
WDT_CTL_WDTEN_Msk | // Enable watchdog timer
|
||||||
|
WDT_CTL_INTEN_Msk | // Enable interrupt
|
||||||
|
WDT_CTL_WKF_Msk | // Clear wake-up flag
|
||||||
|
WDT_CTL_WKEN_Msk | // Enable wake-up on timeout
|
||||||
|
WDT_CTL_IF_Msk | // Clear interrupt flag
|
||||||
|
WDT_CTL_RSTF_Msk | // Clear reset flag
|
||||||
|
(wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout
|
||||||
|
WDT_CTL_RSTCNT_Msk; // Reset watchdog timer
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WDT_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* Check WDT interrupt flag */
|
||||||
|
if (WDT_GET_TIMEOUT_INT_FLAG()) {
|
||||||
|
/* Continue another piece of cascaded WDT timeout */
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
} else {
|
||||||
|
/* Clear all flags */
|
||||||
|
WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,106 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2018 Nuvoton
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
|
||||||
|
/* All reset source flags */
|
||||||
|
#define SYS_RSTSTS_ALLRF_Msk \
|
||||||
|
(SYS_RSTSTS_PORF_Msk | \
|
||||||
|
SYS_RSTSTS_PINRF_Msk | \
|
||||||
|
SYS_RSTSTS_WDTRF_Msk | \
|
||||||
|
SYS_RSTSTS_LVRF_Msk | \
|
||||||
|
SYS_RSTSTS_BODRF_Msk | \
|
||||||
|
SYS_RSTSTS_SYSRF_Msk | \
|
||||||
|
SYS_RSTSTS_CPURF_Msk | \
|
||||||
|
SYS_RSTSTS_CPULKRF_Msk)
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
uint32_t reset_reason_raw = hal_reset_reason_get_raw();
|
||||||
|
reset_reason_t reset_reason_cast;
|
||||||
|
uint32_t reset_reason_count = 0;
|
||||||
|
|
||||||
|
if (SYS_IS_POR_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_POWER_ON;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_RSTPIN_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PIN_RESET;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_WDT_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_WATCHDOG;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_LVR_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PLATFORM;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_BOD_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_BROWN_OUT;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This MCU supports MKROM and we need to take care of bootloader/SYSRESETREQ flow. */
|
||||||
|
if (SYS_IS_SYSTEM_RST()) {
|
||||||
|
if (reset_reason_raw & (SYS_RSTSTS_ALLRF_Msk & ~SYS_RSTSTS_SYSRF_Msk)) {
|
||||||
|
/* We may boot from bootloader which would reset to go to LDROM/APROM at its end
|
||||||
|
* through writing 1 to SYSRESETREQ bit. If there are other reset reasons, we think
|
||||||
|
* it is just the case and ignore the reset reason with SYSRESETREQ. */
|
||||||
|
} else {
|
||||||
|
reset_reason_cast = RESET_REASON_SOFTWARE;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_CPU_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PLATFORM;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset_reason_raw & SYS_RSTSTS_CPULKRF_Msk) {
|
||||||
|
reset_reason_cast = RESET_REASON_LOCKUP;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset_reason_count == 0) {
|
||||||
|
reset_reason_cast = RESET_REASON_UNKNOWN;
|
||||||
|
} else if (reset_reason_count >= 2) {
|
||||||
|
reset_reason_cast = RESET_REASON_MULTIPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reset_reason_cast;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
return (SYS->RSTSTS & SYS_RSTSTS_ALLRF_Msk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
SYS_CLEAR_RST_SOURCE(SYS->RSTSTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,205 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2018 Nuvoton
|
||||||
|
*
|
||||||
|
* 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 "watchdog_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
|
||||||
|
/* Micro seconds per second */
|
||||||
|
#define NU_US_PER_SEC 1000000
|
||||||
|
|
||||||
|
/* Watchdog clock per second */
|
||||||
|
#define NU_WDTCLK_PER_SEC (__LIRC)
|
||||||
|
|
||||||
|
/* Convert watchdog clock to nearest ms */
|
||||||
|
#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC))
|
||||||
|
|
||||||
|
/* Convert ms to nearest watchdog clock */
|
||||||
|
#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000)
|
||||||
|
|
||||||
|
/* List of hardware-supported watchdog timeout in clocks */
|
||||||
|
#define NU_WDT_16CLK 16
|
||||||
|
#define NU_WDT_64CLK 64
|
||||||
|
#define NU_WDT_256CLK 256
|
||||||
|
#define NU_WDT_1024CLK 1024
|
||||||
|
#define NU_WDT_4096CLK 4096
|
||||||
|
#define NU_WDT_16384CLK 16384
|
||||||
|
#define NU_WDT_65536CLK 65536
|
||||||
|
#define NU_WDT_262144CLK 262144
|
||||||
|
|
||||||
|
/* Watchdog reset delay */
|
||||||
|
#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK
|
||||||
|
|
||||||
|
/* Support watchdog timeout values beyond H/W
|
||||||
|
*
|
||||||
|
* Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks.
|
||||||
|
* To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to
|
||||||
|
* reach one large timeout specified in hal_watchdog_init.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Track if WDT H/W has been initialized */
|
||||||
|
static bool wdt_hw_inited = 0;
|
||||||
|
/* Hold initially-configured timeout in hal_watchdog_init */
|
||||||
|
static uint32_t wdt_timeout_reload_ms = 0;
|
||||||
|
/* Track remaining timeout for cascading */
|
||||||
|
static uint32_t wdt_timeout_rmn_clk = 0;
|
||||||
|
|
||||||
|
static void watchdog_setup_cascade_timeout(void);
|
||||||
|
static void WDT_IRQHandler(void);
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
/* Check validity of arguments */
|
||||||
|
if (! config || ! config->timeout_ms) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdt_timeout_reload_ms = config->timeout_ms;
|
||||||
|
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||||
|
|
||||||
|
if (! wdt_hw_inited) {
|
||||||
|
wdt_hw_inited = 1;
|
||||||
|
|
||||||
|
/* Enable IP module clock */
|
||||||
|
CLK_EnableModuleClock(WDT_MODULE);
|
||||||
|
|
||||||
|
/* Select IP clock source */
|
||||||
|
CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0);
|
||||||
|
|
||||||
|
/* Set up IP interrupt */
|
||||||
|
NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler);
|
||||||
|
NVIC_EnableIRQ(WDT_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags & Disable interrupt & Disable WDT */
|
||||||
|
WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
return wdt_timeout_reload_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
watchdog_features_t wdt_feat;
|
||||||
|
|
||||||
|
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
|
||||||
|
wdt_feat.max_timeout = UINT32_MAX;
|
||||||
|
/* Support re-configuring watchdog timer */
|
||||||
|
wdt_feat.update_config = 1;
|
||||||
|
/* Support stopping watchdog timer */
|
||||||
|
wdt_feat.disable_watchdog = 1;
|
||||||
|
|
||||||
|
return wdt_feat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void watchdog_setup_cascade_timeout(void)
|
||||||
|
{
|
||||||
|
uint32_t wdt_timeout_clk_toutsel;
|
||||||
|
|
||||||
|
if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_262144CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_65536CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_16384CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_4096CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_1024CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_256CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_64CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_16CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||||
|
} else if (wdt_timeout_rmn_clk) {
|
||||||
|
wdt_timeout_rmn_clk = 0;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||||
|
} else {
|
||||||
|
/* WDT has timed-out and will restart system soon. We just disable interrupt to escape
|
||||||
|
* getting stuck in WDT ISR. */
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags & Disable interrupt */
|
||||||
|
WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Configure reset delay on timeout */
|
||||||
|
WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL;
|
||||||
|
|
||||||
|
/* Configure another piece of cascaded WDT timeout */
|
||||||
|
WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval
|
||||||
|
WDT_CTL_WDTEN_Msk | // Enable watchdog timer
|
||||||
|
WDT_CTL_INTEN_Msk | // Enable interrupt
|
||||||
|
WDT_CTL_WKF_Msk | // Clear wake-up flag
|
||||||
|
WDT_CTL_WKEN_Msk | // Enable wake-up on timeout
|
||||||
|
WDT_CTL_IF_Msk | // Clear interrupt flag
|
||||||
|
WDT_CTL_RSTF_Msk | // Clear reset flag
|
||||||
|
(wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout
|
||||||
|
WDT_CTL_RSTCNT_Msk; // Reset watchdog timer
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WDT_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* Check WDT interrupt flag */
|
||||||
|
if (WDT_GET_TIMEOUT_INT_FLAG()) {
|
||||||
|
/* Continue another piece of cascaded WDT timeout */
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
} else {
|
||||||
|
/* Clear all flags */
|
||||||
|
WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,87 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2018 Nuvoton
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
|
||||||
|
/* All reset source flags */
|
||||||
|
#define SYS_RST_SRC_ALL_Msk \
|
||||||
|
(SYS_RST_SRC_RSTS_POR_Msk | \
|
||||||
|
SYS_RST_SRC_RSTS_PAD_Msk | \
|
||||||
|
SYS_RST_SRC_RSTS_WDT_Msk | \
|
||||||
|
SYS_RST_SRC_RSTS_BOD_Msk | \
|
||||||
|
SYS_RST_SRC_RSTS_SYS_Msk | \
|
||||||
|
SYS_RST_SRC_RSTS_CPU_Msk)
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
reset_reason_t reset_reason_cast;
|
||||||
|
uint32_t reset_reason_count = 0;
|
||||||
|
|
||||||
|
if (SYS_IS_POR_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_POWER_ON;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_RSTPIN_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PIN_RESET;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_WDT_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_WATCHDOG;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_BOD_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_BROWN_OUT;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This MCU doesn't support MKROM and we needn't take care of bootloader/SYSRESETREQ flow. */
|
||||||
|
if (SYS_IS_SYSTEM_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_SOFTWARE;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_CPU_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PLATFORM;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset_reason_count == 0) {
|
||||||
|
reset_reason_cast = RESET_REASON_UNKNOWN;
|
||||||
|
} else if (reset_reason_count >= 2) {
|
||||||
|
reset_reason_cast = RESET_REASON_MULTIPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reset_reason_cast;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
return (SYS->RST_SRC & SYS_RST_SRC_ALL_Msk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
SYS_CLEAR_RST_SOURCE(SYS->RST_SRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,211 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2018 Nuvoton
|
||||||
|
*
|
||||||
|
* 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 "watchdog_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
|
||||||
|
/* Micro seconds per second */
|
||||||
|
#define NU_US_PER_SEC 1000000
|
||||||
|
|
||||||
|
/* Watchdog clock per second */
|
||||||
|
#define NU_WDTCLK_PER_SEC (__LIRC)
|
||||||
|
|
||||||
|
/* Convert watchdog clock to nearest ms */
|
||||||
|
#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC))
|
||||||
|
|
||||||
|
/* Convert ms to nearest watchdog clock */
|
||||||
|
#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000)
|
||||||
|
|
||||||
|
/* List of hardware-supported watchdog timeout in clocks */
|
||||||
|
#define NU_WDT_16CLK 16
|
||||||
|
#define NU_WDT_64CLK 64
|
||||||
|
#define NU_WDT_256CLK 256
|
||||||
|
#define NU_WDT_1024CLK 1024
|
||||||
|
#define NU_WDT_4096CLK 4096
|
||||||
|
#define NU_WDT_16384CLK 16384
|
||||||
|
#define NU_WDT_65536CLK 65536
|
||||||
|
#define NU_WDT_262144CLK 262144
|
||||||
|
|
||||||
|
/* Watchdog reset delay */
|
||||||
|
#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK
|
||||||
|
|
||||||
|
/* Support watchdog timeout values beyond H/W
|
||||||
|
*
|
||||||
|
* Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks.
|
||||||
|
* To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to
|
||||||
|
* reach one large timeout specified in hal_watchdog_init.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Track if WDT H/W has been initialized */
|
||||||
|
static bool wdt_hw_inited = 0;
|
||||||
|
/* Hold initially-configured timeout in hal_watchdog_init */
|
||||||
|
static uint32_t wdt_timeout_reload_ms = 0;
|
||||||
|
/* Track remaining timeout for cascading */
|
||||||
|
static uint32_t wdt_timeout_rmn_clk = 0;
|
||||||
|
|
||||||
|
static void watchdog_setup_cascade_timeout(void);
|
||||||
|
/* NOTE: Don't add static modifier here. These IRQ handler symbols are for linking.
|
||||||
|
Vector table relocation is not actually supported for low-resource target. */
|
||||||
|
void WDT_IRQHandler(void);
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
/* Check validity of arguments */
|
||||||
|
if (! config || ! config->timeout_ms) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdt_timeout_reload_ms = config->timeout_ms;
|
||||||
|
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||||
|
|
||||||
|
if (! wdt_hw_inited) {
|
||||||
|
wdt_hw_inited = 1;
|
||||||
|
|
||||||
|
/* Enable IP module clock */
|
||||||
|
CLK_EnableModuleClock(WDT_MODULE);
|
||||||
|
|
||||||
|
/* Select IP clock source */
|
||||||
|
CLK_SetModuleClock(WDT_MODULE, 0, 0);
|
||||||
|
|
||||||
|
/* Set up IP interrupt */
|
||||||
|
NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler);
|
||||||
|
NVIC_EnableIRQ(WDT_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags */
|
||||||
|
WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk;
|
||||||
|
/* Disable interrupt */
|
||||||
|
WDT->IER &= ~WDT_IER_IE_Msk;
|
||||||
|
/* Disable WDT */
|
||||||
|
WDT->CTL &= ~WDT_CTL_WTE_Msk;
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
return wdt_timeout_reload_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
watchdog_features_t wdt_feat;
|
||||||
|
|
||||||
|
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
|
||||||
|
wdt_feat.max_timeout = UINT32_MAX;
|
||||||
|
/* Support re-configuring watchdog timer */
|
||||||
|
wdt_feat.update_config = 1;
|
||||||
|
/* Support stopping watchdog timer */
|
||||||
|
wdt_feat.disable_watchdog = 1;
|
||||||
|
|
||||||
|
return wdt_feat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void watchdog_setup_cascade_timeout(void)
|
||||||
|
{
|
||||||
|
uint32_t wdt_timeout_clk_toutsel;
|
||||||
|
|
||||||
|
if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_262144CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_65536CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_16384CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_4096CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_1024CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_256CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_64CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_16CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||||
|
} else if (wdt_timeout_rmn_clk) {
|
||||||
|
wdt_timeout_rmn_clk = 0;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||||
|
} else {
|
||||||
|
/* WDT has timed-out and will restart system soon. We just disable interrupt to escape
|
||||||
|
* getting stuck in WDT ISR. */
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags */
|
||||||
|
WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk;
|
||||||
|
/* Disable interrupt */
|
||||||
|
WDT->IER &= ~WDT_IER_IE_Msk;
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags */
|
||||||
|
WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk;
|
||||||
|
/* Enable interrupt */
|
||||||
|
WDT->IER = WDT_IER_IE_Msk;
|
||||||
|
/* Configure another piece of cascaded WDT timeout */
|
||||||
|
WDT->CTL = NU_WDT_RESET_DELAY_RSTDSEL | // Reset delay on timeout
|
||||||
|
wdt_timeout_clk_toutsel | // Timeout interval
|
||||||
|
WDT_CTL_WTE_Msk | // Enable watchdog timer
|
||||||
|
WDT_CTL_WTWKE_Msk | // Enable wake-up on timeout
|
||||||
|
(wdt_timeout_rmn_clk ? 0 : WDT_CTL_WTRE_Msk) | // Enable reset on last cascaded timeout
|
||||||
|
WDT_CTL_WTR_Msk; // Reset watchdog timer
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WDT_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* Check WDT interrupt flag */
|
||||||
|
if (WDT_GET_TIMEOUT_INT_FLAG()) {
|
||||||
|
/* Continue another piece of cascaded WDT timeout */
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
} else {
|
||||||
|
/* Clear all flags */
|
||||||
|
WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,8 +1,8 @@
|
||||||
/**************************************************************************//**
|
/**************************************************************************//**
|
||||||
* @file wdt.c
|
* @file wdt.c
|
||||||
* @version V1.00
|
* @version V1.00
|
||||||
* $Revision: 6 $
|
* $Revision: 9 $
|
||||||
* $Date: 14/10/02 7:19p $
|
* $Date: 15/11/12 9:49a $
|
||||||
* @brief NUC472/NUC442 WDT driver source file
|
* @brief NUC472/NUC442 WDT driver source file
|
||||||
*
|
*
|
||||||
* @note
|
* @note
|
||||||
|
@ -49,9 +49,10 @@ void WDT_Open(uint32_t u32TimeoutInterval,
|
||||||
uint32_t u32EnableWakeup)
|
uint32_t u32EnableWakeup)
|
||||||
{
|
{
|
||||||
|
|
||||||
WDT->CTL = u32TimeoutInterval | u32ResetDelay | WDT_CTL_WDTEN_Msk |
|
WDT->CTL = u32TimeoutInterval | WDT_CTL_WDTEN_Msk |
|
||||||
(u32EnableReset << WDT_CTL_RSTEN_Pos) |
|
(u32EnableReset << WDT_CTL_RSTEN_Pos) |
|
||||||
(u32EnableWakeup << WDT_CTL_WKEN_Pos);
|
(u32EnableWakeup << WDT_CTL_WKEN_Pos);
|
||||||
|
WDT->ALTCTL = u32ResetDelay;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2018 Nuvoton
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
|
||||||
|
/* All reset source flags */
|
||||||
|
#define SYS_RSTSTS_ALLRF_Msk \
|
||||||
|
(SYS_RSTSTS_PORF_Msk | \
|
||||||
|
SYS_RSTSTS_PINRF_Msk | \
|
||||||
|
SYS_RSTSTS_WDTRF_Msk | \
|
||||||
|
SYS_RSTSTS_LVRF_Msk | \
|
||||||
|
SYS_RSTSTS_BODRF_Msk | \
|
||||||
|
SYS_RSTSTS_SYSRF_Msk | \
|
||||||
|
SYS_RSTSTS_CPURF_Msk)
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
reset_reason_t reset_reason_cast;
|
||||||
|
uint32_t reset_reason_count = 0;
|
||||||
|
|
||||||
|
if (SYS_IS_POR_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_POWER_ON;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_RSTPIN_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PIN_RESET;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_WDT_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_WATCHDOG;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_LVR_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PLATFORM;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_BOD_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_BROWN_OUT;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This MCU doesn't support MKROM and we needn't take care of bootloader/SYSRESETREQ flow. */
|
||||||
|
if (SYS_IS_SYSTEM_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_SOFTWARE;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYS_IS_CPU_RST()) {
|
||||||
|
reset_reason_cast = RESET_REASON_PLATFORM;
|
||||||
|
reset_reason_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset_reason_count == 0) {
|
||||||
|
reset_reason_cast = RESET_REASON_UNKNOWN;
|
||||||
|
} else if (reset_reason_count >= 2) {
|
||||||
|
reset_reason_cast = RESET_REASON_MULTIPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reset_reason_cast;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
return (SYS->RSTSTS & SYS_RSTSTS_ALLRF_Msk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
SYS_CLEAR_RST_SOURCE(SYS->RSTSTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,205 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2018 Nuvoton
|
||||||
|
*
|
||||||
|
* 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 "watchdog_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
|
||||||
|
/* Micro seconds per second */
|
||||||
|
#define NU_US_PER_SEC 1000000
|
||||||
|
|
||||||
|
/* Watchdog clock per second */
|
||||||
|
#define NU_WDTCLK_PER_SEC (__LIRC)
|
||||||
|
|
||||||
|
/* Convert watchdog clock to nearest ms */
|
||||||
|
#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC))
|
||||||
|
|
||||||
|
/* Convert ms to nearest watchdog clock */
|
||||||
|
#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000)
|
||||||
|
|
||||||
|
/* List of hardware-supported watchdog timeout in clocks */
|
||||||
|
#define NU_WDT_16CLK 16
|
||||||
|
#define NU_WDT_64CLK 64
|
||||||
|
#define NU_WDT_256CLK 256
|
||||||
|
#define NU_WDT_1024CLK 1024
|
||||||
|
#define NU_WDT_4096CLK 4096
|
||||||
|
#define NU_WDT_16384CLK 16384
|
||||||
|
#define NU_WDT_65536CLK 65536
|
||||||
|
#define NU_WDT_262144CLK 262144
|
||||||
|
|
||||||
|
/* Watchdog reset delay */
|
||||||
|
#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK
|
||||||
|
|
||||||
|
/* Support watchdog timeout values beyond H/W
|
||||||
|
*
|
||||||
|
* Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks.
|
||||||
|
* To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to
|
||||||
|
* reach one large timeout specified in hal_watchdog_init.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Track if WDT H/W has been initialized */
|
||||||
|
static bool wdt_hw_inited = 0;
|
||||||
|
/* Hold initially-configured timeout in hal_watchdog_init */
|
||||||
|
static uint32_t wdt_timeout_reload_ms = 0;
|
||||||
|
/* Track remaining timeout for cascading */
|
||||||
|
static uint32_t wdt_timeout_rmn_clk = 0;
|
||||||
|
|
||||||
|
static void watchdog_setup_cascade_timeout(void);
|
||||||
|
static void WDT_IRQHandler(void);
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
/* Check validity of arguments */
|
||||||
|
if (! config || ! config->timeout_ms) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdt_timeout_reload_ms = config->timeout_ms;
|
||||||
|
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||||
|
|
||||||
|
if (! wdt_hw_inited) {
|
||||||
|
wdt_hw_inited = 1;
|
||||||
|
|
||||||
|
/* Enable IP module clock */
|
||||||
|
CLK_EnableModuleClock(WDT_MODULE);
|
||||||
|
|
||||||
|
/* Select IP clock source */
|
||||||
|
CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0);
|
||||||
|
|
||||||
|
/* Set up IP interrupt */
|
||||||
|
NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler);
|
||||||
|
NVIC_EnableIRQ(WDT_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags & Disable interrupt & Disable WDT */
|
||||||
|
WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
return wdt_timeout_reload_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
watchdog_features_t wdt_feat;
|
||||||
|
|
||||||
|
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
|
||||||
|
wdt_feat.max_timeout = UINT32_MAX;
|
||||||
|
/* Support re-configuring watchdog timer */
|
||||||
|
wdt_feat.update_config = 1;
|
||||||
|
/* Support stopping watchdog timer */
|
||||||
|
wdt_feat.disable_watchdog = 1;
|
||||||
|
|
||||||
|
return wdt_feat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void watchdog_setup_cascade_timeout(void)
|
||||||
|
{
|
||||||
|
uint32_t wdt_timeout_clk_toutsel;
|
||||||
|
|
||||||
|
if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_262144CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_65536CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_16384CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_4096CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_1024CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_256CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_64CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6;
|
||||||
|
} else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) {
|
||||||
|
wdt_timeout_rmn_clk -= NU_WDT_16CLK;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||||
|
} else if (wdt_timeout_rmn_clk) {
|
||||||
|
wdt_timeout_rmn_clk = 0;
|
||||||
|
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||||
|
} else {
|
||||||
|
/* WDT has timed-out and will restart system soon. We just disable interrupt to escape
|
||||||
|
* getting stuck in WDT ISR. */
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Clear all flags & Disable interrupt */
|
||||||
|
WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_UnlockReg();
|
||||||
|
|
||||||
|
/* Configure reset delay on timeout */
|
||||||
|
WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL;
|
||||||
|
|
||||||
|
/* Configure another piece of cascaded WDT timeout */
|
||||||
|
WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval
|
||||||
|
WDT_CTL_WDTEN_Msk | // Enable watchdog timer
|
||||||
|
WDT_CTL_INTEN_Msk | // Enable interrupt
|
||||||
|
WDT_CTL_WKF_Msk | // Clear wake-up flag
|
||||||
|
WDT_CTL_WKEN_Msk | // Enable wake-up on timeout
|
||||||
|
WDT_CTL_IF_Msk | // Clear interrupt flag
|
||||||
|
WDT_CTL_RSTF_Msk | // Clear reset flag
|
||||||
|
(wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout
|
||||||
|
WDT_CTL_RSTCNT_Msk; // Reset watchdog timer
|
||||||
|
|
||||||
|
SYS_LockReg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WDT_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* Check WDT interrupt flag */
|
||||||
|
if (WDT_GET_TIMEOUT_INT_FLAG()) {
|
||||||
|
/* Continue another piece of cascaded WDT timeout */
|
||||||
|
watchdog_setup_cascade_timeout();
|
||||||
|
} else {
|
||||||
|
/* Clear all flags */
|
||||||
|
WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,114 @@
|
||||||
|
/**
|
||||||
|
*******************************************************************************
|
||||||
|
* @file watchdog_api.c
|
||||||
|
* @brief Implementation of watchdog_api
|
||||||
|
* @internal
|
||||||
|
* @author ON Semiconductor
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2018 Semiconductor Components Industries LLC (d/b/a “ON Semiconductor”).
|
||||||
|
* All rights reserved. This software and/or documentation is licensed by ON Semiconductor
|
||||||
|
* under limited terms and conditions. The terms and conditions pertaining to the software
|
||||||
|
* and/or documentation are available at http://www.onsemi.com/site/pdf/ONSEMI_T&C.pdf
|
||||||
|
* (“ON Semiconductor Standard Terms and Conditions of Sale, Section 8 Software”) and
|
||||||
|
* if applicable the software license agreement. Do not use this software and/or
|
||||||
|
* documentation unless you have carefully read and you agree to the limited terms and
|
||||||
|
* conditions. By using this software and/or documentation, you agree to the limited
|
||||||
|
* terms and conditions.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
* ON SEMICONDUCTOR SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL,
|
||||||
|
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
* @endinternal
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "watchdog_api.h"
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "clock.h" // Peripheral clock control definitions.
|
||||||
|
#include "wdt_map.h" // Watchdog hardware register definitions.
|
||||||
|
#include "memory_map.h" // Pointer to watchdog peripheral in memory.
|
||||||
|
|
||||||
|
|
||||||
|
// watchdog_api feature definitions
|
||||||
|
#define WDT_MAX_TIMEOUT_MS ((uint32_t)8000)
|
||||||
|
#define WDT_CAN_UPDATE ((boolean)True)
|
||||||
|
#define WDT_CAN_STOP ((boolean)True)
|
||||||
|
|
||||||
|
// WDT LOAD register definitions
|
||||||
|
#define WDT_MAX_LOAD_VAL ((uint32_t)0x3FFFF)
|
||||||
|
#define WDT_TICKS_PER_MS (WDT_MAX_LOAD_VAL / WDT_MAX_TIMEOUT_MS)
|
||||||
|
|
||||||
|
// WDT KICK register definitions
|
||||||
|
#define WDT_KICK_VAL ((uint32_t)1)
|
||||||
|
|
||||||
|
// WDT LOCK register definitions
|
||||||
|
#define WDT_LOCK_DISABLE ((uint32_t)0x1ACCE551)
|
||||||
|
#define WDT_LOCK_ENABLE ((uint32_t)0x00000000)
|
||||||
|
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
if (!config || config->timeout_ms > WDT_MAX_TIMEOUT_MS || config->timeout_ms == 0) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CLOCK_IS_ENABLED(CLOCK_WDOG)) {
|
||||||
|
CLOCK_ENABLE(CLOCK_WDOG);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable write lock in case WDT is being reconfigured.
|
||||||
|
WDTREG->LOCK = WDT_LOCK_DISABLE;
|
||||||
|
|
||||||
|
while (WDTREG->STATUS.BITS.WRITE_BUSY_ANY);
|
||||||
|
WDTREG->LOAD = config->timeout_ms * WDT_TICKS_PER_MS;
|
||||||
|
|
||||||
|
while (WDTREG->STATUS.BITS.WRITE_BUSY_LOAD);
|
||||||
|
WDTREG->CONTROL.BITS.WDT_EN = True;
|
||||||
|
|
||||||
|
while (WDTREG->STATUS.BITS.WRITE_BUSY_CONTROL);
|
||||||
|
WDTREG->LOCK = WDT_LOCK_ENABLE;
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
// Write any value to kick watchdog.
|
||||||
|
WDTREG->KICK = WDT_KICK_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
WDTREG->LOCK = WDT_LOCK_DISABLE;
|
||||||
|
|
||||||
|
while (WDTREG->STATUS.BITS.WRITE_BUSY_ANY);
|
||||||
|
WDTREG->CONTROL.BITS.WDT_EN = False;
|
||||||
|
|
||||||
|
while (WDTREG->STATUS.BITS.WRITE_BUSY_ANY);
|
||||||
|
CLOCK_DISABLE(CLOCK_WDOG);
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
while (WDTREG->STATUS.BITS.WRITE_BUSY_LOAD);
|
||||||
|
return WDTREG->LOAD / WDT_TICKS_PER_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
const watchdog_features_t features = {
|
||||||
|
.max_timeout = WDT_MAX_TIMEOUT_MS,
|
||||||
|
.update_config = WDT_CAN_UPDATE,
|
||||||
|
.disable_watchdog = WDT_CAN_STOP
|
||||||
|
};
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DEVICE_WATCHDOG
|
||||||
|
|
|
@ -124,10 +124,8 @@
|
||||||
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* Status register need 5 RC LSI divided by prescaler clock to be updated. With
|
/* MBED */
|
||||||
higher prescaler (256), and according to LSI variation, we need to wait at
|
#define HAL_IWDG_DEFAULT_TIMEOUT 96u
|
||||||
least 6 cycles so 39 ms. */
|
|
||||||
#define HAL_IWDG_DEFAULT_TIMEOUT 39U
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -121,6 +121,7 @@
|
||||||
higher prescaler (256), and according to HSI variation, we need to wait at
|
higher prescaler (256), and according to HSI variation, we need to wait at
|
||||||
least 6 cycles so 48 ms. */
|
least 6 cycles so 48 ms. */
|
||||||
#define HAL_IWDG_DEFAULT_TIMEOUT 48U
|
#define HAL_IWDG_DEFAULT_TIMEOUT 48U
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -119,10 +119,8 @@
|
||||||
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* Status register need 5 RC LSI divided by prescaler clock to be updated. With
|
/* MBED */
|
||||||
higher prescaler (256), and according to HSI variation, we need to wait at
|
#define HAL_IWDG_DEFAULT_TIMEOUT 96u
|
||||||
least 6 cycles so 48 ms. */
|
|
||||||
#define HAL_IWDG_DEFAULT_TIMEOUT 48U
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -124,10 +124,8 @@
|
||||||
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* Status register need 5 RC LSI divided by prescaler clock to be updated. With
|
/* MBED */
|
||||||
higher prescaler (256U), and according to HSI variation, we need to wait at
|
#define HAL_IWDG_DEFAULT_TIMEOUT 96u
|
||||||
least 6 cycles so 48 ms. */
|
|
||||||
#define HAL_IWDG_DEFAULT_TIMEOUT 48u
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -117,10 +117,8 @@
|
||||||
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* Status register need 5 RC LSI divided by prescaler clock to be updated. With
|
/* MBED */
|
||||||
higher prescaler (256), and according to HSI variation, we need to wait at
|
#define HAL_IWDG_DEFAULT_TIMEOUT 96u
|
||||||
least 6 cycles so 48 ms. */
|
|
||||||
#define HAL_IWDG_DEFAULT_TIMEOUT 48U
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -124,10 +124,8 @@
|
||||||
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* Status register need 5 RC LSI divided by prescaler clock to be updated. With
|
/* MBED */
|
||||||
higher prescaler (256), and according to LSI variation, we need to wait at
|
#define HAL_IWDG_DEFAULT_TIMEOUT 96u
|
||||||
least 6 cycles so 48 ms. */
|
|
||||||
#define HAL_IWDG_DEFAULT_TIMEOUT 48u
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -132,7 +132,7 @@
|
||||||
* @brief Internal Low Speed oscillator (LSI) value.
|
* @brief Internal Low Speed oscillator (LSI) value.
|
||||||
*/
|
*/
|
||||||
#if !defined (LSI_VALUE)
|
#if !defined (LSI_VALUE)
|
||||||
#define LSI_VALUE ((uint32_t)37000U) /*!< LSI Typical Value in Hz*/
|
#define LSI_VALUE (37000U) /*!< LSI Typical Value in Hz*/
|
||||||
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
||||||
The real value may vary depending on the variations
|
The real value may vary depending on the variations
|
||||||
in voltage and temperature.*/
|
in voltage and temperature.*/
|
||||||
|
|
|
@ -118,10 +118,8 @@
|
||||||
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* Status register need 5 RC LSI divided by prescaler clock to be updated. With
|
/* MBED */
|
||||||
higher prescaler (256), and according to HSI variation, we need to wait at
|
#define HAL_IWDG_DEFAULT_TIMEOUT 96u
|
||||||
least 6 cycles so 48 ms. */
|
|
||||||
#define HAL_IWDG_DEFAULT_TIMEOUT 48u
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
* @brief Internal Low Speed oscillator (LSI) value.
|
* @brief Internal Low Speed oscillator (LSI) value.
|
||||||
*/
|
*/
|
||||||
#if !defined (LSI_VALUE)
|
#if !defined (LSI_VALUE)
|
||||||
#define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/
|
#define LSI_VALUE (32000U) /*!< LSI Typical Value in Hz*/
|
||||||
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
||||||
The real value may vary depending on the variations
|
The real value may vary depending on the variations
|
||||||
in voltage and temperature.*/
|
in voltage and temperature.*/
|
||||||
|
|
|
@ -124,10 +124,8 @@
|
||||||
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
/** @defgroup IWDG_Private_Defines IWDG Private Defines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* Status register need 5 RC LSI divided by prescaler clock to be updated. With
|
/* MBED */
|
||||||
higher prescaler (256), and according to HSI variation, we need to wait at
|
#define HAL_IWDG_DEFAULT_TIMEOUT 96u
|
||||||
least 6 cycles so 48 ms. */
|
|
||||||
#define HAL_IWDG_DEFAULT_TIMEOUT 48u
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2006-2017 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#ifdef DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
#ifdef RCC_FLAG_LPWRRST
|
||||||
|
if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) {
|
||||||
|
return RESET_REASON_WAKE_LOW_POWER;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RCC_FLAG_WWDGRST
|
||||||
|
if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) {
|
||||||
|
return RESET_REASON_WATCHDOG;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RCC_FLAG_IWDGRST
|
||||||
|
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) {
|
||||||
|
return RESET_REASON_WATCHDOG;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RCC_FLAG_SFTRST
|
||||||
|
if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) {
|
||||||
|
return RESET_REASON_SOFTWARE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RCC_FLAG_PORRST
|
||||||
|
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) {
|
||||||
|
return RESET_REASON_POWER_ON;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RCC_FLAG_BORRST
|
||||||
|
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RCC_FLAG_PINRST
|
||||||
|
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) {
|
||||||
|
return RESET_REASON_PIN_RESET;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return RESET_REASON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
return RCC->CSR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
__HAL_RCC_CLEAR_RESET_FLAGS();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
|
@ -0,0 +1,130 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2006-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "watchdog_api.h"
|
||||||
|
#include "reset_reason_api.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "mbed_error.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define MAX_IWDG_PR 0x6 // Max value of Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR)
|
||||||
|
#define MAX_IWDG_RL 0xFFFUL // Max value of Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR).
|
||||||
|
|
||||||
|
// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) to a prescaler_divider value.
|
||||||
|
#define PR2PRESCALER_DIV(PR_BITS) \
|
||||||
|
(4UL << (PR_BITS))
|
||||||
|
|
||||||
|
// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR)
|
||||||
|
// and Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR)
|
||||||
|
// to a timeout value [ms].
|
||||||
|
#define PR_RL2UINT64_TIMEOUT_MS(PR_BITS, RL_BITS) \
|
||||||
|
((PR2PRESCALER_DIV(PR_BITS)) * (RL_BITS) * 1000ULL / (LSI_VALUE))
|
||||||
|
|
||||||
|
// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) and a timeout value [ms]
|
||||||
|
// to Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR)
|
||||||
|
#define PR_TIMEOUT_MS2RL(PR_BITS, TIMEOUT_MS) \
|
||||||
|
((TIMEOUT_MS) * (LSI_VALUE) / (PR2PRESCALER_DIV(PR_BITS)) / 1000UL)
|
||||||
|
|
||||||
|
#define MAX_TIMEOUT_MS_UINT64 PR_RL2UINT64_TIMEOUT_MS(MAX_IWDG_PR, MAX_IWDG_RL)
|
||||||
|
#if (MAX_TIMEOUT_MS_UINT64 > UINT32_MAX)
|
||||||
|
#define MAX_TIMEOUT_MS UINT32_MAX
|
||||||
|
#else
|
||||||
|
#define MAX_TIMEOUT_MS (MAX_TIMEOUT_MS_UINT64 & 0xFFFFFFFFUL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INVALID_IWDG_PR ((MAX_IWDG_PR) + 1) // Arbitrary value used to mark an invalid PR bits value.
|
||||||
|
|
||||||
|
// Pick a minimal Prescaler_divider bits (PR) value suitable for given timeout.
|
||||||
|
static uint8_t pick_min_iwdg_pr(const uint32_t timeout_ms) {
|
||||||
|
for (uint8_t pr = 0; pr <= MAX_IWDG_PR; pr++) {
|
||||||
|
// Check that max timeout for given pr is greater than
|
||||||
|
// or equal to timeout_ms.
|
||||||
|
if (PR_RL2UINT64_TIMEOUT_MS(pr, MAX_IWDG_RL) >= timeout_ms) {
|
||||||
|
return pr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INVALID_IWDG_PR;
|
||||||
|
}
|
||||||
|
|
||||||
|
IWDG_HandleTypeDef IwdgHandle;
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
const uint8_t pr = pick_min_iwdg_pr(config->timeout_ms);
|
||||||
|
if (pr == INVALID_IWDG_PR) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
const uint32_t rl = PR_TIMEOUT_MS2RL(pr, config->timeout_ms);
|
||||||
|
|
||||||
|
IwdgHandle.Instance = IWDG;
|
||||||
|
|
||||||
|
IwdgHandle.Init.Prescaler = pr;
|
||||||
|
IwdgHandle.Init.Reload = rl;
|
||||||
|
#if defined IWDG_WINR_WIN
|
||||||
|
IwdgHandle.Init.Window = IWDG_WINDOW_DISABLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (HAL_IWDG_Init(&IwdgHandle) != HAL_OK)
|
||||||
|
{
|
||||||
|
error("HAL_IWDG_Init error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
HAL_IWDG_Refresh(&IwdgHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
return WATCHDOG_STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
// Wait for the Watchdog_prescaler_value_update bit (PVU) of
|
||||||
|
// Status_register (IWDG_SR) to be reset.
|
||||||
|
while (READ_BIT(IWDG->SR, IWDG_SR_PVU)) {
|
||||||
|
}
|
||||||
|
// Read Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR).
|
||||||
|
const uint8_t pr = (IWDG->PR & IWDG_PR_PR_Msk) >> IWDG_PR_PR_Pos;
|
||||||
|
|
||||||
|
// Wait for the Watchdog_counter_reload_value_update bit (RVU) of
|
||||||
|
// Status_register (IWDG_SR) to be reset.
|
||||||
|
while (READ_BIT(IWDG->SR, IWDG_SR_RVU)) {
|
||||||
|
}
|
||||||
|
// Read Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR).
|
||||||
|
const uint32_t rl = (IWDG->RLR & IWDG_RLR_RL_Msk) >> IWDG_RLR_RL_Pos;
|
||||||
|
|
||||||
|
return PR_RL2UINT64_TIMEOUT_MS(pr, rl);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
watchdog_features_t features;
|
||||||
|
features.max_timeout = MAX_TIMEOUT_MS;
|
||||||
|
features.update_config = true;
|
||||||
|
features.disable_watchdog = false;
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_WATCHDOG
|
|
@ -0,0 +1,132 @@
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @file resetreason_api.c
|
||||||
|
*******************************************************************************
|
||||||
|
* @section License
|
||||||
|
* <b>(C) Copyright 2018 Silicon Labs, http://www.silabs.com</b>
|
||||||
|
*******************************************************************************
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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 "device.h"
|
||||||
|
#include "reset_reason_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "em_rmu.h"
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
uint32_t reasonmask = RMU_ResetCauseGet();
|
||||||
|
|
||||||
|
/* Only care about the upper bit, since that is 'most significant' reset reason */
|
||||||
|
reasonmask = 1 << (31 - __CLZ(reasonmask));
|
||||||
|
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_PORST) {
|
||||||
|
return RESET_REASON_POWER_ON;
|
||||||
|
}
|
||||||
|
#if defined(RMU_RSTCAUSE_BODUNREGRST)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BODUNREGRST) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(RMU_RSTCAUSE_BODREGRST)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BODREGRST) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(RMU_RSTCAUSE_AVDDBOD)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_AVDDBOD) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(RMU_RSTCAUSE_DVDDBOD)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_DVDDBOD) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(RMU_RSTCAUSE_DECBOD)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_DECBOD) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_EXTRST) {
|
||||||
|
return RESET_REASON_PIN_RESET;
|
||||||
|
}
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_WDOGRST) {
|
||||||
|
return RESET_REASON_WATCHDOG;
|
||||||
|
}
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_LOCKUPRST) {
|
||||||
|
return RESET_REASON_LOCKUP;
|
||||||
|
}
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_SYSREQRST) {
|
||||||
|
return RESET_REASON_SOFTWARE;
|
||||||
|
}
|
||||||
|
#if defined(RMU_RSTCAUSE_EM4RST)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_EM4RST) {
|
||||||
|
return RESET_REASON_WAKE_LOW_POWER;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(RMU_RSTCAUSE_EM4WURST)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_EM4WURST) {
|
||||||
|
return RESET_REASON_WAKE_LOW_POWER;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(RMU_RSTCAUSE_BODAVDD0)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BODAVDD0) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(RMU_RSTCAUSE_BODAVDD1)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BODAVDD1) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(BU_PRESENT) && defined(_SILICON_LABS_32B_SERIES_0)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BUBODVDDDREG) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BUBODBUVIN) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BUBODUNREG) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BUBODREG) {
|
||||||
|
return RESET_REASON_BROWN_OUT;
|
||||||
|
}
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BUMODERST) {
|
||||||
|
return RESET_REASON_PLATFORM;
|
||||||
|
}
|
||||||
|
#elif defined(RMU_RSTCAUSE_BUMODERST)
|
||||||
|
if (reasonmask & RMU_RSTCAUSE_BUMODERST) {
|
||||||
|
return RESET_REASON_PLATFORM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return RESET_REASON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
return RMU->RSTCAUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
RMU_ResetCauseClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DEVICE_RESET_REASON */
|
|
@ -0,0 +1,100 @@
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @file watchdog_api.c
|
||||||
|
*******************************************************************************
|
||||||
|
* @section License
|
||||||
|
* <b>(C) Copyright 2018 Silicon Labs, http://www.silabs.com</b>
|
||||||
|
*******************************************************************************
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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 "device.h"
|
||||||
|
#include "watchdog_api.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
#include "clocking.h"
|
||||||
|
#include "em_cmu.h"
|
||||||
|
#include "em_wdog.h"
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||||
|
{
|
||||||
|
if (config == 0 || config->timeout_ms > 262145 || config->timeout_ms == 0) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t timeout = config->timeout_ms;
|
||||||
|
if (timeout <= 9) {
|
||||||
|
timeout = 0;
|
||||||
|
} else {
|
||||||
|
timeout -= 2;
|
||||||
|
/* get bit position of highest bit set */
|
||||||
|
timeout = 31 - __CLZ(timeout);
|
||||||
|
/* need to go one over */
|
||||||
|
timeout += 1;
|
||||||
|
/* convert to wdog setting. if bit 4 is the highest, then the
|
||||||
|
* watchdog setting == 1. That means watchdog setting 0xF == 2^18 = 256k */
|
||||||
|
if (timeout > 18) {
|
||||||
|
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
WDOG_Init_TypeDef wdog_init = WDOG_INIT_DEFAULT;
|
||||||
|
wdog_init.clkSel = wdogClkSelULFRCO;
|
||||||
|
wdog_init.em2Run = true;
|
||||||
|
wdog_init.em3Run = true;
|
||||||
|
wdog_init.perSel = timeout;
|
||||||
|
|
||||||
|
WDOGn_Init(DEFAULT_WDOG, &wdog_init);
|
||||||
|
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_watchdog_kick(void)
|
||||||
|
{
|
||||||
|
WDOGn_Feed(DEFAULT_WDOG);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_status_t hal_watchdog_stop(void)
|
||||||
|
{
|
||||||
|
WDOGn_Enable(DEFAULT_WDOG, false);
|
||||||
|
return WATCHDOG_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_watchdog_get_reload_value(void)
|
||||||
|
{
|
||||||
|
uint32_t period = (DEFAULT_WDOG->CTRL & _WDOG_CTRL_PERSEL_MASK) >> _WDOG_CTRL_PERSEL_SHIFT;
|
||||||
|
if (period == 0) {
|
||||||
|
return 9;
|
||||||
|
} else {
|
||||||
|
period += 3;
|
||||||
|
return (1U << period) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||||
|
{
|
||||||
|
watchdog_features_t feat = {
|
||||||
|
.max_timeout = 262145,
|
||||||
|
.update_config = true,
|
||||||
|
.disable_watchdog = true
|
||||||
|
};
|
||||||
|
return feat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DEVICE_WATCHDOG */
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2017 All rights reserved
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#ifdef DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "TMPM066.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define MAXRSTREASON 6
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg);
|
||||||
|
static uint8_t bit_pos(uint32_t reg);
|
||||||
|
static bool bit_status(uint32_t reg, uint8_t bit_no);
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason1[MAXRSTREASON] = {
|
||||||
|
RESET_REASON_POWER_ON,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_PIN_RESET,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_BROWN_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason2[MAXRSTREASON] = {
|
||||||
|
RESET_REASON_SOFTWARE,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_WATCHDOG
|
||||||
|
};
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
TSB_AOREG->RSTFLG = 0x00;
|
||||||
|
TSB_AOREG->RSTFLG1 = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0x00;
|
||||||
|
|
||||||
|
ret = (((TSB_AOREG->RSTFLG1 & 0xFF) << 8) | (TSB_AOREG->RSTFLG & 0xFF));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
reset_reason_t ret;
|
||||||
|
|
||||||
|
uint8_t NoOfSetBitCountReg1 = set_bit_count(TSB_AOREG->RSTFLG);
|
||||||
|
uint8_t NoOfSetBitCountReg2 = set_bit_count(TSB_AOREG->RSTFLG1);
|
||||||
|
|
||||||
|
if (NoOfSetBitCountReg1 != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg1 > 0x01) {
|
||||||
|
if (bit_status(TSB_AOREG->RSTFLG, 0) && bit_status(TSB_AOREG->RSTFLG, 3)) {
|
||||||
|
ret = RESET_REASON_POWER_ON;
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = reset_reason1[bit_pos(TSB_AOREG->RSTFLG)];
|
||||||
|
}
|
||||||
|
} else if (NoOfSetBitCountReg2 != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg2 > 0x01) {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
} else {
|
||||||
|
ret = reset_reason2[bit_pos(TSB_AOREG->RSTFLG1)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bit_status(uint32_t reg, uint8_t bit_no)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
if (reg & (1 << bit_no)) {
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t count = 0;
|
||||||
|
int8_t index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < (sizeof(uint32_t) * 8); index++) {
|
||||||
|
if (reg & (1 << index)) {
|
||||||
|
count++;
|
||||||
|
if (count > 0x01) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t bit_pos(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t bit_no = 0;
|
||||||
|
|
||||||
|
for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) {
|
||||||
|
if (reg & (1 << bit_no)) {
|
||||||
|
return bit_no;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#ifdef DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "TMPM3H6.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg);
|
||||||
|
static uint8_t bit_pos(uint32_t reg);
|
||||||
|
static bool bit_status(uint32_t reg, uint8_t bit_no);
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason1[6] = {
|
||||||
|
RESET_REASON_POWER_ON,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_PIN_RESET,
|
||||||
|
RESET_REASON_WAKE_LOW_POWER,
|
||||||
|
RESET_REASON_BROWN_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason2[4] = {
|
||||||
|
RESET_REASON_SOFTWARE,
|
||||||
|
RESET_REASON_LOCKUP,
|
||||||
|
RESET_REASON_WATCHDOG,
|
||||||
|
RESET_REASON_PLATFORM
|
||||||
|
};
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
TSB_RLM->RSTFLG0 = 0;
|
||||||
|
TSB_RLM->RSTFLG1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
uint32_t ret = (((TSB_RLM->RSTFLG1 & 0xFF) << 8) | (TSB_RLM->RSTFLG0 & 0xFF));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
char multi_flag = 0;
|
||||||
|
reset_reason_t ret;
|
||||||
|
|
||||||
|
uint8_t NoOfSetBitCountReg1 = set_bit_count(TSB_RLM->RSTFLG0);
|
||||||
|
uint8_t NoOfSetBitCountReg2 = set_bit_count(TSB_RLM->RSTFLG1);
|
||||||
|
|
||||||
|
if (NoOfSetBitCountReg1 != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg1 > 0x01) {
|
||||||
|
if (bit_status(TSB_RLM->RSTFLG0, 3)) {
|
||||||
|
ret = RESET_REASON_POWER_ON;
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = reset_reason1[bit_pos(TSB_RLM->RSTFLG0)];
|
||||||
|
}
|
||||||
|
} else if (NoOfSetBitCountReg2 != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg2 > 0x01) {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
} else {
|
||||||
|
ret = reset_reason2[bit_pos(TSB_RLM->RSTFLG1)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bit_status(uint32_t reg, uint8_t bit_no)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
if (reg & (1 << bit_no)) {
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t count = 0;
|
||||||
|
int8_t index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < (sizeof(uint32_t) * 8); index++) {
|
||||||
|
if (reg & (1 << index)) {
|
||||||
|
count++;
|
||||||
|
if (count > 0x01) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t bit_pos(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t bit_no = 0;
|
||||||
|
|
||||||
|
for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) {
|
||||||
|
if (reg & (1 << bit_no)) {
|
||||||
|
return bit_no;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#ifdef DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "TMPM3HQ.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg);
|
||||||
|
static uint8_t bit_pos(uint32_t reg);
|
||||||
|
static bool bit_status(uint32_t reg, uint8_t bit_no);
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason1[6] = {
|
||||||
|
RESET_REASON_POWER_ON,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_PIN_RESET,
|
||||||
|
RESET_REASON_WAKE_LOW_POWER,
|
||||||
|
RESET_REASON_BROWN_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason2[4] = {
|
||||||
|
RESET_REASON_SOFTWARE,
|
||||||
|
RESET_REASON_LOCKUP,
|
||||||
|
RESET_REASON_WATCHDOG,
|
||||||
|
RESET_REASON_PLATFORM
|
||||||
|
};
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
TSB_RLM->RSTFLG0 = 0;
|
||||||
|
TSB_RLM->RSTFLG1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
uint32_t ret = (((TSB_RLM->RSTFLG1 & 0xFF) << 8) | (TSB_RLM->RSTFLG0 & 0xFF));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
char multi_flag = 0;
|
||||||
|
reset_reason_t ret;
|
||||||
|
|
||||||
|
uint8_t NoOfSetBitCountReg1 = set_bit_count(TSB_RLM->RSTFLG0);
|
||||||
|
uint8_t NoOfSetBitCountReg2 = set_bit_count(TSB_RLM->RSTFLG1);
|
||||||
|
|
||||||
|
if (NoOfSetBitCountReg1 != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg1 > 0x01) {
|
||||||
|
if (bit_status(TSB_RLM->RSTFLG0, 3)) {
|
||||||
|
ret = RESET_REASON_POWER_ON;
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = reset_reason1[bit_pos(TSB_RLM->RSTFLG0)];
|
||||||
|
}
|
||||||
|
} else if (NoOfSetBitCountReg2 != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg2 > 0x01) {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
} else {
|
||||||
|
ret = reset_reason2[bit_pos(TSB_RLM->RSTFLG1)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bit_status(uint32_t reg, uint8_t bit_no)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
if (reg & (1 << bit_no)) {
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t count = 0;
|
||||||
|
int8_t index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < (sizeof(uint32_t) * 8); index++) {
|
||||||
|
if (reg & (1 << index)) {
|
||||||
|
count++;
|
||||||
|
if (count > 0x01) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t bit_pos(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t bit_no = 0;
|
||||||
|
|
||||||
|
for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) {
|
||||||
|
if (reg & (1 << bit_no)) {
|
||||||
|
return bit_no;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#ifdef DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "TMPM46B.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg);
|
||||||
|
static uint8_t bit_pos(uint32_t reg);
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason[7] = {
|
||||||
|
RESET_REASON_PIN_RESET,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_WATCHDOG,
|
||||||
|
RESET_REASON_WAKE_LOW_POWER,
|
||||||
|
RESET_REASON_SOFTWARE,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_BROWN_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
TSB_CG->RSTFLG = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
ret = TSB_CG->RSTFLG;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
reset_reason_t ret;
|
||||||
|
|
||||||
|
uint8_t NoOfSetBitCountReg = set_bit_count(TSB_CG->RSTFLG);
|
||||||
|
|
||||||
|
if (NoOfSetBitCountReg != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg > 0x01) {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
} else {
|
||||||
|
ret = reset_reason[bit_pos(TSB_CG->RSTFLG)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t count = 0;
|
||||||
|
int8_t index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < (sizeof(uint32_t) * 8); index++) {
|
||||||
|
if ((reg & (1 << index)) && index != 1) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t bit_pos(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t bit_no = 0;
|
||||||
|
|
||||||
|
for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) {
|
||||||
|
if ((reg & (1 << bit_no)) && bit_no != 1) {
|
||||||
|
return bit_no;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved
|
||||||
|
*
|
||||||
|
* 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 "reset_reason_api.h"
|
||||||
|
|
||||||
|
#ifdef DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#include "TMPM4G9.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg);
|
||||||
|
static uint8_t bit_pos(uint32_t reg);
|
||||||
|
static bool bit_status(uint32_t reg, uint8_t bit_no);
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason1[6] = {
|
||||||
|
RESET_REASON_POWER_ON,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_UNKNOWN,
|
||||||
|
RESET_REASON_PIN_RESET,
|
||||||
|
RESET_REASON_WAKE_LOW_POWER,
|
||||||
|
RESET_REASON_BROWN_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
static reset_reason_t reset_reason2[4] = {
|
||||||
|
RESET_REASON_SOFTWARE,
|
||||||
|
RESET_REASON_LOCKUP,
|
||||||
|
RESET_REASON_WATCHDOG,
|
||||||
|
RESET_REASON_PLATFORM
|
||||||
|
};
|
||||||
|
|
||||||
|
void hal_reset_reason_clear(void)
|
||||||
|
{
|
||||||
|
TSB_RLM->RSTFLG0 = 0;
|
||||||
|
TSB_RLM->RSTFLG1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hal_reset_reason_get_raw(void)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
ret = (((TSB_RLM->RSTFLG1 & 0xFF) << 8) | (TSB_RLM->RSTFLG0 & 0xFF));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_reason_t hal_reset_reason_get(void)
|
||||||
|
{
|
||||||
|
char multi_flag = 0;
|
||||||
|
reset_reason_t ret;
|
||||||
|
|
||||||
|
uint8_t NoOfSetBitCountReg1 = set_bit_count(TSB_RLM->RSTFLG0);
|
||||||
|
uint8_t NoOfSetBitCountReg2 = set_bit_count(TSB_RLM->RSTFLG1);
|
||||||
|
|
||||||
|
if (NoOfSetBitCountReg1 != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg1 > 0x01) {
|
||||||
|
if (bit_status(TSB_RLM->RSTFLG0, 3)) {
|
||||||
|
ret = RESET_REASON_POWER_ON;
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = reset_reason1[bit_pos(TSB_RLM->RSTFLG0)];
|
||||||
|
}
|
||||||
|
} else if (NoOfSetBitCountReg2 != 0x00) {
|
||||||
|
if (NoOfSetBitCountReg2 > 0x01) {
|
||||||
|
ret = RESET_REASON_MULTIPLE;
|
||||||
|
} else {
|
||||||
|
ret = reset_reason2[bit_pos(TSB_RLM->RSTFLG1)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = RESET_REASON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bit_status(uint32_t reg, uint8_t bit_no)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
if (reg & (1 << bit_no)) {
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t set_bit_count(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t count = 0;
|
||||||
|
int8_t index = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < (sizeof(uint32_t) * 8); index++) {
|
||||||
|
if (reg & (1 << index)) {
|
||||||
|
count++;
|
||||||
|
if (count > 0x01) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t bit_pos(uint32_t reg)
|
||||||
|
{
|
||||||
|
uint8_t bit_no = 0;
|
||||||
|
|
||||||
|
for (bit_no = 0; bit_no < (sizeof(uint32_t) * 8); bit_no++) {
|
||||||
|
if (reg & (1 << bit_no)) {
|
||||||
|
return bit_no;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_RESET_REASON
|
|
@ -1507,6 +1507,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_FC",
|
"SERIAL_FC",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -1517,7 +1518,8 @@
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"TRNG",
|
"TRNG",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"USBDEVICE"
|
"USBDEVICE",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"release_versions": ["2", "5"],
|
"release_versions": ["2", "5"],
|
||||||
"device_name": "MK64FN1M0xxx12",
|
"device_name": "MK64FN1M0xxx12",
|
||||||
|
@ -1659,6 +1661,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
"SERIAL_FC",
|
"SERIAL_FC",
|
||||||
|
@ -1668,7 +1671,8 @@
|
||||||
"SPISLAVE",
|
"SPISLAVE",
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"TRNG",
|
"TRNG",
|
||||||
"FLASH"
|
"FLASH",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"default_lib": "std",
|
"default_lib": "std",
|
||||||
"release_versions": ["2", "5"],
|
"release_versions": ["2", "5"],
|
||||||
|
@ -1910,7 +1914,9 @@
|
||||||
"SPI",
|
"SPI",
|
||||||
"SPISLAVE",
|
"SPISLAVE",
|
||||||
"SPI_ASYNCH",
|
"SPI_ASYNCH",
|
||||||
"STDIO_MESSAGES"
|
"STDIO_MESSAGES",
|
||||||
|
"WATCHDOG",
|
||||||
|
"RESET_REASON"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"MIMXRT1050_EVK": {
|
"MIMXRT1050_EVK": {
|
||||||
|
@ -3220,7 +3226,8 @@
|
||||||
],
|
],
|
||||||
"release_versions": ["2", "5"],
|
"release_versions": ["2", "5"],
|
||||||
"device_name": "STM32H743ZI",
|
"device_name": "STM32H743ZI",
|
||||||
"bootloader_supported": true
|
"bootloader_supported": true,
|
||||||
|
"device_has_remove": ["WATCHDOG"]
|
||||||
},
|
},
|
||||||
"NUCLEO_H743ZI2": {
|
"NUCLEO_H743ZI2": {
|
||||||
"inherits": ["NUCLEO_H743ZI"],
|
"inherits": ["NUCLEO_H743ZI"],
|
||||||
|
@ -5831,6 +5838,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"RTC",
|
"RTC",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -5842,7 +5850,8 @@
|
||||||
"USTICKER",
|
"USTICKER",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"ITM",
|
"ITM",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 2,
|
"forced_reset_timeout": 2,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -5908,6 +5917,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"RTC",
|
"RTC",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -5918,7 +5928,8 @@
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"USTICKER",
|
"USTICKER",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 2,
|
"forced_reset_timeout": 2,
|
||||||
"device_name": "EFM32LG990F256",
|
"device_name": "EFM32LG990F256",
|
||||||
|
@ -5986,6 +5997,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"RTC",
|
"RTC",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -5996,7 +6008,8 @@
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"USTICKER",
|
"USTICKER",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 2,
|
"forced_reset_timeout": 2,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -6062,6 +6075,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
"SLEEP",
|
"SLEEP",
|
||||||
|
@ -6069,7 +6083,8 @@
|
||||||
"SPISLAVE",
|
"SPISLAVE",
|
||||||
"SPI_ASYNCH",
|
"SPI_ASYNCH",
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"USTICKER"
|
"USTICKER",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 2,
|
"forced_reset_timeout": 2,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -6135,6 +6150,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
"SLEEP",
|
"SLEEP",
|
||||||
|
@ -6142,7 +6158,8 @@
|
||||||
"SPISLAVE",
|
"SPISLAVE",
|
||||||
"SPI_ASYNCH",
|
"SPI_ASYNCH",
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"USTICKER"
|
"USTICKER",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 2,
|
"forced_reset_timeout": 2,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -6208,6 +6225,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"RTC",
|
"RTC",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -6218,7 +6236,8 @@
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"USTICKER",
|
"USTICKER",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 2,
|
"forced_reset_timeout": 2,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -6307,6 +6326,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"RTC",
|
"RTC",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -6317,7 +6337,8 @@
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"USTICKER",
|
"USTICKER",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 2,
|
"forced_reset_timeout": 2,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -6377,6 +6398,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"RTC",
|
"RTC",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -6387,7 +6409,8 @@
|
||||||
"STDIO_MESSAGES",
|
"STDIO_MESSAGES",
|
||||||
"USTICKER",
|
"USTICKER",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 5,
|
"forced_reset_timeout": 5,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -6454,6 +6477,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"RTC",
|
"RTC",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -6465,7 +6489,8 @@
|
||||||
"USTICKER",
|
"USTICKER",
|
||||||
"TRNG",
|
"TRNG",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 2,
|
"forced_reset_timeout": 2,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -6542,6 +6567,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"RTC",
|
"RTC",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
|
@ -6553,7 +6579,8 @@
|
||||||
"USTICKER",
|
"USTICKER",
|
||||||
"TRNG",
|
"TRNG",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"forced_reset_timeout": 5,
|
"forced_reset_timeout": 5,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -6783,6 +6810,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_ASYNCH",
|
"SERIAL_ASYNCH",
|
||||||
"SERIAL_FC",
|
"SERIAL_FC",
|
||||||
|
@ -7405,7 +7433,8 @@
|
||||||
"CAN",
|
"CAN",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"EMAC",
|
"EMAC",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG"
|
||||||
],
|
],
|
||||||
"release_versions": ["5"],
|
"release_versions": ["5"],
|
||||||
"device_name": "NUC472HI8AE",
|
"device_name": "NUC472HI8AE",
|
||||||
|
@ -7470,6 +7499,7 @@
|
||||||
"SPI",
|
"SPI",
|
||||||
"TRNG",
|
"TRNG",
|
||||||
"SPISLAVE",
|
"SPISLAVE",
|
||||||
|
"WATCHDOG",
|
||||||
"802_15_4_PHY",
|
"802_15_4_PHY",
|
||||||
"MPU",
|
"MPU",
|
||||||
"USTICKER"
|
"USTICKER"
|
||||||
|
@ -7532,7 +7562,9 @@
|
||||||
"SPI_ASYNCH",
|
"SPI_ASYNCH",
|
||||||
"CAN",
|
"CAN",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG",
|
||||||
|
"RESET_REASON"
|
||||||
],
|
],
|
||||||
"components_add": ["FLASHIAP"],
|
"components_add": ["FLASHIAP"],
|
||||||
"release_versions": ["2", "5"],
|
"release_versions": ["2", "5"],
|
||||||
|
@ -7599,7 +7631,9 @@
|
||||||
"SLEEP",
|
"SLEEP",
|
||||||
"SPI",
|
"SPI",
|
||||||
"SPISLAVE",
|
"SPISLAVE",
|
||||||
"SPI_ASYNCH"
|
"SPI_ASYNCH",
|
||||||
|
"WATCHDOG",
|
||||||
|
"RESET_REASON"
|
||||||
],
|
],
|
||||||
"release_versions": ["5"],
|
"release_versions": ["5"],
|
||||||
"device_name": "NANO130KE3BN",
|
"device_name": "NANO130KE3BN",
|
||||||
|
@ -7957,7 +7991,9 @@
|
||||||
"FLASH",
|
"FLASH",
|
||||||
"CAN",
|
"CAN",
|
||||||
"EMAC",
|
"EMAC",
|
||||||
"MPU"
|
"MPU",
|
||||||
|
"WATCHDOG",
|
||||||
|
"RESET_REASON"
|
||||||
],
|
],
|
||||||
"release_versions": ["5"],
|
"release_versions": ["5"],
|
||||||
"bootloader_supported": true,
|
"bootloader_supported": true,
|
||||||
|
@ -7994,6 +8030,7 @@
|
||||||
"PORTIN",
|
"PORTIN",
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SLEEP",
|
"SLEEP",
|
||||||
"I2C",
|
"I2C",
|
||||||
|
@ -8057,6 +8094,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SERIAL_FC",
|
"SERIAL_FC",
|
||||||
"SPI",
|
"SPI",
|
||||||
|
@ -8228,6 +8266,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SLEEP",
|
"SLEEP",
|
||||||
"SPI",
|
"SPI",
|
||||||
|
@ -8255,6 +8294,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SPI",
|
"SPI",
|
||||||
"I2C",
|
"I2C",
|
||||||
|
@ -8542,6 +8582,7 @@
|
||||||
"PORTINOUT",
|
"PORTINOUT",
|
||||||
"PORTOUT",
|
"PORTOUT",
|
||||||
"PWMOUT",
|
"PWMOUT",
|
||||||
|
"RESET_REASON",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
"SLEEP",
|
"SLEEP",
|
||||||
"SPI",
|
"SPI",
|
||||||
|
@ -8725,7 +8766,6 @@
|
||||||
"macros": ["__TT_M4G9__"],
|
"macros": ["__TT_M4G9__"],
|
||||||
"supported_toolchains": ["GCC_ARM", "ARM", "IAR"],
|
"supported_toolchains": ["GCC_ARM", "ARM", "IAR"],
|
||||||
"device_has": ["USTICKER",
|
"device_has": ["USTICKER",
|
||||||
"RESET_REASON",
|
|
||||||
"ANALOGIN",
|
"ANALOGIN",
|
||||||
"ANALOGOUT",
|
"ANALOGOUT",
|
||||||
"SERIAL",
|
"SERIAL",
|
||||||
|
|
Loading…
Reference in New Issue