diff --git a/babblesim/.gitignore b/babblesim/.gitignore new file mode 100644 index 000000000..78e34f10a --- /dev/null +++ b/babblesim/.gitignore @@ -0,0 +1,3 @@ +hw/babblesim/components +hw/babblesim/src +nrfx/src \ No newline at end of file diff --git a/babblesim/README.md b/babblesim/README.md new file mode 100644 index 000000000..c9ba3ef37 --- /dev/null +++ b/babblesim/README.md @@ -0,0 +1 @@ +BabbleSim support for Apache NimBLE diff --git a/babblesim/core/include/argparse.h b/babblesim/core/include/argparse.h new file mode 100644 index 000000000..7f98b0282 --- /dev/null +++ b/babblesim/core/include/argparse.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef BSIM_NRF_ARGS_H +#define BSIM_NRF_ARGS_H + +#include +#include "NRF_hw_args.h" +#include "bs_cmd_line.h" +#include "bs_cmd_line_typical.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct nrf52_bsim_args_t { + BS_BASIC_DEVICE_OPTIONS_FIELDS + nrf_hw_sub_args_t nrf_hw; +}; + +struct nrf52_bsim_args_t *nrfbsim_argsparse(int argc, char *argv[]); +void nrfbsim_register_args(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/babblesim/core/include/cmsis.h b/babblesim/core/include/cmsis.h new file mode 100644 index 000000000..8f9a6a3d4 --- /dev/null +++ b/babblesim/core/include/cmsis.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This header defines replacements for inline + * ARM Cortex-M CMSIS intrinsics. + */ + +#ifndef BOARDS_POSIX_NRF52_BSIM_CMSIS_H +#define BOARDS_POSIX_NRF52_BSIM_CMSIS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Implement the following ARM intrinsics as no-op: + * - ARM Data Synchronization Barrier + * - ARM Data Memory Synchronization Barrier + * - ARM Instruction Synchronization Barrier + * - ARM No Operation + */ +#ifndef __DMB +#define __DMB() +#endif + +#ifndef __DSB +#define __DSB() +#endif + +#ifndef __ISB +#define __ISB() +#endif + +#ifndef __NOP +#define __NOP() +#endif + +void NVIC_SystemReset(void); +void __disable_irq(void); +void __enable_irq(void); +uint32_t __get_PRIMASK(void); + +#ifdef __cplusplus +} +#endif + +#endif /* BOARDS_POSIX_NRF52_BSIM_CMSIS_H */ diff --git a/babblesim/core/include/core_cm4.h b/babblesim/core/include/core_cm4.h new file mode 100644 index 000000000..ef8f9c3fb --- /dev/null +++ b/babblesim/core/include/core_cm4.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BSIM_CORE_CM4_H +#define _BSIM_CORE_CM4_H + +#include + +/* Include the original ext_NRF52_hw_models core_cm4.h */ +#include <../HW_models/core_cm4.h> + +/* Add missing function definitions */ +extern void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority); +extern void NVIC_EnableIRQ(IRQn_Type IRQn); +extern void NVIC_DisableIRQ(IRQn_Type IRQn); + +void __WFI(void); + +#ifndef __REV +#define __REV __builtin_bswap32 +#endif + +#endif diff --git a/babblesim/core/include/time_machine.h b/babblesim/core/include/time_machine.h new file mode 100644 index 000000000..da28d0139 --- /dev/null +++ b/babblesim/core/include/time_machine.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _TIME_MACHINE_H +#define _TIME_MACHINE_H + +#include "bs_types.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +extern bs_time_t now; +bs_time_t tm_get_abs_time(void); +bs_time_t tm_get_hw_time(void); +bs_time_t tm_hw_time_to_abs_time(bs_time_t hwtime); +bs_time_t tm_abs_time_to_hw_time(bs_time_t abstime); + +void tm_reset_hw_times(void); + +void tm_find_next_timer_to_trigger(void); +bs_time_t tm_get_next_timer_abstime(void); + +void tm_update_last_phy_sync_time(bs_time_t abs_time); + +void tm_set_phy_max_resync_offset(bs_time_t offset_in_us); + +void tm_run_forever(void); + +void tm_sleep_until_hw_time(bs_time_t hw_time); + +void tm_sleep_until_abs_time(bs_time_t time); + +void tm_start(void); + +void tm_tick(void); + +void tm_tick_limited(bs_time_t max_time_diff); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/babblesim/core/pkg.yml b/babblesim/core/pkg.yml new file mode 100644 index 000000000..3b0c2e9a6 --- /dev/null +++ b/babblesim/core/pkg.yml @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: babblesim/core +pkg.type: sdk +pkg.description: time machine, irq handeler, core +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-nimble/nimble/controller" + - "@apache-mynewt-nimble/nimble/transport" + - "babblesim/hw/babblesim" + +pkg.req_apis: + - ble_transport + +pkg.init: + bsim_start: 9999 diff --git a/babblesim/core/src/argparse.c b/babblesim/core/src/argparse.c new file mode 100644 index 000000000..68f13de43 --- /dev/null +++ b/babblesim/core/src/argparse.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "bs_tracing.h" +#include "bs_oswrap.h" +#include "bs_dump_files.h" +#include "argparse.h" +#include "NRF_hw_args.h" +#include "bs_cmd_line.h" +#include "bs_dynargs.h" +#include "bs_cmd_line_typical.h" +#include "NRF_HWLowL.h" + +static bs_args_struct_t *args_struct; +static struct nrf52_bsim_args_t arg; +const char *bogus_sim_id = "bogus"; + +static void cmd_trace_lvl_found(char *argv, int offset) +{ + bs_trace_set_level(arg.verb); +} + +static void cmd_gdev_nbr_found(char *argv, int offset) +{ + bs_trace_set_prefix_dev(arg.global_device_nbr); +} + +static bool nosim; +static void cmd_nosim_found(char *argv, int offset) +{ + hwll_set_nosim(true); +} + +static void print_no_sim_warning(void) +{ + bs_trace_warning("Neither simulation id or the device number " + "have been set. I assume you want to run " + "without a BabbleSim phy (-nosim)\n"); + bs_trace_warning("If this is not what you wanted, check with " + "--help how to set them\n"); + bs_trace_raw(3, "setting sim_id to 'bogus', device number to 0 " + "and nosim\n"); +} + +void nrfbsim_register_args(void) +{ +#define args (&arg) + /* This define is quite ugly, but allows reusing the definitions + * provided by the utils library */ + static bs_args_struct_t args_struct_toadd[] = { + ARG_TABLE_S_ID, + ARG_TABLE_P_ID_2G4, + ARG_TABLE_DEV_NBR, + ARG_TABLE_GDEV_NBR, + ARG_TABLE_VERB, + ARG_TABLE_SEED, + ARG_TABLE_COLOR, + ARG_TABLE_NOCOLOR, + ARG_TABLE_FORCECOLOR, + _NRF_HW_SUB_CMD_ARG_STRUCT, + /* + * Fields: + * manual, mandatory, switch, + * option_name, var_name, type, + * destination, callback, + * description + */ + {false, false, true, + "nosim", "", 'b', + (void *)&nosim, cmd_nosim_found, + "(debug feature) Do not connect to the phy"}, + BS_DUMP_FILES_ARGS, + {true, false, false, + "argsmain", "arg", 'l', + NULL, NULL, + "The arguments that follow will be passed to main (default)"}, + ARG_TABLE_ENDMARKER + }; +#undef args + + bs_add_dynargs(&args_struct, args_struct_toadd); +} + +/** + * Check the arguments provided in the command line: set args based on it or + * defaults, and check they are correct + */ +struct nrf52_bsim_args_t *nrfbsim_argsparse(int argc, char *argv[]) +{ + bs_args_set_defaults(args_struct); + arg.verb = 2; + bs_trace_set_level(arg.verb); + nrf_hw_sub_cmline_set_defaults(&arg.nrf_hw); + static const char default_phy[] = "2G4"; + + for (int i = 1; i < argc; i++) { + if (bs_is_option(argv[i], "argsmain", 0)) { + continue; + } + + if (!bs_args_parse_one_arg(argv[i], args_struct)) { + bs_args_print_switches_help(args_struct); + bs_trace_error_line("Incorrect option %s\n", + argv[i]); + } + } + + /** + * If the user did not set the simulation id or device number + * we assume he wanted to run with nosim (but warn him) + */ + if ((!nosim) && (arg.s_id == NULL) && (arg.device_nbr == UINT_MAX)) { + print_no_sim_warning(); + nosim = true; + hwll_set_nosim(true); + } + if (nosim) { + if (arg.s_id == NULL) { + arg.s_id = (char *)bogus_sim_id; + } + if (arg.device_nbr == UINT_MAX) { + arg.device_nbr = 0; + } + } + + if (arg.device_nbr == UINT_MAX) { + bs_args_print_switches_help(args_struct); + bs_trace_error_line("The command line option " + "needs to be set\n"); + } + if (arg.global_device_nbr == UINT_MAX) { + arg.global_device_nbr = arg.device_nbr; + bs_trace_set_prefix_dev(arg.global_device_nbr); + } + if (!arg.s_id) { + bs_args_print_switches_help(args_struct); + bs_trace_error_line("The command line option " + "needs to be set\n"); + } + if (!arg.p_id) { + arg.p_id = (char *)default_phy; + } + + if (arg.rseed == UINT_MAX) { + arg.rseed = 0x1000 + arg.device_nbr; + } + return &arg; +} diff --git a/babblesim/core/src/cmsis.c b/babblesim/core/src/cmsis.c new file mode 100644 index 000000000..622676c88 --- /dev/null +++ b/babblesim/core/src/cmsis.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * Copyright (c) 2020 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "irq_ctrl.h" + +#include "irq_sources.h" +#include +#include "cmsis.h" +#include "os/sim.h" + +#include +#include +#include +#include "irq_sources.h" +#include +#include "cmsis.h" + +extern void (* systemVectors[256])(void); + +/* + * Replacement for ARMs NVIC functions() + */ +void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + hw_irq_ctrl_raise_im_from_sw(IRQn); +} + +void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + hw_irq_ctrl_clear_irq(IRQn); +} + +void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + hw_irq_ctrl_disable_irq(IRQn); +} + +void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + hw_irq_ctrl_enable_irq(IRQn); +} + +void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + hw_irq_ctrl_prio_set(IRQn, priority); +} + +uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + return hw_irq_ctrl_get_prio(IRQn); +} + +void NVIC_SystemReset(void) +{ + inner_main_clean_up(1); +} + +/* + * Replacements for some other CMSIS functions + */ +void __enable_irq(void) +{ + hw_irq_ctrl_change_lock(false); +} + +void __disable_irq(void) +{ + hw_irq_ctrl_change_lock(true); +} + +uint32_t __get_PRIMASK(void) +{ + return hw_irq_ctrl_get_current_lock(); +} + +void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + systemVectors[(int32_t)IRQn + 16] = (void(*)(void))vector; +} diff --git a/babblesim/core/src/irq_handler.c b/babblesim/core/src/irq_handler.c new file mode 100644 index 000000000..805d7ecdc --- /dev/null +++ b/babblesim/core/src/irq_handler.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + * + * SW side of the IRQ handling + */ + +#include +#include "irq_ctrl.h" +#include "irq_sources.h" +#include "os/sim.h" + +static int currently_running_irq = -1; +extern void (* const systemVectors[256])(void); + +/** + * When an interrupt is raised, this function is called to handle it and, if + * needed, swap to a re-enabled thread + * + * Note that even that this function is executing in a Zephyr thread, it is + * effectively the model of the interrupt controller passing context to the IRQ + * handler and therefore its priority handling + */ + +void posix_interrupt_raised(void) +{ + uint64_t irq_lock; + int irq_nbr; + + irq_lock = hw_irq_ctrl_get_current_lock(); + + if (irq_lock) { + /* "spurious" wakes can happen with interrupts locked */ + return; + } + + while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1) { + int last_current_running_prio = hw_irq_ctrl_get_cur_prio(); + int last_running_irq = currently_running_irq; + + hw_irq_ctrl_set_cur_prio(hw_irq_ctrl_get_prio(irq_nbr)); + hw_irq_ctrl_clear_irq(irq_nbr); + + currently_running_irq = irq_nbr; + systemVectors[irq_nbr + 16](); + currently_running_irq = last_running_irq; + + hw_irq_ctrl_set_cur_prio(last_current_running_prio); + } +} + +/** + * Thru this function the IRQ controller can raise an immediate interrupt which + * will interrupt the SW itself + * (this function should only be called from the HW model code, from SW threads) + */ +void posix_irq_handler_im_from_sw(void) +{ + int sr = 0; + + sr = sig_block_irq_on(); + /* + * if a higher priority interrupt than the possibly currently running is + * pending we go immediately into irq_handler() to vector into its + * handler + */ + if (hw_irq_ctrl_get_highest_prio_irq() != -1) { + posix_interrupt_raised(); + } + if (sr) { + sig_unblock_irq_off(); + } +} diff --git a/babblesim/core/src/main_config.c b/babblesim/core/src/main_config.c new file mode 100644 index 000000000..4116e0797 --- /dev/null +++ b/babblesim/core/src/main_config.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017-2018 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "NRF_HW_model_top.h" +#include "NRF_HWLowL.h" +#include "bs_tracing.h" +#include "bs_symbols.h" +#include "bs_types.h" +#include "bs_rand_main.h" +#include "bs_pc_backchannel.h" +#include "bs_dump_files.h" +#include "argparse.h" +#include "time_machine.h" +#include "os/mynewt.h" +#include +#include "os/sim.h" + +uint global_device_nbr; +struct nrf52_bsim_args_t *args; + +void +bst_tick(bs_time_t time) +{ + return; +} + +uint8_t +inner_main_clean_up(int exit_code) +{ + hwll_terminate_simulation(); + nrf_hw_models_free_all(); + bs_dump_files_close_all(); + + bs_clean_back_channels(); + return 0; +} + +uint8_t +main_clean_up_trace_wrap(void) +{ + return inner_main_clean_up(0); +} + +void +bsim_init(int argc, char** argv, int (*main_fn)(int argc, char **arg)) +{ + setvbuf(stdout, NULL, _IOLBF, 512); + setvbuf(stderr, NULL, _IOLBF, 512); + + bs_trace_register_cleanup_function(main_clean_up_trace_wrap); + bs_trace_register_time_function(tm_get_abs_time); + + nrf_hw_pre_init(); + nrfbsim_register_args(); + + args = nrfbsim_argsparse(argc, argv); + global_device_nbr = args->global_device_nbr; + + bs_read_function_names_from_Tsymbols(argv[0]); + + nrf_hw_initialize(&args->nrf_hw); + os_init(main_fn); + os_start(); +} + +void +bsim_start(void) +{ + bs_trace_raw(9, "%s: Connecting to phy...\n", __func__); + hwll_connect_to_phy(args->device_nbr, args->s_id, args->p_id); + bs_trace_raw(9, "%s: Connected\n", __func__); + + bs_random_init(args->rseed); + bs_dump_files_open(args->s_id, args->global_device_nbr); +} diff --git a/babblesim/core/src/time_machine.c b/babblesim/core/src/time_machine.c new file mode 100644 index 000000000..38b3f424a --- /dev/null +++ b/babblesim/core/src/time_machine.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2017-2018 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "NRF_HW_model_top.h" +#include "NRF_HWLowL.h" +#include "bs_tracing.h" +#include "bs_types.h" +#include "bs_utils.h" +#include +#include +#include +#include +#include + +/* Note: All timers are relative to hw_time and NOT to 'now' */ +extern bs_time_t timer_nrf_main_timer; + +/* The events priorities are as in this list from top to bottom + * Priority being which timer executes first if several trigger at the same + * instant + */ +static enum { + NRF_HW_MAIN_TIMER = 0, + NUMBER_OF_TIMERS, + NONE +} next_timer_index = NONE; + +static bs_time_t *Timer_list[NUMBER_OF_TIMERS] = { + &timer_nrf_main_timer, +}; +static bs_time_t next_timer_time = TIME_NEVER; + +/* + * Current absolute time of this device, as the device knows it. + * It is never reset: + */ +bs_time_t now; +/* Current time the HW of this device things it is */ +static bs_time_t hw_time; +/* + * Offset between the current absolute time of the device and the HW time + * That is, the absolute time when the HW_time got reset + */ +static bs_time_t hw_time_delta; + +/* Last time we synchronized with the bsim PHY, in device abs time */ +static bs_time_t last_bsim_phy_sync_time; + +#define BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET 1000000 +/* At least every second we will inform the simulator about our timing */ +static bs_time_t max_resync_offset = BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET; + +/** + * Set the maximum amount of time the device will spend without talking + * (synching) with the phy. + * This does not change the functional behavior of the Zephyr code or of the + * radio emulation, and it is only relevant if special test code running in the + * device interacts behind the scenes with other devices test code. + * Setting for example a value of 5ms will ensure that this device time + * will never be more than 5ms away from the phy. Setting it in all devices + * to 5ms would then ensure no device time is farther apart than 5ms from any + * other. + * + * Note that setting low values has a performance penalty. + */ +void +tm_set_phy_max_resync_offset(bs_time_t offset_in_us) +{ + max_resync_offset = offset_in_us; +} + +/** + * Return the absolute current time (no HW model except the RADIO + * should look into this) + */ +bs_time_t +tm_get_abs_time(void) +{ + return now; +} + +/** + * Return the current HW time + */ +bs_time_t +tm_get_hw_time(void) +{ + return hw_time; +} + +bs_time_t +posix_get_hw_cycle(void) +{ + return tm_get_hw_time(); +} + +/** + * Reset the HW time + */ +static void +tm_reset_hw_time(void) +{ + hw_time = 0; + hw_time_delta = now; + if (now != 0) { + bs_trace_error_line("Reset not supposed to happen after " + "initialization\n"); + } +} + +/** + * Update the current hw_time value given the absolute time + */ +INLINE void +tm_update_HW_time(void) +{ + hw_time = now - hw_time_delta; +} + +/* + * Reset the HW time + */ +void +tm_reset_hw_times(void) +{ + tm_reset_hw_time(); +} + +/** + * Advance the internal time values of this device until time + */ +void +tm_sleep_until_abs_time(bs_time_t time) +{ + if (time >= now) { + /* + * Ensure that at least we sync with the phy + * every max_resync_offset + */ + if (time > last_bsim_phy_sync_time + max_resync_offset) { + hwll_sync_time_with_phy(time); + last_bsim_phy_sync_time = time; + } + + now = time; + } else { + /* LCOV_EXCL_START */ + bs_trace_warning_manual_time_line(now, "next_time_time " + "corrupted (%"PRItime"<= %"PRItime", timer idx=%i)\n", + time, now, next_timer_index); + /* LCOV_EXCL_STOP */ + } + tm_update_HW_time(); +} + +/** + * Keep track of the last time we synchronized the time with the scheduler + */ +void +tm_update_last_phy_sync_time(bs_time_t abs_time) +{ + last_bsim_phy_sync_time = abs_time; +} + +/** + * Advance the internal time values of this device + * until the HW time reaches hw_time + */ +void +tm_sleep_until_hw_time(bs_time_t hw_time) +{ + bs_time_t next_time = TIME_NEVER; + + if (hw_time != TIME_NEVER) { + next_time = hw_time + hw_time_delta; + } + + tm_sleep_until_abs_time(next_time); +} + +/** + * Look into all timers and update next_timer accordingly + * To be called each time a "timed process" updates its timer + */ +void +tm_find_next_timer_to_trigger(void) +{ + next_timer_time = *Timer_list[0]; + next_timer_index = 0; + + for (uint i = 1; i < NUMBER_OF_TIMERS; i++) { + if (next_timer_time > *Timer_list[i]) { + next_timer_time = *Timer_list[i]; + next_timer_index = i; + } + } +} + +bs_time_t +tm_get_next_timer_abstime(void) +{ + return next_timer_time + hw_time_delta; +} + +bs_time_t +tm_hw_time_to_abs_time(bs_time_t hwtime) +{ + if (hwtime == TIME_NEVER) { + return TIME_NEVER; + } + return hwtime + hw_time_delta; +} + +bs_time_t +tm_abs_time_to_hw_time(bs_time_t abstime) +{ + if (abstime == TIME_NEVER) { + return TIME_NEVER; + } + return abstime - hw_time_delta; +} + +void +tm_tick_limited(bs_time_t max_time_diff) +{ + bs_time_t time_to_wait; + + if (max_time_diff != TIME_NEVER && now + max_time_diff < next_timer_time) { + time_to_wait = now + max_time_diff; + } else { + time_to_wait = next_timer_time; + } + + tm_sleep_until_hw_time(time_to_wait); + switch (next_timer_index) { + case NRF_HW_MAIN_TIMER: + nrf_hw_some_timer_reached(); + break; + default: + bs_trace_error_time_line("next_timer_index " + "corrupted\n"); + break; + } + tm_find_next_timer_to_trigger(); +} + +void +tm_tick(void) +{ + tm_tick_limited(TIME_NEVER); +} diff --git a/babblesim/hw/babblesim/pkg.yml b/babblesim/hw/babblesim/pkg.yml new file mode 100644 index 000000000..ad28efbcb --- /dev/null +++ b/babblesim/hw/babblesim/pkg.yml @@ -0,0 +1,44 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: babblesim/hw/babblesim +pkg.description: BabbleSim stuff +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" + +pkg.type: sdk + +pkg.include_dirs: + - components/ext_NRF52_hw_models/src/nrfx/mdk_replacements + - components/ext_NRF52_hw_models/src/HW_models + - components/ext_NRF52_hw_models/src/nrfx_config + - components/ext_NRF52_hw_models/src/nrfx/nrfx_replacements + - components/libUtilv1/src/ + - components/libPhyComv1/src/ + - components/libRandv2/src/ + - components/ext_libCryptov1/src/ + +pkg.src_dirs: + - src + +pkg.pre_build_cmds: + scripts/pre_build1.sh: 1 + +pkg.lflags: + - -ldl \ No newline at end of file diff --git a/babblesim/hw/babblesim/scripts/pre_build1.sh b/babblesim/hw/babblesim/scripts/pre_build1.sh new file mode 100755 index 000000000..3f3fec5ad --- /dev/null +++ b/babblesim/hw/babblesim/scripts/pre_build1.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 [ -z ${BSIM_COMPONENTS_PATH+x} ]; then + echo "This board requires the BabbleSim simulator. Please set" \ + "the environment variable BSIM_COMPONENTS_PATH to point to its components" \ + "folder. More information can be found in" \ + "https://babblesim.github.io/folder_structure_and_env.html" + exit 1 +fi + +if [ -z ${BSIM_OUT_PATH+x} ]; then + echo "This board requires the BabbleSim simulator. Please set" \ + "the environment variable BSIM_OUT_PATH to point to the folder where the" \ + "simulator is compiled to. More information can be found in" \ + "https://babblesim.github.io/folder_structure_and_env.html" + exit 1 +fi + +if [[ -d "$(pwd)/components" ]] +then + echo "Babblesim components: Directory exists. Removing and linking again..." + rm -r $(pwd)/components +else + echo "Babblesim components: Linking components..." +fi + +ln -nsf $BSIM_OUT_PATH/components + +if [[ -d "$(pwd)/src" ]] +then + echo "Babblesim libraries src: Directory exists. Removing and linking again..." + rm -r $(pwd)/src +else + echo "Babblesim components: Linking components..." +fi + +mkdir -p src +ln -nsf $BSIM_OUT_PATH/components + +# Create links to all .32.a files +# find $BSIM_OUT_PATH/lib/$lib -name "*.32.a" -type f -exec ln -t src -nsf {} \; + +# Copy all .32.a files +find $BSIM_OUT_PATH/lib/$lib -name "*.32.a" -type f -exec cp -t src -f {} \; + +# XXX: Workaround for bad linking by newt. Sometimes newt will link +# nrf weak functions from nrf_hal_originals.o instead of their BabbleSim +# replacements inside libNRF52_hw_models.32.a. But as long as the other +# weak functions, that do not have their replacements, are not used, +# we can just remove the file from the .a library here. +ar d src/libNRF52_hw_models.32.a nrf_hal_originals.o diff --git a/babblesim/hw/bsp/nrf52_bsim/bsp.yml b/babblesim/hw/bsp/nrf52_bsim/bsp.yml new file mode 100644 index 000000000..edd2189d1 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/bsp.yml @@ -0,0 +1,60 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +bsp.name: "nRF52 DK" +bsp.url: https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK +bsp.maker: "Nordic Semiconductor" +bsp.arch: bsim_arch +bsp.compiler: "@apache-mynewt-core/compiler/sim" +bsp.downloadscript: "hw/bsp/nrf52_bsim/nordic_pca10040_download.sh" +bsp.debugscript: "hw/bsp/nrf52_bsim/nordic_pca10040_debug.sh" +bsp.downloadscript.WINDOWS.OVERWRITE: "hw/bsp/nrf52_bsim/nordic_pca10040_download.cmd" +bsp.debugscript.WINDOWS.OVERWRITE: "hw/bsp/nrf52_bsim/nordic_pca10040_debug.cmd" + +bsp.flash_map: + areas: + # System areas. + FLASH_AREA_BOOTLOADER: + device: 0 + offset: 0x00000000 + size: 16kB + FLASH_AREA_IMAGE_0: + device: 0 + offset: 0x00008000 + size: 232kB + FLASH_AREA_IMAGE_1: + device: 0 + offset: 0x00042000 + size: 232kB + FLASH_AREA_IMAGE_SCRATCH: + device: 0 + offset: 0x0007c000 + size: 4kB + + # User areas. + FLASH_AREA_REBOOT_LOG: + user_id: 0 + device: 0 + offset: 0x00004000 + size: 16kB + FLASH_AREA_NFFS: + user_id: 1 + device: 0 + offset: 0x0007d000 + size: 12kB diff --git a/babblesim/hw/bsp/nrf52_bsim/include/bsp/bsp.h b/babblesim/hw/bsp/nrf52_bsim/include/bsp/bsp.h new file mode 100644 index 000000000..c096b887c --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/include/bsp/bsp.h @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 H_BSP_H +#define H_BSP_H + +#include + +#include "os/mynewt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define special stackos sections */ +#define sec_data_core __attribute__((section(".data.core"))) +#define sec_bss_core __attribute__((section(".bss.core"))) +#define sec_bss_nz_core __attribute__((section(".bss.core.nz"))) + +/* More convenient section placement macros. */ +#define bssnz_t sec_bss_nz_core + +extern uint8_t _ram_start; +#define RAM_SIZE 0x10000 + +/* LED pins */ +#define LED_1 (17) +#define LED_2 (18) +#define LED_3 (19) +#define LED_4 (20) +#define LED_BLINK_PIN (LED_1) + +/* Buttons */ +#define BUTTON_1 (13) +#define BUTTON_2 (14) +#define BUTTON_3 (15) +#define BUTTON_4 (16) + +/* Arduino pins */ +#define ARDUINO_PIN_D0 11 +#define ARDUINO_PIN_D1 12 +#define ARDUINO_PIN_D2 13 +#define ARDUINO_PIN_D3 14 +#define ARDUINO_PIN_D4 15 +#define ARDUINO_PIN_D5 16 +#define ARDUINO_PIN_D6 17 +#define ARDUINO_PIN_D7 18 +#define ARDUINO_PIN_D8 19 +#define ARDUINO_PIN_D9 20 +#define ARDUINO_PIN_D10 22 +#define ARDUINO_PIN_D11 23 +#define ARDUINO_PIN_D12 24 +#define ARDUINO_PIN_D13 25 +#define ARDUINO_PIN_A0 3 +#define ARDUINO_PIN_A1 4 +#define ARDUINO_PIN_A2 28 +#define ARDUINO_PIN_A3 29 +#define ARDUINO_PIN_A4 30 +#define ARDUINO_PIN_A5 31 + +#define ARDUINO_PIN_RX ARDUINO_PIN_D0 +#define ARDUINO_PIN_TX ARDUINO_PIN_D1 + +#define ARDUINO_PIN_SCL 27 +#define ARDUINO_PIN_SDA 26 + +#define ARDUINO_PIN_SCK ARDUINO_PIN_D13 +#define ARDUINO_PIN_MOSI ARDUINO_PIN_D11 +#define ARDUINO_PIN_MISO ARDUINO_PIN_D12 + +#ifdef __cplusplus +} +#endif + +#endif /* H_BSP_H */ diff --git a/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h b/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h new file mode 100644 index 000000000..32bc97bcb --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 _OS_ARCH_ARM_H +#define _OS_ARCH_ARM_H + +#include +#include "syscfg/syscfg.h" +#include "mcu/cmsis_nvic.h" +#include "mcu/cortex_m4.h" +#include +#include "mcu/mcu_sim.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* CPU status register */ +typedef uint32_t os_sr_t; + +/* Stack element */ +typedef uint32_t os_stack_t; + +struct stack_frame; +void os_arch_frame_init(struct stack_frame *sf); + +/* Stack sizes for common OS tasks */ +#define OS_SANITY_STACK_SIZE (2000) +#if MYNEWT_VAL(OS_SYSVIEW) +#define OS_IDLE_STACK_SIZE (80) +#else +#define OS_IDLE_STACK_SIZE (4000) +#endif + +static inline int +os_arch_in_isr(void) +{ + return hw_irq_ctrl_get_irq_status(); +} + +/* Include common arch definitions and APIs */ +#include "os/arch/common.h" + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_ARCH_ARM_H */ diff --git a/babblesim/hw/bsp/nrf52_bsim/include/os/sim.h b/babblesim/hw/bsp/nrf52_bsim/include/os/sim.h new file mode 100644 index 000000000..3d8837b81 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/include/os/sim.h @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 H_KERNEL_SIM_ +#define H_KERNEL_SIM_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "os/mynewt.h" +#include "mcu/mcu_sim.h" +struct os_task; +struct stack_frame; + +struct stack_frame { + int sf_mainsp; /* stack on which main() is executing */ + sigjmp_buf sf_jb; + struct os_task *sf_task; +}; + +void sim_task_start(struct stack_frame *sf, int rc); +os_stack_t *sim_task_stack_init(struct os_task *t, os_stack_t *stack_top, + int size); +os_error_t sim_os_start(void); +void sim_os_stop(void); +os_error_t sim_os_init(void); +void sim_ctx_sw(struct os_task *next_t); +os_sr_t sim_save_sr(void); +void sim_restore_sr(os_sr_t osr); +int sim_in_critical(void); +void sim_tick_idle(os_time_t ticks); +int sig_block_irq_on(); +void sig_unblock_irq_off(); + +uint8_t inner_main_clean_up(int exit_code); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.cmd b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.cmd new file mode 100755 index 000000000..3444fd327 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.cmd @@ -0,0 +1,22 @@ +@rem +@rem Licensed to the Apache Software Foundation (ASF) under one +@rem or more contributor license agreements. See the NOTICE file +@rem distributed with this work for additional information +@rem regarding copyright ownership. The ASF licenses this file +@rem to you under the Apache License, Version 2.0 (the +@rem "License"); you may not use this file except in compliance +@rem with the License. You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, +@rem software distributed under the License is distributed on an +@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@rem KIND, either express or implied. See the License for the +@rem specific language governing permissions and limitations +@rem under the License. +@rem + +@rem Execute a shell with a script of the same name and .sh extension + +@bash "%~dp0%~n0.sh" diff --git a/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.sh b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.sh new file mode 100755 index 000000000..1e248e4e6 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +# Called with following variables set: +# - CORE_PATH is absolute path to @apache-mynewt-core +# - BSP_PATH is absolute path to hw/bsp/bsp_name +# - BIN_BASENAME is the path to prefix to target binary, +# .elf appended to name is the ELF file +# - FEATURES holds the target features string +# - EXTRA_JTAG_CMD holds extra parameters to pass to jtag software +# - RESET set if target should be reset when attaching +# - NO_GDB set if we should not start gdb to debug +# + +. $CORE_PATH/hw/scripts/jlink.sh + +FILE_NAME=$BIN_BASENAME.elf + +if [ $# -gt 2 ]; then + SPLIT_ELF_NAME=$3.elf + # TODO -- this magic number 0x42000 is the location of the second image + # slot. we should either get this from a flash map file or somehow learn + # this from the image itself + EXTRA_GDB_CMDS="add-symbol-file $SPLIT_ELF_NAME 0x8000 -readnow" +fi + +JLINK_DEV="nRF52" + +jlink_debug diff --git a/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.cmd b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.cmd new file mode 100755 index 000000000..3444fd327 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.cmd @@ -0,0 +1,22 @@ +@rem +@rem Licensed to the Apache Software Foundation (ASF) under one +@rem or more contributor license agreements. See the NOTICE file +@rem distributed with this work for additional information +@rem regarding copyright ownership. The ASF licenses this file +@rem to you under the Apache License, Version 2.0 (the +@rem "License"); you may not use this file except in compliance +@rem with the License. You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, +@rem software distributed under the License is distributed on an +@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@rem KIND, either express or implied. See the License for the +@rem specific language governing permissions and limitations +@rem under the License. +@rem + +@rem Execute a shell with a script of the same name and .sh extension + +@bash "%~dp0%~n0.sh" diff --git a/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.sh b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.sh new file mode 100755 index 000000000..08d45b464 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# Called with following variables set: +# - CORE_PATH is absolute path to @apache-mynewt-core +# - BSP_PATH is absolute path to hw/bsp/bsp_name +# - BIN_BASENAME is the path to prefix to target binary, +# .elf appended to name is the ELF file +# - IMAGE_SLOT is the image slot to download to (for non-mfg-image, non-boot) +# - FEATURES holds the target features string +# - EXTRA_JTAG_CMD holds extra parameters to pass to jtag software +# - MFG_IMAGE is "1" if this is a manufacturing image +# - FLASH_OFFSET contains the flash offset to download to +# - BOOT_LOADER is set if downloading a bootloader + +. $CORE_PATH/hw/scripts/jlink.sh + +if [ "$MFG_IMAGE" ]; then + FLASH_OFFSET=0x0 +fi + +JLINK_DEV="nRF52" + +common_file_to_load +jlink_load diff --git a/babblesim/hw/bsp/nrf52_bsim/pkg.yml b/babblesim/hw/bsp/nrf52_bsim/pkg.yml new file mode 100644 index 000000000..6662a76dd --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/pkg.yml @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: babblesim/hw/bsp/nrf52_bsim +pkg.type: bsp +pkg.description: nRF52 on BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" + +pkg.cflags: + - '-DNRF52832_XXAA' + - '-DBABBLESIM' + +pkg.cflags.HARDFLOAT: + - -mfloat-abi=hard -mfpu=fpv4-sp-d16 + +pkg.deps: + - "@apache-mynewt-core/hw/drivers/uart/uart_hal" + - "babblesim/hw/mcu/nordic/nrf52_bsim" + - "babblesim/hw/babblesim" + - "babblesim/core" diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c new file mode 100644 index 000000000..6700e90a6 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "os/mynewt.h" +#include "os/sim.h" +#include "sim_priv.h" +#include + +/* + * From HAL_CM4.s + */ +extern void SVC_Handler(void); +extern void PendSV_Handler(void); +extern void SysTick_Handler(void); + +/* + * Assert that 'sf_mainsp' and 'sf_jb' are at the specific offsets where + * os_arch_frame_init() expects them to be. + */ +CTASSERT(offsetof(struct stack_frame, sf_mainsp) == 0); +CTASSERT(offsetof(struct stack_frame, sf_jb) == 4); + +void +os_arch_task_start(struct stack_frame *sf, int rc) +{ + sim_task_start(sf, rc); +} + +os_stack_t * +os_arch_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size) +{ + return sim_task_stack_init(t, stack_top, size); +} + +os_error_t +os_arch_os_start(void) +{ + return sim_os_start(); +} + +void +os_arch_os_stop(void) +{ + sim_os_stop(); +} + +void +PendSV_Handler(void) +{ + sim_switch_tasks(); +} + +os_error_t +os_arch_os_init(void) +{ + NVIC_SetVector(PendSV_IRQn, (uint32_t)PendSV_Handler); + return sim_os_init(); +} + +void +os_arch_ctx_sw(struct os_task *next_t) +{ + sim_ctx_sw(next_t); +} + +os_sr_t +os_arch_save_sr(void) +{ + sim_save_sr(); + return hw_irq_ctrl_change_lock(1); +} + +void +os_arch_restore_sr(os_sr_t osr) +{ + hw_irq_ctrl_change_lock(osr); + sim_restore_sr(osr); +} + + +int +os_arch_in_critical(void) +{ + return sim_in_critical(); +} + +void +__assert_func(const char *file, int line, const char *func, const char *e) +{ +#if MYNEWT_VAL(OS_ASSERT_CB) + os_assert_cb(); +#endif + _Exit(1); +} diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch_stack_frame.s b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch_stack_frame.s new file mode 100644 index 000000000..81e5c066e --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch_stack_frame.s @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 defined MN_LINUX +#define sigsetjmp __sigsetjmp +#define CNAME(x) x +#elif defined MN_OSX +#define sigsetjmp sigsetjmp +#define CNAME(x) _ ## x +#elif defined MN_FreeBSD +#define sigsetjmp sigsetjmp +#define CNAME(x) x +#else +#error "unsupported platform" +#endif + + .text + .code32 + .p2align 4, 0x90 /* align on 16-byte boundary and fill with NOPs */ + + .globl CNAME(os_arch_frame_init) + .globl _os_arch_frame_init + /* + * void os_arch_frame_init(struct stack_frame *sf) + */ +CNAME(os_arch_frame_init): + push %ebp /* function prologue for backtrace */ + mov %esp,%ebp + push %esi /* save %esi before using it as a tmpreg */ + + /* + * At this point we are executing on the main() stack: + * ---------------- + * stack_frame ptr 0xc(%esp) + * ---------------- + * return address 0x8(%esp) + * ---------------- + * saved ebp 0x4(%esp) + * ---------------- + * saved esi 0x0(%esp) + * ---------------- + */ + movl 0xc(%esp),%esi /* %esi = 'sf' */ + movl %esp,0x0(%esi) /* sf->mainsp = %esp */ + + /* + * Switch the stack so the stack pointer stored in 'sf->sf_jb' points + * to the task stack. This is slightly complicated because OS X wants + * the incoming stack pointer to be 16-byte aligned. + * + * ---------------- + * sf (other fields) + * ---------------- + * sf (sf_jb) 0x4(%esi) + * ---------------- + * sf (sf_mainsp) 0x0(%esi) + * ---------------- + * alignment padding variable (0 to 12 bytes) + * ---------------- + * savemask (0) 0x4(%esp) + * ---------------- + * pointer to sf_jb 0x0(%esp) + * ---------------- + */ + movl %esi,%esp + subl $0x8,%esp /* make room for sigsetjmp() arguments */ + andl $0xfffffff0,%esp /* align %esp on 16-byte boundary */ + leal 0x4(%esi),%eax /* %eax = &sf->sf_jb */ + movl %eax,0x0(%esp) + movl $0, 0x4(%esp) + call CNAME(sigsetjmp) /* sigsetjmp(sf->sf_jb, 0) */ + test %eax,%eax + jne 1f + movl 0x0(%esi),%esp /* switch back to the main() stack */ + pop %esi + pop %ebp + ret /* return to os_arch_task_stack_init() */ +1: + lea 2f,%ecx + push %ecx /* retaddr */ + push $0 /* frame pointer */ + movl %esp,%ebp /* handcrafted prologue for backtrace */ + push %eax /* rc */ + push %esi /* sf */ + call CNAME(os_arch_task_start) /* os_arch_task_start(sf, rc) */ + /* never returns */ +2: + nop diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_priv.h b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_priv.h new file mode 100644 index 000000000..39984dfc2 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_priv.h @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 H_SIM_PRIV_ +#define H_SIM_PRIV_ + +#include +#include "os/mynewt.h" +#include "mcu/mcu_sim.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define OS_USEC_PER_TICK (1000000 / OS_TICKS_PER_SEC) + +void sim_switch_tasks(void); +void sim_tick(void); +void sim_signals_init(void); +void sim_signals_cleanup(void); + +extern pid_t sim_pid; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_gen.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_gen.c new file mode 100644 index 000000000..b3c192fcd --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_gen.c @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * This file contains code that is shared by both sim implementations (signals + * and no-signals). + */ + +#include "os/mynewt.h" + +#include + +#ifdef __APPLE__ +#define _XOPEN_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include "os/sim.h" +#include "sim_priv.h" + +#define sim_setjmp(__jb) sigsetjmp(__jb, 0) +#define sim_longjmp(__jb, __ret) siglongjmp(__jb, __ret) + +pid_t sim_pid; + +void +sim_switch_tasks(void) +{ + struct os_task *t, *next_t; + struct stack_frame *sf; + int rc; + + OS_ASSERT_CRITICAL(); + + t = os_sched_get_current_task(); + next_t = os_sched_next_task(); + if (t == next_t) { + /* + * Context switch not needed - just return. + */ + return; + } + + if (t) { + sf = (struct stack_frame *) t->t_stackptr; + + rc = sim_setjmp(sf->sf_jb); + if (rc != 0) { + OS_ASSERT_CRITICAL(); + return; + } + } + + os_sched_ctx_sw_hook(next_t); + + os_sched_set_current_task(next_t); + + sf = (struct stack_frame *) next_t->t_stackptr; + sim_longjmp(sf->sf_jb, 1); +} + +void +sim_tick(void) +{ + struct timeval time_now, time_diff; + int ticks; + + static struct timeval time_last; + static int time_inited; + + OS_ASSERT_CRITICAL(); + + if (!time_inited) { + gettimeofday(&time_last, NULL); + time_inited = 1; + } + + gettimeofday(&time_now, NULL); + if (timercmp(&time_now, &time_last, <)) { + /* + * System time going backwards. + */ + time_last = time_now; + } else { + timersub(&time_now, &time_last, &time_diff); + + ticks = time_diff.tv_sec * OS_TICKS_PER_SEC; + ticks += time_diff.tv_usec / OS_USEC_PER_TICK; + + /* + * Update 'time_last' but account for the remainder usecs that did not + * contribute towards whole 'ticks'. + */ + time_diff.tv_sec = 0; + time_diff.tv_usec %= OS_USEC_PER_TICK; + timersub(&time_now, &time_diff, &time_last); + + os_time_advance(ticks); + } +} + +#define OS_TICK_PRIO 7 + +static void +sim_start_timer(void) +{ + /* Intitialize and start system clock timer */ + os_tick_init(OS_TICKS_PER_SEC, OS_TICK_PRIO); +} + +static void +sim_stop_timer(void) +{ + struct itimerval it; + int rc; + + memset(&it, 0, sizeof(it)); + + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); +} + +/* + * Called from 'os_arch_frame_init()' when setjmp returns indirectly via + * longjmp. The return value of setjmp is passed to this function as 'rc'. + */ +void +sim_task_start(struct stack_frame *sf, int rc) +{ + struct os_task *task; + + /* + * Interrupts are disabled when a task starts executing. This happens in + * two different ways: + * - via sim_os_start() for the first task. + * - via os_sched() for all other tasks. + * + * Enable interrupts before starting the task. + */ + OS_EXIT_CRITICAL(0); + + task = sf->sf_task; + task->t_func(task->t_arg); + + /* A task handler should never return. */ + assert(0); +} + +os_stack_t * +sim_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size) +{ + struct stack_frame *sf; + + sf = (struct stack_frame *) ((uint8_t *) stack_top - sizeof(*sf)); + sf->sf_task = t; + + os_arch_frame_init(sf); + + return ((os_stack_t *)sf); +} + +os_error_t +sim_os_start(void) +{ + struct stack_frame *sf; + struct os_task *t; + os_sr_t sr; + + /* + * Disable interrupts before enabling any interrupt sources. Pending + * interrupts will be recognized when the first task starts executing. + */ + OS_ENTER_CRITICAL(sr); + assert(sr == 0); + + /* Enable the interrupt sources */ + sim_start_timer(); + + t = os_sched_next_task(); + os_sched_set_current_task(t); + + g_os_started = 1; + + sf = (struct stack_frame *) t->t_stackptr; + sim_longjmp(sf->sf_jb, 1); + + return 0; +} + +/** + * Stops the tick timer and clears the "started" flag. This function is only + * implemented for sim. + */ +void +sim_os_stop(void) +{ + sim_stop_timer(); + sim_signals_cleanup(); + g_os_started = 0; +} + +os_error_t +sim_os_init(void) +{ + sim_pid = getpid(); + g_current_task = NULL; + + STAILQ_INIT(&g_os_task_list); + TAILQ_INIT(&g_os_run_list); + TAILQ_INIT(&g_os_sleep_list); + + sim_signals_init(); + + os_init_idle_task(); + + return OS_OK; +} diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_nosig.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_nosig.c new file mode 100644 index 000000000..fadb712ad --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_nosig.c @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * This file implements the "no-signals" version of sim. This implementation + * does not use signals to perform context switches. This is the less correct + * version of sim: the OS tick timer only runs while the idle task is active. + * Therefore, a sleeping high-priority task will not preempt a low-priority + * task due to a timing event (e.g., delay or callout expired). However, this + * version of sim does not suffer from the stability issues that affect the + * "signals" implementation. + * + * To use this version of sim, disable the MCU_NATIVE_USE_SIGNALS syscfg + * setting. + */ + +#include "os/mynewt.h" + +#if !MYNEWT_VAL(MCU_NATIVE_USE_SIGNALS) + +#include + +#ifdef __APPLE__ +#define _XOPEN_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "sim_priv.h" + +static sigset_t nosigs; +static sigset_t suspsigs; /* signals delivered in sigsuspend() */ + +static int ctx_sw_pending; +static int interrupts_enabled = 1; + +void +sim_ctx_sw(struct os_task *next_t) +{ + if (interrupts_enabled) { + /* Perform the context switch immediately. */ + sim_switch_tasks(); + } else { + /* Remember that we want to perform a context switch. Perform it when + * interrupts are re-enabled. + */ + ctx_sw_pending = 1; + } +} + +/* + * Enter a critical section. + * + * Returns 1 if interrupts were already disabled; 0 otherwise. + */ +os_sr_t +sim_save_sr(void) +{ + if (!interrupts_enabled) { + return 1; + } + + interrupts_enabled = 0; + return 0; +} + +void +sim_restore_sr(os_sr_t osr) +{ + OS_ASSERT_CRITICAL(); + assert(osr == 0 || osr == 1); + + if (osr == 1) { + /* Exiting a nested critical section */ + return; + } + + if (ctx_sw_pending) { + /* A context switch was requested while interrupts were disabled. + * Perform it now that interrupts are enabled again. + */ + ctx_sw_pending = 0; + sim_switch_tasks(); + } + interrupts_enabled = 1; +} + +int +sim_in_critical(void) +{ + return !interrupts_enabled; +} + +/** + * Unblocks the SIGALRM signal that is delivered by the OS tick timer. + */ +static void +unblock_timer(void) +{ + sigset_t sigs; + int rc; + + sigemptyset(&sigs); + sigaddset(&sigs, SIGALRM); + + rc = sigprocmask(SIG_UNBLOCK, &sigs, NULL); + assert(rc == 0); +} + +/** + * Blocks the SIGALRM signal that is delivered by the OS tick timer. + */ +static void +block_timer(void) +{ + sigset_t sigs; + int rc; + + sigemptyset(&sigs); + sigaddset(&sigs, SIGALRM); + + rc = sigprocmask(SIG_BLOCK, &sigs, NULL); + assert(rc == 0); +} + +static void +sig_handler_alrm(int sig) +{ + /* Wake the idle task. */ + sigaddset(&suspsigs, sig); +} + +void +sim_tick_idle(os_time_t ticks) +{ + int rc; + struct itimerval it; + + OS_ASSERT_CRITICAL(); + + if (ticks > 0) { + /* + * Enter tickless regime and set the timer to fire after 'ticks' + * worth of time has elapsed. + */ + it.it_value.tv_sec = ticks / OS_TICKS_PER_SEC; + it.it_value.tv_usec = (ticks % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = OS_USEC_PER_TICK; + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); + } + + unblock_timer(); + + sigemptyset(&suspsigs); + sigsuspend(&nosigs); /* Wait for a signal to wake us up */ + + block_timer(); + + /* + * Call handlers for signals delivered to the process during sigsuspend(). + * The SIGALRM handler is called before any other handlers to ensure that + * OS time is always correct. + */ + if (sigismember(&suspsigs, SIGALRM)) { + sim_tick(); + } + + if (ticks > 0) { + /* + * Enable the periodic timer interrupt. + */ + it.it_value.tv_sec = 0; + it.it_value.tv_usec = OS_USEC_PER_TICK; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = OS_USEC_PER_TICK; + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); + } +} + +void +sim_signals_init(void) +{ + sigset_t sigset_alrm; + struct sigaction sa; + int error; + + block_timer(); + + sigemptyset(&nosigs); + + sigemptyset(&sigset_alrm); + sigaddset(&sigset_alrm, SIGALRM); + + memset(&sa, 0, sizeof sa); + sa.sa_handler = sig_handler_alrm; + sa.sa_mask = sigset_alrm; + sa.sa_flags = SA_RESTART; + error = sigaction(SIGALRM, &sa, NULL); + assert(error == 0); +} + +void +sim_signals_cleanup(void) +{ + int error; + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_handler = SIG_DFL; + error = sigaction(SIGALRM, &sa, NULL); + assert(error == 0); +} + +#endif /* !MYNEWT_VAL(MCU_NATIVE_USE_SIGNALS) */ diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_sig.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_sig.c new file mode 100644 index 000000000..c26abcea0 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/sim_sched_sig.c @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * This file implements the "signals" version of sim. This implementation uses + * signals to perform context switches. This is the more correct version of + * sim: the OS tick timer will cause a high-priority task to preempt a + * low-priority task. Unfortunately, there are stability issues because a task + * can be preempted while it is in the middle of a system call, potentially + * causing deadlock or memory corruption. + * + * To use this version of sim, enable the MCU_NATIVE_USE_SIGNALS syscfg + * setting. + */ + +#include "os/mynewt.h" + +#if MYNEWT_VAL(MCU_NATIVE_USE_SIGNALS) + +#include "sim_priv.h" + +#include + +#ifdef __APPLE__ +#define _XOPEN_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include + +static bool suspended; /* process is blocked in sigsuspend() */ +static sigset_t suspsigs; /* signals delivered in sigsuspend() */ +static sigset_t allsigs; +static sigset_t nosigs; + +static int in_irq; +int counter = 0; + +int +sig_block_irq_on() +{ + int error; + + counter++; + + error = sigprocmask(SIG_BLOCK, &allsigs, NULL); + + in_irq = 1; + assert(error == 0); + return 1; +} + +void +sig_unblock_irq_off() +{ + int error; + + in_irq = 0; + + if (counter > 0) { + counter--; + return; + } + + error = sigprocmask(SIG_UNBLOCK, &allsigs, NULL); + assert(error == 0); + +} + +void +sim_ctx_sw(struct os_task *next_t) +{ + /* + * gdb will stop execution of the program on most signals (e.g. SIGUSR1) + * whereas it passes SIGURG to the process without any special settings. + */ + kill(sim_pid, SIGURG); +} + +static void +ctxsw_handler(int sig) +{ + assert(in_irq==0); + OS_ASSERT_CRITICAL(); + + /* + * Just record that this handler was called when the process was blocked. + * The handler will be called after sigsuspend() returns in the correct + * order. + */ + if (suspended) { + sigaddset(&suspsigs, sig); + } else { + sim_switch_tasks(); + } +} + +/* + * Disable signals and enter a critical section. + * + * Returns 1 if signals were already blocked and 0 otherwise. + */ +os_sr_t +sim_save_sr(void) +{ + int error; + sigset_t omask; + + counter++; + + error = sigprocmask(SIG_BLOCK, &allsigs, &omask); + assert(error == 0); + + /* + * If any one of the signals in 'allsigs' is present in 'omask' then + * we are already inside a critical section. + */ + return (sigismember(&omask, SIGURG)); +} + +void +sim_restore_sr(os_sr_t osr) +{ + int error; + + OS_ASSERT_CRITICAL(); + assert(osr == 0 || osr == 1); + + if (counter > 0) { + counter--; + } + + if (osr == 1 || in_irq == 1 || counter > 0) { + /* Exiting a nested critical section */ + return; + } + + error = sigprocmask(SIG_UNBLOCK, &allsigs, NULL); + assert(error == 0); +} + +int +sim_in_critical(void) +{ + int error; + sigset_t omask; + + error = sigprocmask(SIG_SETMASK, NULL, &omask); + assert(error == 0); + + /* + * If any one of the signals in 'allsigs' is present in 'omask' then + * we are already inside a critical section. + */ + return (sigismember(&omask, SIGURG)); +} + +static struct { + int num; + void (*handler)(int sig); +} signals[] = { +// { SIGALRM, timer_handler }, + { SIGURG, ctxsw_handler }, +}; + +#define NUMSIGS (sizeof(signals)/sizeof(signals[0])) + +void +sim_tick_idle(os_time_t ticks) +{ + int i, rc, sig; + struct itimerval it; + void (*handler)(int sig); + + OS_ASSERT_CRITICAL(); + + if (ticks > 0) { + /* + * Enter tickless regime and set the timer to fire after 'ticks' + * worth of time has elapsed. + */ + it.it_value.tv_sec = ticks / OS_TICKS_PER_SEC; + it.it_value.tv_usec = (ticks % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = OS_USEC_PER_TICK; + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); + } + + suspended = true; + sigemptyset(&suspsigs); + sigsuspend(&nosigs); /* Wait for a signal to wake us up */ + suspended = false; + + /* + * Call handlers for signals delivered to the process during sigsuspend(). + * The SIGALRM handler is called before any other handlers to ensure that + * OS time is always correct. + */ + if (sigismember(&suspsigs, SIGALRM)) { + sim_tick(); + } + for (i = 0; i < NUMSIGS; i++) { + sig = signals[i].num; + handler = signals[i].handler; + if (sig != SIGALRM && sigismember(&suspsigs, sig)) { + handler(sig); + } + } + + if (ticks > 0) { + /* + * Enable the periodic timer interrupt. + */ + it.it_value.tv_sec = 0; + it.it_value.tv_usec = OS_USEC_PER_TICK; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = OS_USEC_PER_TICK; + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); + } +} + +void +sim_signals_init(void) +{ + int i, error; + struct sigaction sa; + + sigemptyset(&nosigs); + sigemptyset(&allsigs); + for (i = 0; i < NUMSIGS; i++) { + sigaddset(&allsigs, signals[i].num); + } + + for (i = 0; i < NUMSIGS; i++) { + memset(&sa, 0, sizeof sa); + sa.sa_handler = signals[i].handler; + sa.sa_mask = allsigs; + sa.sa_flags = SA_RESTART; + error = sigaction(signals[i].num, &sa, NULL); + assert(error == 0); + } + + /* + * We use SIGALRM as a proxy for 'allsigs' to check if we are inside + * a critical section (for e.g. see sim_in_critical()). Make sure + * that SIGALRM is indeed present in 'allsigs'. + */ +// assert(sigismember(&allsigs, SIGALRM)); +} + +void +sim_signals_cleanup(void) +{ + int i, error; + struct sigaction sa; + + for (i = 0; i < NUMSIGS; i++) { + memset(&sa, 0, sizeof sa); + sa.sa_handler = SIG_DFL; + error = sigaction(signals[i].num, &sa, NULL); + assert(error == 0); + } +} + +#endif /* MYNEWT_VAL(MCU_NATIVE_USE_SIGNALS) */ diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/startup_nrf52_bsim.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/startup_nrf52_bsim.c new file mode 100644 index 000000000..d4810689b --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/startup_nrf52_bsim.c @@ -0,0 +1,231 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "nrf.h" + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! Weak symbol reference. */ +#define WEAK __attribute__ ((weak)) + +/************************************************************************************************** + Functions +**************************************************************************************************/ + +extern void SystemInit(void); +static void SystemDefaultHandler(void); + +/* Core vectors. */ +void WEAK Reset_Handler(void); +void WEAK NMI_Handler(void); +void WEAK HardFault_Handler(void); +void WEAK MemoryManagement_Handler(void); +void WEAK BusFault_Handler(void); +void WEAK UsageFault_Handler(void); +void WEAK SVC_Handler(void); +void WEAK DebugMon_Handler(void); +void WEAK PendSV_Handler(void); +void WEAK SysTick_Handler(void); +void WEAK POWER_CLOCK_IRQHandler(void); +void WEAK RADIO_IRQHandler(void); +void WEAK UARTE0_UART0_IRQHandler(void); +void WEAK SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void); +void WEAK SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void); +void WEAK NFCT_IRQHandler(void); +void WEAK GPIOTE_IRQHandler(void); +void WEAK SAADC_IRQHandler(void); +void WEAK TIMER0_IRQHandler(void); +void WEAK TIMER1_IRQHandler(void); +void WEAK TIMER2_IRQHandler(void); +void WEAK RTC0_IRQHandler(void); +void WEAK TEMP_IRQHandler(void); +void WEAK RNG_IRQHandler(void); +void WEAK ECB_IRQHandler(void); +void WEAK CCM_AAR_IRQHandler(void); +void WEAK WDT_IRQHandler(void); +void WEAK RTC1_IRQHandler(void); +void WEAK QDEC_IRQHandler(void); +void WEAK COMP_LPCOMP_IRQHandler(void); +void WEAK SWI0_EGU0_IRQHandler(void); +void WEAK SWI1_EGU1_IRQHandler(void); +void WEAK SWI2_EGU2_IRQHandler(void); +void WEAK SWI3_EGU3_IRQHandler(void); +void WEAK SWI4_EGU4_IRQHandler(void); +void WEAK SWI5_EGU5_IRQHandler(void); +void WEAK TIMER3_IRQHandler(void); +void WEAK TIMER4_IRQHandler(void); +void WEAK PWM0_IRQHandler(void); +void WEAK PDM_IRQHandler(void); +void WEAK MWU_IRQHandler(void); +void WEAK PWM1_IRQHandler(void); +void WEAK PWM2_IRQHandler(void); +void WEAK SPIM2_SPIS2_SPI2_IRQHandler(void); +void WEAK RTC2_IRQHandler(void); +void WEAK I2S_IRQHandler(void); +void WEAK FPU_IRQHandler(void); + +/* Assign default weak references. Override these values by defining a new function with the same name. */ +#pragma weak NMI_Handler = SystemDefaultHandler +#pragma weak HardFault_Handler = SystemDefaultHandler +#pragma weak MemoryManagement_Handler = SystemDefaultHandler +#pragma weak BusFault_Handler = SystemDefaultHandler +#pragma weak UsageFault_Handler = SystemDefaultHandler +#pragma weak SVC_Handler = SystemDefaultHandler +#pragma weak DebugMon_Handler = SystemDefaultHandler +#pragma weak PendSV_Handler = SystemDefaultHandler +#pragma weak SysTick_Handler = SystemDefaultHandler +#pragma weak POWER_CLOCK_IRQHandler = SystemDefaultHandler +#pragma weak RADIO_IRQHandler = SystemDefaultHandler +#pragma weak UARTE0_UART0_IRQHandler = SystemDefaultHandler +#pragma weak SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler = SystemDefaultHandler +#pragma weak SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler = SystemDefaultHandler +#pragma weak NFCT_IRQHandler = SystemDefaultHandler +#pragma weak GPIOTE_IRQHandler = SystemDefaultHandler +#pragma weak SAADC_IRQHandler = SystemDefaultHandler +#pragma weak TIMER0_IRQHandler = SystemDefaultHandler +#pragma weak TIMER1_IRQHandler = SystemDefaultHandler +#pragma weak TIMER2_IRQHandler = SystemDefaultHandler +#pragma weak RTC0_IRQHandler = SystemDefaultHandler +#pragma weak TEMP_IRQHandler = SystemDefaultHandler +#pragma weak RNG_IRQHandler = SystemDefaultHandler +#pragma weak ECB_IRQHandler = SystemDefaultHandler +#pragma weak CCM_AAR_IRQHandler = SystemDefaultHandler +#pragma weak WDT_IRQHandler = SystemDefaultHandler +#pragma weak RTC1_IRQHandler = SystemDefaultHandler +#pragma weak QDEC_IRQHandler = SystemDefaultHandler +#pragma weak COMP_LPCOMP_IRQHandler = SystemDefaultHandler +#pragma weak SWI0_EGU0_IRQHandler = SystemDefaultHandler +#pragma weak SWI1_EGU1_IRQHandler = SystemDefaultHandler +#pragma weak SWI2_EGU2_IRQHandler = SystemDefaultHandler +#pragma weak SWI3_EGU3_IRQHandler = SystemDefaultHandler +#pragma weak SWI4_EGU4_IRQHandler = SystemDefaultHandler +#pragma weak SWI5_EGU5_IRQHandler = SystemDefaultHandler +#pragma weak TIMER3_IRQHandler = SystemDefaultHandler +#pragma weak TIMER4_IRQHandler = SystemDefaultHandler +#pragma weak PWM0_IRQHandler = SystemDefaultHandler +#pragma weak PDM_IRQHandler = SystemDefaultHandler +#pragma weak MWU_IRQHandler = SystemDefaultHandler +#pragma weak PWM1_IRQHandler = SystemDefaultHandler +#pragma weak PWM2_IRQHandler = SystemDefaultHandler +#pragma weak SPIM2_SPIS2_SPI2_IRQHandler = SystemDefaultHandler +#pragma weak RTC2_IRQHandler = SystemDefaultHandler +#pragma weak I2S_IRQHandler = SystemDefaultHandler +#pragma weak FPU_IRQHandler = SystemDefaultHandler + +/************************************************************************************************** + Global variables +**************************************************************************************************/ + +/*! Core vector table */ +void (* systemVectors[256])(void) = +{ + 0, /* 0: The initial stack pointer */ + Reset_Handler, /* 1: The reset handler */ + NMI_Handler, /* 2: The NMI handler */ + HardFault_Handler, /* 3: The hard fault handler */ + MemoryManagement_Handler, /* 4: The MPU fault handler */ + BusFault_Handler, /* 5: The bus fault handler */ + UsageFault_Handler, /* 6: The usage fault handler */ + 0, /* 7: Reserved */ + 0, /* 8: Reserved */ + 0, /* 9: Reserved */ + 0, /* 10: Reserved */ + SVC_Handler, /* 11: SVCall handler */ + DebugMon_Handler, /* 12: Debug monitor handler */ + 0, /* 13: Reserved */ + PendSV_Handler, /* 14: The PendSV handler */ + SysTick_Handler, /* 15: The SysTick handler */ + + /* External interrupts */ + POWER_CLOCK_IRQHandler, /* 16: POWER_CLOCK */ + RADIO_IRQHandler, /* 17: RADIO */ + UARTE0_UART0_IRQHandler, /* 18: UART0 */ + SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler, /* 19: SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 */ + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler, /* 20: SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 */ + NFCT_IRQHandler, /* 21: NFCT */ + GPIOTE_IRQHandler, /* 22: GPIOTE */ + SAADC_IRQHandler, /* 23: SAADC */ + TIMER0_IRQHandler, /* 24: TIMER0 */ + TIMER1_IRQHandler, /* 25: TIMER1 */ + TIMER2_IRQHandler, /* 26: TIMER2 */ + RTC0_IRQHandler, /* 27: RTC0 */ + TEMP_IRQHandler, /* 28: TEMP */ + RNG_IRQHandler, /* 29: RNG */ + ECB_IRQHandler, /* 30: ECB */ + CCM_AAR_IRQHandler, /* 31: CCM_AAR */ + WDT_IRQHandler, /* 32: WDT */ + RTC1_IRQHandler, /* 33: RTC1 */ + QDEC_IRQHandler, /* 34: QDEC */ + COMP_LPCOMP_IRQHandler, /* 35: COMP_LPCOMP */ + SWI0_EGU0_IRQHandler, /* 36: SWI0_EGU0 */ + SWI1_EGU1_IRQHandler, /* 37: SWI1_EGU1 */ + SWI2_EGU2_IRQHandler, /* 38: SWI2_EGU2 */ + SWI3_EGU3_IRQHandler, /* 39: SWI3_EGU3 */ + SWI4_EGU4_IRQHandler, /* 40: SWI4_EGU4 */ + SWI5_EGU5_IRQHandler, /* 41: SWI5_EGU5 */ + TIMER3_IRQHandler, /* 42: TIMER3 */ + TIMER4_IRQHandler, /* 43: TIMER4 */ + PWM0_IRQHandler, /* 44: PWM0 */ + PDM_IRQHandler, /* 45: PDM */ + 0, /* 46: Reserved */ + 0, /* 47: Reserved */ + MWU_IRQHandler, /* 48: MWU */ + PWM1_IRQHandler, /* 49: PWM1 */ + PWM2_IRQHandler, /* 50: PWM2 */ + SPIM2_SPIS2_SPI2_IRQHandler, /* 51: SPIM2_SPIS2_SPI2 */ + RTC2_IRQHandler, /* 52: RTC2 */ + I2S_IRQHandler, /* 53: I2S */ + FPU_IRQHandler, /* 54: FPU */ + 0, /* 55: Reserved */ + 0, /* 56: Reserved */ + 0, /* 57: Reserved */ + 0, /* 58: Reserved */ + 0, /* 59: Reserved */ + 0, /* 60: Reserved */ + 0, /* 61: Reserved */ + 0, /* 62: Reserved */ + 0 /* 63: Reserved */ + /* 64..127: Reserved */ +}; + +/*************************************************************************************************/ +/*! + * \brief Reset handler. + */ +/*************************************************************************************************/ +void Reset_Handler(void) +{ + /* Core initialization. */ + SystemInit(); +} + +/*************************************************************************************************/ +/*! + * \brief Default vector handler. + * + * \param None. + */ +/*************************************************************************************************/ +static void SystemDefaultHandler(void) +{ + volatile unsigned int forever = 1; + while (forever); +} diff --git a/babblesim/hw/bsp/nrf52_bsim/src/hal_bsp.c b/babblesim/hw/bsp/nrf52_bsim/src/hal_bsp.c new file mode 100644 index 000000000..4250249e5 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/hal_bsp.c @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 +#include +#include +#include "os/mynewt.h" +#include "nrfx.h" +#include "flash_map/flash_map.h" +#include "hal/hal_bsp.h" +#include "hal/hal_flash.h" +#include "hal/hal_system.h" +#include "mcu/nrf52_hal.h" +#include "mcu/nrf52_periph.h" +#include "bsp/bsp.h" +#include "defs/sections.h" +#include "uart_hal/uart_hal.h" +#include "uart/uart.h" +#if MYNEWT_VAL(ENC_FLASH_DEV) +#include +#endif + +/* + * What memory to include in coredump. + */ +static const struct hal_bsp_mem_dump dump_cfg[] = { + [0] = { + .hbmd_start = &_ram_start, + .hbmd_size = RAM_SIZE + } +}; + +#if MYNEWT_VAL(ENC_FLASH_DEV) +static sec_data_secret struct eflash_nrf5x_dev enc_flash_dev0 = { + .end_dev = { + .efd_hal = { + .hf_itf = &enc_flash_funcs, + }, + .efd_hwdev = &nrf52k_flash_dev + } +}; +#endif + +const struct hal_flash * +hal_bsp_flash_dev(uint8_t id) +{ +// /* +// * Internal flash mapped to id 0. +// */ +// if (id == 0) { +// return &nrf52k_flash_dev; +// } +//#if MYNEWT_VAL(ENC_FLASH_DEV) +// if (id == 1) { +// return &enc_flash_dev0.end_dev.efd_hal; +// } +//#endif + return NULL; +} + +const struct hal_bsp_mem_dump * +hal_bsp_core_dump(int *area_cnt) +{ + *area_cnt = sizeof(dump_cfg) / sizeof(dump_cfg[0]); + return dump_cfg; +} + +int +hal_bsp_power_state(int state) +{ + return (0); +} + +/** + * Returns the configured priority for the given interrupt. If no priority + * configured, return the priority passed in + * + * @param irq_num + * @param pri + * + * @return uint32_t + */ +uint32_t +hal_bsp_get_nvic_priority(int irq_num, uint32_t pri) +{ + uint32_t cfg_pri; + + switch (irq_num) { + /* Radio gets highest priority */ + case RADIO_IRQn: + cfg_pri = 0; + break; + default: + cfg_pri = pri; + } + return cfg_pri; +} + +static void +nrf52_periph_create_timers(void) +{ + int rc; + + (void)rc; + +#if MYNEWT_VAL(TIMER_0) + rc = hal_timer_init(0, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_1) + rc = hal_timer_init(1, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_2) + rc = hal_timer_init(2, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_3) + rc = hal_timer_init(3, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_4) + rc = hal_timer_init(4, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_5) + rc = hal_timer_init(5, NULL); + assert(rc == 0); +#endif + +#if MYNEWT_VAL(OS_CPUTIME_TIMER_NUM) >= 0 + rc = os_cputime_init(MYNEWT_VAL(OS_CPUTIME_FREQ)); + assert(rc == 0); +#endif +} + +static struct uart_dev os_bsp_uart0; + +void +hal_bsp_init(void) +{ + /* Make sure system clocks have started */ + hal_system_clock_start(); + + /* Create all available nRF52840 peripherals */ +// nrf52_periph_create(); + nrf52_periph_create_timers(); + + int rc; + + rc = os_dev_create((struct os_dev *) &os_bsp_uart0, "uart0", + OS_DEV_INIT_PRIMARY, 0, uart_hal_init, (void *) NULL); + assert(rc == 0); +} + +void +hal_bsp_deinit(void) +{ +} diff --git a/babblesim/hw/bsp/nrf52_bsim/src/sbrk.c b/babblesim/hw/bsp/nrf52_bsim/src/sbrk.c new file mode 100644 index 000000000..5df43c951 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/sbrk.c @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + +/* put these in the data section so they are not cleared by _start */ +static char *sbrkBase __attribute__ ((section (".data"))); +static char *sbrkLimit __attribute__ ((section (".data"))); +static char *brk __attribute__ ((section (".data"))); + +void +_sbrkInit(char *base, char *limit) { + sbrkBase = base; + sbrkLimit = limit; + brk = base; +} + +void * +_sbrk(int incr) +{ + void *prev_brk; + + if (incr < 0) { + /* Returning memory to the heap. */ + incr = -incr; + if (brk - incr < sbrkBase) { + prev_brk = (void *)-1; + } else { + prev_brk = brk; + brk -= incr; + } + } else { + /* Allocating memory from the heap. */ + if (sbrkLimit - brk >= incr) { + prev_brk = brk; + brk += incr; + } else { + prev_brk = (void *)-1; + } + } + + return prev_brk; +} diff --git a/babblesim/hw/bsp/nrf52_bsim/syscfg.yml b/babblesim/hw/bsp/nrf52_bsim/syscfg.yml new file mode 100644 index 000000000..0e9eb607a --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/syscfg.yml @@ -0,0 +1,73 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +syscfg.defs: + BSP_NRF52: + description: 'Set to indicate that BSP has NRF52' + value: 1 + SOFT_PWM: + description: 'Enable soft PWM' + value: 0 + ENC_FLASH_DEV: + description: 'Encrypting flash driver over interal flash for testing' + value: 0 + UARTBB_0: + description: 'Enable bit-banger UART 0' + value: 0 + RAM_RESIDENT: + description: 'Compile app to be loaded to RAM' + value: 0 + +syscfg.vals: + OS_MAIN_STACK_SIZE: 8000 + BLE_HCI_TRANSPORT: uart + MCU_TIMER_POLLER_PRIO: 0 + BLE_LL_PRIO: 1 + MCU_UART_POLLER_PRIO: 2 + + # Enable nRF52832 MCU + MCU_TARGET: nRF52832 + # Set default pins for peripherals + UART_0_PIN_TX: 6 + UART_0_PIN_RX: 8 + UART_0_PIN_RTS: 5 + UART_0_PIN_CTS: 7 + SPI_0_MASTER_PIN_SCK: 23 + SPI_0_MASTER_PIN_MOSI: 24 + SPI_0_MASTER_PIN_MISO: 25 + SPI_0_SLAVE_PIN_SCK: 23 + SPI_0_SLAVE_PIN_MOSI: 24 + SPI_0_SLAVE_PIN_MISO: 25 + SPI_0_SLAVE_PIN_SS: 22 + I2C_0_PIN_SCL: 27 + I2C_0_PIN_SDA: 26 + + CONFIG_FCB_FLASH_AREA: FLASH_AREA_NFFS + REBOOT_LOG_FLASH_AREA: FLASH_AREA_REBOOT_LOG + NFFS_FLASH_AREA: FLASH_AREA_NFFS + COREDUMP_FLASH_AREA: FLASH_AREA_IMAGE_1 + MCU_DCDC_ENABLED: 1 + MCU_LFCLK_SOURCE: LFXO + BOOT_SERIAL_DETECT_PIN: 13 # Button 1 + +syscfg.vals.BLE_CONTROLLER: + TIMER_0: 0 + TIMER_5: 1 + OS_CPUTIME_FREQ: 32768 + OS_CPUTIME_TIMER_NUM: 5 + BLE_LL_RFMGMT_ENABLE_TIME: 1500 diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h new file mode 100644 index 000000000..11a812d33 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h @@ -0,0 +1,28 @@ +/* mbed Microcontroller Library - cmsis_nvic + * Copyright (c) 2009-2011 ARM Limited. All rights reserved. + * + * CMSIS-style functionality to support dynamic vectors + */ + +#ifndef MBED_CMSIS_NVIC_H +#define MBED_CMSIS_NVIC_H + +#include +#include "nrf.h" + +#define NVIC_NUM_VECTORS (16 + 38) // CORE + MCU Peripherals +#define NVIC_USER_IRQ_OFFSET 16 + +#ifdef __cplusplus +extern "C" { +#endif + +void NVIC_Relocate(void); +void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector); +uint32_t NVIC_GetVector(IRQn_Type IRQn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cortex_m4.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cortex_m4.h new file mode 100644 index 000000000..93f204447 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cortex_m4.h @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 __MCU_CORTEX_M4_H__ +#define __MCU_CORTEX_M4_H__ + +#include "nrf.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __MCU_CORTEX_M4_H__ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu.h new file mode 100644 index 000000000..1950c85fd --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu.h @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 __MCU_MCU_H_ +#define __MCU_MCU_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Defines for naming GPIOs. NOTE: the nordic chip docs use numeric labels for + * ports. Port A corresponds to Port 0, B to 1, etc. The nrf52832 has only one + * port and thus uses pins 0 - 31. The nrf52840 has two ports but Port 1 only + * has 16 pins. + */ +#define MCU_GPIO_PORTA(pin) ((0 * 16) + (pin)) +#define MCU_GPIO_PORTB(pin) ((1 * 16) + (pin)) + +#if NRF52 + +#define MCU_SYSVIEW_INTERRUPTS \ + "I#1=Reset,I#2=MNI,I#3=HardFault,I#4=MemoryMgmt,I#5=BusFault,I#6=UsageFault," \ + "I#11=SVCall,I#12=DebugMonitor,I#14=PendSV,I#15=SysTick," \ + "I#16=POWER_CLOCK,I#17=RADIO,I#18=UARTE0_UART0,I#19=SPIx0_TWIx0," \ + "I#20=SPIx1_TWIx1,I#21=NFCT,I#22=GPIOTE,I#23=SAADC," \ + "I#24=TIMER0,I#25=TIMER1,I#26=TIMER2,I#27=RTC0,I#28=TEMP,I#29=RNG,I#30=ECB," \ + "I#31=CCM_AAR,I#32=WDT,I#33=RTC1,I#34=QDEC,I#35=COMP_LPCOMP,I#36=SWI0_EGU0," \ + "I#37=SWI1_EGU1,I#38=SWI2_EGU2,I#39=SWI3_EGU3,I#40=SWI4_EGU4,I#41=SWI5_EGU5," \ + "I#42=TIMER3,I#43=TIMER4,I#44=PWM0,I#45=PDM,I#48=MWU,I#49=PWM1,I#50=PWM2," \ + "I#51=SPIx2,I#52=RTC2,I#53=I2S,I#54=FPU" + +#elif NRF52840_XXAA + +#define MCU_SYSVIEW_INTERRUPTS \ + "I#1=Reset,I#2=MNI,I#3=HardFault,I#4=MemoryMgmt,I#5=BusFault,I#6=UsageFault," \ + "I#11=SVCall,I#12=DebugMonitor,I#14=PendSV,I#15=SysTick," \ + "I#16=POWER_CLOCK,I#17=RADIO,I#18=UARTE0_UART0,I#19=SPIx0_TWIx0," \ + "I#20=SPIx1_TWIx1,I#21=NFCT,I#22=GPIOTE,I#23=SAADC," \ + "I#24=TIMER0,I#25=TIMER1,I#26=TIMER2,I#27=RTC0,I#28=TEMP,I#29=RNG,I#30=ECB," \ + "I#31=CCM_AAR,I#32=WDT,I#33=RTC1,I#34=QDEC,I#35=COMP_LPCOMP,I#36=SWI0_EGU0," \ + "I#37=SWI1_EGU1,I#38=SWI2_EGU2,I#39=SWI3_EGU3,I#40=SWI4_EGU4,I#41=SWI5_EGU5," \ + "I#42=TIMER3,I#43=TIMER4,I#44=PWM0,I#45=PDM,I#48=MWU,I#49=PWM1,I#50=PWM2," \ + "I#51=SPIx2,I#52=RTC2,I#53=I2S,I#54=FPU,I#55=USBD," \ + "I#56=UARTE1,I#57=QSPI,I#58=CRYPTOCELL,I#61=PWM3,I#63=SPIM3" + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __MCU_MCU_H_ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu_sim.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu_sim.h new file mode 100644 index 000000000..26f6cb984 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu_sim.h @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 __MCU_SIM_H__ +#define __MCU_SIM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *native_flash_file; +extern char *native_uart_log_file; +extern const char *native_uart_dev_strs[]; + +void mcu_sim_parse_args(int argc, char **argv); + +void static inline hal_debug_break(void) {} + +#ifdef __cplusplus +} +#endif + +#endif /* __MCU_SIM_H__ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_clock.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_clock.h new file mode 100644 index 000000000..d86aa98bf --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_clock.h @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 H_NRF52_CLOCK_ +#define H_NRF52_CLOCK_ + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * Request HFXO clock be turned on. Note that each request must have a + * corresponding release. + * + * @return int 0: hfxo was already on. 1: hfxo was turned on. + */ +int nrf52_clock_hfxo_request(void); + +/** + * Release the HFXO; caller no longer needs the HFXO to be turned on. Each call + * to release should have been preceeded by a corresponding call to request the + * HFXO + * + * + * @return int 0: HFXO not stopped by this call (others using it) 1: HFXO + * stopped. + */ +int nrf52_clock_hfxo_release(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_NRF52_CLOCK_ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_hal.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_hal.h new file mode 100644 index 000000000..df9a01654 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_hal.h @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 H_NRF52_HAL_ +#define H_NRF52_HAL_ + +#include "cmsis.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* Helper functions to enable/disable interrupts. */ +#define __HAL_DISABLE_INTERRUPTS(x) \ + do { \ + x = __get_PRIMASK(); \ + __disable_irq(); \ + } while(0); + +#define __HAL_ENABLE_INTERRUPTS(x) \ + do { \ + if (!x) { \ + __enable_irq(); \ + } \ + } while(0); + +struct nrf52_uart_cfg { + int8_t suc_pin_tx; /* pins for IO */ + int8_t suc_pin_rx; + int8_t suc_pin_rts; + int8_t suc_pin_cts; +}; +const struct nrf52_uart_cfg *bsp_uart_config(void); + +struct nrf52_hal_i2c_cfg { + int scl_pin; + int sda_pin; + uint32_t i2c_frequency; +}; +struct hal_flash; +extern const struct hal_flash nrf52k_flash_dev; +extern const struct hal_flash nrf52k_qspi_dev; + +/* SPI configuration (used for both master and slave) */ +struct nrf52_hal_spi_cfg { + uint8_t sck_pin; + uint8_t mosi_pin; + uint8_t miso_pin; + uint8_t ss_pin; +}; + +/* + * GPIO pin mapping + * + * The logical GPIO pin numbers (0 to N) are mapped to ports in the following + * manner: + * pins 0 - 31: Port 0 + * pins 32 - 48: Port 1. + * + * The nrf52832 has only one port with 32 pins. The nrf52840 has 48 pins and + * uses two ports. + * + * NOTE: in order to save code space, there is no checking done to see if the + * user specifies a pin that is not used by the processor. If an invalid pin + * number is used unexpected and/or erroneous behavior will result. + */ +#if defined(NRF52832_XXAA) || defined(NRF52810_XXAA) || defined(NRF52811_XXAA) +#define HAL_GPIO_INDEX(pin) (pin) +#define HAL_GPIO_PORT(pin) (NRF_P0) +#define HAL_GPIO_MASK(pin) (1 << pin) +#define HAL_GPIOTE_PIN_MASK GPIOTE_CONFIG_PSEL_Msk +#endif + +#ifdef NRF52840_XXAA +#define HAL_GPIO_INDEX(pin) ((pin) & 0x1F) +#define HAL_GPIO_PORT(pin) ((pin) > 31 ? NRF_P1 : NRF_P0) +#define HAL_GPIO_MASK(pin) (1 << HAL_GPIO_INDEX(pin)) +#define HAL_GPIOTE_PIN_MASK (0x3FUL << GPIOTE_CONFIG_PSEL_Pos) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_NRF52_HAL_ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_periph.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_periph.h new file mode 100644 index 000000000..0e49371ba --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_periph.h @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 H_NRF52_PERIPH_ +#define H_NRF52_PERIPH_ + +#ifdef __cplusplus + extern "C" { +#endif + +void nrf52_periph_create(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_NRF52_PERIPH_ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml b/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml new file mode 100644 index 000000000..4f332acba --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: babblesim/hw/mcu/nordic/nrf52_bsim +pkg.description: nRF52 on BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" + +pkg.deps: + - "babblesim/nrfx" + +pkg.deps.BLE_CONTROLLER: + - "@apache-mynewt-nimble/nimble/drivers/nrf52" diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_os_tick.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_os_tick.c new file mode 100644 index 000000000..a2d7170ab --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_os_tick.c @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 +#include "os/mynewt.h" +#include "hal/hal_os_tick.h" +#include "nrf.h" +#include "mcu/cmsis_nvic.h" +#include "mcu/mcu_sim.h" +#include +#include +#include +#include +#include + +/* The OS scheduler requires a low-frequency timer. */ +#if MYNEWT_VAL(OS_SCHEDULING) && !MYNEWT_VAL(MCU_LFCLK_SOURCE) + #error The OS scheduler requires a low-frequency timer; configure MCU_LFCLK_SOURCE +#endif + +#define RTC_FREQ 32768 /* in Hz */ +#define OS_TICK_TIMER NRF_RTC1 +#define OS_TICK_IRQ RTC1_IRQn +#define OS_TICK_CMPREG 3 /* generate timer interrupt */ +#define RTC_COMPARE_INT_MASK(ccreg) (1UL << ((ccreg) + 16)) + +struct hal_os_tick +{ + int ticks_per_ostick; + os_time_t max_idle_ticks; + uint32_t lastocmp; +}; + +struct hal_os_tick g_hal_os_tick; + +/* + * Implement (x - y) where the range of both 'x' and 'y' is limited to 24-bits. + * + * For example: + * + * sub24(0, 0xffffff) = 1 + * sub24(0xffffff, 0xfffffe) = 1 + * sub24(0xffffff, 0) = -1 + * sub24(0x7fffff, 0) = 8388607 + * sub24(0x800000, 0) = -8388608 + */ +static inline int +sub24(uint32_t x, uint32_t y) +{ + int result; + + assert(x <= 0xffffff); + assert(y <= 0xffffff); + + result = x - y; + if (result & 0x800000) { + return (result | 0xff800000); + } else { + return (result & 0x007fffff); + } +} + +static inline uint32_t +nrf52_os_tick_counter(void) +{ + return nrf_rtc_counter_get(OS_TICK_TIMER); +} + +static inline void +nrf52_os_tick_set_ocmp(uint32_t ocmp) +{ + int delta; + uint32_t counter; + + OS_ASSERT_CRITICAL(); + while (1) { + ocmp &= 0xffffff; + nrf_rtc_cc_set(OS_TICK_TIMER, OS_TICK_CMPREG, ocmp); + counter = nrf52_os_tick_counter(); + /* + * From nRF52 Product specification + * + * - If Counter is 'N' writing (N) or (N + 1) to CC register + * may not trigger a compare event. + * + * - If Counter is 'N' writing (N + 2) to CC register is guaranteed + * to trigger a compare event at 'N + 2'. + */ + delta = sub24(ocmp, counter); + if (delta > 2) { + break; + } + ocmp += g_hal_os_tick.ticks_per_ostick; + } +} + +static void +nrf52_timer_handler(void) +{ + int delta; + int ticks; + os_sr_t sr; + uint32_t counter; + + os_trace_isr_enter(); + OS_ENTER_CRITICAL(sr); + + /* Calculate elapsed ticks and advance OS time. */ + + counter = nrf52_os_tick_counter(); + delta = sub24(counter, g_hal_os_tick.lastocmp); + ticks = delta / g_hal_os_tick.ticks_per_ostick; + os_time_advance(ticks); + + /* Clear timer interrupt */ + OS_TICK_TIMER->EVENTS_COMPARE[OS_TICK_CMPREG] = 0; + + /* Update the time associated with the most recent tick */ + g_hal_os_tick.lastocmp = (g_hal_os_tick.lastocmp + + (ticks * g_hal_os_tick.ticks_per_ostick)) & 0xffffff; + + /* Update the output compare to interrupt at the next tick */ + nrf52_os_tick_set_ocmp(g_hal_os_tick.lastocmp + g_hal_os_tick.ticks_per_ostick); + + OS_EXIT_CRITICAL(sr); + os_trace_isr_exit(); +} + +/* Wait For Interrupt */ +void +__WFI(void) +{ + while (hw_irq_ctrl_get_irq_status() == 0) { + tm_tick(); + } +} + +void +os_tick_idle(os_time_t ticks) +{ + uint32_t ocmp; + + OS_ASSERT_CRITICAL(); + + if (ticks > 0) { + /* + * Enter tickless regime during long idle durations. + */ + if (ticks > g_hal_os_tick.max_idle_ticks) { + ticks = g_hal_os_tick.max_idle_ticks; + } + ocmp = g_hal_os_tick.lastocmp + (ticks*g_hal_os_tick.ticks_per_ostick); + nrf52_os_tick_set_ocmp(ocmp); + } + + __WFI(); + + if (ticks > 0) { + /* + * Update OS time before anything else when coming out of + * the tickless regime. + */ + nrf52_timer_handler(); + } +} + +extern void nrf_rtc_regw_sideeffects(int i); + +void +os_tick_init(uint32_t os_ticks_per_sec, int prio) +{ + uint32_t sr; + + assert(RTC_FREQ % os_ticks_per_sec == 0); + + g_hal_os_tick.lastocmp = 0; + g_hal_os_tick.ticks_per_ostick = RTC_FREQ / os_ticks_per_sec; + + /* + * The maximum number of OS ticks allowed to elapse during idle is + * limited to 1/4th the number of timer ticks before the 24-bit counter + * rolls over. + */ + g_hal_os_tick.max_idle_ticks = (1UL << 22) / g_hal_os_tick.ticks_per_ostick; + + /* disable interrupts */ + OS_ENTER_CRITICAL(sr); + + /* Set isr in vector table and enable interrupt */ + NVIC_SetPriority(OS_TICK_IRQ, prio); + NVIC_SetVector(OS_TICK_IRQ, (uint32_t)nrf52_timer_handler); + NVIC_EnableIRQ(OS_TICK_IRQ); + + /* + * Program the OS_TICK_TIMER to operate at 32KHz and trigger an output + * compare interrupt at a rate of 'os_ticks_per_sec'. + */ + nrf_rtc_task_trigger(OS_TICK_TIMER, NRF_RTC_TASK_STOP); + nrf_rtc_task_trigger(OS_TICK_TIMER, NRF_RTC_TASK_CLEAR); + nrf_rtc_event_disable(OS_TICK_TIMER, 0xffffffff); + nrf_rtc_int_disable(OS_TICK_TIMER, 0xffffffff); + nrf_rtc_int_enable(OS_TICK_TIMER, RTC_COMPARE_INT_MASK(OS_TICK_CMPREG)); + + OS_TICK_TIMER->EVENTS_COMPARE[OS_TICK_CMPREG] = 0; + nrf_rtc_cc_set(OS_TICK_TIMER, OS_TICK_CMPREG, g_hal_os_tick.ticks_per_ostick); + + nrf_rtc_task_trigger(OS_TICK_TIMER, NRF_RTC_TASK_START); + + OS_EXIT_CRITICAL(sr); +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_reset_cause.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_reset_cause.c new file mode 100644 index 000000000..32182c1ec --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_reset_cause.c @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 +#include "hal/hal_system.h" + +enum hal_reset_reason +hal_reset_cause(void) +{ + static enum hal_reset_reason reason; + uint32_t reg; + + if (reason) { + return reason; + } + reg = NRF_POWER->RESETREAS; + + if (reg & (POWER_RESETREAS_DOG_Msk | POWER_RESETREAS_LOCKUP_Msk)) { + reason = HAL_RESET_WATCHDOG; + } else if (reg & POWER_RESETREAS_SREQ_Msk) { + reason = HAL_RESET_SOFT; + } else if (reg & POWER_RESETREAS_RESETPIN_Msk) { + reason = HAL_RESET_PIN; + } else if (reg & POWER_RESETREAS_OFF_Msk) { + reason = HAL_RESET_SYS_OFF_INT; + } else { + reason = HAL_RESET_POR; /* could also be brownout */ + } + NRF_POWER->RESETREAS = reg; + return reason; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_system.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_system.c new file mode 100644 index 000000000..4f46f3469 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_system.c @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "syscfg/syscfg.h" +#include "hal/hal_system.h" +#include "hal/hal_debug.h" +#include "nrf.h" +#include "cmsis.h" +#include "mcu/mcu_sim.h" +#include "hal/nrf_clock.h" + +/** + * Function called at startup. Called after BSS and .data initialized but + * prior to the _start function. + * + * NOTE: this function is called by both the bootloader and the application. + * If you add code here that you do not want executed in either case you need + * to conditionally compile it using the config variable BOOT_LOADER (will + * be set to 1 in case of bootloader build) + * + */ +void +hal_system_init(void) +{ +#if MYNEWT_VAL(MCU_DCDC_ENABLED) + NRF_POWER->DCDCEN = 1; +#endif +} + +void +hal_system_reset(void) +{ + +#if MYNEWT_VAL(HAL_SYSTEM_RESET_CB) + hal_system_reset_cb(); +#endif + + while (1) { + HAL_DEBUG_BREAK(); + NVIC_SystemReset(); + } +} + +int +hal_debugger_connected(void) +{ + return 0; +} + +/** + * hal system clock start + * + * Makes sure the LFCLK and/or HFCLK is started. + */ +void +hal_system_clock_start(void) +{ +#if MYNEWT_VAL(MCU_LFCLK_SOURCE) + uint32_t regmsk; + uint32_t regval; + uint32_t clksrc; + + regmsk = CLOCK_LFCLKSTAT_STATE_Msk | CLOCK_LFCLKSTAT_SRC_Msk; + regval = CLOCK_LFCLKSTAT_STATE_Running << CLOCK_LFCLKSTAT_STATE_Pos; + +#if MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFXO) + regval |= CLOCK_LFCLKSTAT_SRC_Xtal << CLOCK_LFCLKSTAT_SRC_Pos; + clksrc = CLOCK_LFCLKSRC_SRC_Xtal; +#elif MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFSYNTH) + regval |= CLOCK_LFCLKSTAT_SRC_Synth << CLOCK_LFCLKSTAT_SRC_Pos; + clksrc = CLOCK_LFCLKSRC_SRC_Synth; +#elif MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFRC) + regval |= CLOCK_LFCLKSTAT_SRC_RC << CLOCK_LFCLKSTAT_SRC_Pos; + clksrc = CLOCK_LFCLKSRC_SRC_RC; +#else + #error Unknown LFCLK source selected +#endif + +#if MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFSYNTH) + /* Must turn on HFLCK for synthesized 32768 crystal */ + nrf52_clock_hfxo_request(); +#else + /* Make sure HFCLK is stopped */ + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); +#endif + + /* Check if this clock source is already running */ + if ((NRF_CLOCK_regs.LFCLKSTAT & regmsk) != regval) { + + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTOP); + NRF_CLOCK_regs.EVENTS_LFCLKSTARTED = 0; + NRF_CLOCK_regs.LFCLKSRC = clksrc; + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART); + + /* Wait here till started! */ +// while (1) { +// if (NRF_CLOCK_regs.EVENTS_LFCLKSTARTED) { +// if ((NRF_CLOCK_regs.LFCLKSTAT & regmsk) == regval) { +// break; +// } +// } +// } + } +#endif +} + + +void* +NRF_RADIO_BASE_FUN(void) +{ + return NULL; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_timer.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_timer.c new file mode 100644 index 000000000..0e3d914c9 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_timer.c @@ -0,0 +1,949 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 +#include +#include +#include +#include +#include "os/mynewt.h" +#include "mcu/cmsis_nvic.h" +#include "hal/hal_timer.h" +#include "nrf.h" +#include "mcu/nrf52_hal.h" +#include "mcu/nrf52_clock.h" +#include "hal/nrf_timer.h" + +/* IRQ prototype */ +typedef void (*hal_timer_irq_handler_t)(void); + +/* User CC 2 for reading counter, CC 3 for timer isr */ +#define NRF_TIMER_CC_READ (NRF_TIMER_CC_CHANNEL2) +#define NRF_TIMER_CC_INT (3) + +/* Output compare 2 used for RTC timers */ +#define NRF_RTC_TIMER_CC_INT (2) + +/* Maximum number of hal timers used */ +#define NRF52_HAL_TIMER_MAX (6) + +/* Maximum timer frequency */ +#define NRF52_MAX_TIMER_FREQ (16000000) + +struct nrf52_hal_timer { + uint8_t tmr_enabled; + uint8_t tmr_irq_num; + uint8_t tmr_rtc; + uint8_t tmr_pad; + uint32_t tmr_cntr; + uint32_t timer_isrs; + uint32_t tmr_freq; + void *tmr_reg; + TAILQ_HEAD(hal_timer_qhead, hal_timer) hal_timer_q; +}; + +#if MYNEWT_VAL(TIMER_0) +struct nrf52_hal_timer nrf52_hal_timer0; +#endif +#if MYNEWT_VAL(TIMER_1) +struct nrf52_hal_timer nrf52_hal_timer1; +#endif +#if MYNEWT_VAL(TIMER_2) +struct nrf52_hal_timer nrf52_hal_timer2; +#endif +#if MYNEWT_VAL(TIMER_3) +struct nrf52_hal_timer nrf52_hal_timer3; +#endif +#if MYNEWT_VAL(TIMER_4) +struct nrf52_hal_timer nrf52_hal_timer4; +#endif +#if MYNEWT_VAL(TIMER_5) +struct nrf52_hal_timer nrf52_hal_timer5; +#endif + +static const struct nrf52_hal_timer *nrf52_hal_timers[NRF52_HAL_TIMER_MAX] = { +#if MYNEWT_VAL(TIMER_0) + &nrf52_hal_timer0, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_1) + &nrf52_hal_timer1, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_2) + &nrf52_hal_timer2, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_3) + &nrf52_hal_timer3, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_4) + &nrf52_hal_timer4, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_5) + &nrf52_hal_timer5 +#else + NULL +#endif +}; + +/* Resolve timer number into timer structure */ +#define NRF52_HAL_TIMER_RESOLVE(__n, __v) \ + if ((__n) >= NRF52_HAL_TIMER_MAX) { \ + rc = EINVAL; \ + goto err; \ + } \ + (__v) = (struct nrf52_hal_timer *) nrf52_hal_timers[(__n)]; \ + if ((__v) == NULL) { \ + rc = EINVAL; \ + goto err; \ + } + +/* Interrupt mask for interrupt enable/clear */ +#define NRF_TIMER_INT_MASK(x) ((1 << (uint32_t)(x)) << 16) + +static uint32_t +nrf_read_timer_cntr(NRF_TIMER_Type *hwtimer) +{ + uint32_t tcntr; + + /* Force a capture of the timer into 'cntr' capture channel; read it */ + nrf_timer_task_trigger(hwtimer, NRF_TIMER_TASK_CAPTURE2); + tcntr = hwtimer->CC[NRF_TIMER_CC_READ]; + + return tcntr; +} + +/** + * nrf timer set ocmp + * + * Set the OCMP used by the timer to the desired expiration tick + * + * NOTE: Must be called with interrupts disabled. + * + * @param timer Pointer to timer. + */ +static void +nrf_timer_set_ocmp(struct nrf52_hal_timer *bsptimer, uint32_t expiry) +{ + int32_t delta_t; + uint32_t temp; + uint32_t cntr; + NRF_TIMER_Type *hwtimer; + NRF_RTC_Type *rtctimer; + + if (bsptimer->tmr_rtc) { + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + nrf_rtc_int_disable(rtctimer, NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT)); + temp = bsptimer->tmr_cntr; + cntr = nrf_rtc_counter_get(rtctimer); + if (rtctimer->EVENTS_OVRFLW) { + temp += (1UL << 24); + cntr = nrf_rtc_counter_get(rtctimer); + } + temp |= cntr; + delta_t = (int32_t)(expiry - temp); + + /* + * The nRF52xxx documentation states that COMPARE event is guaranteed + * only if value written to CC register is at least 2 greater than the + * current counter value. We also need to account for possible extra + * tick during calculations so effectively any delta less than 3 needs + * to be handled differently. TICK event is used to have interrupt on + * each subsequent tick so we won't miss any and in case we detected + * mentioned extra tick during calculations, interrupt is triggered + * immediately. Delta 0 or less means we should always fire immediately. + */ + if (delta_t < 1) { + nrf_rtc_int_disable(rtctimer, RTC_INTENCLR_TICK_Msk); + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } else if (delta_t < 3 && 0) { + nrf_rtc_int_enable(rtctimer, RTC_INTENSET_TICK_Msk); + if (nrf_rtc_counter_get(rtctimer) != cntr) { + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + } else { + nrf_rtc_int_disable(rtctimer, RTC_INTENCLR_TICK_Msk); + + if (delta_t < (1UL << 24)) { + nrf_rtc_cc_set(rtctimer, NRF_RTC_TIMER_CC_INT, expiry & 0x00ffffff); + } else { + /* CC too far ahead. Just make sure we set compare far ahead */ + nrf_rtc_cc_set(rtctimer, NRF_RTC_TIMER_CC_INT, cntr + (1UL << 23)); + } + nrf_rtc_int_enable(rtctimer, NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT)); + } + } else { + hwtimer = bsptimer->tmr_reg; + + /* Disable ocmp interrupt and set new value */ + nrf_timer_int_disable(hwtimer, NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)); + + /* Set output compare register to timer expiration */ + nrf_timer_cc_set(hwtimer, NRF_TIMER_CC_INT, expiry); + + /* Clear interrupt flag */ + hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0; + + /* Enable the output compare interrupt */ + nrf_timer_int_enable(hwtimer, NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)); + + /* Force interrupt to occur as we may have missed it */ + if ((int32_t)(nrf_read_timer_cntr(hwtimer) - expiry) >= 0) { + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + } +} + +/* Disable output compare used for timer */ +static void +nrf_timer_disable_ocmp(NRF_TIMER_Type *hwtimer) +{ + nrf_timer_int_disable(hwtimer, NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)); +} + +static void +nrf_rtc_disable_ocmp(NRF_RTC_Type *rtctimer) +{ + nrf_rtc_int_disable(rtctimer, NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT)); + nrf_rtc_int_disable(rtctimer, RTC_INTENCLR_TICK_Msk); +} + +static uint32_t +hal_timer_read_bsptimer(struct nrf52_hal_timer *bsptimer) +{ + uint32_t low32; + uint32_t ctx; + uint32_t tcntr; + NRF_RTC_Type *rtctimer; + + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + __HAL_DISABLE_INTERRUPTS(ctx); + tcntr = bsptimer->tmr_cntr; + low32 = nrf_rtc_counter_get(rtctimer); + if (rtctimer->EVENTS_OVRFLW) { + tcntr += (1UL << 24); + bsptimer->tmr_cntr = tcntr; + low32 = nrf_rtc_counter_get(rtctimer); + rtctimer->EVENTS_OVRFLW = 0; + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + tcntr |= low32; + __HAL_ENABLE_INTERRUPTS(ctx); + + return tcntr; +} + +#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \ + MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4) || MYNEWT_VAL(TIMER_5)) +/** + * hal timer chk queue + * + * + * @param bsptimer + */ +static void +hal_timer_chk_queue(struct nrf52_hal_timer *bsptimer) +{ + uint32_t tcntr; + uint32_t ctx; + struct hal_timer *timer; + + /* disable interrupts */ + __HAL_DISABLE_INTERRUPTS(ctx); + while ((timer = TAILQ_FIRST(&bsptimer->hal_timer_q)) != NULL) { + if (bsptimer->tmr_rtc) { + tcntr = hal_timer_read_bsptimer(bsptimer); + } else { + tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg); + } + if ((int32_t)(tcntr - timer->expiry) >= 0) { + TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link); + timer->link.tqe_prev = NULL; + timer->cb_func(timer->cb_arg); + } else { + break; + } + } + + /* Any timers left on queue? If so, we need to set OCMP */ + timer = TAILQ_FIRST(&bsptimer->hal_timer_q); + if (timer) { + nrf_timer_set_ocmp(bsptimer, timer->expiry); + } else { + if (bsptimer->tmr_rtc) { + nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg); + } else { + nrf_timer_disable_ocmp(bsptimer->tmr_reg); + } + } + __HAL_ENABLE_INTERRUPTS(ctx); +} +#endif + +/** + * hal timer irq handler + * + * Generic HAL timer irq handler. + * + * @param tmr + */ +/** + * hal timer irq handler + * + * This is the global timer interrupt routine. + * + */ +#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \ + MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4)) + +static void +hal_timer_irq_handler(struct nrf52_hal_timer *bsptimer) +{ + uint32_t compare; + NRF_TIMER_Type *hwtimer; + + os_trace_isr_enter(); + + /* Check interrupt source. If set, clear them */ + hwtimer = bsptimer->tmr_reg; + compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT]; + if (compare) { + hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0; + } + + /* XXX: make these stats? */ + /* Count # of timer isrs */ + ++bsptimer->timer_isrs; + + /* + * NOTE: we dont check the 'compare' variable here due to how the timer + * is implemented on this chip. There is no way to force an output + * compare, so if we are late setting the output compare (i.e. the timer + * counter is already passed the output compare value), we use the NVIC + * to set a pending interrupt. This means that there will be no compare + * flag set, so all we do is check to see if the compare interrupt is + * enabled. + */ + if (hwtimer->INTENCLR & NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)) { + hal_timer_chk_queue(bsptimer); + /* XXX: Recommended by nordic to make sure interrupts are cleared */ + compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT]; + } + + os_trace_isr_exit(); +} +#endif + +#if MYNEWT_VAL(TIMER_5) +static void +hal_rtc_timer_irq_handler(struct nrf52_hal_timer *bsptimer) +{ + uint32_t overflow; + uint32_t compare; + uint32_t tick; + NRF_RTC_Type *rtctimer; + + os_trace_isr_enter(); + + /* Check interrupt source. If set, clear them */ + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT]; + if (compare) { + rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT] = 0; + } + + tick = rtctimer->EVENTS_TICK; + if (tick) { + rtctimer->EVENTS_TICK = 0; + } + + overflow = rtctimer->EVENTS_OVRFLW; + if (overflow) { + rtctimer->EVENTS_OVRFLW = 0; + bsptimer->tmr_cntr += (1UL << 24); + } + + /* Count # of timer isrs */ + ++bsptimer->timer_isrs; + + /* + * NOTE: we dont check the 'compare' variable here due to how the timer + * is implemented on this chip. There is no way to force an output + * compare, so if we are late setting the output compare (i.e. the timer + * counter is already passed the output compare value), we use the NVIC + * to set a pending interrupt. This means that there will be no compare + * flag set, so all we do is check to see if the compare interrupt is + * enabled. + */ + hal_timer_chk_queue(bsptimer); + + /* Recommended by nordic to make sure interrupts are cleared */ + compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT]; + + os_trace_isr_exit(); +} +#endif + +#if MYNEWT_VAL(TIMER_0) +void +nrf52_timer0_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer0); +} +#endif + +#if MYNEWT_VAL(TIMER_1) +void +nrf52_timer1_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer1); +} +#endif + +#if MYNEWT_VAL(TIMER_2) +void +nrf52_timer2_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer2); +} +#endif + +#if MYNEWT_VAL(TIMER_3) +void +nrf52_timer3_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer3); +} +#endif + +#if MYNEWT_VAL(TIMER_4) +void +nrf52_timer4_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer4); +} +#endif + +#if MYNEWT_VAL(TIMER_5) +void +nrf52_timer5_irq_handler(void) +{ + hal_rtc_timer_irq_handler(&nrf52_hal_timer5); +} +#endif + +/** + * hal timer init + * + * Initialize platform specific timer items + * + * @param timer_num Timer number to initialize + * @param cfg Pointer to platform specific configuration + * + * @return int 0: success; error code otherwise + */ +int +hal_timer_init(int timer_num, void *cfg) +{ + int rc; + uint8_t irq_num; + struct nrf52_hal_timer *bsptimer; + void *hwtimer; + hal_timer_irq_handler_t irq_isr; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + /* If timer is enabled do not allow init */ + if (bsptimer->tmr_enabled) { + rc = EINVAL; + goto err; + } + + switch (timer_num) { +#if MYNEWT_VAL(TIMER_0) + case 0: + irq_num = TIMER0_IRQn; + hwtimer = NRF_TIMER0; + irq_isr = nrf52_timer0_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_1) + case 1: + irq_num = TIMER1_IRQn; + hwtimer = NRF_TIMER1; + irq_isr = nrf52_timer1_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_2) + case 2: + irq_num = TIMER2_IRQn; + hwtimer = NRF_TIMER2; + irq_isr = nrf52_timer2_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_3) + case 3: + irq_num = TIMER3_IRQn; + hwtimer = NRF_TIMER3; + irq_isr = nrf52_timer3_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_4) + case 4: + irq_num = TIMER4_IRQn; + hwtimer = NRF_TIMER4; + irq_isr = nrf52_timer4_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_5) + case 5: + irq_num = RTC0_IRQn; + hwtimer = NRF_RTC0; + irq_isr = nrf52_timer5_irq_handler; + bsptimer->tmr_rtc = 1; + break; +#endif + default: + hwtimer = NULL; + break; + } + + if (hwtimer == NULL) { + rc = EINVAL; + goto err; + } + + bsptimer->tmr_reg = hwtimer; + bsptimer->tmr_irq_num = irq_num; + + /* Disable IRQ, set priority and set vector in table */ + NVIC_DisableIRQ(irq_num); + NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1); + NVIC_SetVector(irq_num, (uint32_t)irq_isr); + + return 0; + +err: + return rc; +} + +/** + * hal timer config + * + * Configure a timer to run at the desired frequency. This starts the timer. + * + * @param timer_num + * @param freq_hz + * + * @return int + */ +int +hal_timer_config(int timer_num, uint32_t freq_hz) +{ + int rc; + uint8_t prescaler; + uint32_t ctx; + uint32_t div; + uint32_t min_delta; + uint32_t max_delta; + struct nrf52_hal_timer *bsptimer; + NRF_TIMER_Type *hwtimer; +#if MYNEWT_VAL(TIMER_5) + NRF_RTC_Type *rtctimer; +#endif + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + +#if MYNEWT_VAL(TIMER_5) + if (timer_num == 5) { + /* NOTE: we only allow the RTC frequency to be set at 32768 */ + if (bsptimer->tmr_enabled || (freq_hz != 32768) || + (bsptimer->tmr_reg == NULL)) { + rc = EINVAL; + goto err; + } + + bsptimer->tmr_freq = freq_hz; + bsptimer->tmr_enabled = 1; + + __HAL_DISABLE_INTERRUPTS(ctx); + + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + + /* Stop the timer first */ + nrf_rtc_task_trigger(rtctimer, NRF_RTC_TASK_STOP); + nrf_rtc_task_trigger(rtctimer, NRF_RTC_TASK_CLEAR); + + /* Always no prescaler */ + rtctimer->PRESCALER = 0; + + /* Clear overflow events and set overflow interrupt */ + rtctimer->EVENTS_OVRFLW = 0; + nrf_rtc_int_enable(rtctimer, RTC_INTENSET_OVRFLW_Msk); + + /* Start the timer */ + nrf_rtc_task_trigger(rtctimer, NRF_RTC_TASK_START); + /* Set isr in vector table and enable interrupt */ + NVIC_EnableIRQ(bsptimer->tmr_irq_num); + + __HAL_ENABLE_INTERRUPTS(ctx); + return 0; + } +#endif + + /* Set timer to desired frequency */ + div = NRF52_MAX_TIMER_FREQ / freq_hz; + + /* + * Largest prescaler is 2^9 and must make sure frequency not too high. + * If hwtimer is NULL it means that the timer was not initialized prior + * to call. + */ + if (bsptimer->tmr_enabled || (div == 0) || (div > 512) || + (bsptimer->tmr_reg == NULL)) { + rc = EINVAL; + goto err; + } + + if (div == 1) { + prescaler = 0; + } else { + /* Find closest prescaler */ + for (prescaler = 1; prescaler < 10; ++prescaler) { + if (div <= (1 << prescaler)) { + min_delta = div - (1 << (prescaler - 1)); + max_delta = (1 << prescaler) - div; + if (min_delta < max_delta) { + prescaler -= 1; + } + break; + } + } + } + + /* Now set the actual frequency */ + bsptimer->tmr_freq = NRF52_MAX_TIMER_FREQ / (1 << prescaler); + bsptimer->tmr_enabled = 1; + + /* disable interrupts */ + __HAL_DISABLE_INTERRUPTS(ctx); + +#if MYNEWT_VAL_CHOICE(MCU_HFCLK_SOURCE, HFXO) + /* Make sure HFXO is started */ + nrf52_clock_hfxo_request(); +#endif + hwtimer = bsptimer->tmr_reg; + + /* Stop the timer first */ + nrf_timer_task_trigger(hwtimer, NRF_TIMER_TASK_STOP); + nrf_timer_task_trigger(hwtimer, NRF_TIMER_TASK_CLEAR); + + /* Put the timer in timer mode using 32 bits. */ + nrf_timer_mode_set(hwtimer, NRF_TIMER_MODE_TIMER); + hwtimer->BITMODE = TIMER_BITMODE_BITMODE_32Bit; + + /* Set the pre-scalar */ + hwtimer->PRESCALER = prescaler; + + /* Start the timer */ + nrf_timer_task_trigger(hwtimer, NRF_TIMER_TASK_START); + + NVIC_EnableIRQ(bsptimer->tmr_irq_num); + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; + +err: + return rc; +} + +/** + * hal timer deinit + * + * De-initialize a HW timer. + * + * @param timer_num + * + * @return int + */ +int +hal_timer_deinit(int timer_num) +{ + int rc; + uint32_t ctx; + struct nrf52_hal_timer *bsptimer; + NRF_TIMER_Type *hwtimer; + NRF_RTC_Type *rtctimer; + + rc = 0; + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + __HAL_DISABLE_INTERRUPTS(ctx); + if (bsptimer->tmr_rtc) { + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + nrf_rtc_int_disable(rtctimer, NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT)); + nrf_rtc_task_trigger(rtctimer, NRF_RTC_TASK_STOP); + } else { + hwtimer = (NRF_TIMER_Type *)bsptimer->tmr_reg; + nrf_timer_int_disable(hwtimer, NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)); + hwtimer->TASKS_SHUTDOWN = 1; + } + bsptimer->tmr_enabled = 0; + bsptimer->tmr_reg = NULL; + +#if MYNEWT_VAL_CHOICE(MCU_HFCLK_SOURCE, HFXO) + if (timer_num != 5) { + nrf52_clock_hfxo_release(); + } +#endif + __HAL_ENABLE_INTERRUPTS(ctx); + +err: + return rc; +} + +/** + * hal timer get resolution + * + * Get the resolution of the timer. This is the timer period, in nanoseconds + * + * @param timer_num + * + * @return uint32_t The + */ +uint32_t +hal_timer_get_resolution(int timer_num) +{ + int rc; + uint32_t resolution; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + resolution = 1000000000 / bsptimer->tmr_freq; + return resolution; + +err: + rc = 0; + return rc; +} + +/** + * hal timer read + * + * Returns the timer counter. NOTE: if the timer is a 16-bit timer, only + * the lower 16 bits are valid. If the timer is a 64-bit timer, only the + * low 32-bits are returned. + * + * @return uint32_t The timer counter register. + */ +uint32_t +hal_timer_read(int timer_num) +{ + int rc; + uint32_t tcntr; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + if (bsptimer->tmr_rtc) { + tcntr = hal_timer_read_bsptimer(bsptimer); + } else { + tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg); + } + + return tcntr; + + /* Assert here since there is no invalid return code */ +err: + assert(0); + rc = 0; + return rc; +} + +/** + * hal timer delay + * + * Blocking delay for n ticks + * + * @param timer_num + * @param ticks + * + * @return int 0 on success; error code otherwise. + */ +int +hal_timer_delay(int timer_num, uint32_t ticks) +{ + uint32_t until; + + until = hal_timer_read(timer_num) + ticks; + while ((int32_t)(hal_timer_read(timer_num) - until) <= 0) { + /* Loop here till finished */ + } + + return 0; +} + +/** + * + * Initialize the HAL timer structure with the callback and the callback + * argument. Also initializes the HW specific timer pointer. + * + * @param cb_func + * + * @return int + */ +int +hal_timer_set_cb(int timer_num, struct hal_timer *timer, hal_timer_cb cb_func, + void *arg) +{ + int rc; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + timer->cb_func = cb_func; + timer->cb_arg = arg; + timer->link.tqe_prev = NULL; + timer->bsp_timer = bsptimer; + + rc = 0; + +err: + return rc; +} + +int +hal_timer_start(struct hal_timer *timer, uint32_t ticks) +{ + int rc; + uint32_t tick; + struct nrf52_hal_timer *bsptimer; + + /* Set the tick value at which the timer should expire */ + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + if (bsptimer->tmr_rtc) { + tick = hal_timer_read_bsptimer(bsptimer) + ticks; + } else { + tick = nrf_read_timer_cntr(bsptimer->tmr_reg) + ticks; + } + rc = hal_timer_start_at(timer, tick); + return rc; +} + +int +hal_timer_start_at(struct hal_timer *timer, uint32_t tick) +{ + uint32_t ctx; + struct hal_timer *entry; + struct nrf52_hal_timer *bsptimer; + + if ((timer == NULL) || (timer->link.tqe_prev != NULL) || + (timer->cb_func == NULL)) { + return EINVAL; + } + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + timer->expiry = tick; + + __HAL_DISABLE_INTERRUPTS(ctx); + + if (TAILQ_EMPTY(&bsptimer->hal_timer_q)) { + TAILQ_INSERT_HEAD(&bsptimer->hal_timer_q, timer, link); + } else { + TAILQ_FOREACH(entry, &bsptimer->hal_timer_q, link) { + if ((int32_t)(timer->expiry - entry->expiry) < 0) { + TAILQ_INSERT_BEFORE(entry, timer, link); + break; + } + } + if (!entry) { + TAILQ_INSERT_TAIL(&bsptimer->hal_timer_q, timer, link); + } + } + + /* If this is the head, we need to set new OCMP */ + if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) { + nrf_timer_set_ocmp(bsptimer, timer->expiry); + } + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; +} + +/** + * hal timer stop + * + * Stop a timer. + * + * @param timer + * + * @return int + */ +int +hal_timer_stop(struct hal_timer *timer) +{ + uint32_t ctx; + int reset_ocmp; + struct hal_timer *entry; + struct nrf52_hal_timer *bsptimer; + + if (timer == NULL) { + return EINVAL; + } + + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + + __HAL_DISABLE_INTERRUPTS(ctx); + + if (timer->link.tqe_prev != NULL) { + reset_ocmp = 0; + if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) { + /* If first on queue, we will need to reset OCMP */ + entry = TAILQ_NEXT(timer, link); + reset_ocmp = 1; + } + TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link); + timer->link.tqe_prev = NULL; + if (reset_ocmp) { + if (entry) { + nrf_timer_set_ocmp((struct nrf52_hal_timer *)entry->bsp_timer, + entry->expiry); + } else { + if (bsptimer->tmr_rtc) { + nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg); + } else { + nrf_timer_disable_ocmp(bsptimer->tmr_reg); + } + } + } + } + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_uart.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_uart.c new file mode 100644 index 000000000..41ac9b1db --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_uart.c @@ -0,0 +1,478 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "os/mynewt.h" +#include "hal/hal_uart.h" +#include "bsp/bsp.h" + +#ifdef MN_LINUX +#include +#endif +#ifdef MN_OSX +#include +#endif +#ifdef MN_FreeBSD +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcu/mcu_sim.h" +#include "native_uart_cfg_priv.h" +#include "syscfg/syscfg.h" + +#define UART_CNT 2 + +#if MYNEWT_VAL(CONSOLE_UART_TX_BUF_SIZE) +#define UART_MAX_BYTES_PER_POLL MYNEWT_VAL(CONSOLE_UART_TX_BUF_SIZE) - 2 +#else +#define UART_MAX_BYTES_PER_POLL 64 +#endif +#define UART_POLLER_STACK_SZ OS_STACK_ALIGN(1024) + +struct uart { + int u_open; + int u_fd; + int u_tx_run; + int u_rx_char; + hal_uart_rx_char u_rx_func; + hal_uart_tx_char u_tx_func; + hal_uart_tx_done u_tx_done; + void *u_func_arg; +}; + +const char *native_uart_dev_strs[UART_CNT]; + +/* + * XXXX should try to use O_ASYNC/SIGIO for byte arrival notification, + * so we wouldn't need an OS for pseudo ttys. + */ +char *native_uart_log_file = NULL; +static int uart_log_fd = -1; + +static struct uart uarts[UART_CNT]; +static int uart_poller_running; +static struct os_task uart_poller_task; +static os_stack_t uart_poller_stack[UART_POLLER_STACK_SZ]; + +static void +uart_open_log(void) +{ + if (native_uart_log_file && uart_log_fd < 0) { + uart_log_fd = open(native_uart_log_file, O_WRONLY | O_CREAT | O_TRUNC, + 0666); + assert(uart_log_fd >= 0); + } +} + +static void +uart_log_data(struct uart *u, int istx, uint8_t data) +{ + static struct { + struct uart *uart; + int istx; + uint32_t time; + int chars_in_line; + } state = { + .uart = NULL, + .istx = 0 + }; + uint32_t now; + char tmpbuf[32]; + int len; + + if (uart_log_fd < 0) { + return; + } + now = os_time_get(); + if (state.uart) { + if (u != state.uart || now != state.time || istx != state.istx) { + /* + * End current printout. + */ + if (write(uart_log_fd, "\n", 1) != 1) { + assert(0); + } + state.uart = NULL; + } else { + if (state.chars_in_line == 8) { + if (write(uart_log_fd, "\n\t", 2) != 2) { + assert(0); + } + state.chars_in_line = 0; + } + len = snprintf(tmpbuf, sizeof(tmpbuf), "%c (%02x) ", + isalnum(data) ? data : '?', data); + if (write(uart_log_fd, tmpbuf, len) != len) { + assert(0); + } + state.chars_in_line++; + } + } + if (u && state.uart == NULL) { + len = snprintf(tmpbuf, sizeof(tmpbuf), "%u:uart%d %s\n\t%c (%02x) ", + now, u - uarts, istx ? "tx" : "rx", isalnum(data) ? data : '?', data); + if (write(uart_log_fd, tmpbuf, len) != len) { + assert(0); + } + state.chars_in_line = 1; + state.uart = u; + state.istx = istx; + state.time = now; + } +} + +static int +uart_transmit_char(struct uart *uart) +{ + int sr; + int rc; + char ch; + + OS_ENTER_CRITICAL(sr); + rc = uart->u_tx_func(uart->u_func_arg); + if (rc < 0) { + /* + * No more data to send. + */ + uart->u_tx_run = 0; + if (uart->u_tx_done) { + uart->u_tx_done(uart->u_func_arg); + } + OS_EXIT_CRITICAL(sr); + return 0; + } + ch = rc; + uart_log_data(uart, 1, ch); + OS_EXIT_CRITICAL(sr); + rc = write(uart->u_fd, &ch, 1); + if (rc <= 0) { + /* XXX EOF/error, what now? */ + return -1; + } + return 0; +} + +static void +uart_poller(void *arg) +{ + int i; + int rc; + int bytes; + int sr; + int didwork; + unsigned char ch; + struct uart *uart; + + while (1) { + for (i = 0; i < UART_CNT; i++) { + if (!uarts[i].u_open) { + continue; + } + uart = &uarts[i]; + + for (bytes = 0; bytes < UART_MAX_BYTES_PER_POLL; bytes++) { + didwork = 0; + if (uart->u_tx_run) { + uart_transmit_char(uart); + didwork = 1; + } + if (uart->u_rx_char < 0) { + rc = read(uart->u_fd, &ch, 1); + if (rc == 0) { + /* XXX EOF, what now? */ + assert(0); + } else if (rc > 0) { + uart->u_rx_char = ch; + } + } + if (uart->u_rx_char >= 0) { + OS_ENTER_CRITICAL(sr); + uart_log_data(uart, 0, uart->u_rx_char); + rc = uart->u_rx_func(uart->u_func_arg, uart->u_rx_char); + /* Delivered */ + if (rc >= 0) { + uart->u_rx_char = -1; + didwork = 1; + } + OS_EXIT_CRITICAL(sr); + } + if (!didwork) { + break; + } + } + } + uart_log_data(NULL, 0, 0); + os_time_delay(OS_TICKS_PER_SEC / 100); + } +} + +static void +set_nonblock(int fd) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags == -1) { + const char msg[] = "fcntl(F_GETFL) fail"; + write(1, msg, sizeof(msg)); + return; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + const char msg[] = "fcntl(F_SETFL) fail"; + write(1, msg, sizeof(msg)); + return; + } +} + +static int +uart_pty_set_attr(int fd) +{ + struct termios tios; + + if (tcgetattr(fd, &tios)) { + const char msg[] = "tcgetattr() failed"; + write(1, msg, sizeof(msg)); + return -1; + } + + tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); + tios.c_cflag |= CS8 | CREAD; + tios.c_iflag = IGNPAR; + tios.c_oflag = 0; + tios.c_lflag = 0; + if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { + const char msg[] = "tcsetattr() failed"; + write(1, msg, sizeof(msg)); + return -1; + } + return 0; +} + +static int +uart_pty(int port) +{ + int fd; + int loop_slave; + char pty_name[32]; + char msg[64]; + + if (openpty(&fd, &loop_slave, pty_name, NULL, NULL) < 0) { + const char msg[] = "openpty() failed"; + write(1, msg, sizeof(msg)); + return -1; + } + + if (uart_pty_set_attr(loop_slave)) { + goto err; + } + + snprintf(msg, sizeof(msg), "uart%d at %s\n", port, pty_name); + write(1, msg, strlen(msg)); + return fd; + err: + close(fd); + close(loop_slave); + return -1; +} + +/** + * Opens an external device terminal (/dev/cu.<...>). + */ +static int +uart_open_dev(int port, int32_t baudrate, uint8_t databits, + uint8_t stopbits, enum hal_uart_parity parity, + enum hal_uart_flow_ctl flow_ctl) +{ + const char *filename; + int fd; + int rc; + + filename = native_uart_dev_strs[port]; + assert(filename != NULL); + + fd = open(filename, O_RDWR); + if (fd < 0) { + return -1; + } + + rc = uart_dev_set_attr(fd, baudrate, databits, + stopbits, parity, flow_ctl); + if (rc != 0) { + close(fd); + return rc; + } + + dprintf(1, "uart%d at %s\n", port, filename); + + return fd; +} + +void +hal_uart_start_tx(int port) +{ + int sr; + + if (port >= UART_CNT || uarts[port].u_open == 0) { + return; + } + OS_ENTER_CRITICAL(sr); + uarts[port].u_tx_run = 1; + if (!os_started()) { + /* + * XXX this is a hack. + */ + uart_transmit_char(&uarts[port]); + } + OS_EXIT_CRITICAL(sr); +} + +void +hal_uart_start_rx(int port) +{ + /* nothing to do here */ +} + +void +hal_uart_blocking_tx(int port, uint8_t data) +{ + if (port >= UART_CNT || uarts[port].u_open == 0) { + return; + } + + /* XXX: Count statistics and add error checking here. */ + (void) write(uarts[port].u_fd, &data, sizeof(data)); +} + +int +hal_uart_init_cbs(int port, hal_uart_tx_char tx_func, hal_uart_tx_done tx_done, + hal_uart_rx_char rx_func, void *arg) +{ + struct uart *uart; + int rc; + + if (port >= UART_CNT) { + return -1; + } + + uart = &uarts[port]; + if (uart->u_open) { + return -1; + } + uart->u_tx_func = tx_func; + uart->u_tx_done = tx_done; + uart->u_rx_func = rx_func; + uart->u_func_arg = arg; + uart->u_rx_char = -1; + + if (!uart_poller_running) { + uart_poller_running = 1; + rc = os_task_init(&uart_poller_task, "uartpoll", uart_poller, NULL, + MYNEWT_VAL(MCU_UART_POLLER_PRIO), OS_WAIT_FOREVER, uart_poller_stack, + UART_POLLER_STACK_SZ); + assert(rc == 0); + } + return 0; +} + +int +hal_uart_config(int port, int32_t baudrate, uint8_t databits, uint8_t stopbits, + enum hal_uart_parity parity, enum hal_uart_flow_ctl flow_ctl) +{ + struct uart *uart; + + if (port >= UART_CNT) { + return -1; + } + + uart = &uarts[port]; + if (uart->u_open) { + return -1; + } + + if (native_uart_dev_strs[port] == NULL) { + uart->u_fd = uart_pty(port); + } else { + uart->u_fd = uart_open_dev(port, baudrate, databits, stopbits, + parity, flow_ctl); + } + + if (uart->u_fd < 0) { + return -1; + } + set_nonblock(uart->u_fd); + + + uart_open_log(); + uart->u_open = 1; + return 0; +} + +int +hal_uart_close(int port) +{ + struct uart *uart; + int rc; + + if (port >= UART_CNT) { + rc = -1; + goto err; + } + + uart = &uarts[port]; + if (!uart->u_open) { + rc = -1; + goto err; + } + + close(uart->u_fd); + + uart->u_open = 0; + return (0); + err: + return (rc); +} + +int +hal_uart_init(int port, void *arg) +{ + return (0); +} + +int +uart_set_dev(int port, const char *dev_str) +{ + if (port < 0 || port >= UART_CNT) { + return SYS_EINVAL; + } + + if (uarts[port].u_open) { + return SYS_EBUSY; + } + + native_uart_dev_strs[port] = dev_str; + + return 0; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_watchdog.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_watchdog.c new file mode 100644 index 000000000..d94c7e332 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_watchdog.c @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "hal/hal_watchdog.h" + +int +hal_watchdog_init(uint32_t expire_msecs) +{ + return (0); +} + +void +hal_watchdog_enable(void) +{ +} + +void +hal_watchdog_tickle(void) +{ +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg.c new file mode 100644 index 000000000..5e38ac7bf --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg.c @@ -0,0 +1,248 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 +#include +#include +#include +#include +#include + +/* B0 defined in bits/termios.h collides with nrfx/mdk/nrf52.h */ +#undef B0 + +#include "os/mynewt.h" +#include "native_uart_cfg_priv.h" + +/* uint64 is used here to accommodate speed_t, whatever that is. */ +static const uint64_t uart_baud_table[][2] = { +#ifdef B50 + { 50, B50 }, +#endif +#ifdef B75 + { 75, B75 }, +#endif +#ifdef B110 + { 110, B110 }, +#endif +#ifdef B134 + { 134, B134 }, +#endif +#ifdef B150 + { 150, B150 }, +#endif +#ifdef B200 + { 200, B200 }, +#endif +#ifdef B300 + { 300, B300 }, +#endif +#ifdef B600 + { 600, B600 }, +#endif +#ifdef B1200 + { 1200, B1200 }, +#endif +#ifdef B1800 + { 1800, B1800 }, +#endif +#ifdef B2400 + { 2400, B2400 }, +#endif +#ifdef B4800 + { 4800, B4800 }, +#endif +#ifdef B9600 + { 9600, B9600 }, +#endif +#ifdef B19200 + { 19200, B19200 }, +#endif +#ifdef B38400 + { 38400, B38400 }, +#endif +#ifdef B57600 + { 57600, B57600 }, +#endif +#ifdef B115200 + { 115200, B115200 }, +#endif +#ifdef B230400 + { 230400, B230400 }, +#endif +#ifdef B460800 + { 460800, B460800 }, +#endif +#ifdef B500000 + { 500000, B500000 }, +#endif +#ifdef B576000 + { 576000, B576000 }, +#endif +#ifdef B921600 + { 921600, B921600 }, +#endif +#ifdef B1000000 + { 1000000, B1000000 }, +#endif +#ifdef B1152000 + { 1152000, B1152000 }, +#endif +#ifdef B1500000 + { 1500000, B1500000 }, +#endif +#ifdef B2000000 + { 2000000, B2000000 }, +#endif +#ifdef B2500000 + { 2500000, B2500000 }, +#endif +#ifdef B3000000 + { 3000000, B3000000 }, +#endif +#ifdef B3500000 + { 3500000, B3500000 }, +#endif +#ifdef B3710000 + { 3710000, B3710000 }, +#endif +#ifdef B4000000 + { 4000000, B4000000 }, +#endif +}; +#define UART_BAUD_TABLE_SZ (sizeof uart_baud_table / sizeof uart_baud_table[0]) + +/** + * Returns 0 on failure. + */ +speed_t +uart_baud_to_speed(int_least32_t baud) +{ + int i; + + for (i = 0; i < UART_BAUD_TABLE_SZ; i++) { + if (uart_baud_table[i][0] == baud) { + return uart_baud_table[i][1]; + } + } + + return 0; +} + +/** + * Configures an external device terminal (/dev/cu.<...>). + */ +int +uart_dev_set_attr(int fd, int32_t baudrate, uint8_t databits, + uint8_t stopbits, enum hal_uart_parity parity, + enum hal_uart_flow_ctl flow_ctl) +{ + struct termios tty; + speed_t speed; + int rc; + + assert(fd >= 0); + + memset(&tty, 0, sizeof(tty)); + cfmakeraw(&tty); + + speed = uart_baud_to_speed(baudrate); + if (speed == 0) { + fprintf(stderr, "invalid baud rate: %d\n", (int)baudrate); + assert(0); + } + + tty.c_cflag |= (speed | CLOCAL | CREAD); + + /* Set flow control. */ + switch (flow_ctl) { + case HAL_UART_FLOW_CTL_NONE: + tty.c_cflag &= ~CRTSCTS; + break; + + case HAL_UART_FLOW_CTL_RTS_CTS: + tty.c_cflag |= CRTSCTS; + break; + + default: + fprintf(stderr, "invalid flow control setting: %d\n", flow_ctl); + return -1; + } + + errno = 0; + rc = cfsetospeed(&tty, speed); + if (rc != 0) { + fprintf(stderr, "cfsetospeed failed; %d (%s) baudrate=%d\n", + errno, strerror(errno), (int)baudrate); + return -1; + } + + errno = 0; + rc = cfsetispeed(&tty, speed); + if (rc != 0) { + fprintf(stderr, "cfsetispeed failed; %d (%s) baudrate=%d\n", + errno, strerror(errno), (int)baudrate); + return -1; + } + + switch (databits) { + case 7: + tty.c_cflag |= CS7; + + switch (parity) { + case HAL_UART_PARITY_ODD: + tty.c_cflag |= PARENB; + tty.c_cflag |= PARODD; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + break; + + case HAL_UART_PARITY_EVEN: + tty.c_cflag |= PARENB; + tty.c_cflag &= ~PARODD; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + break; + + default: + return SYS_EINVAL; + } + + case 8: + if (parity != HAL_UART_PARITY_NONE) { + return SYS_EINVAL; + } + tty.c_cflag |= CS8; + tty.c_cflag &= ~PARENB; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + break; + + default: + return SYS_EINVAL; + } + + rc = tcsetattr(fd, TCSANOW, &tty); + if (rc != 0) { + fprintf(stderr, "tcsetattr failed; %d (%s)\n", errno, strerror(errno)); + return -1; + } + + return 0; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg_priv.h b/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg_priv.h new file mode 100644 index 000000000..786a68add --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg_priv.h @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 H_NATIVE_UART_CFG_PRIV_ +#define H_NATIVE_UART_CFG_PRIV_ + +#include +#include "hal/hal_uart.h" + +speed_t uart_baud_to_speed(int_least32_t baud); +int uart_dev_set_attr(int fd, int32_t baudrate, uint8_t databits, + uint8_t stopbits, enum hal_uart_parity parity, + enum hal_uart_flow_ctl flow_ctl); + +#endif diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/nrf52_clock.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/nrf52_clock.c new file mode 100644 index 000000000..25ccc7fdd --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/nrf52_clock.c @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 +#include +#include +#include +#include "mcu/nrf52_hal.h" +#include "nrfx.h" +#include "syscfg/syscfg.h" +#include "os/os.h" + +static uint8_t nrf52_clock_hfxo_refcnt; + +/** + * Request HFXO clock be turned on. Note that each request must have a + * corresponding release. + * + * @return int 0: hfxo was already on. 1: hfxo was turned on. + */ +int +nrf52_clock_hfxo_request(void) +{ + int started; + uint32_t ctx; + +#if MYNEWT_VAL_CHOICE(MCU_HFCLK_SOURCE, HFINT) + /* Cannot enable/disable hfxo if it is not present */ + assert(0); +#endif + + started = 0; + __HAL_DISABLE_INTERRUPTS(ctx); + assert(nrf52_clock_hfxo_refcnt < 0xff); + if (nrf52_clock_hfxo_refcnt == 0) { + /* Check the current STATE and SRC of HFCLK */ + if ((NRF_CLOCK->HFCLKSTAT & + (CLOCK_HFCLKSTAT_SRC_Msk | CLOCK_HFCLKSTAT_STATE_Msk)) != + (CLOCK_HFCLKSTAT_SRC_Xtal << CLOCK_HFCLKSTAT_SRC_Pos | + CLOCK_HFCLKSTAT_STATE_Running << CLOCK_HFCLKSTAT_STATE_Pos)) { + NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART); + while (!NRF_CLOCK->EVENTS_HFCLKSTARTED) { +#if BABBLESIM + tm_tick(); +#endif + } + } + started = 1; + } + ++nrf52_clock_hfxo_refcnt; + __HAL_ENABLE_INTERRUPTS(ctx); + + return started; +} + +/** + * Release the HFXO. This means that the caller no longer needs the HFXO to be + * turned on. Each call to release should have been preceeded by a corresponding + * call to request the HFXO + * + * + * @return int 0: HFXO not stopped by this call (others using it) 1: HFXO + * stopped. + */ +int +nrf52_clock_hfxo_release(void) +{ + int stopped; + uint32_t ctx; + +#if MYNEWT_VAL_CHOICE(MCU_HFCLK_SOURCE, HFINT) + /* Cannot enable/disable hfxo if it is not present */ + assert(0); +#endif + + stopped = 0; + __HAL_DISABLE_INTERRUPTS(ctx); + assert(nrf52_clock_hfxo_refcnt != 0); + --nrf52_clock_hfxo_refcnt; + if (nrf52_clock_hfxo_refcnt == 0) { + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); + stopped = 1; + } + __HAL_ENABLE_INTERRUPTS(ctx); + + return stopped; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c new file mode 100644 index 000000000..00224cdc0 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c @@ -0,0 +1,37 @@ +/* Copyright (c) 2012 ARM LIMITED + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of ARM nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "mcu/cmsis_nvic.h" +#include "nrf.h" + + +void SystemInit(void) +{ +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/syscfg.yml b/babblesim/hw/mcu/nordic/nrf52_bsim/syscfg.yml new file mode 100644 index 000000000..b1bc4b874 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/syscfg.yml @@ -0,0 +1,526 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +syscfg.defs: + MCU_TARGET: + description: > + Specifies target MCU, shall be set by BSP. + value: + restrictions: + - $notnull + choices: + - nRF52810 + - nRF52811 + - nRF52832 + - nRF52840 + + MCU_FLASH_MIN_WRITE_SIZE: + description: > + Specifies the required alignment for internal flash writes. + Used internally by the newt tool. + value: 1 + + MCU_DCDC_ENABLED: + description: > + Specifies whether or not to enable DC/DC regulator. This requires + external circuitry so is defined to be zero by default and + expected to be overridden by the BSP. + value: 0 + + MCU_HFCLK_SOURCE: + description: > + Selected source for high frequency clock (HFCLK). + Selecting HFXO will still mostly use the HFINT but will switch to HFXO when requested (BLE, certain timers, etc...) + Selecting HFINT should only be used in the case where an external 32MHz crystal oscillator is not present. + value: HFXO + choices: + - HFXO + - HFINT + restrictions: + - '(MCU_HFCLK_SOURCE == "HFXO") || (MCU_LFCLK_SOURCE != "LFSYNTH")' + + MCU_LFCLK_SOURCE: + description: > + Selected source for low frequency clock (LFCLK). + value: + choices: + - LFRC # 32.768 kHz RC oscillator + - LFXO # 32.768 kHz crystal oscillator + - LFSYNTH # 32.768 kHz synthesized from HFCLK + + MCU_I2C_RECOVERY_DELAY_USEC: + description: > + Time to wait for activity on SCL line after triggering start task + before restarting TWI controller. This is to recover from state + where controller is unresponsive due to glitch on I2C bus. + Note: Default value seems to work fine, but may need to be tuned. + value: 100 + + MCU_BUS_DRIVER_I2C_USE_TWIM: + description: > + Enables usage of i2c_nrf52_twim bus driver for I2C. + If disabled, standard i2c_hal driver is used. + value: 0 + + MCU_GPIO_USE_PORT_EVENT: + description: > + When enabled, hal_gpio will use GPIOTE PORT event instead of PIN + events for interrupts. This mode may be less accurate (i.e. pulse + length needs to be longer in order to be detected) but it reduces + power consumption since it does not require HFCLK to be running. + Refer to nRF52xxx Product Specification document for more details. + value: 0 + + MCU_DEBUG_IGNORE_BKPT: + description: > + When enabled, asm(bkpt) will be ignored. If not set, it will hit + the breakpoint wherever it gets called, For example, reset and crash + value: 0 + + +# MCU peripherals definitions + I2C_0: + description: 'Enable nRF52xxx I2C (TWI) 0' + value: 0 + restrictions: + - '!(SPI_0_MASTER && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + - '!(SPI_0_SLAVE && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + - '!(SPI_1_MASTER && (MCU_TARGET == "nrf52811"))' + - '!(SPI_1_SLAVE && (MCU_TARGET == "nrf52811"))' + I2C_0_PIN_SCL: + description: 'SCL pin for I2C_0' + value: '' + I2C_0_PIN_SDA: + description: 'SDA pin for I2C_0' + value: '' + I2C_0_FREQ_KHZ: + description: 'Frequency [kHz] for I2C_0' + value: 100 + + I2C_1: + description: 'Enable nRF52xxx I2C (TWI) 1' + value: 0 + restrictions: + - "!SPI_1_MASTER" + - "!SPI_1_SLAVE" + I2C_1_PIN_SCL: + description: 'SCL pin for I2C_1' + value: '' + I2C_1_PIN_SDA: + description: 'SDA pin for I2C_1' + value: '' + I2C_1_FREQ_KHZ: + description: 'Frequency [kHz] for I2C_1' + value: 100 + + SPI_0_MASTER: + description: 'Enable nRF52xxx SPI Master 0' + value: 0 + restrictions: + - "!SPI_0_SLAVE" + - '!(I2C_0 && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + SPI_0_MASTER_PIN_SCK: + description: 'SCK pin for SPI_0_MASTER' + value: '' + SPI_0_MASTER_PIN_MOSI: + description: 'MOSI pin for SPI_0_MASTER' + value: '' + SPI_0_MASTER_PIN_MISO: + description: 'MISO pin for SPI_0_MASTER' + value: '' + + SPI_0_SLAVE: + description: 'Enable nRF52xxx SPI Slave 0' + value: 0 + restrictions: + - "!SPI_0_MASTER" + - '!(I2C_0 && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + SPI_0_SLAVE_PIN_SCK: + description: 'SCK pin for SPI_0_SLAVE' + value: '' + SPI_0_SLAVE_PIN_MOSI: + description: 'MOSI pin for SPI_0_SLAVE' + value: '' + SPI_0_SLAVE_PIN_MISO: + description: 'MISO pin for SPI_0_SLAVE' + value: '' + SPI_0_SLAVE_PIN_SS: + description: 'SS pin for SPI_0_SLAVE' + value: '' + + SPI_1_MASTER: + description: 'Enable nRF52xxx SPI Master 1' + value: 0 + restrictions: + - "!SPI_1_SLAVE" + - '!(I2C_1 && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + - '!(I2C_0 && ((MCU_TARGET == "nrf52811")))' + SPI_1_MASTER_PIN_SCK: + description: 'SCK pin for SPI_1_MASTER' + value: '' + SPI_1_MASTER_PIN_MOSI: + description: 'MOSI pin for SPI_1_MASTER' + value: '' + SPI_1_MASTER_PIN_MISO: + description: 'MISO pin for SPI_1_MASTER' + value: '' + + SPI_1_SLAVE: + description: 'Enable nRF52xxx SPI Slave 1' + value: 0 + restrictions: + - "!SPI_1_MASTER" + - '!(I2C_1 && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + - '!(I2C_0 && ((MCU_TARGET == "nrf52811")))' + SPI_1_SLAVE_PIN_SCK: + description: 'SCK pin for SPI_1_SLAVE' + value: '' + SPI_1_SLAVE_PIN_MOSI: + description: 'MOSI pin for SPI_1_SLAVE' + value: '' + SPI_1_SLAVE_PIN_MISO: + description: 'MISO pin for SPI_1_SLAVE' + value: '' + SPI_1_SLAVE_PIN_SS: + description: 'SS pin for SPI_1_SLAVE' + value: '' + + SPI_2_MASTER: + description: 'Enable nRF52xxx SPI Master 2' + value: 0 + restrictions: + - "!SPI_2_SLAVE" + SPI_2_MASTER_PIN_SCK: + description: 'SCK pin for SPI_2_MASTER' + value: '' + SPI_2_MASTER_PIN_MOSI: + description: 'MOSI pin for SPI_2_MASTER' + value: '' + SPI_2_MASTER_PIN_MISO: + description: 'MISO pin for SPI_2_MASTER' + value: '' + + SPI_2_SLAVE: + description: 'Enable nRF52xxx SPI Slave 2' + value: 0 + restrictions: + - "!SPI_2_MASTER" + SPI_2_SLAVE_PIN_SCK: + description: 'SCK pin for SPI_2_SLAVE' + value: '' + SPI_2_SLAVE_PIN_MOSI: + description: 'MOSI pin for SPI_2_SLAVE' + value: '' + SPI_2_SLAVE_PIN_MISO: + description: 'MISO pin for SPI_2_SLAVE' + value: '' + SPI_2_SLAVE_PIN_SS: + description: 'SS pin for SPI_2_SLAVE' + value: '' + + SPI_3_MASTER: + description: 'Enable nRF52xxx SPI Master 3' + value: 0 + restrictions: + - 'MCU_TARGET == "nRF52840" || !SPI_3_MASTER' + SPI_3_MASTER_PIN_SCK: + description: 'SCK pin for SPI_3_MASTER' + value: '' + SPI_3_MASTER_PIN_MOSI: + description: 'MOSI pin for SPI_3_MASTER' + value: '' + SPI_3_MASTER_PIN_MISO: + description: 'MISO pin for SPI_3_MASTER' + value: '' + + ADC_0: + description: 'Enable nRF52xxx ADC 0' + value: 0 + + ADC_0_REFMV_0: + description: 'reference mV in AREF0 if used' + value: 0 + + PWM_0: + description: 'Enable nRF52xxx PWM 0' + value: 0 + PWM_1: + description: 'Enable nRF52xxx PWM 1' + value: 0 + PWM_2: + description: 'Enable nRF52xxx PWM 2' + value: 0 + PWM_3: + description: 'Enable nRF52xxx PWM 3' + value: 0 + restrictions: + - 'MCU_TARGET == "nRF52840" || !PWM_3' + + TRNG: + description: 'Enable nRF52xxx TRNG' + value: 0 + + CRYPTO: + description: 'Enable nRF52xxx CRYPTO' + value: 0 + + UART_0: + description: 'Enable nRF52xxx UART0' + value: 1 + UART_0_PIN_TX: + description: 'TX pin for UART0' + value: '' + UART_0_PIN_RX: + description: 'RX pin for UART0' + value: '' + UART_0_PIN_RTS: + description: 'RTS pin for UART0' + value: -1 + UART_0_PIN_CTS: + description: 'CTS pin for UART0' + value: -1 + + UART_1: + description: 'Enable nRF52xxx UART1' + value: 0 + restrictions: + - 'MCU_TARGET == "nRF52840" || !UART_1' + UART_1_PIN_TX: + description: 'TX pin for UART1' + value: '' + UART_1_PIN_RX: + description: 'RX pin for UART1' + value: '' + UART_1_PIN_RTS: + description: 'RTS pin for UART1' + value: -1 + UART_1_PIN_CTS: + description: 'CTS pin for UART1' + value: -1 + + TEMP: + description: 'Enable nRF52xxx internal temperature mesurement' + value: 0 + + TIMER_0: + description: 'Enable nRF52xxx Timer 0' + value: 1 + TIMER_1: + description: 'Enable nRF52xxx Timer 1' + value: 0 + TIMER_2: + description: 'Enable nRF52xxx Timer 2' + value: 0 + TIMER_3: + description: 'Enable nRF52xxx Timer 3' + value: 0 + TIMER_4: + description: 'Enable nRF52xxx Timer 4' + value: 0 + TIMER_5: + description: 'Enable nRF52xxx RTC 0' + value: 0 + + QSPI_ENABLE: + description: 'NRF52 QSPI' + value: 0 + + QSPI_READOC: + description: > + QSPI Command to use + 0 - 0x09 Fast Read + 1 - 0x3B Fast Read Dual Output + 2 - 0xBB Fast Read Dual I/O + 3 - 0x6B Fast Read Quad Output + 4 - 0xEB Fast Read Quad I/O + value: 0 + QSPI_WRITEOC: + description: > + QSPI Command to use + 0 - 0x02 Page program + 1 - 0xA2 Page program Dual Data + 2 - 0x32 Page program Quad Data + 3 - 0x38 Page program Quad I/O + value: 0 + QSPI_ADDRMODE: + description: 'Address lentgh 0=24 bits, 1=32 bits' + value: 0 + QSPI_DPMCONFIG: + description: 'Deep power mode enable' + value: 0 + QSPI_SCK_DELAY: + description: > + Minimum amount of time that the CSN pin must stay high + before it can go low again. Value is specified in number of 16 + MHz periods (62.5 ns). + value: 0 + QSPI_SCK_FREQ: + description: '32MHz clock divider (0-31). Clock = 32MHz / (1+divider)' + value: 0 + QSPI_SPI_MODE: + description: 'SPI 0=Mode0 or 1=Mode3' + value: 0 + + QSPI_FLASH_SECTOR_SIZE: + description: 'QSPI sector size. In most cases it should be 4096.' + value: 0 + QSPI_FLASH_PAGE_SIZE: + description: > + QSPI page size. Writes can only be performed to one page at a time. + In most cases it should be 256. + value: 0 + + QSPI_FLASH_SECTOR_COUNT: + description: 'QSPI sector count' + value: -1 + QSPI_PIN_CS: + description: 'CS pin for QSPI' + value: -1 + QSPI_PIN_SCK: + description: 'SCK pin for QSPI' + value: -1 + QSPI_PIN_DIO0: + description: 'DIO0 pin for QSPI' + value: -1 + QSPI_PIN_DIO1: + description: 'DIO1 pin for QSPI' + value: -1 + QSPI_PIN_DIO2: + description: 'DIO2 pin for QSPI' + value: -1 + QSPI_PIN_DIO3: + description: 'DIO3 pin for QSPI' + value: -1 + + NFC_PINS_AS_GPIO: + description: 'Use NFC pins as GPIOs instead of NFC functionality' + value: 1 + + GPIO_AS_PIN_RESET: + description: 'Enable pin reset' + value: 0 + +# Deprecated settings + + MCU_NRF52832: + description: Use MCU_TARGET instead + value: 0 + restrictions: + - "!MCU_NRF52840" + deprecated: 1 + MCU_NRF52840: + description: Use MCU_TARGET instead + value: 0 + restrictions: + - "!MCU_NRF52832" + deprecated: 1 + + XTAL_32768: + description: Use MCU_LFCLK_SOURCE instead + value: 0 + restrictions: + - "!XTAL_RC" + - "!XTAL_32768_SYNTH" + deprecated: 1 + XTAL_RC: + description: Use MCU_LFCLK_SOURCE instead + value: 0 + restrictions: + - "!XTAL_32768" + - "!XTAL_32768_SYNTH" + deprecated: 1 + XTAL_32768_SYNTH: + description: Use MCU_LFCLK_SOURCE instead + value: 0 + restrictions: + - "!XTAL_32768" + - "!XTAL_RC" + deprecated: 1 + + MCU_NATIVE_USE_SIGNALS: + description: > + Whether to use POSIX signals to implement context switches. Valid + values are as follows: + 1: More correctness; less stability. The OS tick timer will + cause a high-priority task to preempt a low-priority task. + This causes stability issues because a task can be preempted + while it is in the middle of a system call, potentially + causing deadlock or memory corruption. + + 0: Less correctness; more stability. The OS tick timer only + runs while the idle task is active. Therefore, a sleeping + high-priority task will not preempt a low-priority task due + to a timing event (e.g., delay or callout expired). + However, this version of sim does not suffer from the + stability issues that affect the "signals" implementation. + + Unit tests should use 1. Long-running sim processes should use 0. + + value: 1 + MCU_NATIVE: + description: > + Set to indicate that we are using native mcu. + value: 1 + MCU_FLASH_STYLE_ST: + description: Emulated flash layout is similar to one in STM32. + value: 1 + restrictions: + - "!MCU_FLASH_STYLE_NORDIC" + MCU_FLASH_STYLE_NORDIC: + description: > + Emulated flash layout is similar to one in NRF51/2 and SAMD21. + value: 0 + restrictions: + - "!MCU_FLASH_STYLE_ST" + MCU_UART_POLLER_PRIO: + description: 'Priority of native UART poller task.' + type: task_priority + value: 1 + MCU_TIMER_POLLER_PRIO: + description: 'Priority of native HAL timer task.' + type: task_priority + value: 0 + +syscfg.vals: + OS_TICKS_PER_SEC: 128 + +syscfg.vals.MCU_NRF52832: + MCU_TARGET: nRF52832 +syscfg.vals.MCU_NRF52840: + MCU_TARGET: nRF52840 + +syscfg.vals.XTAL_32768: + MCU_LFCLK_SOURCE: LFXO +syscfg.vals.XTAL_RC: + MCU_LFCLK_SOURCE: LFRC +syscfg.vals.XTAL_32768_SYNTH: + MCU_LFCLK_SOURCE: LFSYNTH + +syscfg.restrictions: + - "!I2C_0 || (I2C_0_PIN_SCL && I2C_0_PIN_SDA)" + - "!I2C_1 || (I2C_1_PIN_SCL && I2C_1_PIN_SDA)" + - "!SPI_0_MASTER || (SPI_0_MASTER_PIN_SCK && SPI_0_MASTER_PIN_MOSI && SPI_0_MASTER_PIN_MISO)" + - "!SPI_1_MASTER || (SPI_1_MASTER_PIN_SCK && SPI_1_MASTER_PIN_MOSI && SPI_1_MASTER_PIN_MISO)" + - "!SPI_2_MASTER || (SPI_2_MASTER_PIN_SCK && SPI_2_MASTER_PIN_MOSI && SPI_2_MASTER_PIN_MISO)" + - "!SPI_3_MASTER || (SPI_3_MASTER_PIN_SCK && SPI_3_MASTER_PIN_MOSI && SPI_3_MASTER_PIN_MISO)" + - "!SPI_0_SLAVE || (SPI_0_SLAVE_PIN_SCK && SPI_0_SLAVE_PIN_MOSI && SPI_0_SLAVE_PIN_MISO && SPI_0_SLAVE_PIN_SS)" + - "!SPI_1_SLAVE || (SPI_1_SLAVE_PIN_SCK && SPI_1_SLAVE_PIN_MOSI && SPI_1_SLAVE_PIN_MISO && SPI_1_SLAVE_PIN_SS)" + - "!SPI_2_SLAVE || (SPI_2_SLAVE_PIN_SCK && SPI_2_SLAVE_PIN_MOSI && SPI_2_SLAVE_PIN_MISO && SPI_2_SLAVE_PIN_SS)" + - "!UART_0 || (UART_0_PIN_TX && UART_0_PIN_RX)" + - "!UART_1 || (UART_1_PIN_TX && UART_1_PIN_RX)" + - "(OS_TICKS_PER_SEC == 128 || OS_TICKS_PER_SEC == 256 || OS_TICKS_PER_SEC == 512 || OS_TICKS_PER_SEC == 1024)" diff --git a/babblesim/libc/LICENSE b/babblesim/libc/LICENSE new file mode 100644 index 000000000..b7915742b --- /dev/null +++ b/babblesim/libc/LICENSE @@ -0,0 +1,133 @@ +Baselibc is based on klibc 1.5.23 and tinyprintf modules. +None of the GPL-licensed parts of klibc are used. + +Baselibc is licensed under the BSD license: + +Copyright (c) 2012 Petteri Aimonen +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Kustaa Nyholm or SpareTimeLabs nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The original licenses of the modules are included below: + +------------------ Tinyprintf license ------------------ + +Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Kustaa Nyholm or SpareTimeLabs nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------- klibc license ------------------------- +This license applies to all files in directory and its subdirectories, +unless otherwise noted in individual files. + + +Some files are derived from files derived from the include/ directory +of the Linux kernel, and are licensed under the terms of the GNU +General Public License, version 2, as released by the Free Software +Foundation, Inc.; incorporated herein by reference. +[These files are not included in the baselibc.] + + ----- + +Some files are derived from files copyrighted by the Regents of The +University of California, and are available under the following +license: + +Note: The advertising clause in the license appearing on BSD Unix +files was officially rescinded by the Director of the Office of +Technology Licensing of the University of California on July 22 +1999. He states that clause 3 is "hereby deleted in its entirety." + + * Copyright (c) + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + +For all remaining files [of klibc], the following license applies: + + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * Any copyright notice(s) and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/babblesim/libc/pkg.yml b/babblesim/libc/pkg.yml new file mode 100644 index 000000000..297bfa9f8 --- /dev/null +++ b/babblesim/libc/pkg.yml @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: babblesim/libc +pkg.type: sdk +pkg.description: Functions from apache-mynewt-core/libc that not exists in Linux system. +pkg.author: "Codecoup" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/kernel/os" diff --git a/babblesim/libc/src/strlcat.c b/babblesim/libc/src/strlcat.c new file mode 100644 index 000000000..6d9508705 --- /dev/null +++ b/babblesim/libc/src/strlcat.c @@ -0,0 +1,30 @@ +/* + * strlcat.c + */ + +#include + +size_t strlcat(char *dst, const char *src, size_t size) +{ + size_t bytes = 0; + char *q = dst; + const char *p = src; + char ch; + + while (bytes < size && *q) { + q++; + bytes++; + } + if (bytes == size) + return (bytes + strlen(src)); + + while ((ch = *p++)) { + if (bytes + 1 < size) + *q++ = ch; + + bytes++; + } + + *q = '\0'; + return bytes; +} diff --git a/babblesim/libc/src/strlcpy.c b/babblesim/libc/src/strlcpy.c new file mode 100644 index 000000000..3ec8fd2df --- /dev/null +++ b/babblesim/libc/src/strlcpy.c @@ -0,0 +1,26 @@ +/* + * strlcpy.c + */ + +#include + +size_t strlcpy(char *dst, const char *src, size_t size) +{ + size_t bytes = 0; + char *q = dst; + const char *p = src; + char ch; + + while ((ch = *p++)) { + if (bytes + 1 < size) + *q++ = ch; + + bytes++; + } + + /* If size == 0 there is no space for a final null... */ + if (size) + *q = '\0'; + + return bytes; +} diff --git a/babblesim/nrfx/pkg.yml b/babblesim/nrfx/pkg.yml new file mode 100644 index 000000000..54a385e2c --- /dev/null +++ b/babblesim/nrfx/pkg.yml @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +pkg.name: babblesim/nrfx +pkg.description: nrfx wrapper for BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.type: sdk + +pkg.cflags: -std=gnu99 +pkg.include_dirs: + - src/ + - src/drivers/ + - src/hal/ + - src/mdk/ + +pkg.deps: + - "@apache-mynewt-core/hw/hal" + +pkg.pre_build_cmds: + scripts/link_nrfx.sh: 1 diff --git a/babblesim/nrfx/scripts/link_nrfx.sh b/babblesim/nrfx/scripts/link_nrfx.sh new file mode 100755 index 000000000..2b59847eb --- /dev/null +++ b/babblesim/nrfx/scripts/link_nrfx.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +mkdir -p ./src/ +for f in nrfx.h drivers hal mdk; do + ln -sfn ${NRFX_BASE}/${f} ./src/${f} +done \ No newline at end of file