diff --git a/AGENTS.md b/AGENTS.md index 2d8c362d..129e8084 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/NOTICE b/NOTICE index 0f5e719f..7a1e9383 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/README.md b/README.md index a5e62416..36f39dc7 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 567f2bc7..0e49790c 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -21,7 +21,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 board-specific configuration +│ ├── 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 @@ -40,9 +40,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 ``` -The AkidaTag build uses the Zephyr board target `nrf5340dk/nrf5340/cpuapp` with the board's -devicetree and MCUboot overlays and `CONFIG_AKIDATAG_BOARD=y`. The target name comes from Zephyr; -the custom overlays define the AkidaTag hardware. +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 @@ -71,10 +73,14 @@ On macOS, Docker Desktop has no USB passthrough, so build inside Docker and flas ## 3. Build ```sh -./scripts/run.sh -d -b --app demo_apps +./scripts/run.sh -d -b --app demo_apps # hardware revision 1 +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -d -b --rev 2 --app demo_apps # hardware revision 2 ``` -A Docker build lands in `build_docker/demo_apps/`; a host build in `build/demo_apps/`. +A Docker build lands in `build_docker/demo_apps/`; a host build in `build/demo_apps/`. `--rev 2` +changes the configuration, not the directory, so the two revisions overwrite each other's build +unless you set `BUILD_DIR`, which is why the revision 2 command above builds into +`build_docker_rev2/`. `./scripts/run.sh -d -i` opens a shell inside the image. | Output | What it is | @@ -97,9 +103,11 @@ Flashing `merged.hex` and `merged_CPUNET.hex` over SWD replaces everything on th bootloader included. It does not touch the AKD1500's flash, so a model on the board survives. ```sh -./scripts/run.sh -d -f -jf --app demo_apps # Linux: J-Link inside Docker -BUILD_DIR=build_docker ./scripts/run.sh -f -jf --app demo_apps # macOS: host J-Link -./scripts/run.sh -d -r # reset the board +./scripts/run.sh -d -f -jf --app demo_apps # Linux: J-Link inside Docker +BUILD_DIR=build_docker ./scripts/run.sh -f -jf --app demo_apps # macOS: host J-Link +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -d -f -jf --app demo_apps # Linux: the revision 2 build +BUILD_DIR=build_docker_rev2 ./scripts/run.sh -f -jf --app demo_apps # macOS: the revision 2 build +./scripts/run.sh -d -r # reset the board ``` Use the J-Link path, `-jf`, on an AkidaTag board. The board's debug header reports a target diff --git a/docs/hardware/block-diagram.md b/docs/hardware/block-diagram.md index 626d1790..c133f896 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 f759048d..bba4a126 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/`, diff --git a/docs/setup.md b/docs/setup.md index de22ade9..de3a5095 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 diff --git a/scripts/run.sh b/scripts/run.sh index a6a38091..0449fe4a 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" @@ -435,6 +446,7 @@ fi # ----------------------------------------------------------------------------- APP_SRC_DIR="" APP_BUILD_DIR="" +BOARD_TARGET="" BUILD_CMD="" FLASH_CMD="" @@ -457,14 +469,17 @@ 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 + # 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) - 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 +503,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/Kconfig b/src/Kconfig index 6d6538fd..1793a5ca 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/README.md b/src/README.md index 4ccf693c..866e51e0 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 diff --git a/src/boards/brainchip/akidatag/Kconfig.akidatag b/src/boards/brainchip/akidatag/Kconfig.akidatag new file mode 100644 index 00000000..ff84f359 --- /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 00000000..d15b064b --- /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 00000000..d151c3c0 --- /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 00000000..216e58cf --- /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 00000000..50b0f89b --- /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_2.overlay b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_2.overlay new file mode 100644 index 00000000..3898afb4 --- /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/akidatag_nrf5340_cpuapp_defconfig b/src/boards/brainchip/akidatag/akidatag_nrf5340_cpuapp_defconfig new file mode 100644 index 00000000..302cf13a --- /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 00000000..a4de1e87 --- /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 00000000..1a246abf --- /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 00000000..65d767b3 --- /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 00000000..f69ba607 --- /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 00000000..e8806364 --- /dev/null +++ b/src/boards/brainchip/akidatag/board.yml @@ -0,0 +1,13 @@ +board: + name: akidatag + full_name: AkidaTag + vendor: brainchip + socs: + - name: nrf5340 + revision: + format: number + default: "1" + exact: true + revisions: + - name: "1" + - name: "2" 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 00000000..1c596b58 --- /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 6934f5a0..4fbb20a5 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 07c54c39..00000000 --- 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/core/interface/akd_spi_flash/akd_spi_flash.cpp b/src/core/interface/akd_spi_flash/akd_spi_flash.cpp index 2663a758..1eade2f5 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/ble_services/ble_initialization.c b/src/core/interface/ble_services/ble_initialization.c index 4561d2ad..542ac75f 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; diff --git a/src/core/interface/camera/spi_camera.c b/src/core/interface/camera/spi_camera.c index c2ad0f8c..f73c6208 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 b74938e6..edffa580 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 be483478..9d2b1012 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_1.overlay b/src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_1.overlay new file mode 100644 index 00000000..eb4d29c4 --- /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/boards/akidatag_nrf5340_cpuapp_2.overlay b/src/sysbuild/mcuboot/boards/akidatag_nrf5340_cpuapp_2.overlay new file mode 100644 index 00000000..bd010fd1 --- /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"; +}; 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 00000000..66645ac0 --- /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 6ff959e7..00000000 --- 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