From 5d3cdd0a74d8ff88181388ec4a9e868d6b0c51cc Mon Sep 17 00:00:00 2001
From: puddly <32534428+puddly@users.noreply.github.com>
Date: Thu, 4 Jan 2024 13:00:03 -0500
Subject: [PATCH] Add the EFR32 watchdog to RPC firmware (#33)
* Create a `.gitignore` file
* Add a watchdog Gecko SDK extension
* Trust Gecko SDK extensions when building
* Allow patching the generated project file
* Add watchdog to RCP firmwares
* Ensure `pip` is available
* `yq` is available in Debian, use it directly
* Use correct parameter for `slc signature trust` command
* Ensure extension path is absolute
* Link extensions within the SDK to get slc-cli to actually work
* Revert namespacing for `#define`s hard-coded in the SDK
* [WIP] Simplify extension to bare minimum
* Register watchdog initialization later
* Remove debugging code
* Reset the watchdog timer at 25%
* Pass through `slcp_yaml_changes`
* Feed watchdog timer within the app, not in a timer interrupt handler
* Drop watchdog period to 2 seconds
* Stop running the watchdog when in debugger
---
.github/workflows/build.yaml | 7 ++
.github/workflows/silabs-firmware-build.yaml | 22 +++++
.gitignore | 1 +
Dockerfile | 1 +
.../inc/nc_efr32_wdog.h | 26 ++++++
.../nc_efr32_watchdog.slcc | 38 ++++++++
.../nc_efr32_watchdog.slce | 8 ++
.../src/nc_efr32_wdog.c | 92 +++++++++++++++++++
8 files changed, 195 insertions(+)
create mode 100644 .gitignore
create mode 100644 gecko_sdk_extensions/nc_efr32_watchdog_extension/inc/nc_efr32_wdog.h
create mode 100644 gecko_sdk_extensions/nc_efr32_watchdog_extension/nc_efr32_watchdog.slcc
create mode 100644 gecko_sdk_extensions/nc_efr32_watchdog_extension/nc_efr32_watchdog.slce
create mode 100644 gecko_sdk_extensions/nc_efr32_watchdog_extension/src/nc_efr32_wdog.c
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 358cb150..283e3bd1 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -98,10 +98,16 @@ jobs:
device: MGM210PA32JIA
components: simple_led:board_activity,cpc_security_secondary_none,zigbee_mfglib
patchpath: "RCPMultiPAN/Yellow"
+ slcp_yaml_changes: >
+ . += {"sdk_extension": [{"id": "nc_efr32_watchdog", version: "1.0.0"}]}
+ | .component += [{"from": "nc_efr32_watchdog", "id": "nc_efr32_watchdog"}]
- target: skyconnect
device: EFR32MG21A020F512IM32
components: cpc_security_secondary_none,zigbee_mfglib
patchpath: "RCPMultiPAN/SkyConnect"
+ slcp_yaml_changes: >
+ . += {"sdk_extension": [{"id": "nc_efr32_watchdog", version: "1.0.0"}]}
+ | .component += [{"from": "nc_efr32_watchdog", "id": "nc_efr32_watchdog"}]
uses: ./.github/workflows/silabs-firmware-build.yaml
with:
image_name: ${{ needs.build-container.outputs.image_name }}
@@ -111,6 +117,7 @@ jobs:
device: ${{ matrix.device }}
components: ${{ matrix.components }}
patchpath: ${{ matrix.patchpath }}
+ slcp_yaml_changes: ${{ matrix.slcp_yaml_changes }}
sdk_version: ${{ needs.build-container.outputs.sdk_version }}
metadata_fw_type: "rcp-uart-802154"
baudrate: 460800
diff --git a/.github/workflows/silabs-firmware-build.yaml b/.github/workflows/silabs-firmware-build.yaml
index 8d640808..81b6899f 100644
--- a/.github/workflows/silabs-firmware-build.yaml
+++ b/.github/workflows/silabs-firmware-build.yaml
@@ -47,6 +47,9 @@ on:
required: false
default: "null"
type: string
+ slcp_yaml_changes:
+ required: false
+ type: string
jobs:
firmware-build:
@@ -63,6 +66,19 @@ jobs:
- name: Adjust permission
shell: bash
run: chown builder .
+
+ - name: Link SDK extensions
+ shell: bash
+ run: |
+ # XXX: slc-cli does not actually work when the extensions aren't in the SDK!
+ ln -s $PWD/gecko_sdk_extensions /gecko_sdk/extension
+
+ - name: Trust SDK extensions
+ run: |
+ for ext in /gecko_sdk/extension/*/; do
+ slc signature trust --extension-path="$ext"
+ done
+
- name: Generate Firmware Project
run: |
slc generate \
@@ -110,6 +126,12 @@ jobs:
sed -i "s/^C_DEFS\s*=.*$/C_DEFS = '-DOPENTHREAD_BUILD_DATETIME=\"$meta_datetime\"' ${{ inputs.extra_c_defs }}/" \
"${{ inputs.project_name }}.Makefile"
+ - name: Patch SLCP project file
+ if: "${{ inputs.slcp_yaml_changes != '' }}"
+ run: |
+ cd ${{ inputs.firmware_name }}
+ yq --in-place --yaml-output '${{ inputs.slcp_yaml_changes }}' "${{ inputs.project_name }}.slcp"
+
- name: Build Firmware
run: |
cd ${{ inputs.firmware_name }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..496ee2ca
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.DS_Store
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index b053f6c2..8929e12d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,6 +10,7 @@ RUN \
git \
git-lfs \
jq \
+ yq \
libgl1 \
make \
default-jre-headless \
diff --git a/gecko_sdk_extensions/nc_efr32_watchdog_extension/inc/nc_efr32_wdog.h b/gecko_sdk_extensions/nc_efr32_watchdog_extension/inc/nc_efr32_wdog.h
new file mode 100644
index 00000000..d1af5b8b
--- /dev/null
+++ b/gecko_sdk_extensions/nc_efr32_watchdog_extension/inc/nc_efr32_wdog.h
@@ -0,0 +1,26 @@
+/***************************************************************************//**
+ * @file nc_efr32_wdog.h
+ * @brief Legacy HAL Watchdog
+ *******************************************************************************
+ * # License
+ * Copyright 2022 Silicon Laboratories, Inc, www.silabs.com
+ *******************************************************************************
+ *
+ * The licensor of this software is Silicon Laboratories Inc. Your use of this
+ * software is governed by the terms of Silicon Labs Master Software License
+ * Agreement (MSLA) available at
+ * www.silabs.com/about-us/legal/master-software-license-agreement. This
+ * software is distributed to you in Source Code format and is governed by the
+ * sections of the MSLA applicable to Source Code.
+ *
+ ******************************************************************************/
+
+#include
+#include "em_cmu.h"
+#include "em_wdog.h"
+#include "em_rmu.h"
+#include "sli_cpc_timer.h"
+#include "sl_component_catalog.h"
+
+void nc_enable_watchdog(void);
+void nc_periodic_timer(sli_cpc_timer_handle_t *handle, void *data);
\ No newline at end of file
diff --git a/gecko_sdk_extensions/nc_efr32_watchdog_extension/nc_efr32_watchdog.slcc b/gecko_sdk_extensions/nc_efr32_watchdog_extension/nc_efr32_watchdog.slcc
new file mode 100644
index 00000000..688ae1ba
--- /dev/null
+++ b/gecko_sdk_extensions/nc_efr32_watchdog_extension/nc_efr32_watchdog.slcc
@@ -0,0 +1,38 @@
+root_path: ./
+id: nc_efr32_watchdog
+label: EFR32 Watchdog
+package: ext-comp
+category: External Components
+quality: production
+description: >
+ EFR32 Watchdog.
+requires:
+ - name: component_catalog
+ - name: emlib_wdog
+ - name: emlib_wdog
+provides:
+ - name: nc_efr32_watchdog
+
+source:
+ - path: src/nc_efr32_wdog.c
+
+include:
+ - path: inc
+ file_list:
+ - path: nc_efr32_wdog.h
+
+template_contribution:
+ - name: component_catalog
+ value: nc_efr32_watchdog
+ - name: event_handler
+ value:
+ event: service_init
+ include: "nc_efr32_wdog.h"
+ handler: nc_enable_watchdog
+ priority: 9999 # load very very late
+ - name: event_handler
+ value:
+ event: service_process_action
+ include: "nc_efr32_wdog.h"
+ handler: nc_poke_watchdog
+ priority: 9999 # run last
diff --git a/gecko_sdk_extensions/nc_efr32_watchdog_extension/nc_efr32_watchdog.slce b/gecko_sdk_extensions/nc_efr32_watchdog_extension/nc_efr32_watchdog.slce
new file mode 100644
index 00000000..ba087a3f
--- /dev/null
+++ b/gecko_sdk_extensions/nc_efr32_watchdog_extension/nc_efr32_watchdog.slce
@@ -0,0 +1,8 @@
+id: "nc_efr32_watchdog"
+label: "EFR32 Watchdog"
+version: "1.0.0"
+sdk:
+ id: "gecko_sdk"
+ version: 4.3.2
+component_path:
+ - path: "./"
\ No newline at end of file
diff --git a/gecko_sdk_extensions/nc_efr32_watchdog_extension/src/nc_efr32_wdog.c b/gecko_sdk_extensions/nc_efr32_watchdog_extension/src/nc_efr32_wdog.c
new file mode 100644
index 00000000..21979c00
--- /dev/null
+++ b/gecko_sdk_extensions/nc_efr32_watchdog_extension/src/nc_efr32_wdog.c
@@ -0,0 +1,92 @@
+/***************************************************************************//**
+ * @file nc_efr32_wdog.c
+ * @brief Legacy HAL Watchdog
+ *******************************************************************************
+ * # License
+ * Copyright 2022 Silicon Laboratories, Inc, www.silabs.com
+ *******************************************************************************
+ *
+ * The licensor of this software is Silicon Laboratories Inc. Your use of this
+ * software is governed by the terms of Silicon Labs Master Software License
+ * Agreement (MSLA) available at
+ * www.silabs.com/about-us/legal/master-software-license-agreement. This
+ * software is distributed to you in Source Code format and is governed by the
+ * sections of the MSLA applicable to Source Code.
+ *
+ ******************************************************************************/
+
+#include "em_wdog.h"
+#include "nc_efr32_wdog.h"
+
+static bool feed_watchdog_on_warn_interrupt;
+
+
+#if (_SILICON_LABS_32B_SERIES >= 1)
+void WDOG0_IRQHandler(void)
+{
+ uint32_t interrupts;
+
+ interrupts = WDOGn_IntGet(WDOG0);
+ WDOGn_IntClear(WDOG0, interrupts);
+
+ if (feed_watchdog_on_warn_interrupt) {
+ WDOGn_Feed(WDOG0);
+ feed_watchdog_on_warn_interrupt = false;
+ }
+}
+#endif
+
+
+void nc_enable_watchdog(void)
+{
+ // Enable LE interface
+#if !defined(_SILICON_LABS_32B_SERIES_2)
+ CMU_ClockEnable(cmuClock_HFLE, true);
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
+#endif
+
+#if defined(_SILICON_LABS_32B_SERIES_2) && !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
+ CMU_ClockEnable(cmuClock_WDOG0, true);
+#endif
+
+ // Make sure FULL reset is used on WDOG timeout
+#if defined(_RMU_CTRL_WDOGRMODE_MASK)
+ RMU_ResetControl(rmuResetWdog, rmuResetModeFull);
+#endif
+
+ WDOG_Init_TypeDef init = WDOG_INIT_DEFAULT;
+ init.enable = false;
+ init.debugRun = false;
+ init.perSel = wdogPeriod_64k; // 2 seconds
+ init.warnSel = wdogWarnTime75pct;
+
+#if defined(_WDOG_CTRL_CLKSEL_MASK)
+ init.clkSel = wdogClkSelLFRCO;
+#else
+ // Series 2 devices select watchdog oscillator with the CMU.
+ CMU_ClockSelectSet(cmuClock_WDOG0, cmuSelect_LFRCO);
+#endif
+
+ WDOGn_Unlock(WDOG0);
+ WDOGn_Init(WDOG0, &init);
+
+ // Enable warning interrupt
+ NVIC_ClearPendingIRQ(WDOG0_IRQn);
+ WDOGn_IntClear(WDOG0, WDOG_IF_WARN);
+ NVIC_EnableIRQ(WDOG0_IRQn);
+ WDOGn_IntEnable(WDOG0, WDOG_IEN_WARN);
+
+ WDOGn_Enable(WDOG0, true);
+ WDOGn_Feed(WDOG0);
+
+ feed_watchdog_on_warn_interrupt = false;
+}
+
+
+void nc_poke_watchdog()
+{
+ CORE_DECLARE_IRQ_STATE;
+ CORE_ENTER_ATOMIC();
+ feed_watchdog_on_warn_interrupt = true;
+ CORE_EXIT_ATOMIC();
+}