From 438fca0ace369eae189a4c0ce33e99bc8d8df966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blik?= Date: Thu, 21 May 2026 20:20:21 +0200 Subject: [PATCH] Initial bare-metal foundation for nRF52840 PTT-FHSS - Fully open toolchain: arm-none-eabi-gcc inside Podman/Docker container - Platform-agnostic build via justfile (auto-detects podman vs docker) - CMake + Ninja build system with arm-none-eabi toolchain file - nRF52840 linker script and startup with full 64-entry vector table - Register access via typed bitfield unions (include/regs.h) - FHSS channel sequencer: AES-128-ECB PRNG over 40 channels (2402-2480 MHz) - Low-power sleep via SYSTEM_ON WFI + GPIOTE wakeup on button press - Vendor deps as shallow git submodules: nrfx, CMSIS_5, tiny-AES-c --- .gitignore | 1 + .gitmodules | 9 ++ CMakeLists.txt | 71 ++++++++++++++++ Dockerfile | 11 +++ README.md | 123 ++++++++++++++++++++++++++++ cmake/arm-none-eabi.cmake | 16 ++++ include/fhss.h | 6 ++ include/power.h | 4 + include/radio.h | 7 ++ include/regs.h | 90 ++++++++++++++++++++ justfile | 44 ++++++++++ link/nrf52840.ld | 66 +++++++++++++++ src/fhss.c | 41 ++++++++++ src/main.c | 15 ++++ src/power.c | 37 +++++++++ src/radio.c | 27 ++++++ src/startup.c | 168 ++++++++++++++++++++++++++++++++++++++ vendor/CMSIS_5 | 1 + vendor/nrfx | 1 + vendor/tiny-aes-c | 1 + 20 files changed, 739 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 cmake/arm-none-eabi.cmake create mode 100644 include/fhss.h create mode 100644 include/power.h create mode 100644 include/radio.h create mode 100644 include/regs.h create mode 100644 justfile create mode 100644 link/nrf52840.ld create mode 100644 src/fhss.c create mode 100644 src/main.c create mode 100644 src/power.c create mode 100644 src/radio.c create mode 100644 src/startup.c create mode 160000 vendor/CMSIS_5 create mode 160000 vendor/nrfx create mode 160000 vendor/tiny-aes-c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..534f4bd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "vendor/nrfx"] + path = vendor/nrfx + url = https://github.com/NordicSemiconductor/nrfx.git +[submodule "vendor/CMSIS_5"] + path = vendor/CMSIS_5 + url = https://github.com/ARM-software/CMSIS_5.git +[submodule "vendor/tiny-aes-c"] + path = vendor/tiny-aes-c + url = https://github.com/kokke/tiny-AES-c.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ac0ef2b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 3.22) + +# must be set before project() +set(CMAKE_TOOLCHAIN_FILE "${CMAKE_SOURCE_DIR}/cmake/arm-none-eabi.cmake") + +project(ptt_fhss C ASM) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) + +# sources +add_executable(firmware + src/startup.c + src/main.c + src/radio.c + src/fhss.c + src/power.c + vendor/tiny-aes-c/aes.c +) + +# include paths +target_include_directories(firmware PRIVATE + include + vendor/nrfx/mdk # nRF52840 device headers (nrf52840.h etc.) + vendor/CMSIS_5/CMSIS/Core/Include # core_cm4.h, cmsis_gcc.h etc. + vendor/tiny-aes-c +) + +# preprocessor defines +target_compile_definitions(firmware PRIVATE + NRF52840_XXAA # device variant required by nrfx/mdk headers +) + +# compiler flags +set(CPU_FLAGS + -mcpu=cortex-m4 + -mthumb + -mfpu=fpv4-sp-d16 + -mfloat-abi=hard +) + +target_compile_options(firmware PRIVATE + ${CPU_FLAGS} + -Os + -ffunction-sections + -fdata-sections + -fno-exceptions + -Wall + -Wextra + -Werror +) + +# linker +target_link_options(firmware PRIVATE + ${CPU_FLAGS} + -T ${CMAKE_SOURCE_DIR}/link/nrf52840.ld + -Wl,--gc-sections + -Wl,--print-memory-usage + -nostartfiles + -specs=nano.specs + -specs=nosys.specs +) + +# post-build: .hex + size report +add_custom_command(TARGET firmware POST_BUILD + COMMAND arm-none-eabi-objcopy + -O ihex $ + ${CMAKE_BINARY_DIR}/firmware.hex + COMMAND arm-none-eabi-size $ + VERBATIM +) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e8ea987 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc-arm-none-eabi \ + binutils-arm-none-eabi \ + libnewlib-arm-none-eabi \ + cmake \ + ninja-build \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /src diff --git a/README.md b/README.md new file mode 100644 index 0000000..0193b2c --- /dev/null +++ b/README.md @@ -0,0 +1,123 @@ +# ptt-fhss + +Bare-metal PTT (Push-to-Talk) firmware for the **Seeed XIAO BLE (nRF52840)** with +frequency-hopping spread spectrum (FHSS) on the 2.4 GHz band. + +Designed to be low-power, hard to detect, and built with a fully open toolchain - +no Zephyr, no Nordic SDK, no SoftDevice. + +## Hardware + +| Component | Part | +|-----------|------| +| Target | Seeed XIAO BLE (nRF52840) | +| Programmer | RP2040 running DAPLink | + +## How it works + +### FHSS + +The radio hops across 40 channels (2402-2480 MHz, 2 MHz steps) every 2 ms. +The hopping sequence is generated by AES-128-ECB keyed with a shared secret - +both devices derive identical sequences independently without any synchronisation +traffic. To an observer with an SDR the transmissions appear as short, scattered +impulses with no identifiable pattern. + +### Low power + +The nRF52840 stays in SYSTEM_ON sleep (`WFI`) with the DC/DC converter active +(~1.5 uA quiescent). A GPIOTE edge event on the PTT button wakes the CPU; +the radio is active only during the burst. + +### Register access + +All hardware register writes use typed bitfield unions defined in `include/regs.h` +rather than raw bit-shift expressions. The union layout is guaranteed correct with +`arm-none-eabi-gcc` (LSB-first bitfields on Cortex-M). + +## Toolchain + +Everything that produces the binary runs inside a container. The host only needs +tools that talk to hardware (pyocd) or manage the build (just). + +| Tool | Purpose | Install | +|------|---------|---------| +| podman or docker | Container runtime | distro package | +| just | Task runner | `cargo install just` or distro package | +| pyocd | Flash / debug via DAPLink | `pip install pyocd` | +| git | Source control + submodules | distro package | + +Inside the container: `debian:bookworm-slim` + `gcc-arm-none-eabi` from apt + +`cmake` + `ninja`. + +## Quick start + +```sh +git clone ptt +cd ptt +git submodule update --init --depth=1 + +just build # build firmware.hex inside container +just flash # flash via DAPLink (host pyocd) +``` + +On first run `just build` pulls the container image and compiles. Subsequent +builds reuse the cached image and only recompile changed files. + +## Tasks + +``` +just build compile firmware inside the container +just flash build + flash via DAPLink +just gdbserver start pyocd GDB server on port 3333 +just clean remove build/ +just clean-all remove build/ and the container image +``` + +## Project structure + +``` +. +|-- Dockerfile container image (debian + arm-gcc from apt) +|-- justfile build / flash / debug tasks +|-- CMakeLists.txt +|-- cmake/ +| \-- arm-none-eabi.cmake CMake toolchain file +|-- link/ +| \-- nrf52840.ld linker script (no SoftDevice, Flash @ 0x00000000) +|-- include/ +| |-- regs.h hardware register bitfield unions +| |-- radio.h +| |-- fhss.h +| \-- power.h +|-- src/ +| |-- startup.c vector table (64 entries) + Reset_Handler +| |-- main.c +| |-- radio.c RADIO peripheral driver (stub) +| |-- fhss.c AES-ECB hopping sequence generator +| \-- power.c DC/DC, GPIOTE wakeup, WFI sleep +\-- vendor/ + |-- nrfx/ Nordic HAL headers, pinned to v2.9.0 (includes mdk/) + |-- CMSIS_5/ ARM core headers (core_cm4.h etc.) + \-- tiny-aes-c/ Public domain AES-128 implementation +``` + +## Before first flash + +The XIAO BLE ships with a SoftDevice which occupies the start of Flash. +Erase it before flashing bare-metal firmware: + +```sh +pyocd erase --target nrf52840 --chip +``` + +## Status + +| Module | State | +|--------|-------| +| Startup / vector table | done | +| Linker script | done | +| Power management (sleep + wakeup) | done | +| FHSS sequence generator | done | +| RADIO driver | stub - TX loop not yet implemented | +| Sync protocol | not started | diff --git a/cmake/arm-none-eabi.cmake b/cmake/arm-none-eabi.cmake new file mode 100644 index 0000000..8881fc0 --- /dev/null +++ b/cmake/arm-none-eabi.cmake @@ -0,0 +1,16 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR arm) + +set(CMAKE_C_COMPILER arm-none-eabi-gcc) +set(CMAKE_CXX_COMPILER arm-none-eabi-g++) +set(CMAKE_ASM_COMPILER arm-none-eabi-gcc) +set(CMAKE_OBJCOPY arm-none-eabi-objcopy) +set(CMAKE_SIZE arm-none-eabi-size) + +# prevent cmake from link-testing the compiler against the host +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +# do not search host paths for libraries or headers +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/include/fhss.h b/include/fhss.h new file mode 100644 index 0000000..fb1b95b --- /dev/null +++ b/include/fhss.h @@ -0,0 +1,6 @@ +#pragma once +#include + +void fhss_init(void); +uint8_t fhss_next_channel(void); /* next channel from AES-ECB PRNG sequence */ +void fhss_sync_tick(void); /* call every FHSS_DWELL_MS ms */ diff --git a/include/power.h b/include/power.h new file mode 100644 index 0000000..119e403 --- /dev/null +++ b/include/power.h @@ -0,0 +1,4 @@ +#pragma once + +void power_init(void); +void power_sleep_until_button(void); /* SYSTEM_ON WFI, woken by GPIOTE event */ diff --git a/include/radio.h b/include/radio.h new file mode 100644 index 0000000..8a8a62d --- /dev/null +++ b/include/radio.h @@ -0,0 +1,7 @@ +#pragma once +#include + +void radio_init(void); +void radio_set_channel(uint8_t ch); /* 0-39, maps to 2402-2480 MHz */ +void radio_tx(const uint8_t *data, uint8_t len); +void radio_tx_burst(void); /* TX with FHSS hopping */ diff --git a/include/regs.h b/include/regs.h new file mode 100644 index 0000000..4b5ee0b --- /dev/null +++ b/include/regs.h @@ -0,0 +1,90 @@ +#pragma once +#include + +/* + * Hardware register bitfield unions for nRF52840 peripherals. + * Layout is guaranteed correct only with arm-none-eabi-gcc (LSB-first bitfields). + * Bit ranges match nRF52840 Product Specification v1.7. + */ + +/* GPIOTE */ + +/* CONFIG[n]: channel configuration */ +typedef union { + struct { + uint32_t MODE : 2; /* [1:0] 0=Disabled 1=Event 3=Task */ + uint32_t : 6; /* [7:2] reserved */ + uint32_t PSEL : 5; /* [12:8] pin number within port */ + uint32_t PORT : 1; /* [13] 0=Port0 1=Port1 */ + uint32_t : 2; /* [15:14] reserved */ + uint32_t POLARITY : 2; /* [17:16] 0=None 1=LoToHi 2=HiToLo 3=Toggle */ + uint32_t : 2; /* [19:18] reserved */ + uint32_t OUTINIT : 1; /* [20] initial output value for Task mode */ + uint32_t : 11; /* [31:21] reserved */ + } bit; + uint32_t reg; +} gpiote_config_t; + +#define GPIOTE_MODE_DISABLED 0u +#define GPIOTE_MODE_EVENT 1u +#define GPIOTE_MODE_TASK 3u +#define GPIOTE_POL_NONE 0u +#define GPIOTE_POL_LOTOHI 1u +#define GPIOTE_POL_HITOLO 2u +#define GPIOTE_POL_TOGGLE 3u + +/* INTENSET / INTENCLR: interrupt enable */ +typedef union { + struct { + uint32_t IN0 : 1; /* [0] channel 0 input event */ + uint32_t IN1 : 1; /* [1] channel 1 input event */ + uint32_t IN2 : 1; /* [2] */ + uint32_t IN3 : 1; /* [3] */ + uint32_t IN4 : 1; /* [4] */ + uint32_t IN5 : 1; /* [5] */ + uint32_t IN6 : 1; /* [6] */ + uint32_t IN7 : 1; /* [7] */ + uint32_t : 23; /* [30:8] reserved */ + uint32_t PORT : 1; /* [31] PORT event */ + } bit; + uint32_t reg; +} gpiote_inten_t; + +/* RADIO */ + +/* FREQUENCY: radio channel */ +typedef union { + struct { + uint32_t FREQUENCY : 7; /* [6:0] offset from base frequency in MHz */ + uint32_t : 1; /* [7] reserved */ + uint32_t MAP : 1; /* [8] 0: base=2400 MHz 1: base=2360 MHz */ + uint32_t : 23; /* [31:9] reserved */ + } bit; + uint32_t reg; +} radio_frequency_t; + +#define RADIO_MAP_DEFAULT 0u /* channel n -> 2400+n MHz */ +#define RADIO_MAP_BLE 1u /* channel n -> 2360+n MHz */ + +/* TXPOWER: transmit power */ +typedef union { + struct { + int32_t TXPOWER : 8; /* [7:0] signed dBm: +8, +7, +6, +5, +4, +3, +2, + 0, -4, -8, -12, -16, -20, -40 */ + uint32_t : 24; /* [31:8] reserved */ + } bit; + uint32_t reg; +} radio_txpower_t; + +/* MODE: radio data rate and modulation */ +typedef union { + struct { + uint32_t MODE : 4; /* [3:0] 0=NRF_1Mbit 1=NRF_2Mbit 4=BLE_1Mbit ... */ + uint32_t : 28; /* [31:4] reserved */ + } bit; + uint32_t reg; +} radio_mode_t; + +#define RADIO_MODE_NRF_1MBIT 0u +#define RADIO_MODE_NRF_2MBIT 1u +#define RADIO_MODE_BLE_1MBIT 4u diff --git a/justfile b/justfile new file mode 100644 index 0000000..147bf92 --- /dev/null +++ b/justfile @@ -0,0 +1,44 @@ +# variables +image := "ptt-builder" +build_dir := "build" + +# podman takes priority over docker +engine := `command -v podman 2>/dev/null \ + || command -v docker 2>/dev/null \ + || { echo "error: podman or docker required" >&2; exit 1; }` + +# user-namespace mapping: podman rootless vs docker +user_ns := `command -v podman >/dev/null 2>&1 \ + && echo "--userns=keep-id" \ + || echo "--user $(id -u):$(id -g)"` + +# recipes +# build container image (only rebuilt when Dockerfile changes) +image-build: + {{engine}} build -t {{image}} . + +# compile firmware inside the container +build: image-build + {{engine}} run --rm \ + {{user_ns}} \ + -v "{{justfile_directory()}}:/src:z" \ + {{image}} \ + sh -c "cmake -B /src/{{build_dir}} -G Ninja \ + -DCMAKE_BUILD_TYPE=MinSizeRel /src \ + && ninja -C /src/{{build_dir}}" + +# flash firmware via pyocd on the host (requires USB / DAPLink) +flash: build + pyocd flash --target nrf52840 {{build_dir}}/firmware.hex + +# start GDB server for debugging +gdbserver: + pyocd gdbserver --target nrf52840 --port 3333 + +# remove build artifacts +clean: + rm -rf {{build_dir}} + +# remove build artifacts AND the container image +clean-all: clean + {{engine}} rmi {{image}} 2>/dev/null || true diff --git a/link/nrf52840.ld b/link/nrf52840.ld new file mode 100644 index 0000000..e6565b6 --- /dev/null +++ b/link/nrf52840.ld @@ -0,0 +1,66 @@ +/* + * nRF52840 - no SoftDevice + * Flash: 1 MB @ 0x00000000 + * RAM: 256 KB @ 0x20000000 + * + * Before first flash, erase the entire chip to remove any SoftDevice: + * pyocd erase --target nrf52840 --chip + */ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1024K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256K +} + +/* stack grows downward from the top of RAM */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +ENTRY(Reset_Handler) + +SECTIONS +{ + /* vector table must be at the start of Flash */ + .isr_vector : + { + KEEP(*(.isr_vector)) + . = ALIGN(4); + } > FLASH + + /* code and read-only data */ + .text : + { + *(.text .text.*) + *(.rodata .rodata.*) + . = ALIGN(4); + _etext = .; + } > FLASH + + /* load address of .data in Flash - Reset_Handler copies from here */ + _sidata = LOADADDR(.data); + + /* initialized variables: stored in Flash, run from RAM */ + .data : + { + _sdata = .; + *(.data .data.*) + . = ALIGN(4); + _edata = .; + } > RAM AT > FLASH + + /* zero-initialized variables: Reset_Handler clears this region */ + .bss (NOLOAD) : + { + _sbss = .; + *(.bss .bss.*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } > RAM + + /DISCARD/ : + { + *(.ARM.exidx*) + *(.gnu.linkonce.armexidx.*) + } +} diff --git a/src/fhss.c b/src/fhss.c new file mode 100644 index 0000000..7bd39d8 --- /dev/null +++ b/src/fhss.c @@ -0,0 +1,41 @@ +#include "fhss.h" +#include + +#define FHSS_CHANNELS 40u +#define FHSS_DWELL_MS 2u + +/* TODO: replace with a real shared secret before deployment */ +static const uint8_t shared_key[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static uint32_t slot; + +void fhss_init(void) +{ + slot = 0u; +} + +uint8_t fhss_next_channel(void) +{ + uint8_t block[16] = {0}; + struct AES_ctx ctx; + + /* encode slot counter big-endian into the AES input block */ + block[0] = (uint8_t)(slot >> 24); + block[1] = (uint8_t)(slot >> 16); + block[2] = (uint8_t)(slot >> 8); + block[3] = (uint8_t)(slot ); + + AES_init_ctx(&ctx, shared_key); + AES_ECB_encrypt(&ctx, block); /* encrypts block in-place */ + + slot++; + return block[0] % FHSS_CHANNELS; +} + +void fhss_sync_tick(void) +{ + slot++; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..f77b10e --- /dev/null +++ b/src/main.c @@ -0,0 +1,15 @@ +#include "radio.h" +#include "fhss.h" +#include "power.h" + +int main(void) +{ + power_init(); + radio_init(); + fhss_init(); + + while (1) { + power_sleep_until_button(); + radio_tx_burst(); + } +} diff --git a/src/power.c b/src/power.c new file mode 100644 index 0000000..e3ede6a --- /dev/null +++ b/src/power.c @@ -0,0 +1,37 @@ +#include "power.h" +#include "regs.h" +#include +#include + +/* P0.02 on XIAO BLE - adjust to match your schematic */ +#define BUTTON_PIN 2u + +void power_init(void) +{ + /* DC/DC converter has lower quiescent current than the LDO */ + NRF_POWER->DCDCEN = 1u; + + NRF_GPIOTE->CONFIG[0] = (gpiote_config_t){ + .bit = { + .MODE = GPIOTE_MODE_EVENT, + .PSEL = BUTTON_PIN, + .PORT = 0u, + .POLARITY = GPIOTE_POL_LOTOHI, + } + }.reg; + + NRF_GPIOTE->INTENSET = (gpiote_inten_t){ .bit.IN0 = 1u }.reg; + + NVIC_EnableIRQ(GPIOTE_IRQn); +} + +void power_sleep_until_button(void) +{ + NRF_POWER->TASKS_LOWPWR = 1u; + __WFI(); +} + +void GPIOTE_IRQHandler(void) +{ + NRF_GPIOTE->EVENTS_IN[0] = 0u; +} diff --git a/src/radio.c b/src/radio.c new file mode 100644 index 0000000..5a26f54 --- /dev/null +++ b/src/radio.c @@ -0,0 +1,27 @@ +#include "radio.h" +#include "fhss.h" +#include "regs.h" +#include + +void radio_init(void) +{ + /* TODO: configure RADIO peripheral (MODE, PCNF0/1, BASE/PREFIX, CRC) */ +} + +void radio_set_channel(uint8_t ch) +{ + NRF_RADIO->FREQUENCY = (radio_frequency_t){ + .bit = { .FREQUENCY = ch, .MAP = RADIO_MAP_DEFAULT } + }.reg; +} + +void radio_tx(const uint8_t *data, uint8_t len) +{ + (void)data; (void)len; + /* TODO: load packet, enable TX, wait for END event, disable */ +} + +void radio_tx_burst(void) +{ + /* TODO: hop + TX loop driven by fhss_next_channel() */ +} diff --git a/src/startup.c b/src/startup.c new file mode 100644 index 0000000..da72a6a --- /dev/null +++ b/src/startup.c @@ -0,0 +1,168 @@ +#include + +/* linker script symbols */ +extern uint32_t _sidata; /* load address of .data in Flash */ +extern uint32_t _sdata; /* start of .data in RAM */ +extern uint32_t _edata; /* end of .data in RAM */ +extern uint32_t _sbss; +extern uint32_t _ebss; +extern uint32_t _estack; /* address equals initial SP value */ + +extern int main(void); + +void Reset_Handler(void); + +static void __attribute__((used)) Default_Handler(void) +{ + while (1); +} + +/* ARM Cortex-M4 core exceptions */ +void NMI_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void HardFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void MemManage_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void BusFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void UsageFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void SVC_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void DebugMon_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void PendSV_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void SysTick_Handler(void) __attribute__((weak, alias("Default_Handler"))); + +/* nRF52840 peripheral IRQs (IRQ0-IRQ47) */ +void POWER_CLOCK_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void RADIO_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void UARTE0_UART0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void NFCT_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void GPIOTE_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SAADC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void TIMER0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void TIMER1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void TIMER2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void RTC0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void TEMP_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void RNG_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void ECB_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void CCM_AAR_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void WDT_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void RTC1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void QDEC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void COMP_LPCOMP_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SWI0_EGU0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SWI1_EGU1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SWI2_EGU2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SWI3_EGU3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SWI4_EGU4_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SWI5_EGU5_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void TIMER3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void TIMER4_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void PWM0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void PDM_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void MWU_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void PWM1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void PWM2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SPIM2_SPIS2_SPI2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void RTC2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void I2S_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void FPU_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void USBD_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void UARTE1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void QSPI_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void CRYPTOCELL_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void PWM3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SPIM3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); + +/* vector table: 64 entries (16 core + 48 IRQs) */ + +typedef void (*vector_fn)(void); + +__attribute__((section(".isr_vector"), used)) +const vector_fn vectors[64] = { + /* 0 */ (vector_fn)&_estack, + /* 1 */ Reset_Handler, + /* 2 */ NMI_Handler, + /* 3 */ HardFault_Handler, + /* 4 */ MemManage_Handler, + /* 5 */ BusFault_Handler, + /* 6 */ UsageFault_Handler, + /* 7 */ 0, + /* 8 */ 0, + /* 9 */ 0, + /* 10 */ 0, + /* 11 */ SVC_Handler, + /* 12 */ DebugMon_Handler, + /* 13 */ 0, + /* 14 */ PendSV_Handler, + /* 15 */ SysTick_Handler, + + /* IRQ0 */ POWER_CLOCK_IRQHandler, + /* IRQ1 */ RADIO_IRQHandler, + /* IRQ2 */ UARTE0_UART0_IRQHandler, + /* IRQ3 */ SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler, + /* IRQ4 */ SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler, + /* IRQ5 */ NFCT_IRQHandler, + /* IRQ6 */ GPIOTE_IRQHandler, + /* IRQ7 */ SAADC_IRQHandler, + /* IRQ8 */ TIMER0_IRQHandler, + /* IRQ9 */ TIMER1_IRQHandler, + /* IRQ10 */ TIMER2_IRQHandler, + /* IRQ11 */ RTC0_IRQHandler, + /* IRQ12 */ TEMP_IRQHandler, + /* IRQ13 */ RNG_IRQHandler, + /* IRQ14 */ ECB_IRQHandler, + /* IRQ15 */ CCM_AAR_IRQHandler, + /* IRQ16 */ WDT_IRQHandler, + /* IRQ17 */ RTC1_IRQHandler, + /* IRQ18 */ QDEC_IRQHandler, + /* IRQ19 */ COMP_LPCOMP_IRQHandler, + /* IRQ20 */ SWI0_EGU0_IRQHandler, + /* IRQ21 */ SWI1_EGU1_IRQHandler, + /* IRQ22 */ SWI2_EGU2_IRQHandler, + /* IRQ23 */ SWI3_EGU3_IRQHandler, + /* IRQ24 */ SWI4_EGU4_IRQHandler, + /* IRQ25 */ SWI5_EGU5_IRQHandler, + /* IRQ26 */ TIMER3_IRQHandler, + /* IRQ27 */ TIMER4_IRQHandler, + /* IRQ28 */ PWM0_IRQHandler, + /* IRQ29 */ PDM_IRQHandler, + /* IRQ30 */ 0, /* reserved */ + /* IRQ31 */ 0, /* reserved */ + /* IRQ32 */ MWU_IRQHandler, + /* IRQ33 */ PWM1_IRQHandler, + /* IRQ34 */ PWM2_IRQHandler, + /* IRQ35 */ SPIM2_SPIS2_SPI2_IRQHandler, + /* IRQ36 */ RTC2_IRQHandler, + /* IRQ37 */ I2S_IRQHandler, + /* IRQ38 */ FPU_IRQHandler, + /* IRQ39 */ USBD_IRQHandler, + /* IRQ40 */ UARTE1_IRQHandler, + /* IRQ41 */ QSPI_IRQHandler, + /* IRQ42 */ CRYPTOCELL_IRQHandler, + /* IRQ43 */ 0, /* reserved */ + /* IRQ44 */ 0, /* reserved */ + /* IRQ45 */ PWM3_IRQHandler, + /* IRQ46 */ 0, /* reserved */ + /* IRQ47 */ SPIM3_IRQHandler, +}; + +/* Reset_Handler */ + +void Reset_Handler(void) +{ + /* copy .data initializers from Flash to RAM */ + uint32_t *src = &_sidata; + uint32_t *dst = &_sdata; + while (dst < &_edata) { + *dst++ = *src++; + } + + /* zero .bss */ + dst = &_sbss; + while (dst < &_ebss) { + *dst++ = 0u; + } + + main(); + while (1); +} diff --git a/vendor/CMSIS_5 b/vendor/CMSIS_5 new file mode 160000 index 0000000..55b1983 --- /dev/null +++ b/vendor/CMSIS_5 @@ -0,0 +1 @@ +Subproject commit 55b19837f5703e418ca37894d5745b1dc05e4c91 diff --git a/vendor/nrfx b/vendor/nrfx new file mode 160000 index 0000000..16756ca --- /dev/null +++ b/vendor/nrfx @@ -0,0 +1 @@ +Subproject commit 16756cadac53aa72e4262dc3e17db73f6bda715c diff --git a/vendor/tiny-aes-c b/vendor/tiny-aes-c new file mode 160000 index 0000000..2385675 --- /dev/null +++ b/vendor/tiny-aes-c @@ -0,0 +1 @@ +Subproject commit 23856752fbd139da0b8ca6e471a13d5bcc99a08d