Merge pull request #10857 from ARMmbed/feature-watchdog

Add Watchdog and ResetReason
pull/10873/head
Martin Kojtal 2019-07-03 11:43:52 +01:00 committed by GitHub
commit ccb63d771e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 6278 additions and 56 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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.
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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(&current_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(&current_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(&current_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(&current_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(&current_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);
}

View File

@ -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.
}

View File

@ -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
/** @}*/

View File

@ -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);
}

View File

@ -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
/** @}*/

View File

@ -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(&current_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(&current_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(&current_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(&current_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(&current_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);
}

View File

@ -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
/** @}*/

View File

@ -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);
}

View File

@ -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
/** @}*/

View File

@ -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"

View File

@ -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());
}

View File

@ -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")

View File

@ -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
) )

View File

@ -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
) )

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
/**@}*/
/**@}*/

View File

@ -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

View File

@ -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" \

View File

@ -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",

47
drivers/ResetReason.cpp Normal file
View File

@ -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

77
drivers/ResetReason.h Normal file
View File

@ -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

103
drivers/Watchdog.cpp Normal file
View File

@ -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

135
drivers/Watchdog.h Normal file
View File

@ -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

150
hal/reset_reason_api.h Normal file
View File

@ -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
/** @}*/

178
hal/watchdog_api.h Normal file
View File

@ -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
View File

@ -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"

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
/** /**
* @} * @}
*/ */

View File

@ -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
/** /**
* @} * @}
*/ */

View File

@ -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
/** /**
* @} * @}
*/ */

View File

@ -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
/** /**
* @} * @}
*/ */

View File

@ -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
/** /**
* @} * @}
*/ */

View File

@ -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
/** /**
* @} * @}
*/ */

View File

@ -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.*/

View File

@ -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
/** /**
* @} * @}
*/ */

View File

@ -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.*/

View File

@ -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
/** /**
* @} * @}
*/ */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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",