diff --git a/doc/nrf/libraries/others/network_core_monitor.rst b/doc/nrf/libraries/others/network_core_monitor.rst index 501d8957e8e6..8494a1f92d70 100644 --- a/doc/nrf/libraries/others/network_core_monitor.rst +++ b/doc/nrf/libraries/others/network_core_monitor.rst @@ -27,12 +27,8 @@ The library uses two general-purpose registers of the IPC peripheral in the appl The ``GPMEM[0]`` register is divided into two 16-bit parts. -The ``COUNTER`` value is incremented by the network core every :kconfig:option:`CONFIG_NCM_APP_FEEDING_INTERVAL_MSEC`. -The application core periodically calls the :c:func:`ncm_net_status_check` function to check the status of the network core. +The ``COUNTER`` value is incremented by the network core every :kconfig:option:`CONFIG_NCM_FEEDING_INTERVAL_MSEC`. If the network core is suspended, the counter value is not updated. -The :c:func:`ncm_net_status_check` function returns error code ``-EBUSY``. - -To correctly detect the network core status, the :c:func:`ncm_net_status_check` function should be called less frequently than the value set in the :kconfig:option:`CONFIG_NCM_APP_FEEDING_INTERVAL_MSEC` Kconfig option. The ``FLAGS`` field has the ``Reset`` flag as the bit 0. @@ -43,13 +39,23 @@ During the startup of the network core, the reset bit is set and the cause of th This value is rewritten from the network core's ``RESET.RESETREAS`` register. For a detailed description of the bits in this register, see the `RESETREAS`_ section for nRF5340. -The :c:func:`ncm_net_status_check` function returns the following error codes: +The :c:func:`ncm_net_core_event_handler` function may be implemented by your application. +On the application core, the network core monitor checks the values of IPC registers written by the network core every :kconfig:option:`CONFIG_NCM_FEEDING_INTERVAL_MSEC`. +If the network core malfunctions and fails to increment the ``COUNTER`` value, the :c:func:`ncm_net_core_event_handler` function is called on the application core. +This function is also called when the network core is restarted. +The network core monitor provides a ``__weak`` implementation of that function in the :file:`nrf/subsys/net_core_monitor/app_core.c` file. + +The following events are supported and also listed in the :file:`nrf/include/net_core_monitor.h` file: + +* :c:macro:`NCM_EVT_NET_CORE_RESET` -* ``-EBUSY`` if the network core is suspended -* ``-EFAULT`` if a network core reset has occurred + * Event triggered when a network core reset occurs. + * The ``reset_reas`` variable holds the reason for the reset. + It is rewritten from the ``RESET.RESETREAS`` register. -The function takes a pointer to a variable of type uint32_t as a parameter. -When a network core reset is detected, the cause of the reset is stored in this pointer. +* :c:macro:`NCM_EVT_NET_CORE_FREEZE` + + * Event triggered when the network core is not responding. Configuration ************* @@ -68,38 +74,28 @@ Usage To enable the Network core monitor library, set the :kconfig:option:`CONFIG_NET_CORE_MONITOR` Kconfig option. -On the application core, periodically call the :c:func:`ncm_net_status_check` function to monitor the state of the network core. +The :c:func:`ncm_net_core_event_handler` function can be used to notify the application about the status of the network core. +To define the user action for the event, you must override the ``__weak`` function definition of :c:func:`ncm_net_core_event_handler`. +Otherwise, the ``__weak``` definition is called and it prints information about the event. + See the following usage example. .. code-block:: #include "net_core_monitor.h" ... - static void print_reset(uint32_t reset_reas) - { - if (reset_reas & NRF_RESET_RESETREAS_RESETPIN_MASK) { - printk("Reset by pin-reset\n"); - } else if (reset_reas & NRF_RESET_RESETREAS_DOG0_MASK) { - printk("Reset by application watchdog timer 0 \n"); - } else if (reset_reas & NRF_RESET_RESETREAS_SREQ_MASK) { - printk("Reset by soft-reset\n"); - } else if (reset_reas) { - printk("Reset by a different source (0x%08X)\n", reset_reas); - } - } - - int main(void) + /* This is the override for the __weak handler. */ + void ncm_net_core_event_handler(enum ncm_event_type event, uint32_t reset_reas) { - uint32_t reset_reas; - ... - for (;;) { - ret = ncm_net_status_check(&reset_reas); - if (ret == -EBUSY) { - /* do something*/ - } else if (ret == -EFAULT) { - print_reset(reset_reas); - } - k_sleep(K_MSEC(1000)); + switch (event) { + case NCM_EVT_NET_CORE_RESET: + printk("The network core reset.\n"); + /* do something */ + break; + case NCM_EVT_NET_CORE_FREEZE: + printk("The network core is not responding.\n"); + /* do something */ + break; } } diff --git a/include/net_core_monitor.h b/include/net_core_monitor.h index 62842dae11b5..3b30ec156d92 100644 --- a/include/net_core_monitor.h +++ b/include/net_core_monitor.h @@ -18,21 +18,29 @@ extern "C" { #endif -/** @brief Check the status of the network core. - * - * The function should be called less frequently than - * @kconfig{CONFIG_NCM_APP_FEEDING_INTERVAL_MSEC} to correctly detect the network core status. +/** @brief Network core monitor event types, used to signal the application. */ +enum ncm_event_type { + /** Event triggered when a network core reset occurs. + * The ``reset_reas`` variable holds the reason for the reset. + * It is rewritten from the RESET.RESETREAS register. + */ + NCM_EVT_NET_CORE_RESET, + + /** Event triggered when the network core is not responding. */ + NCM_EVT_NET_CORE_FREEZE +}; + +/** @brief Event handler that is called by the Network core monitor library when an event occurs. * - * @param[out] reset_reas Reason for network core reset. - * When the -EFAULT code is returned, the variable is set. - * This value is rewritten from the network core's RESET.RESETREAS - * register. + * @note This function should be defined by the application. + * Otherwise, `__weak` definition will called and it prints information about the event. * - * @retval 0 If network core works properly. - * @retval -EBUSY If network core failure occurred. - * @retval -EFAULT If network core restart occurred. + * @param[out] event Event occurring. + * @param[out] reset_reas Reason for network core reset. + * When the NCM_EVT_NET_CORE_RESET event was triggered the variable is set. + * This value is rewritten from the network core's RESET.RESETREAS register. */ -int ncm_net_status_check(uint32_t * const reset_reas); +extern void ncm_net_core_event_handler(enum ncm_event_type event, uint32_t reset_reas); #ifdef __cplusplus } diff --git a/subsys/net_core_monitor/Kconfig b/subsys/net_core_monitor/Kconfig index c173b2b0959e..be084928d5e9 100644 --- a/subsys/net_core_monitor/Kconfig +++ b/subsys/net_core_monitor/Kconfig @@ -10,14 +10,21 @@ config NET_CORE_MONITOR depends on (SOC_NRF5340_CPUAPP || SOC_NRF5340_CPUNET) help Enable the Network Core Monitor module. + To define the user action for event, you need to override the + weak function definition of the ncm_net_core_event_handler. if NET_CORE_MONITOR menu "Net Core Monitor" -config NCM_APP_FEEDING_INTERVAL_MSEC - default 500 - int "Application core feeding interval (in ms)" +config NCM_FEEDING_INTERVAL_MSEC + default 500 if SOC_NRF5340_CPUNET + default 1000 if SOC_NRF5340_CPUAPP + int "Feeding interval in milliseconds" + help + The value of this parameter on the application core must be greater + than the value on the network core. Otherwise the network core monitor + will report false positive network code malfunctions. config NCM_RESET_INIT_PRIORITY int "Reset init priority" diff --git a/subsys/net_core_monitor/app_core.c b/subsys/net_core_monitor/app_core.c index c0f52fc9b1c0..9eeedf90021e 100644 --- a/subsys/net_core_monitor/app_core.c +++ b/subsys/net_core_monitor/app_core.c @@ -4,11 +4,14 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ +#include #include #include #include #include #include "common.h" +#include +#include "net_core_monitor.h" #include @@ -17,7 +20,12 @@ LOG_MODULE_REGISTER(net_core_monitor, CONFIG_NET_CORE_MONITOR_LOG_LEVEL); #define IPC_MEM_CNT_IDX 0 #define IPC_MEM_REAS_IDX 1 -int ncm_net_status_check(uint32_t * const reset_reas) +#define NET_CORE_CHECK_INTERVAL_MSEC CONFIG_NCM_FEEDING_INTERVAL_MSEC + +static void ncm_work_handler(struct k_work *work); +static K_WORK_DELAYABLE_DEFINE(ncm_work, ncm_work_handler); + +static int ncm_net_status_check(uint32_t * const reset_reas) { uint32_t gpmem; uint16_t cnt; @@ -49,3 +57,54 @@ int ncm_net_status_check(uint32_t * const reset_reas) prv_cnt = cnt; return 0; } + +static void ncm_work_handler(struct k_work *work) +{ + int ret; + uint32_t reset_reas; + + ret = ncm_net_status_check(&reset_reas); + + if (ret == -EBUSY) { + ncm_net_core_event_handler(NCM_EVT_NET_CORE_FREEZE, 0); + } else if (ret == -EFAULT) { + ncm_net_core_event_handler(NCM_EVT_NET_CORE_RESET, reset_reas); + } else { + /* Nothing to do. */ + } + + k_work_reschedule(&ncm_work, K_MSEC(NET_CORE_CHECK_INTERVAL_MSEC)); +} + +__weak void ncm_net_core_event_handler(enum ncm_event_type event, uint32_t reset_reas) +{ + switch (event) { + case NCM_EVT_NET_CORE_RESET: + LOG_DBG("The network core reset."); + if (reset_reas & NRF_RESET_RESETREAS_RESETPIN_MASK) { + LOG_DBG("Reset by pin-reset."); + } else if (reset_reas & NRF_RESET_RESETREAS_DOG0_MASK) { + LOG_DBG("Reset by application watchdog timer 0."); + } else if (reset_reas & NRF_RESET_RESETREAS_SREQ_MASK) { + LOG_DBG("Reset by soft-reset"); + } else if (reset_reas) { + LOG_DBG("Reset by a different source (0x%08X).", reset_reas); + } else { + /* Nothing to do. */ + } + + break; + case NCM_EVT_NET_CORE_FREEZE: + LOG_DBG("The network core is not responding."); + break; + } +} + +static int app_init(void) +{ + LOG_DBG("Network Core Monitor Init"); + k_work_schedule(&ncm_work, K_MSEC(NET_CORE_CHECK_INTERVAL_MSEC)); + return 0; +} + +SYS_INIT(app_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/subsys/net_core_monitor/common.h b/subsys/net_core_monitor/common.h index fcb37ef77992..8fd24cbff7c0 100644 --- a/subsys/net_core_monitor/common.h +++ b/subsys/net_core_monitor/common.h @@ -16,8 +16,11 @@ extern "C" { #define CNT_MSK (0xFFFF << CNT_POS) /* Bit mask of Counter field. */ #define FLAGS_POS (16UL) /* Position of Flags field. */ #define FLAGS_MSK (0xFFFF << FLAGS_POS) /* Bit mask of Flags field. */ -#define FLAGS_RESET BIT(0) /* Reset bit */ -#define CNT_INIT_VAL (0x0055) /* Initialization value for counter */ +#define FLAGS_RESET BIT(0) /* Reset bit. */ +#define CNT_INIT_VAL (0x0055) /* Initialization value for counter. */ + +#define IPC_MEM_CNT_IDX 0 /** Index of the memory cell that stores the counter. */ +#define IPC_MEM_REAS_IDX 1 /** Index of the memory cell that stores the reset reason. */ #ifdef __cplusplus } diff --git a/subsys/net_core_monitor/net_core.c b/subsys/net_core_monitor/net_core.c index 6c76d17a78be..1f2b0db90fa1 100644 --- a/subsys/net_core_monitor/net_core.c +++ b/subsys/net_core_monitor/net_core.c @@ -18,12 +18,9 @@ LOG_MODULE_REGISTER(net_core_monitor, CONFIG_NET_CORE_MONITOR_LOG_LEVEL); /* General purpose memory IPC of the application core. * Access possible only through the memory address. */ -#define APP_IPC_GPMEM_0_S (*(volatile uint32_t *)(0x5002A610)) -#define APP_IPC_GPMEM_0_NS (*(volatile uint32_t *)(0x4002A610)) -#define APP_IPC_GPMEM_1_S (*(volatile uint32_t *)(0x5002A614)) -#define APP_IPC_GPMEM_1_NS (*(volatile uint32_t *)(0x4002A614)) -#define APP_IPC_GPMEM_0 APP_IPC_GPMEM_0_S -#define APP_IPC_GPMEM_1 APP_IPC_GPMEM_1_S +#define APP_IPC_GPMEM_0_S ((volatile uint32_t *)(0x5002A610)) +#define APP_IPC_GPMEM_0_NS ((volatile uint32_t *)(0x4002A610)) +#define APP_IPC_GPMEM APP_IPC_GPMEM_0_S static void ncm_work_handler(struct k_work *work); static K_WORK_DELAYABLE_DEFINE(ncm_work, ncm_work_handler); @@ -31,13 +28,13 @@ static K_WORK_DELAYABLE_DEFINE(ncm_work, ncm_work_handler); static void ncm_work_handler(struct k_work *work) { static uint16_t live_cnt = CNT_INIT_VAL; - uint32_t gpmem = APP_IPC_GPMEM_0; + uint32_t gpmem = APP_IPC_GPMEM[IPC_MEM_CNT_IDX]; live_cnt++; gpmem = (gpmem & (~CNT_MSK)) | (live_cnt << CNT_POS); - APP_IPC_GPMEM_0 = gpmem; + APP_IPC_GPMEM[IPC_MEM_CNT_IDX] = gpmem; - k_work_reschedule(&ncm_work, K_MSEC(CONFIG_NCM_APP_FEEDING_INTERVAL_MSEC)); + k_work_reschedule(&ncm_work, K_MSEC(CONFIG_NCM_FEEDING_INTERVAL_MSEC)); } static int reset(void) @@ -50,11 +47,12 @@ static int reset(void) /* A notification that a core reset has occurred. * And set the non-zero value of the counter. */ - APP_IPC_GPMEM_0 = (APP_IPC_GPMEM_0 & FLAGS_MSK) - | (FLAGS_RESET << FLAGS_POS) - | (CNT_INIT_VAL << CNT_POS); + APP_IPC_GPMEM[IPC_MEM_CNT_IDX] = (APP_IPC_GPMEM[IPC_MEM_CNT_IDX] & FLAGS_MSK) + | (FLAGS_RESET << FLAGS_POS) + | (CNT_INIT_VAL << CNT_POS); + /* Save the reason for the reset. */ - APP_IPC_GPMEM_1 = reas; + APP_IPC_GPMEM[IPC_MEM_REAS_IDX] = reas; return 0; }