From d66f69ff38fb930a2cb52efd8c1e5f47dde073e4 Mon Sep 17 00:00:00 2001 From: Nikunj Kotecha Date: Sun, 27 Sep 2026 09:42:46 -0700 Subject: [PATCH 1/6] fix(ble): drive the DK status LED only in DK builds The disconnect handler called dk_set_led_off() on every board, while every other DK LED call is guarded by CONFIG_DK_BOARD. On the AkidaTag board the DK library's LED table came from the nRF5340 DK devicetree, so the call cleared the output latch of P0.29, the console UART's TX pin, which the UART owns while it runs. Without the DK devicetree the table is empty and the call would log an error at every disconnect instead. --- src/core/interface/ble_services/ble_initialization.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/interface/ble_services/ble_initialization.c b/src/core/interface/ble_services/ble_initialization.c index 4561d2a..542ac75 100644 --- a/src/core/interface/ble_services/ble_initialization.c +++ b/src/core/interface/ble_services/ble_initialization.c @@ -1049,7 +1049,9 @@ static void disconnected_ble(struct bt_conn* conn, uint8_t reason) { bt_conn_unref(current_conn); current_conn = NULL; } +#ifdef CONFIG_DK_BOARD dk_set_led_off(CON_STATUS_LED); +#endif led_set_state(LED_STATE_NORMAL_APP); ble_connection_callback(BLE_NOT_CONNECTED); app_start_flag = FLAG_DISABLE; From 31191c570032d42f2514cd871776ce719d4d81db Mon Sep 17 00:00:00 2001 From: Nikunj Kotecha Date: Sun, 27 Sep 2026 09:44:54 -0700 Subject: [PATCH 2/6] refactor(boards): describe the AkidaTag board as a Zephyr board definition The AkidaTag board was built as the nRF5340 DK with an application overlay and an MCUboot overlay on top. Zephyr can only attach hardware revisions to a board of its own, and the nRF5340 DK has none, so the board now has a board definition in src/boards/brainchip/akidatag/, adapted from the DK's. Its devicetree is split into what every revision shares and a revision 1 overlay, and board.yml declares revision 1 as the default. MCUboot's changes move into the sysbuild configuration directory src/sysbuild/mcuboot/, whose boards/ overlays sysbuild finds by board and revision name. MCUboot then no longer reads its own prj.conf, so the directory restates it; the project's settings stay in mcuboot.conf. run.sh builds akidatag/nrf5340/cpuapp with src as the board root, and names the DK target explicitly instead of reading it from the environment. The revision 1 network core image is byte-identical to the one built from the overlays. MCUboot and the application differ only where the DK devicetree used to leak in: MCUboot no longer carries pin control code for the DK's PWM LED, and the application no longer carries the DK's LED table or its Arduino node labels. --- NOTICE | 24 ++ scripts/run.sh | 12 +- .../brainchip/akidatag/Kconfig.akidatag | 6 + .../brainchip/akidatag/Kconfig.defconfig | 16 + .../akidatag_nrf5340_cpuapp-pinctrl.dtsi | 76 ++++ .../akidatag/akidatag_nrf5340_cpuapp.dts | 229 ++++++++++ .../akidatag_nrf5340_cpuapp_1.overlay | 94 ++++ .../akidatag_nrf5340_cpuapp_defconfig | 8 + .../akidatag_nrf5340_cpunet-pinctrl.dtsi | 29 ++ .../akidatag/akidatag_nrf5340_cpunet.dts | 89 ++++ .../akidatag_nrf5340_cpunet_defconfig | 7 + src/boards/brainchip/akidatag/board.cmake | 13 + src/boards/brainchip/akidatag/board.yml | 12 + .../brainchip/akidatag/pre_dt_board.cmake | 6 + src/boards/dk.conf | 10 +- src/boards/nrf5340_cpuapp_akidatag.overlay | 401 ------------------ .../boards/akidatag_nrf5340_cpuapp_1.overlay | 67 +++ .../boards/nrf5340dk_nrf5340_cpuapp.overlay} | 0 src/sysbuild/mcuboot/prj.conf | 48 +++ src/sysbuild/mcuboot_akidatag.overlay | 97 ----- 20 files changed, 734 insertions(+), 510 deletions(-) create mode 100644 src/boards/brainchip/akidatag/Kconfig.akidatag create mode 100644 src/boards/brainchip/akidatag/Kconfig.defconfig create mode 100644 src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp-pinctrl.dtsi create mode 100644 src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp.dts create mode 100644 src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_1.overlay create mode 100644 src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_defconfig create mode 100644 src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet-pinctrl.dtsi create mode 100644 src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet.dts create mode 100644 src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet_defconfig create mode 100644 src/boards/brainchip/akidatag/board.cmake create mode 100644 src/boards/brainchip/akidatag/board.yml create mode 100644 src/boards/brainchip/akidatag/pre_dt_board.cmake delete mode 100644 src/boards/nrf5340_cpuapp_akidatag.overlay create mode 100644 src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_1.overlay rename src/sysbuild/{mcuboot_dk.overlay => mcuboot/boards/nrf5340dk_nrf5340_cpuapp.overlay} (100%) create mode 100644 src/sysbuild/mcuboot/prj.conf delete mode 100644 src/sysbuild/mcuboot_akidatag.overlay diff --git a/NOTICE b/NOTICE index 0f5e719..7a1e938 100644 --- a/NOTICE +++ b/NOTICE @@ -167,6 +167,30 @@ that a source redistribution retains the list of conditions it asks for: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +Zephyr nRF5340 DK board and MCUboot configuration +-------------------------------------------------------------------------------- + +Upstream: Zephyr RTOS and MCUboot as shipped in nRF Connect SDK v3.1.1, + zephyr/boards/nordic/nrf5340dk/ and + bootloader/mcuboot/boot/zephyr/prj.conf +Paths: src/boards/brainchip/akidatag/ + src/sysbuild/mcuboot/prj.conf +Licence: Apache License, Version 2.0 (SPDX-License-Identifier: Apache-2.0) +Copyright: Copyright (c) 2019-2022 Nordic Semiconductor ASA + Copyright (c) 2022 Zephyr Project members and individual contributors + Copyright (c) 2021 Linaro Limited (pre_dt_board.cmake) + +The AkidaTag board definition is adapted from Zephyr's nRF5340 DK board. Its +Kconfig files, board.cmake, pre_dt_board.cmake and defconfig files, the network +core devicetree and its pinctrl file follow the DK's, and the application core +devicetree keeps the DK's chosen nodes, regulator, crystal and partition +settings. Each of those files carries the upstream copyright and SPDX lines; +the pin descriptions, the revision overlays and board.yml are BrainChip's. +src/sysbuild/mcuboot/prj.conf restates MCUboot's own prj.conf, which declares +no copyright or licence of its own; MCUboot is distributed under the Apache +License, Version 2.0. The licence text is in LICENSE. + -------------------------------------------------------------------------------- Keyword-spotting sample input -------------------------------------------------------------------------------- diff --git a/scripts/run.sh b/scripts/run.sh index a6a3809..b868dfe 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -435,6 +435,7 @@ fi # ----------------------------------------------------------------------------- APP_SRC_DIR="" APP_BUILD_DIR="" +BOARD_TARGET="" BUILD_CMD="" FLASH_CMD="" @@ -457,14 +458,16 @@ if [[ -n "$APP" ]]; then CMAKE_EXTRA_ARGS+=(-DCONFIG_AUDIO_CAPTURE_TEST=n) # Overlay selection using USE_AUDIO if $DK_OVERLAY; then + BOARD_TARGET="nrf5340dk/nrf5340/cpuapp" CMAKE_EXTRA_ARGS+=(-DCONFIG_AKIDATAG_BOARD=n) CMAKE_EXTRA_ARGS+=("-DEXTRA_CONF_FILE=boards/dk.conf") CMAKE_EXTRA_ARGS+=("-DDTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpuapp.overlay") - CMAKE_EXTRA_ARGS+=("-Dmcuboot_DTC_OVERLAY_FILE=/akidatag/src/sysbuild/mcuboot_dk.overlay") else + BOARD_TARGET="akidatag/nrf5340/cpuapp" CMAKE_EXTRA_ARGS+=(-DCONFIG_AKIDATAG_BOARD=y) - CMAKE_EXTRA_ARGS+=("-DDTC_OVERLAY_FILE=boards/nrf5340_cpuapp_akidatag.overlay") - CMAKE_EXTRA_ARGS+=("-Dmcuboot_DTC_OVERLAY_FILE=/akidatag/src/sysbuild/mcuboot_akidatag.overlay") + # A relative board root resolves against the application directory, so + # this is src/, which holds boards/brainchip/akidatag/ + CMAKE_EXTRA_ARGS+=("-DBOARD_ROOT=.") fi ;; *) @@ -488,8 +491,7 @@ if [[ -n "$APP" ]]; then fi fi - # IMPORTANT: "$BOARD" must stay escaped so it expands inside the environment - BUILD_CMD="west build -p always -b \"\$BOARD\" -s \"$APP_SRC_DIR\" -d \"$APP_BUILD_DIR\"" + BUILD_CMD="west build -p always -b \"$BOARD_TARGET\" -s \"$APP_SRC_DIR\" -d \"$APP_BUILD_DIR\"" # Append CMake args only if we have any if (( ${#CMAKE_EXTRA_ARGS[@]} > 0 )); then diff --git a/src/boards/brainchip/akidatag/Kconfig.akidatag b/src/boards/brainchip/akidatag/Kconfig.akidatag new file mode 100644 index 0000000..ff84f35 --- /dev/null +++ b/src/boards/brainchip/akidatag/Kconfig.akidatag @@ -0,0 +1,6 @@ +# Copyright (c) 2022 Zephyr Project members and individual contributors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_AKIDATAG + select SOC_NRF5340_CPUAPP_QKAA if BOARD_AKIDATAG_NRF5340_CPUAPP + select SOC_NRF5340_CPUNET_QKAA if BOARD_AKIDATAG_NRF5340_CPUNET diff --git a/src/boards/brainchip/akidatag/Kconfig.defconfig b/src/boards/brainchip/akidatag/Kconfig.defconfig new file mode 100644 index 0000000..d15b064 --- /dev/null +++ b/src/boards/brainchip/akidatag/Kconfig.defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2019-2020 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config HW_STACK_PROTECTION + default ARCH_HAS_STACK_PROTECTION + +if BOARD_AKIDATAG_NRF5340_CPUAPP + +config BT_HCI_IPC + default y if BT + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 4096 if BT_HCI_IPC + +endif # BOARD_AKIDATAG_NRF5340_CPUAPP diff --git a/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp-pinctrl.dtsi b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp-pinctrl.dtsi new file mode 100644 index 0000000..d151c3c --- /dev/null +++ b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp-pinctrl.dtsi @@ -0,0 +1,76 @@ +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c1_default: i2c1_default { + group1 { + psels = , + ; + }; + }; + + i2c1_sleep: i2c1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + pdm0_default: pdm0_default { + group1 { + psels = , + ; + }; + }; + + /* P0.08 to P0.10 are the SPIM4 high-speed pins. High drive keeps the SCK + * and MOSI edges clean at 16 and 32 MHz. + */ + spi4_default: spi4_default { + group1 { + psels = , + , + ; + nordic,drive-mode = ; + }; + }; + + spi4_sleep: spi4_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spi3_default: spi3_default { + group1 { + psels = , + , + ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp.dts b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp.dts new file mode 100644 index 0000000..216e58c --- /dev/null +++ b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp.dts @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2019-2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "akidatag_nrf5340_cpuapp-pinctrl.dtsi" + +/ { + model = "BrainChip AkidaTag NRF5340 Application"; + compatible = "brainchip,akidatag-nrf5340-cpuapp"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + zephyr,bt-hci = &bt_hci_ipc0; + zephyr,sram = &sram0_image; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + /* Power enables and status lines that are not a bus of their own. */ + gpios { + compatible = "gpio-keys"; + + akd_lp: akd_lp { + gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + }; + + akd_async: akd_async { + gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + }; + + imui: imui { + gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + }; + + akd_enb: akd_enb { + gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>; + }; + + acc_enb: acc_enb { + gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>; + }; + + pdm_enb: pdm_enb { + gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + }; + + akd_0v_enb: akd_0v_enb { + gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>; + }; + + fg_int: fg_int { + gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + }; + + chgr_sts1: chgr_sts1 { + gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; + }; + + chgr_sts2: chgr_sts2 { + gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>; + }; + }; + + zephyr,user { + /* Current-sense amplifier outputs: index 0 is the 1.8 V rail, 1 the 0.8 V rail. */ + io-channels = <&adc 0>, <&adc 1>; + }; + + aliases { + akd-lp = &akd_lp; + spi2 = &spi2; + akd-spi = &spi4; + imui = &imui; + akd-enb = &akd_enb; + acc-enb = &acc_enb; + pdm-enb = &pdm_enb; + akd-0v-enb = &akd_0v_enb; + akd-async = &akd_async; + fg-int = &fg_int; + chgr-sts1 = &chgr_sts1; + chgr-sts2 = &chgr_sts2; + watchdog = &wdt; + watchdog0 = &wdt0; + }; +}; + +&vregmain { + regulator-initial-mode = ; +}; + +&vregradio { + regulator-initial-mode = ; +}; + +&vregh { + status = "okay"; +}; + +&lfxo { + load-capacitors = "internal"; + load-capacitance-picofarad = <7>; +}; + +/* P0.02 and P0.03 are AKD1500 GPIOs, so the NFC antenna function is released. */ +&uicr { + nfct-pins-as-gpios; +}; + +&clock { + hfclkaudio-frequency = <12288000>; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&ipc0 { + status = "okay"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&i2c1 { + compatible = "nordic,nrf-twim"; + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-1 = <&i2c1_sleep>; + pinctrl-names = "default", "sleep"; + + mysensor: mysensor@6a { + compatible = "i2c-device"; + status = "okay"; + reg = <0x6a>; + }; +}; + +dmic_dev: &pdm0 { + status = "okay"; + pinctrl-0 = <&pdm0_default>; + pinctrl-names = "default"; + clock-source = "ACLK"; +}; + +&adc { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + /* 1.8 V rail current, AIN0 on P0.04 */ + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1_3"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + zephyr,resolution = <12>; + }; + + /* 0.8 V rail current, AIN1 on P0.05 */ + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1_3"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + zephyr,resolution = <12>; + }; +}; + +/* AKD1500 host interface. SPIM4 is the only instance that runs above 8 MHz. */ +&spi4 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi4_default>; + pinctrl-1 = <&spi4_sleep>; + pinctrl-names = "default", "sleep"; + /* MISO sample delay that reads cleanly at 8, 16 and 32 MHz; `spi_rxdelay` + * overrides it at runtime. + */ + rx-delay = <1>; + cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>, + <&gpio0 12 GPIO_ACTIVE_LOW>; + + akd: akd@0 { + compatible = "spi-device"; + reg = <0>; + spi-max-frequency = <32000000>; + label = "AKD"; + }; + + /* akd_flash@1, the AKD1500's model flash reached through its slave-to-master + * feed-through, is defined per revision. + */ +}; + +/* Flash IC1: the MCUboot update slot and the LittleFS volume. */ +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; +}; + +#include diff --git a/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_1.overlay b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_1.overlay new file mode 100644 index 0000000..50b0f89 --- /dev/null +++ b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_1.overlay @@ -0,0 +1,94 @@ +/* + * AkidaTag hardware revision 1: the camera shares SPIM3 with flash IC1, both + * flashes are Micron MT25QU128ABA, and the board has a red and a green LED, a + * user button and a DFU button. + */ + +/ { + chosen { + nordic,pm-ext-flash = &ext_flash; + }; + + gpios { + akdreset: akdreset { + gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + + cam_enb: cam_enb { + gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + }; + }; + + custom_buttons { + compatible = "gpio-keys"; + + user_btn: user_btn { + gpios = <&gpio0 26 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "User Button"; + }; + + dfu_btn: dfu_btn { + gpios = <&gpio1 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "DFU Button"; + }; + }; + + custom_leds { + compatible = "gpio-leds"; + + led_red: led_red { + gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + }; + + led_green: led_green { + gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>; + }; + }; + + aliases { + akdreset = &akdreset; + cam-enb = &cam_enb; + user-button = &user_btn; + mcuboot-button0 = &dfu_btn; + mcuboot-led0 = &led_red; + }; +}; + +&spi4 { + akd_flash: mt25qu128aba@1 { + compatible = "jedec,spi-nor"; + reg = <1>; + spi-max-frequency = <8000000>; + size = ; + jedec-id = [20 bb 18]; + has-dpd; + t-enter-dpd = <10000>; + t-exit-dpd = <35000>; + }; +}; + +&spi3 { + cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>, + <&gpio0 18 GPIO_ACTIVE_LOW>; + + camera: camera@0 { + compatible = "spi-device"; + reg = <0>; + spi-max-frequency = <8000000>; + label = "CAMERA"; + }; + + /* Named flash@0 although it is on chip select 1: the node name is also the + * device name, which the firmware image carries. + */ + ext_flash: flash@0 { + compatible = "jedec,spi-nor"; + reg = <1>; + spi-max-frequency = <8000000>; + size = ; + jedec-id = [20 bb 18]; + has-dpd; + t-enter-dpd = <10000>; + t-exit-dpd = <35000>; + }; +}; diff --git a/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_defconfig b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_defconfig new file mode 100644 index 0000000..302cf13 --- /dev/null +++ b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_defconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ARM_MPU=y +CONFIG_ARM_TRUSTZONE_M=y +CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet-pinctrl.dtsi b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet-pinctrl.dtsi new file mode 100644 index 0000000..a4de1e8 --- /dev/null +++ b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet-pinctrl.dtsi @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; +}; diff --git a/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet.dts b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet.dts new file mode 100644 index 0000000..1a246ab --- /dev/null +++ b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet.dts @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "akidatag_nrf5340_cpunet-pinctrl.dtsi" + +/ { + model = "BrainChip AkidaTag NRF5340 Network"; + compatible = "brainchip,akidatag-nrf5340-cpunet"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; + }; + + aliases { + watchdog0 = &wdt0; + }; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +/* The application core never hands these pins to the network core, so this + * console has no output on this board. + */ +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&flash1 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0xc000>; + }; + + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 0x17000>; + }; + + slot1_partition: partition@23000 { + label = "image-1"; + reg = <0x00023000 0x17000>; + }; + + storage_partition: partition@3a000 { + label = "storage"; + reg = <0x0003a000 0x6000>; + }; + }; +}; + +&ieee802154 { + status = "okay"; +}; + +#include diff --git a/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet_defconfig b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet_defconfig new file mode 100644 index 0000000..65d767b --- /dev/null +++ b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpunet_defconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ARM_MPU=y +CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/src/boards/brainchip/akidatag/board.cmake b/src/boards/brainchip/akidatag/board.cmake new file mode 100644 index 0000000..f69ba60 --- /dev/null +++ b/src/boards/brainchip/akidatag/board.cmake @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_AKIDATAG_NRF5340_CPUAPP) + board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") +endif() + +if(CONFIG_BOARD_AKIDATAG_NRF5340_CPUNET) + board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") +endif() + +include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/src/boards/brainchip/akidatag/board.yml b/src/boards/brainchip/akidatag/board.yml new file mode 100644 index 0000000..756503d --- /dev/null +++ b/src/boards/brainchip/akidatag/board.yml @@ -0,0 +1,12 @@ +board: + name: akidatag + full_name: AkidaTag + vendor: brainchip + socs: + - name: nrf5340 + revision: + format: number + default: "1" + exact: true + revisions: + - name: "1" diff --git a/src/boards/brainchip/akidatag/pre_dt_board.cmake b/src/boards/brainchip/akidatag/pre_dt_board.cmake new file mode 100644 index 0000000..1c596b5 --- /dev/null +++ b/src/boards/brainchip/akidatag/pre_dt_board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2021 Linaro Limited +# SPDX-License-Identifier: Apache-2.0 + +# The nRF5340 devicetree gives several peripherals the same address, such as the +# flash controller and the KMU, and the POWER and CLOCK blocks. +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/src/boards/dk.conf b/src/boards/dk.conf index 6934f5a..4fbb20a 100644 --- a/src/boards/dk.conf +++ b/src/boards/dk.conf @@ -1,11 +1,7 @@ # Kconfig fragment merged only by the DK build, via EXTRA_CONF_FILE in the -# --dk branch of scripts/run.sh. It is deliberately NOT named after a board -# target: both the AkidaTag board and the DK are built for the same Zephyr board -# (nrf5340dk/nrf5340/cpuapp, see docker/Dockerfile), so an auto-discovered -# boards/nrf5340dk_nrf5340_cpuapp.conf would be merged into the AkidaTag build as -# well and could not tell the two apart. The board difference in this project -# is carried by the CMake arguments run.sh selects, so the override lives there -# too, next to the devicetree overlay choice. +# --dk branch of scripts/run.sh, next to the devicetree overlay that branch +# selects. The AkidaTag board has its own board definition in +# boards/brainchip/akidatag/ and never reads this file. # Distinguish the DK from the AkidaTag board on air. The legacy advertising packet # is 31 bytes and this name is one character away from filling it: flags (3) + diff --git a/src/boards/nrf5340_cpuapp_akidatag.overlay b/src/boards/nrf5340_cpuapp_akidatag.overlay deleted file mode 100644 index 07c54c3..0000000 --- a/src/boards/nrf5340_cpuapp_akidatag.overlay +++ /dev/null @@ -1,401 +0,0 @@ -&qspi { - status = "disabled"; -}; -/* Disable default LEDs */ -&led0 { - status = "disabled"; -}; - -&led1 { - status = "disabled"; -}; - -&led2 { - status = "disabled"; -}; - -&led3 { - status = "disabled"; -}; - -/* Disable default buttons */ -&button0 { - status = "disabled"; -}; - -&button1 { - status = "disabled"; -}; - -&button2 { - status = "disabled"; -}; - -&button3 { - status = "disabled"; -}; -&gpio_fwd { - status = "disabled"; -}; - -&pwm0 { - status = "disabled"; -}; -&uicr { - nfct-pins-as-gpios; -}; -/* Disable the entire gpio-keys and leds nodes if needed */ -/ { - buttons { - status = "disabled"; - }; - - leds { - status = "disabled"; - }; -}; -&pinctrl { - spi2_default: spi2_default { - group1 { - psels = , - , - ; - /* ADD THIS - disable trace function on these pins */ - nordic,drive-mode = ; - }; - }; - - spi2_sleep: spi2_sleep { - group1 { - psels = , - , - ; - low-power-enable; - }; - }; - - /* Akida host SPI on SPIM4 (only nRF5340 instance that does >8 MHz). - * P0.08/09/10 are the dedicated high-speed pins; HIGH DRIVE (H0H1) is - * required for clean SCK/MOSI edges at 16/32 MHz. */ - spi4_default: spi4_default { - group1 { - psels = , - , - ; - nordic,drive-mode = ; - }; - }; - - spi4_sleep: spi4_sleep { - group1 { - psels = , - , - ; - low-power-enable; - }; - }; - - uart0_default_alt: uart0_default_alt { - group1 { - psels = , - ; - }; - }; - - uart0_sleep_alt: uart0_sleep_alt { - group1 { - psels = , - ; - low-power-enable; - }; - }; - - pdm0_default_alt: pdm0_default_alt { - group1 { - psels = , - ; - }; - }; - - /omit-if-no-ref/ i2c1_default: i2c1_default { - group1 { - psels = , - ; - }; - }; - - /omit-if-no-ref/ i2c1_sleep: i2c1_sleep { - group1 { - psels = , - ; - low-power-enable; - }; - }; - spi3_default: spi3_default { - group1 { - psels = , - , - ; - }; - }; - - spi3_sleep: spi3_sleep { - group1 { - psels = , - , - ; - low-power-enable; - }; - }; - -}; - -/* PDM mic configurations */ - -&clock { - hfclkaudio-frequency = <12288000>; -}; - -&pdm0 { - status = "okay"; - clock-source = "ACLK"; -}; - -dmic_dev: &pdm0 { - status = "okay"; - pinctrl-0 = <&pdm0_default_alt>; - pinctrl-names = "default"; - clock-source = "ACLK"; - -}; -/ { - chosen { - nordic,pm-ext-flash = &ext_flash; - }; -}; - -&i2c1 { - status = "okay"; - clock-frequency = ; // 400 kHz - pinctrl-0 = <&i2c1_default>; - pinctrl-1 = <&i2c1_sleep>; - pinctrl-names = "default", "sleep"; - mysensor: mysensor@6a{ - compatible = "i2c-device"; - status = "okay"; - reg = < 0x6a >; - }; -}; - - -&ipc0 { - status = "okay"; -}; - - -/* Akida moved off SPIM2 (8 MHz HW cap) to SPIM4 (up to 32 MHz) on the same - * physical pins P0.08/09/10 + CS P0.11/P0.12. SPIM2 disabled to free the pins. */ -&spi2 { - status = "disabled"; -}; - -&spi4 { - compatible = "nordic,nrf-spim"; - status = "okay"; - pinctrl-0 = <&spi4_default>; - pinctrl-1 = <&spi4_sleep>; - pinctrl-names = "default", "sleep"; - /* max-frequency (32 MHz) and rx-delay-supported come from the SoC dtsi. - * rx-delay=1 (MISO sample delay) reads cleanly at 8/16/32 MHz on this board - * (HW-swept: 32 MHz needs rxd 1-2; 8/16 MHz tolerate 0-2 — so 1 is universal). - * Zephyr re-applies this DT value on every reconfigure. Override at runtime - * with `spi_rxdelay`. */ - rx-delay = <1>; - cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>, /* CS for AKIDA */ - <&gpio0 12 GPIO_ACTIVE_LOW>; /* CS for AKIDA flash (S2M feedthrough) */ - - /* AKD1500 SPI-slave data interface. Host clock applied at runtime - * (CONFIG_AKD_SPI_FREQ_HZ default; `spi_freq` to sweep). Bounded by the - * AKD1500 SPI_S core clock (¼-rule, §3.7.1) — needs the SPI_S core on the - * 400 MHz PLL (see `akd_pll_on`), else it caps ~3-6 MHz on the bypass clock. */ - akd: akd@0 { - compatible = "spi-device"; - reg = <0>; /* Uses first CS pin (P0.11) */ - spi-max-frequency = <32000000>; - label = "AKD"; - }; - - /* mt25qu128aba Flash device at index 1 (accessed via AKD1500 S2M) */ - akd_flash: mt25qu128aba@1 { /* ← @1 to match reg = <1> */ - compatible = "jedec,spi-nor"; - reg = <1>; - spi-max-frequency = <8000000>; - size = ; - jedec-id = [20 bb 18]; - has-dpd; - t-enter-dpd = <10000>; - t-exit-dpd = <35000>; - }; -}; - -&uart0 { - status = "okay"; - compatible = "nordic,nrf-uarte"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default_alt>; - pinctrl-1 = <&uart0_sleep_alt>; - pinctrl-names = "default", "sleep"; -}; - -&spi3 { - compatible = "nordic,nrf-spim"; - status = "okay"; - pinctrl-0 = <&spi3_default>; - pinctrl-1 = <&spi3_sleep>; - pinctrl-names = "default", "sleep"; - cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>, - <&gpio0 18 GPIO_ACTIVE_LOW>; /* CS for NRF flash */ - - /* camera device at index 0 */ - camera: camera@0 { - compatible = "spi-device"; - reg = <0>; /* Uses first CS pin (P0.25) */ - spi-max-frequency = <8000000>; - label = "CAMERA"; - }; - /* NRF Flash device at index 1 mt25qu128aba*/ - ext_flash: flash@0 { - compatible = "jedec,spi-nor"; - reg = <1>; - spi-max-frequency = <8000000>; - size = ; - jedec-id = [20 bb 18]; - has-dpd; - t-enter-dpd = <10000>; - t-exit-dpd = <35000>; - }; -}; -/ { - aliases { - watchdog = &wdt; - }; -}; - -/ { - gpios { - compatible = "gpio-keys"; - akd_lp: akd_lp { - gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; - }; - - akdreset: akdreset { - gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; - }; - - akd_async: akd_async { - gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; - }; - - imui: imui { - gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; - }; - akd_enb: akd_enb { - gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>; - }; - acc_enb: acc_enb { - gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>; - }; - pdm_enb: pdm_enb { - gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; - }; - akd_0v_enb: akd_0v_enb { - gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>; - }; - cam_enb: cam_enb { - gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; - }; - fg_int: fg_int { - gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; - }; - chgr_sts1: chgr_sts1 { - gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; - }; - chgr_sts2: chgr_sts2 { - gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>; - }; - }; - - /* ---------- Buttons ---------- */ - custom_buttons { - compatible = "gpio-keys"; - - user_btn: user_btn { - gpios = <&gpio0 26 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "User Button"; - }; - }; - - custom_leds { - compatible = "gpio-leds"; - - led_red: led_red { - gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; - }; - - led_green: led_green { - gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>; - }; - }; - - aliases { - akd-lp = &akd_lp; - akdreset = &akdreset; - spi2 = &spi2; - akd-spi = &spi4; /* Akida SPI bus moved to SPIM4 (up to 32 MHz). */ - imui = &imui; - akd-enb = &akd_enb; - acc-enb = &acc_enb; - pdm-enb = &pdm_enb; - akd-0v-enb = &akd_0v_enb; - cam-enb = &cam_enb; - user-button = &user_btn; - akd-async = &akd_async; - fg-int = &fg_int; - chgr-sts1 = &chgr_sts1; - chgr-sts2 = &chgr_sts2; - }; -}; -/ { - zephyr,user { - /* Two ADC channels — index 0 = 1V8 rail, index 1 = 0V8 rail */ - io-channels = <&adc 0>, <&adc 1>; - }; -}; - -&adc { - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - - /* CH0: 1V8_AKD rail — AIN0 = P0.04 */ - channel@0 { - reg = <0>; - zephyr,gain = "ADC_GAIN_1_3"; - zephyr,reference = "ADC_REF_INTERNAL"; - zephyr,acquisition-time = ; - zephyr,input-positive = ; - zephyr,resolution = <12>; - /* NO oversampling — nRF SAADC only supports it for single channel */ - }; - - /* CH1: 0V8_AKD rail — AIN1 = P0.05 */ - channel@1 { - reg = <1>; - zephyr,gain = "ADC_GAIN_1_3"; - zephyr,reference = "ADC_REF_INTERNAL"; - zephyr,acquisition-time = ; - zephyr,input-positive = ; - zephyr,resolution = <12>; - /* NO oversampling — nRF SAADC only supports it for single channel */ - }; -}; \ No newline at end of file diff --git a/src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_1.overlay b/src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_1.overlay new file mode 100644 index 0000000..eb4d29c --- /dev/null +++ b/src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_1.overlay @@ -0,0 +1,67 @@ +/* + * MCUboot on revision 1 reaches flash IC1 through SPIM4 on the SPIM3 pins, and + * leaves the audio clock and the NFC pins to the application. + */ + +&pinctrl { + spi4_flash_default: spi4_flash_default { + group1 { + psels = , + , + ; + }; + }; + + spi4_flash_sleep: spi4_flash_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +/ { + chosen { + nordic,pm-ext-flash = &mcuboot_ext_flash; + }; +}; + +&clock { + /delete-property/ hfclkaudio-frequency; +}; + +&uicr { + /delete-property/ nfct-pins-as-gpios; +}; + +/delete-node/ &camera; +/delete-node/ &ext_flash; + +&spi3 { + status = "disabled"; + /delete-property/ cs-gpios; +}; + +/delete-node/ &akd; +/delete-node/ &akd_flash; + +&spi4 { + pinctrl-0 = <&spi4_flash_default>; + pinctrl-1 = <&spi4_flash_sleep>; + cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; + /* The SoC default, in place of the AKD1500 sample delay */ + rx-delay = <2>; + + mcuboot_ext_flash: mt25qu128aba@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <8000000>; + size = ; + jedec-id = [20 bb 18]; + has-dpd; + t-enter-dpd = <10000>; + t-exit-dpd = <35000>; + }; +}; diff --git a/src/sysbuild/mcuboot_dk.overlay b/src/sysbuild/mcuboot/boards/nrf5340dk_nrf5340_cpuapp.overlay similarity index 100% rename from src/sysbuild/mcuboot_dk.overlay rename to src/sysbuild/mcuboot/boards/nrf5340dk_nrf5340_cpuapp.overlay diff --git a/src/sysbuild/mcuboot/prj.conf b/src/sysbuild/mcuboot/prj.conf new file mode 100644 index 0000000..66645ac --- /dev/null +++ b/src/sysbuild/mcuboot/prj.conf @@ -0,0 +1,48 @@ +# Sysbuild uses this directory as MCUboot's configuration directory, so that +# boards/ here can hold per-board and per-revision devicetree overlays. MCUboot +# then no longer reads its own prj.conf, so this file restates it unchanged from +# bootloader/mcuboot/boot/zephyr/prj.conf in nRF Connect SDK v3.1.1. The project's +# own MCUboot settings stay in ../mcuboot.conf, which sysbuild merges after this. + +CONFIG_PM=n + +CONFIG_MAIN_STACK_SIZE=10240 + +CONFIG_BOOT_SWAP_SAVE_ENCTLV=n +CONFIG_BOOT_ENCRYPT_IMAGE=n + +CONFIG_BOOT_UPGRADE_ONLY=n +CONFIG_BOOT_BOOTSTRAP=n + +### mbedTLS has its own heap +# CONFIG_HEAP_MEM_POOL_SIZE is not set + +### We never want Zephyr's copy of tinycrypt. If tinycrypt is needed, +### MCUboot has its own copy in tree. +# CONFIG_TINYCRYPT is not set +# CONFIG_TINYCRYPT_ECC_DSA is not set +# CONFIG_TINYCRYPT_SHA256 is not set + +CONFIG_FLASH=y + +### Various Zephyr boards enable features that we don't want. +# CONFIG_BT is not set +# CONFIG_BT_CTLR is not set +# CONFIG_I2C is not set + +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y # former CONFIG_MODE_MINIMAL +### Ensure Zephyr logging changes don't use more resources +CONFIG_LOG_DEFAULT_LEVEL=0 +### Use info log level by default +CONFIG_MCUBOOT_LOG_LEVEL_INF=y +### Decrease footprint by ~4 KB in comparison to CBPRINTF_COMPLETE=y +CONFIG_CBPRINTF_NANO=y +### Use picolibc to reduce flash usage +CONFIG_PICOLIBC=y +### Disable malloc arena because we don't need it +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 + +# NCS boot banner +CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="MCUboot" diff --git a/src/sysbuild/mcuboot_akidatag.overlay b/src/sysbuild/mcuboot_akidatag.overlay deleted file mode 100644 index 6ff959e..0000000 --- a/src/sysbuild/mcuboot_akidatag.overlay +++ /dev/null @@ -1,97 +0,0 @@ -&gpio_fwd { - status = "disabled"; -}; -&qspi { - status = "disabled"; - /delete-node/ mx25r64; -}; - -&spi4 { - compatible = "nordic,nrf-spim"; - status = "okay"; - pinctrl-0 = <&spi4_default>; - pinctrl-1 = <&spi4_sleep>; - pinctrl-names = "default", "sleep"; - cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; - - mcuboot_ext_flash: mt25qu128aba@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <8000000>; - size = ; - jedec-id = [20 bb 18]; - has-dpd; - t-enter-dpd = <10000>; - t-exit-dpd = <35000>; - }; -}; -/ { - chosen { - nordic,pm-ext-flash = &mcuboot_ext_flash; - }; - aliases { - mcuboot-button0 = &dfu_button; - mcuboot-led0 = &led_1; - }; - - /* DFU trigger button on P1.01 */ - dfu_buttons { - compatible = "gpio-keys"; - - dfu_button: dfu_button_0 { - label = "DFU Button"; - gpios = <&gpio1 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - }; - }; - - leds { - compatible = "gpio-keys"; - - led_1: led_1 { - label = "DFU LED"; - gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; - - }; - }; -}; - -&pinctrl { -/* SPI pins for external flash */ - spi4_default: spi4_default { - group1 { - psels = , - , - ; - }; - }; - spi4_sleep: spi4_sleep { - group1 { - psels = , - , - ; - low-power-enable; - }; - }; - uart0_default_alt: uart0_default_alt { - group1 { - psels = , - ; - }; - }; - uart0_sleep_alt: uart0_sleep_alt { - group1 { - psels = , - ; - low-power-enable; - }; - }; -}; - -&uart0 { - status = "okay"; - compatible = "nordic,nrf-uarte"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default_alt>; - pinctrl-1 = <&uart0_sleep_alt>; - pinctrl-names = "default", "sleep"; -}; \ No newline at end of file From 9cb03ab6a00469c832555d46b67b9491f3a24809 Mon Sep 17 00:00:00 2001 From: Nikunj Kotecha Date: Sun, 27 Sep 2026 09:45:05 -0700 Subject: [PATCH 3/6] feat(boards): add AkidaTag hardware revision 2 as a build target Revision 2 is a Zephyr board revision of the AkidaTag board, selected with run.sh --rev 2 (akidatag@2/nrf5340/cpuapp). Revision 1 stays the default. The revision 2 overlay follows the revision 2 schematic, netlist and bill of materials: the camera on SPIM2 (P0.06, P0.07, P0.26, chip select P0.25), the camera supply switch on P1.06, the camera level shifter enable on P1.15 as active low, the user button on P1.01, the red, green, blue and white LEDs on P1.14, P0.27, P1.13 and P0.28, no akdreset line, and Winbond W25Q128JW flash in both positions. MCUboot on revision 2 uses the board's flash node directly. The firmware follows the description rather than fixed names: the camera driver takes the camera node's bus, the power-up sequence switches on the camera supply when the board has one, and the AKD1500 flash routines skip the Micron flag status commands when the flash is not a Micron part, since Winbond parts use those opcodes for other commands. The INA190 variant defaults to A3 on revision 2. --- scripts/run.sh | 14 +- src/Kconfig | 6 +- .../akidatag_nrf5340_cpuapp_2.overlay | 123 ++++++++++++++++++ src/boards/brainchip/akidatag/board.yml | 1 + .../interface/akd_spi_flash/akd_spi_flash.cpp | 53 +++++--- src/core/interface/camera/spi_camera.c | 14 +- src/core/interface/gpio/gpio.c | 22 +++- src/include/current_ic/current_ic.h | 6 +- .../boards/akidatag_nrf5340_cpuapp_2.overlay | 13 ++ 9 files changed, 222 insertions(+), 30 deletions(-) create mode 100644 src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_2.overlay create mode 100644 src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_2.overlay diff --git a/scripts/run.sh b/scripts/run.sh index b868dfe..0449fe4 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -29,6 +29,7 @@ Options: -r, --reset | (flag) | Do Board Reset -h, --help | (flag) | Show this help message --dk | (flag) | Select dk board pin configuration overlay file. + --rev | (str) | AkidaTag hardware revision to build for (default: 1). Not used with --dk. -t, --test-cli | (flag) | Run CLI-based hardware validation test (Python) -t --infer-test, --test-cli --infer-test | (flag) | Run CLI-based hardware validation test (Python) only for inference test of kws ################################################################################################### @@ -46,6 +47,9 @@ How to use script - Examples runs: # Build demo_apps with dk board overlay file inside Docker $SCRIPT_INVOCATION -d -b --dk --app demo_apps + # Build demo_apps for AkidaTag hardware revision 2 inside Docker + $SCRIPT_INVOCATION -d -b --rev 2 --app demo_apps + # Flash locally using west flash $SCRIPT_INVOCATION -f --app demo_apps @@ -131,6 +135,7 @@ GENERATE_CONFIG="" SEND_BLE=false CLI_TEST_CMD="" DK_OVERLAY=false +AKIDATAG_REV="" DO_INFER_TEST=false DOCKER=false @@ -233,6 +238,7 @@ while [[ $# -gt 0 ]]; do DK_OVERLAY=true shift ;; + --rev) AKIDATAG_REV="${2:-}"; shift 2;; -r|--reset) DO_RESET=true; shift;; -h|--help) print_help; exit 0;; -t|--test-cli) @@ -272,6 +278,11 @@ if ! $DO_SHELL && ! $DO_MINICOM && ! $DO_RESET && $_needs_app && [[ -z "$APP" ]] exit 1 fi +# Hardware revisions belong to the AkidaTag board; the DK has none +if $DK_OVERLAY && [[ -n "$AKIDATAG_REV" ]]; then + die "--rev selects an AkidaTag hardware revision and cannot be used with --dk" +fi + # --jlink only makes sense with --flash if $DO_JLINK_FLASH && ! $DO_FLASH; then die "--jlink_flash requires --flash" @@ -463,7 +474,8 @@ if [[ -n "$APP" ]]; then CMAKE_EXTRA_ARGS+=("-DEXTRA_CONF_FILE=boards/dk.conf") CMAKE_EXTRA_ARGS+=("-DDTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpuapp.overlay") else - BOARD_TARGET="akidatag/nrf5340/cpuapp" + # Without --rev, the board definition's default revision applies + BOARD_TARGET="akidatag${AKIDATAG_REV:+@$AKIDATAG_REV}/nrf5340/cpuapp" CMAKE_EXTRA_ARGS+=(-DCONFIG_AKIDATAG_BOARD=y) # A relative board root resolves against the application directory, so # this is src/, which holds boards/brainchip/akidatag/ diff --git a/src/Kconfig b/src/Kconfig index 6d6538f..1793a5c 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -134,13 +134,15 @@ config CURRENT_DEFAULT_RATE_HZ choice prompt "INA190 current-sense variant" + default INA190_VARIANT_A3 if BOARD_REVISION = "2" default INA190_VARIANT_A1 depends on AKIDATAG_BOARD help Fitted INA190 amplifier variant. The A1/A3 difference is gain only (A1 = 25 V/V, A3 = 100 V/V); the shunt resistors are board parts. The - variant cannot be auto-detected (analog part, no board ID), so the fitted - one must be selected here. Runtime-overridable via `power variant`. + variant cannot be auto-detected (analog part, no board ID), so the default + follows the board revision the build selects: A1 on revision 1, A3 on + revision 2. Runtime-overridable via `power variant`. config INA190_VARIANT_A1 bool "INA190A1RSW (gain 25 V/V)" diff --git a/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_2.overlay b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_2.overlay new file mode 100644 index 0000000..3898afb --- /dev/null +++ b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_2.overlay @@ -0,0 +1,123 @@ +/* + * AkidaTag hardware revision 2: the camera has SPIM2 to itself behind a level + * translator and a switched supply, both flashes are Winbond W25Q128JW, and the + * board has red, green, blue and white LEDs and a single user button. + */ + +&pinctrl { + spi2_default: spi2_default { + group1 { + psels = , + , + ; + }; + }; + + spi2_sleep: spi2_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +/ { + chosen { + nordic,pm-ext-flash = &ext_flash; + }; + + gpios { + /* Output enable of the camera SPI level translators, active low. */ + cam_enb: cam_enb { + gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + }; + + cam_pwr_enb: cam_pwr_enb { + gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + }; + }; + + custom_buttons { + compatible = "gpio-keys"; + + /* The board pulls this line up externally. */ + user_btn: user_btn { + gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + label = "User Button"; + }; + }; + + custom_leds { + compatible = "gpio-leds"; + + led_red: led_red { + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; + }; + + led_green: led_green { + gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>; + }; + + led_blue: led_blue { + gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + + led_white: led_white { + gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + }; + }; + + aliases { + cam-enb = &cam_enb; + user-button = &user_btn; + mcuboot-button0 = &user_btn; + mcuboot-led0 = &led_red; + }; +}; + +&spi4 { + akd_flash: w25q128jw@1 { + compatible = "jedec,spi-nor"; + reg = <1>; + spi-max-frequency = <8000000>; + size = ; + jedec-id = [ef 60 18]; + has-dpd; + t-enter-dpd = <3000>; + t-exit-dpd = <30000>; + }; +}; + +&spi3 { + cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; + + ext_flash: w25q128jw@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <8000000>; + size = ; + jedec-id = [ef 60 18]; + has-dpd; + t-enter-dpd = <3000>; + t-exit-dpd = <30000>; + }; +}; + +/* Camera. SPIM2 tops out at 8 MHz, the camera's existing clock. */ +&spi2 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi2_default>; + pinctrl-1 = <&spi2_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; + + camera: camera@0 { + compatible = "spi-device"; + reg = <0>; + spi-max-frequency = <8000000>; + label = "CAMERA"; + }; +}; diff --git a/src/boards/brainchip/akidatag/board.yml b/src/boards/brainchip/akidatag/board.yml index 756503d..e880636 100644 --- a/src/boards/brainchip/akidatag/board.yml +++ b/src/boards/brainchip/akidatag/board.yml @@ -10,3 +10,4 @@ board: exact: true revisions: - name: "1" + - name: "2" diff --git a/src/core/interface/akd_spi_flash/akd_spi_flash.cpp b/src/core/interface/akd_spi_flash/akd_spi_flash.cpp index 2663a75..1eade2f 100644 --- a/src/core/interface/akd_spi_flash/akd_spi_flash.cpp +++ b/src/core/interface/akd_spi_flash/akd_spi_flash.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,18 @@ LOG_MODULE_REGISTER(AKD_SPI_FLASH, LOG_LEVEL_DBG); #define CMD_CLEAR_FLAG_STATUS_REG (0x50) #define CMD_READ_FLAG_STATUS_REG (0x70) +#define JEDEC_MANUFACTURER_MICRON (0x20) + +#define AKD_FLASH_NODE DT_NODELABEL(akd_flash) + +/* Only Micron parts latch erase and program failures in a flag status register. + * Other vendors assign its opcodes to unrelated commands, so the checks are left + * out for them. A node that declares no JEDEC ID keeps the checks. */ +#define AKD_FLASH_HAS_FLAG_STATUS \ + COND_CODE_1(DT_NODE_HAS_PROP(AKD_FLASH_NODE, jedec_id), \ + (DT_PROP_BY_IDX(AKD_FLASH_NODE, jedec_id, 0) == JEDEC_MANUFACTURER_MICRON), \ + (true)) + #define CMD_READ_ID (0x9F) #define PAGE_SIZE 256 // Flash page size @@ -113,9 +126,9 @@ int spi_flash_probe(akida::ZephyrSpiDriver spi_flash_driver_) { * all-zero (AN-002: "A sleeping AKD1500 returns 0x00000000 on register * reads"), and a floating MISO reads all-ones. * - * Deliberately part-agnostic rather than pinned to one ID: the AkidaTag board - * carries an MT25QU128ABA behind the AKD1500 and the DK an W25Q128, and this - * has to pass on both. */ + * Deliberately part-agnostic rather than pinned to one ID: AkidaTag revision 1 + * carries an MT25QU128ABA behind the AKD1500, revision 2 and the DK a + * W25Q128, and this has to pass on all of them. */ if (id == 0x000000U || id == FLASH_JEDEC_ID_MASK) { LOG_ERR( "AKD_SPI_FLASH: flash not responding (JEDEC ID 0x%06X). The " @@ -148,7 +161,9 @@ int spi_flash_erase_api(akida::ZephyrSpiDriver spi_flash_driver_, uint32_t secto if (sector_size == 0) { return -EINVAL; } - spi_flash_clear_flag(spi_flash_driver_); + if (AKD_FLASH_HAS_FLAG_STATUS) { + spi_flash_clear_flag(spi_flash_driver_); + } int ret; for (uint32_t i = 0; i < no_of_sectors; i++) { @@ -184,13 +199,15 @@ int spi_flash_erase_api(akida::ZephyrSpiDriver spi_flash_driver_, uint32_t secto LOG_ERR("AKD_SPI_FLASH: Error in erase operation\n"); return ret; } - ret = spi_flash_read_flag_status(spi_flash_driver_); - if ((ret & 0x20) == 0x20) { - LOG_ERR( - "AKD_SPI_FLASH: read_flag_status error in erase operation, error " - "value %x\n", - ret); - return ret; + if (AKD_FLASH_HAS_FLAG_STATUS) { + ret = spi_flash_read_flag_status(spi_flash_driver_); + if ((ret & 0x20) == 0x20) { + LOG_ERR( + "AKD_SPI_FLASH: read_flag_status error in erase operation, error " + "value %x\n", + ret); + return ret; + } } } @@ -208,7 +225,9 @@ int spi_flash_erase(akida::ZephyrSpiDriver spi_flash_driver_, uint32_t address, int spi_flash_write(akida::ZephyrSpiDriver spi_flash_driver_, uint32_t address, const uint8_t* data, size_t length) { size_t offset = 0; - spi_flash_clear_flag(spi_flash_driver_); + if (AKD_FLASH_HAS_FLAG_STATUS) { + spi_flash_clear_flag(spi_flash_driver_); + } while (offset < length) { size_t page_offset = address % PAGE_SIZE; @@ -236,10 +255,12 @@ int spi_flash_write(akida::ZephyrSpiDriver spi_flash_driver_, uint32_t address, LOG_ERR("AKD_SPI_FLASH: Error in write operation"); return ret; } - ret = spi_flash_read_flag_status(spi_flash_driver_); - if ((ret & 0x10) == 0x10) { - LOG_ERR("AKD_SPI_FLASH: read_flag_status error in flash write operation"); - return ret; + if (AKD_FLASH_HAS_FLAG_STATUS) { + ret = spi_flash_read_flag_status(spi_flash_driver_); + if ((ret & 0x10) == 0x10) { + LOG_ERR("AKD_SPI_FLASH: read_flag_status error in flash write operation"); + return ret; + } } address += chunk; offset += chunk; diff --git a/src/core/interface/camera/spi_camera.c b/src/core/interface/camera/spi_camera.c index c2ad0f8..f73c620 100644 --- a/src/core/interface/camera/spi_camera.c +++ b/src/core/interface/camera/spi_camera.c @@ -66,9 +66,9 @@ static __noinit uint8_t camera_frame_buffer[MAX_RGB888_SIZE]; /* ==================== SPI Device & Configuration ==================== */ -/* SPI device used to communicate with the camera */ +/* SPI bus the camera sits on, which depends on the board */ -const struct device* spi3_dev = DEVICE_DT_GET(DT_NODELABEL(spi3)); +const struct device* camera_spi_dev = DEVICE_DT_GET(DT_BUS(DT_NODELABEL(camera))); /* SPI configuration for the camera */ @@ -95,7 +95,7 @@ static void camera_write_reg(uint8_t addr, uint8_t val) { uint8_t tx[2] = {addr | 0x80, val}; struct spi_buf buf = {.buf = tx, .len = 2}; struct spi_buf_set set = {.buffers = &buf, .count = 1}; - spi_write(spi3_dev, &spi_cfg_camera, &set); + spi_write(camera_spi_dev, &spi_cfg_camera, &set); } /** @@ -112,7 +112,7 @@ static uint8_t camera_read_reg(uint8_t addr) { struct spi_buf rxb = {.buf = rx, .len = 3}; struct spi_buf_set txs = {.buffers = &txb, .count = 1}; struct spi_buf_set rxs = {.buffers = &rxb, .count = 1}; - spi_transceive(spi3_dev, &spi_cfg_camera, &txs, &rxs); + spi_transceive(camera_spi_dev, &spi_cfg_camera, &txs, &rxs); return rx[2]; } @@ -162,7 +162,7 @@ static void fifo_read(uint8_t* buf, uint32_t len) { {.buf = NULL, .len = 1}, {.buf = NULL, .len = 1}, {.buf = buf, .len = len}}; struct spi_buf_set tx = {.buffers = txb, .count = 3}; struct spi_buf_set rx = {.buffers = rxb, .count = 3}; - spi_transceive(spi3_dev, &spi_cfg_camera, &tx, &rx); + spi_transceive(camera_spi_dev, &spi_cfg_camera, &tx, &rx); } /* ==================== Camera Initialization & Capture ==================== */ @@ -178,7 +178,7 @@ static void fifo_read(uint8_t* buf, uint32_t len) { */ int camera_init(void) { - if (!device_is_ready(spi3_dev)) { + if (!device_is_ready(camera_spi_dev)) { LOG_ERR("ERROR: SPI not ready"); return -ENODEV; } @@ -378,7 +378,7 @@ static void send_base64_rgb888(const uint8_t* buf, uint32_t len) { */ int camera_start(void) { - if (spi3_dev == NULL) { + if (camera_spi_dev == NULL) { return -ENODEV; } diff --git a/src/core/interface/gpio/gpio.c b/src/core/interface/gpio/gpio.c index b74938e..edffa58 100644 --- a/src/core/interface/gpio/gpio.c +++ b/src/core/interface/gpio/gpio.c @@ -17,6 +17,7 @@ K_SEM_DEFINE(akd_async_sem, 0, 1); #define PDM_ENB_NODE DT_NODELABEL(pdm_enb) #define AKD_0V_ENB_NODE DT_NODELABEL(akd_0v_enb) #define CAM_ENB_NODE DT_NODELABEL(cam_enb) +#define CAM_PWR_ENB_NODE DT_NODELABEL(cam_pwr_enb) #define AKD_ASYNC_ENB_NODE DT_NODELABEL(akd_async) #define AKD_LP_NODE DT_NODELABEL(akd_lp) @@ -30,6 +31,10 @@ static const struct gpio_dt_spec enable_akd_0V = GPIO_DT_SPEC_GET(AKD_0V_ENB_NOD static const struct gpio_dt_spec enable_camera = GPIO_DT_SPEC_GET(CAM_ENB_NODE, gpios); +/* Camera supply switch; its port is NULL on boards that do not switch the supply. */ +static const struct gpio_dt_spec enable_camera_power = + GPIO_DT_SPEC_GET_OR(CAM_PWR_ENB_NODE, gpios, {0}); + static const struct gpio_dt_spec enable_akd_async = GPIO_DT_SPEC_GET(AKD_ASYNC_ENB_NODE, gpios); /* AKD1500 SLEEP pin (active-high): 1 = low-power (clocks gated, model retained) */ @@ -240,6 +245,10 @@ int gpio_init(void) { LOG_ERR("Camera enable GPIO not ready"); return -ENODEV; } + if (enable_camera_power.port != NULL && !gpio_is_ready_dt(&enable_camera_power)) { + LOG_ERR("Camera power enable GPIO not ready"); + return -ENODEV; + } if (!gpio_is_ready_dt(&enable_akd_async)) { LOG_ERR("AKD ASYNC enable GPIO not ready"); return -ENODEV; @@ -278,6 +287,13 @@ int gpio_init(void) { LOG_ERR("Failed to configure camera enable pin (err %d)", err); return err; } + if (enable_camera_power.port != NULL) { + err = gpio_pin_configure_dt(&enable_camera_power, GPIO_OUTPUT_INACTIVE); + if (err) { + LOG_ERR("Failed to configure camera power enable pin (err %d)", err); + return err; + } + } err = gpio_pin_configure_dt(&enable_akd_async, GPIO_INPUT); if (err) { LOG_ERR("Failed to configure AKD ASYNC enable pin (err %d)", err); @@ -353,12 +369,16 @@ void akd_irq_disable(void) { * 2. Enable AKD1500 device * 3. Enable accelerometer * 4. Enable PDM microphone - * 5. Enable camera module + * 5. Enable the camera supply, on boards that switch it + * 6. Enable camera module */ void akidatag_peripherals_power_enable(void) { gpio_pin_set_dt(&enable_akd_0V, GPIO_ENABLE); gpio_pin_set_dt(&enable_akd, GPIO_ENABLE); gpio_pin_set_dt(&enable_acc, GPIO_ENABLE); gpio_pin_set_dt(&enable_pdm, GPIO_ENABLE); + if (enable_camera_power.port != NULL) { + gpio_pin_set_dt(&enable_camera_power, GPIO_ENABLE); + } gpio_pin_set_dt(&enable_camera, GPIO_ENABLE); } \ No newline at end of file diff --git a/src/include/current_ic/current_ic.h b/src/include/current_ic/current_ic.h index be48347..9d2b101 100644 --- a/src/include/current_ic/current_ic.h +++ b/src/include/current_ic/current_ic.h @@ -21,7 +21,7 @@ /* U25 senses VDD_1V8 (shunt R117), U26 senses VDD_0V8_AKD (shunt R118). */ /* Vout(mV) = I(mA) * Rshunt(ohm) * gain => I(mA) = Vout(mV) / (Rshunt*gain)*/ /* The A1/A3 difference is amplifier gain only; the shunts are board parts */ -/* (same on the A1 board — re-verify against the A3 board BOM). */ +/* of the same values on both revisions (revision 2: U18/R55, U17/R28). */ /* ------------------------------------------------------------------------- */ #define SHUNT_OHMS_1V8 0.1f /* R117 */ #define SHUNT_OHMS_0V8 0.02f /* R118 */ @@ -66,8 +66,8 @@ typedef enum { * part, no board ID), so it is selected: boot default CONFIG_INA190_VARIANT, * overridable at runtime. */ typedef enum { - INA190_A1 = 0, /* gain 25 V/V (current AkidaTag board) */ - INA190_A3 = 1, /* gain 100 V/V */ + INA190_A1 = 0, /* gain 25 V/V (AkidaTag revision 1) */ + INA190_A3 = 1, /* gain 100 V/V (AkidaTag revision 2) */ } ina190_variant_t; /* Latest per-rail current/power snapshot maintained by the sampler. */ diff --git a/src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_2.overlay b/src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_2.overlay new file mode 100644 index 0000000..bd010fd --- /dev/null +++ b/src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_2.overlay @@ -0,0 +1,13 @@ +/* MCUboot on revision 2 needs only flash IC1, so the camera and AKD1500 buses stay off. */ + +&spi2 { + status = "disabled"; +}; + +&akd_flash { + status = "disabled"; +}; + +&spi4 { + status = "disabled"; +}; From 7c7e1ed056095c5d666d405992e85aaf36e0a80f Mon Sep 17 00:00:00 2001 From: Nikunj Kotecha Date: Sun, 27 Sep 2026 09:45:25 -0700 Subject: [PATCH 4/6] docs(build): document building for AkidaTag hardware revision 2 Describe --rev 2 wherever the build options are documented, and replace the statements that both boards build as the nRF5340 DK with the board definition and its revisions. --- AGENTS.md | 45 +++++++++++++++++++++++++++-------------- README.md | 2 +- docs/developer-guide.md | 15 +++++++++----- src/README.md | 16 +++++++++++---- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2d8c362..129e808 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,27 +25,41 @@ The selectable application is `demo_apps`, with its entry point at [src/apps/demo_apps/main.cpp](src/apps/demo_apps/main.cpp). It combines the existing demonstrations and shared firmware services. -Build for the AkidaTag board: +Build for the AkidaTag board, hardware revision 1: ```sh ./scripts/run.sh -d -b --app demo_apps ``` +Build for AkidaTag hardware revision 2 into a separate directory: + +```sh +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -d -b --rev 2 --app demo_apps +``` + Build for the nRF5340 DK into a separate directory: ```sh BUILD_DIR=build_docker_dk ./scripts/run.sh -d -b --dk --app demo_apps ``` -The outputs are `build_docker/demo_apps/` and `build_docker_dk/demo_apps/`, -respectively. Without a `BUILD_DIR` override, both commands use the same output -directory. Each build starts with a pristine configuration. - -Both boards use Zephyr's `nrf5340dk/nrf5340/cpuapp` target. `--dk` selects the DK -application and MCUboot overlays, `CONFIG_AKIDATAG_BOARD=n` and -[src/boards/dk.conf](src/boards/dk.conf). Keep board-specific settings with the -appropriate overlay or configuration fragment; the Zephyr target name alone -does not distinguish the two boards. +The outputs are `build_docker/demo_apps/`, `build_docker_rev2/demo_apps/` and +`build_docker_dk/demo_apps/`, respectively. Without a `BUILD_DIR` override, all +three commands use the same output directory. Each build starts with a pristine +configuration. + +The AkidaTag board is a Zephyr board definition in +[src/boards/brainchip/akidatag/](src/boards/brainchip/akidatag/), and its hardware +revisions are Zephyr board revisions. `run.sh` builds it as +`akidatag/nrf5340/cpuapp`, or `akidatag@2/nrf5340/cpuapp` with `--rev 2`, and +passes `src` as the board root; revision 1 is the default in its `board.yml`. +Settings shared by both revisions live in `akidatag_nrf5340_cpuapp.dts`, and each +revision's differences in `akidatag_nrf5340_cpuapp_.overlay`. MCUboot's +own adjustments follow the same naming in `src/sysbuild/mcuboot/boards/`. Kconfig +defaults that depend on the revision, such as the INA190 variant, test +`BOARD_REVISION` in `src/Kconfig`. `--dk` builds Zephyr's `nrf5340dk/nrf5340/cpuapp` +target with the DK application overlay, `CONFIG_AKIDATAG_BOARD=n` and +[src/boards/dk.conf](src/boards/dk.conf). Ordinary builds use the RSA-3072 development key committed at `.env/development_key.pem`. It is intentionally public so a fresh clone can @@ -75,7 +89,8 @@ and make `JLinkExe` available on `PATH`, then flash the container-built output: BUILD_DIR=build_docker ./scripts/run.sh -f -jf --app demo_apps ``` -For the DK build, use `BUILD_DIR=build_docker_dk` and add `--dk`. The script loads +For a revision 2 build, use `BUILD_DIR=build_docker_rev2`; for the DK build, use +`BUILD_DIR=build_docker_dk` and add `--dk`. The script loads `merged_CPUNET.hex` on the network core first and `merged.hex` on the application core second. These files include the bootloader needed for initial programming. Do not substitute an application-only image for the initial full flash. @@ -136,10 +151,10 @@ named `my_demo`, update the following pieces together: still apply the old app's configuration. 4. Add `my_demo` to the app-selection case in `scripts/run.sh`, use `src` as `APP_SRC_DIR`, and pass `-DCONFIG_MY_DEMO=y` instead of `CONFIG_DEMO_APPS`. - Carry over the board-selection arguments for each supported board. Add the - corresponding entry to `get_jlink_jobs` for J-Link flashing and update the - help text and available-app error. The build directory is already derived - from the app name. + Carry over the board target and board-selection arguments for each supported + board. Add the corresponding entry to `get_jlink_jobs` for J-Link flashing + and update the help text and available-app error. The build directory is + already derived from the app name. 5. If the demo needs different model metadata, add the matching profile to `APP_PROFILES` in `src/utils/generate_info.py` and document its configuration fields. The existing model profile is `demo_apps`; a new firmware app name diff --git a/README.md b/README.md index a5e6241..36f39dc 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ git clone https://github.com/Brainchip-Inc/AkidaTag.git && cd AkidaTag # put SEGGER's J-Link V8.88 .deb in docker/tools/ first (docker/tools/README.md), accepting SEGGER's terms ./scripts/build_docker_image.sh --ncs v3.1.1 --python 3.12 # once; downloads the SDK -./scripts/run.sh -d -b --app demo_apps # build for the AkidaTag board (add --dk for the nRF5340 DK) +./scripts/run.sh -d -b --app demo_apps # build for the AkidaTag board (add --rev 2 for hardware revision 2) ./scripts/run.sh -d -f --app demo_apps # flash MCUboot and the application over the debug probe ./scripts/run.sh -d -t # drive the shell over UART and check the AKD1500 link ``` diff --git a/docs/developer-guide.md b/docs/developer-guide.md index 0737627..1cd8a8a 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -22,7 +22,7 @@ If you only want to run the demos from your phone, read the [user guide](user-gu . ├── src/ The firmware. Source directory of the demo_apps application. │ ├── apps/demo_apps/ main.cpp, the app's Kconfig fragment and its sample inputs -│ ├── boards/ Devicetree overlays and dk.conf for the AkidaTag board and the nRF5340 DK +│ ├── boards/ The AkidaTag board definition, with one devicetree overlay per hardware revision │ ├── core/ SPI to the AKD1500, its flash, BLE services, audio, LEDs, battery, boot manager │ ├── deps/ Imported code: the Akida engine, FlatBuffers headers, kissfft (see deps/VENDORING.md) │ ├── include/ Headers @@ -41,10 +41,11 @@ If you only want to run the demos from your phone, read the [user guide](user-gu └── CONTRIBUTING.md Commit and pull request rules, enforced in CI ``` -Both boards build for the same Zephyr board target, `nrf5340dk/nrf5340/cpuapp`. What separates -an AkidaTag build from a DK build is the set of CMake arguments `scripts/run.sh` passes when you -give it `--dk`: the devicetree overlay, the MCUboot overlay, `CONFIG_AKIDATAG_BOARD`, and -`boards/dk.conf`. The two overlays under `src/boards/` list every pin on both boards. +The AkidaTag board is a Zephyr board definition, `src/boards/brainchip/akidatag/`, and its +hardware revisions are Zephyr board revisions: `akidatag_nrf5340_cpuapp.dts` holds what both +revisions share and `akidatag_nrf5340_cpuapp_1.overlay` and `akidatag_nrf5340_cpuapp_2.overlay` +what each revision changes. Together they list every pin. `scripts/run.sh` builds revision 1 +unless you give it `--rev 2`. ## 2. Set up the environment @@ -74,12 +75,15 @@ On macOS, Docker Desktop has no USB passthrough, so build inside Docker and flas ```sh ./scripts/run.sh -d -b --app demo_apps # AkidaTag board +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -d -b --rev 2 --app demo_apps # AkidaTag board, hardware revision 2 BUILD_DIR=build_docker_dk ./scripts/run.sh -d -b --dk --app demo_apps # nRF5340 DK ``` A Docker build lands in `build_docker/demo_apps/`; a host build in `build/demo_apps/`. `--dk` changes the configuration, not the directory, so the two boards overwrite each other's build unless you set `BUILD_DIR`, which is why the DK command above builds into `build_docker_dk/`. +The same holds for `--rev 2`, which builds for hardware revision 2 of the AkidaTag board; without +it, the build is for revision 1. `./scripts/run.sh -d -i` opens a shell inside the image. | Output | What it is | @@ -105,6 +109,7 @@ bootloader included. It does not touch the AKD1500's flash, so a model on the bo ./scripts/run.sh -d -f --app demo_apps # Linux, west flash inside Docker ./scripts/run.sh -f -jf --app demo_apps # host J-Link, network core then application core BUILD_DIR=build_docker ./scripts/run.sh -f -jf --app demo_apps # macOS: flash the Docker build from the host +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -f -jf --app demo_apps # the revision 2 build, from its own directory BUILD_DIR=build_docker_dk ./scripts/run.sh -d -f -jf --dk --app demo_apps # the DK build, from its own directory ./scripts/run.sh -d -r # reset the board ``` diff --git a/src/README.md b/src/README.md index 4ccf693..866e51e 100644 --- a/src/README.md +++ b/src/README.md @@ -584,13 +584,19 @@ MOBILE APP BLE STACK FIRMWARE │ [CMD=3] Select Next Class │ │ │ │ │ -### Build the demo_apps Sample with AkidaTag board overlay file. +### Build the demo_apps Sample for the AkidaTag board. After compiling the project, MCUBoot is automatically built along with the application. The sysbuild system generates a combined image that includes both MCUBoot and the demo_apps application. ``` ./scripts/run.sh -d -b --app demo_apps ``` + +This builds for hardware revision 1. For hardware revision 2, add `--rev 2`: + +``` +./scripts/run.sh -d -b --rev 2 --app demo_apps +``` ### Build the demo_apps Sample with dk board overlay file. After compiling the project, MCUBoot is automatically built along with the application. The sysbuild system generates a combined image that includes both MCUBoot and the demo_apps application. @@ -657,11 +663,13 @@ Both the **application overlay** and the **MCUboot overlay** are selected during ### DK Board - **Application overlay:** `boards/nrf5340dk_nrf5340_cpuapp.overlay` -- **MCUboot overlay:** `sysbuild/mcuboot_dk.overlay` +- **MCUboot overlay:** `sysbuild/mcuboot/boards/nrf5340dk_nrf5340_cpuapp.overlay` ### AkidaTag Board -- **Application overlay:** `boards/nrf5340_cpuapp_akidatag.overlay` -- **MCUboot overlay:** `sysbuild/mcuboot_akidatag.overlay` +- **Board definition:** `boards/brainchip/akidatag/`, with `akidatag_nrf5340_cpuapp.dts` for what + both hardware revisions share and `akidatag_nrf5340_cpuapp_.overlay` for each revision +- **MCUboot overlays:** `sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_.overlay` +- **Revision:** 1 by default, 2 with `--rev 2` ### Model Generation and BLE Transfer From 95066576e57eb3bdd4d0225ce675a969f7095bb1 Mon Sep 17 00:00:00 2001 From: Nikunj Kotecha Date: Sun, 27 Sep 2026 09:45:25 -0700 Subject: [PATCH 5/6] docs(hardware): describe the revision 2 firmware build The datasheet described the firmware on main as not matching revision 2. Its pin table, flash, camera, power and current-sense notes now describe a revision 2 build and how to make one, and list where the default revision 1 build differs. The fuel gauge note states that both revisions share the same current-sign handling, which is checked on the first revision 2 board. Source references point at the board definition that replaces the removed overlays. --- docs/hardware/block-diagram.md | 2 +- docs/hardware/datasheet.md | 83 ++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/docs/hardware/block-diagram.md b/docs/hardware/block-diagram.md index 626d179..c133f89 100644 --- a/docs/hardware/block-diagram.md +++ b/docs/hardware/block-diagram.md @@ -267,7 +267,7 @@ The revision 2 schematic (SI-NRF-AKD_BRD-002 V11, 2026-08-25), netlist report, b materials and board outline; the earlier system block diagram and labelled layout drawing (January 2026); the Texas Instruments INA190 datasheet (SBOS863D) and BQ27427 datasheet (SLUSEB5B); BrainChip AKD1500 documentation for the strap meanings; and the -firmware board overlay `src/boards/nrf5340_cpuapp_akidatag.overlay`, +firmware board definition `src/boards/brainchip/akidatag/`, `src/core/interface/gpio/gpio.c`, `src/core/interface/akd_spi_flash/akd_spi_flash_handler.cpp` and `src/README.md` on `main`. diff --git a/docs/hardware/datasheet.md b/docs/hardware/datasheet.md index e3df473..d2ef142 100644 --- a/docs/hardware/datasheet.md +++ b/docs/hardware/datasheet.md @@ -145,8 +145,9 @@ channel. Source: `src/pm_static.yml`. The firmware's partition map uses the first 8 MB of IC1. Source: `src/pm_static.yml`. Both positions are fitted with the Winbond W25Q128JWPIQ (1.8 V, 128 Mbit) listed in the -Rev2 bill of materials. The firmware on `main` still identifies the devices by the JEDEC ID -of the Micron part named in the schematic symbols, so it does not match the fitted part. +Rev2 bill of materials. A revision 2 build identifies both devices by the Winbond JEDEC ID; +see section 4 for how to build it. The default build is for revision 1 and expects the +Micron part named in the schematic symbols. ### 3.4 Audio: microphones @@ -186,8 +187,7 @@ output; a 1.8 V option exists through unpopulated resistors. The firmware drives an ArduCam Mega camera and supports 96 x 96 and 128 x 128 RGB frames. Source: `src/README.md`, `src/include/camera/spi_camera.h`. -See section 5.3 for the pinout and section 4 for a difference between the header's wiring -and the pins the current firmware uses. +See section 5.3 for the pinout and section 4 for the pins a revision 2 build uses. ### 3.7 Wireless @@ -268,7 +268,8 @@ safety timer. Source: BQ25185 datasheet SLUSF65B, electrical characteristics and Rev2 bill of materials for R84 and R85. The firmware's power-up order is: 0.8 V AKD1500 core, then the AKD1500 1.8 V rail, then -the IMU, then the microphones, then the camera enable. Source: +the IMU, then the microphones, then, in a revision 2 build, the camera supply, then the +camera enable. Source: `akidatag_peripherals_power_enable()` in `src/core/interface/gpio/gpio.c`. No battery is supplied with the board. The firmware programs the fuel gauge for an @@ -277,20 +278,27 @@ source notes that these values are for a test battery, so the state of charge it only as good as the match between those parameters and the cell fitted. Revision 2 connects the battery to the gauge's BAT pin and the charger to its SRX pin, which is the orientation the BQ27427 datasheet specifies for its integrated sense resistor. The firmware -on `main` still inverts the sign of the gauge's current reading to correct for a sense -resistor that its code describes as physically reversed, a correction that inverts the sign -on this orientation. Source: Rev2 netlist; BQ27427 datasheet SLUSEB5B, pin functions; +applies the same current-sign handling on both board revisions: it inverts the sign of the +gauge's current reading to correct for a sense resistor that its code describes as +physically reversed. The resulting sign is checked on the first revision 2 board. Source: +Rev2 netlist; BQ27427 datasheet SLUSEB5B, pin functions; `src/include/fuel_gauge/fuel_gauge.h`, `src/core/interface/fuel_gauge/fuel_gauge.c`. --- ## 4. Pin assignment -The table lists every nRF5340 GPIO as wired on hardware revision 2, and how the firmware on -`main` uses it. Rows marked **differs** are places where the firmware's board definition -still describes the previous board revision; they are listed together after the table. +The table lists every nRF5340 GPIO as wired on hardware revision 2, and how the firmware +uses it when built for revision 2: -| nRF5340 pin | Rev2 signal | Connected to | Firmware use on `main` | +```sh +./scripts/run.sh -d -b --rev 2 --app demo_apps +``` + +The default build, without `--rev 2`, is for revision 1. Where the two revisions differ is +listed after the table. + +| nRF5340 pin | Rev2 signal | Connected to | Firmware use (revision 2 build) | |---|---|---|---| | P0.00 / XL1 | XL1 | 32.768 kHz crystal Y1 | Low-frequency crystal | | P0.01 / XL2 | XL2 | 32.768 kHz crystal Y1 | Low-frequency crystal | @@ -298,8 +306,8 @@ still describes the previous board revision; they are listed together after the | P0.03 / NFC2 | AKD_GPIO3 | AKD1500 GPIO_03 | `akd_async` input, inference-complete interrupt | | P0.04 / AIN0 | I1V8_AIN0 | INA190 U18 output (1.8 V rail current), TP7 | SAADC channel 0 | | P0.05 / AIN1 | I0V8_AIN1 | INA190 U17 output (0.8 V rail current), TP6 | SAADC channel 1 | -| P0.06 / AIN2 | CAM_SPI_CLK | Level shifter U15 to J1 pin 3 | Not used, **differs** (camera SCK expected on P0.17) | -| P0.07 / AIN3 | CAM_SPI_MOSI | Level shifter U15 to J1 pin 5 | Not used, **differs** (camera MOSI expected on P0.13) | +| P0.06 / AIN2 | CAM_SPI_CLK | Level shifter U15 to J1 pin 3 | SPIM2 SCK, camera | +| P0.07 / AIN3 | CAM_SPI_MOSI | Level shifter U15 to J1 pin 5 | SPIM2 MOSI, camera | | P0.08 | HSPI_SCK | AKD1500 SPI_S_SCK, TP5 | SPIM4 SCK, high drive | | P0.09 | HSPI_MOSI | AKD1500 SPI_S_IO0 | SPIM4 MOSI | | P0.10 | HSPI_MISO | AKD1500 SPI_S_IO1 | SPIM4 MISO | @@ -310,50 +318,48 @@ still describes the previous board revision; they are listed together after the | P0.15 | QSPI_IO2 | Flash IC1 W#/DQ2, pull-up | Not used | | P0.16 | QSPI_IO3 | Flash IC1 HOLD#/DQ3, pull-up | Not used | | P0.17 | QSPI_CLK | Flash IC1 C, TP4 | SPIM3 SCK | -| P0.18 | QSPI_CS_0 | Flash IC1 S#, pull-up | SPIM3 chip select 1 (application), chip select 0 (MCUboot) | +| P0.18 | QSPI_CS_0 | Flash IC1 S#, pull-up | SPIM3 chip select 0, application and MCUboot | | P0.19 | VDD_1V8_AKD_EN | Load switch U10 ON, 100 kilohm pull-down | `akd_enb` output | | P0.20 | VDD_1V8_ACC_EN | Load switch U4 ON, pull-down | `acc_enb` output | | P0.21 | VDD_1V8_PDM_EN | Load switch U8 ON, pull-down | `pdm_enb` output | | P0.22 | VDD_0V8_AKD_EN | Load switch U9 ON, then TLV62585 EN | `akd_0v_enb` output | | P0.23 | CHGR_STS1 | BQ25185 STAT1, 10 kilohm pull-up | `chgr_sts1` input | | P0.24 | CHGR_STS2 | BQ25185 STAT2, pull-up | `chgr_sts2` input | -| P0.25 / AIN4 | CAM_SPI_CS | Level shifter U14 to J1 pin 6, 10 kilohm pull-up | SPIM3 chip select 0, camera | -| P0.26 / AIN5 | CAM_SPI_MISO | Level shifter U14 from J1 pin 4 | `user_btn` input, **differs** (no button on this pin) | +| P0.25 / AIN4 | CAM_SPI_CS | Level shifter U14 to J1 pin 6, 10 kilohm pull-up | SPIM2 chip select 0, camera | +| P0.26 / AIN5 | CAM_SPI_MISO | Level shifter U14 from J1 pin 4 | SPIM2 MISO, camera | | P0.27 / AIN6 | LED_G | Q3, RGB LED green | `led_green` output | -| P0.28 / AIN7 | LED_W_1 | Q4, white LED | `led_red` output, **differs** (drives the white LED); MCUboot DFU LED | +| P0.28 / AIN7 | LED_W_1 | Q4, white LED | `led_white`, not driven | | P0.29 | DBG_TXD | CP2105 RXD_SCI, TP11 | UART0 TX | | P0.30 | INT_FL_GAUG | BQ27427 GPOUT, pull-up | `fg_int` input | | P0.31 | ACC_INT1 | ISM330DHCX INT1 | `imui` input | | P1.00 | ACC_INT2 | ISM330DHCX INT2 | Not used | -| P1.01 | USER_IO | Push button SW1, 10 kilohm pull-up | MCUboot DFU button only, **differs** (the application's button is defined on P0.26) | +| P1.01 | USER_IO | Push button SW1, 10 kilohm pull-up | `user_btn` input; MCUboot DFU button | | P1.02 | ACC_FG_SDA | ISM330DHCX SDA, BQ27427 SDA, 2.2 kilohm pull-up | I2C1 SDA | | P1.03 | ACC_FG_SCL | ISM330DHCX SCL, BQ27427 SCL, 2.2 kilohm pull-up | I2C1 SCL | | P1.04 | DBG_RXD | CP2105 TXD_SCI, TP13 | UART0 RX | | P1.05 | AKD_PGOOD | AKD1500 PWR_GOOD through R47, 10 kilohm pull-up to VDD_1V8_AKD, TP1 | Not used | -| P1.06 | CAM_PWR_EN | Load switch U2 ON (camera 3.3 V), 100 kilohm pull-down | Not used, **differs** (camera header power is never enabled) | +| P1.06 | CAM_PWR_EN | Load switch U2 ON (camera 3.3 V), 100 kilohm pull-down | `cam_pwr_enb` output, camera supply | | P1.07 | AKD_LP | AKD1500 SLEEP through R48 | `akd_lp` output, sleep control | | P1.08 | not connected | | Not used on this board | | P1.09 | PDM_PCLK | Microphones U19 and U20 CLOCK | PDM clock | | P1.10 | PDM_PDAT | Microphones U19 and U20 DATA, 100 ohm each | PDM data | | P1.11 | AKD_GPIO0 | AKD1500 GPIO_00 | Not used | | P1.12 | AKD_GPIO1 | AKD1500 GPIO_01 | Not used | -| P1.13 | LED_B | Q1, RGB LED blue | `akdreset` node, unused by code, **differs** | -| P1.14 | LED_R | Q2, RGB LED red | Not used, **differs** (the firmware's red indication is on P0.28) | -| P1.15 | CAM_SPI_EN | Level shifters U14 and U15 output enable, pull-down | `cam_enb` output | +| P1.13 | LED_B | Q1, RGB LED blue | `led_blue`, not driven | +| P1.14 | LED_R | Q2, RGB LED red | `led_red` output; MCUboot DFU LED | +| P1.15 | CAM_SPI_EN | Level shifters U14 and U15 output enable, pull-down | `cam_enb` output, active low | Dedicated pins: SWDIO and SWDCLK to J2; RESET to J2 pin 6; ANT to the antenna matching network; D+, D- and VBUS not connected. Source: Rev2 netlist joined with the nRF5340 ball -map; firmware `src/boards/nrf5340_cpuapp_akidatag.overlay` and -`src/sysbuild/mcuboot_akidatag.overlay`. - -**Differences between the revision 2 wiring and the firmware on `main`.** The firmware's -board definition predates this revision in five places: the camera SPI lines (it shares the -flash bus on P0.17, P0.13 and P0.14, where revision 2 wires the camera to P0.06, P0.07 and -P0.26), the camera supply enable on P1.06 (never driven), the push button (defined on -P0.26, wired on P1.01), the LEDs (the firmware's red LED is the white LED on P0.28; the RGB -red and blue on P1.14 and P1.13 are not driven), and the `akdreset` node on P1.13, which is -the blue LED. The pin table is the hardware; the firmware column describes `main` as it is -today. +map; firmware board definition `src/boards/brainchip/akidatag/` and the MCUboot overlays in +`src/sysbuild/mcuboot/boards/`. + +**Differences between revision 2 and the default build.** The default build is for +revision 1. Compared with a revision 2 build, it puts the camera on the flash bus (P0.17, +P0.13 and P0.14), does not drive the camera supply enable on P1.06, drives P1.15 active +high, reads the push button on P0.26, drives the red LED on P0.28 and the green LED on P0.27 +only, defines an `akdreset` node on P1.13, expects Micron flash parts (section 3.3) and +defaults to the 25 V/V INA190 (section 6.2). --- @@ -441,8 +447,9 @@ fast-charge setting is in section 3.11. The firmware measures the 1.8 V and 0.8 V rails itself through the INA190 amplifiers (`power read`, `power measure`): the shunts are 0.1 ohm on the 1.8 V rail and 0.02 ohm on -the 0.8 V rail, and revision 2 fits the 100 V/V amplifier, so run `power variant a3` first -because the firmware's build-time default is the 25 V/V A1 part. The total draw, which +the 0.8 V rail, and revision 2 fits the 100 V/V amplifier, which a revision 2 build +selects by default. The default build selects revision 1's 25 V/V A1 part, so on that build +run `power variant a3` first. The total draw, which also covers the charger, the LEDs and the 3.3 V rail, needs a meter in series with the battery or the USB input. Source: Rev2 bill of materials, `src/README.md`. @@ -551,8 +558,8 @@ first board shipped. Source: the revision summary on the Rev2 schematic cover sh - Revision 2 design files: schematic SI-NRF-AKD_BRD-002 V11 (2026-08-25), bill of materials NRF-AKD1500-002 V11, netlist report (2026-08-24), placement file, board outline DXF and fabrication artwork set. -- Firmware on `main` of this repository: `src/boards/nrf5340_cpuapp_akidatag.overlay`, - `src/sysbuild/mcuboot_akidatag.overlay`, `src/sysbuild/mcuboot.conf`, `src/prj.conf`, +- Firmware on `main` of this repository: `src/boards/brainchip/akidatag/`, + `src/sysbuild/mcuboot/boards/`, `src/sysbuild/mcuboot.conf`, `src/prj.conf`, `src/Kconfig`, `src/pm_static.yml`, `src/apps/demo_apps/custom_app.conf`, `src/imu_app.conf`, `src/README.md`, `src/core/interface/gpio/gpio.c`, `src/core/interface/audio/pdm_mic.c`, `src/core/interface/ble_services/`, From 214778ab390eff8f64bc926af8dd9b990608a5ac Mon Sep 17 00:00:00 2001 From: Nikunj Kotecha Date: Sun, 27 Sep 2026 10:27:15 -0700 Subject: [PATCH 6/6] docs(setup): add the revision 2 build and flash commands --- docs/setup.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/setup.md b/docs/setup.md index de22ade..de3a509 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -41,28 +41,33 @@ container. ## 3. Build and flash the firmware -Build the application in Docker: +Build the application in Docker. The first command builds for hardware revision 1, the default; +the second builds for hardware revision 2 into its own directory: ```sh ./scripts/run.sh -d -b --app demo_apps +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -d -b --rev 2 --app demo_apps ``` Every build starts with a pristine configuration and writes its output to -`build_docker/demo_apps/`. It signs the images with the public development key committed at -`.env/development_key.pem`. See +`build_docker/demo_apps/`, or under the `BUILD_DIR` it is given. It signs the images with the +public development key committed at `.env/development_key.pem`. See [Application Security](../src/README.md#application-security) for how the key is used and how to replace it. -On Linux, flash through the J-Link from inside the container: +Flash the build that matches the board's revision. On Linux, flash through the J-Link from inside +the container: ```sh -./scripts/run.sh -d -f -jf --app demo_apps +./scripts/run.sh -d -f -jf --app demo_apps # revision 1 +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -d -f -jf --app demo_apps # revision 2 ``` On macOS, flash the container-built output with the host J-Link tools: ```sh -BUILD_DIR=build_docker ./scripts/run.sh -f -jf --app demo_apps +BUILD_DIR=build_docker ./scripts/run.sh -f -jf --app demo_apps # revision 1 +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -f -jf --app demo_apps # revision 2 ``` The script loads `merged_CPUNET.hex` on the network core first and `merged.hex` on the application