Add Doxygen, clang-format, cppcheck, and Gitea CI
Doxygen: - Doxyfile: minimal config, HTML output to docs/, no LaTeX - @file/@brief on all source files, full @param/@return on public API - docs/ added to .gitignore clang-format (14, Linux brace style, 4-space, column 100): - .clang-format added - Applied to entire codebase; this commit is the canonical baseline - just format rewrites in-place; just format-check is the CI gate cppcheck (--enable=warning,style,performance,portability): - Linker-symbol pointer comparisons in startup.c suppressed with inline cppcheck-suppress (false positives, not real bugs) - just lint runs cppcheck; zero warnings required to pass Dockerfile gains clang-format, cppcheck, doxygen packages so all tools run inside the existing container -- host stays clean. Gitea Actions (.gitea/workflows/ci.yml): - Four parallel jobs: build, format, lint, docs - All jobs use the same Dockerfile-based image - Doxygen job fails on any warning line in output
This commit is contained in:
15
.clang-format
Normal file
15
.clang-format
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
IndentWidth: 4
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
ColumnLimit: 100
|
||||||
|
AlignConsecutiveBitFields: true
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
SortIncludes: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
99
.gitea/workflows/ci.yml
Normal file
99
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: ptt-builder
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build firmware
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Build container image
|
||||||
|
run: docker build -t $IMAGE .
|
||||||
|
|
||||||
|
- name: Compile firmware
|
||||||
|
run: |
|
||||||
|
docker run --rm \
|
||||||
|
--user "$(id -u):$(id -g)" \
|
||||||
|
-v "$PWD:/src" \
|
||||||
|
$IMAGE \
|
||||||
|
sh -c "cmake -B /src/build -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=MinSizeRel /src \
|
||||||
|
&& ninja -C /src/build"
|
||||||
|
|
||||||
|
- name: Print size
|
||||||
|
run: |
|
||||||
|
docker run --rm \
|
||||||
|
-v "$PWD:/src" \
|
||||||
|
$IMAGE \
|
||||||
|
arm-none-eabi-size /src/build/firmware
|
||||||
|
|
||||||
|
format:
|
||||||
|
name: Check formatting
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build container image
|
||||||
|
run: docker build -t $IMAGE .
|
||||||
|
|
||||||
|
- name: clang-format check
|
||||||
|
run: |
|
||||||
|
docker run --rm \
|
||||||
|
--user "$(id -u):$(id -g)" \
|
||||||
|
-v "$PWD:/src" \
|
||||||
|
$IMAGE \
|
||||||
|
sh -c "find /src/src /src/include -name '*.c' -o -name '*.h' | \
|
||||||
|
xargs clang-format --dry-run --Werror \
|
||||||
|
--style=file:/src/.clang-format"
|
||||||
|
|
||||||
|
lint:
|
||||||
|
name: Static analysis
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build container image
|
||||||
|
run: docker build -t $IMAGE .
|
||||||
|
|
||||||
|
- name: cppcheck
|
||||||
|
run: |
|
||||||
|
docker run --rm \
|
||||||
|
--user "$(id -u):$(id -g)" \
|
||||||
|
-v "$PWD:/src" \
|
||||||
|
$IMAGE \
|
||||||
|
sh -c "cppcheck --error-exitcode=1 \
|
||||||
|
--enable=warning,style,performance,portability \
|
||||||
|
--suppress=missingInclude \
|
||||||
|
--inline-suppr \
|
||||||
|
--std=c11 \
|
||||||
|
-I /src/include \
|
||||||
|
/src/src/"
|
||||||
|
|
||||||
|
docs:
|
||||||
|
name: Build documentation
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build container image
|
||||||
|
run: docker build -t $IMAGE .
|
||||||
|
|
||||||
|
- name: Doxygen
|
||||||
|
run: |
|
||||||
|
docker run --rm \
|
||||||
|
--user "$(id -u):$(id -g)" \
|
||||||
|
-v "$PWD:/src" \
|
||||||
|
$IMAGE \
|
||||||
|
sh -c "cd /src && doxygen Doxyfile 2>&1 | tee /tmp/doxy.log && \
|
||||||
|
! grep -q 'warning:' /tmp/doxy.log"
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
build/
|
build/
|
||||||
|
docs/
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
libnewlib-arm-none-eabi \
|
libnewlib-arm-none-eabi \
|
||||||
cmake \
|
cmake \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
|
clang-format \
|
||||||
|
cppcheck \
|
||||||
|
doxygen \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|||||||
21
Doxyfile
Normal file
21
Doxyfile
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
PROJECT_NAME = "ptt-fhss"
|
||||||
|
PROJECT_BRIEF = "Bare-metal PTT firmware for nRF52840 with FHSS"
|
||||||
|
PROJECT_NUMBER =
|
||||||
|
OUTPUT_DIRECTORY = docs
|
||||||
|
INPUT = include src
|
||||||
|
FILE_PATTERNS = *.h *.c
|
||||||
|
RECURSIVE = NO
|
||||||
|
EXTRACT_ALL = YES
|
||||||
|
EXTRACT_STATIC = YES
|
||||||
|
QUIET = YES
|
||||||
|
WARNINGS = YES
|
||||||
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
|
WARN_NO_PARAMDOC = YES
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
HTML_OUTPUT = html
|
||||||
|
HTML_TIMESTAMP = NO
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
HAVE_DOT = NO
|
||||||
|
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||||
|
JAVADOC_AUTOBRIEF = YES
|
||||||
|
PREDEFINED = NRF52840_XXAA
|
||||||
@@ -1,6 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* @file fhss.h
|
||||||
|
* @brief FHSS channel sequencer based on AES-128-ECB.
|
||||||
|
*
|
||||||
|
* Both link endpoints derive the same hopping sequence independently from a
|
||||||
|
* shared 128-bit key and a monotonically increasing slot counter. No
|
||||||
|
* synchronisation traffic is required as long as both sides start from the
|
||||||
|
* same slot.
|
||||||
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void fhss_init(void);
|
/** @brief Reset the slot counter to zero. */
|
||||||
uint8_t fhss_next_channel(void); /* next channel from AES-ECB PRNG sequence */
|
void fhss_init(void);
|
||||||
void fhss_sync_tick(void); /* call every FHSS_DWELL_MS ms */
|
|
||||||
|
/**
|
||||||
|
* @brief Return the next channel in the hopping sequence.
|
||||||
|
*
|
||||||
|
* Encrypts the current slot counter big-endian with AES-128-ECB, returns
|
||||||
|
* @c block[0] % 40, and advances the slot counter.
|
||||||
|
*
|
||||||
|
* @return Channel index in [0, 39].
|
||||||
|
*/
|
||||||
|
uint8_t fhss_next_channel(void);
|
||||||
|
|
||||||
|
/** @brief Advance the slot counter without transmitting (receiver side). */
|
||||||
|
void fhss_sync_tick(void);
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* @file power.h
|
||||||
|
* @brief Power management: DC/DC regulator, GPIOTE wakeup, SYSTEM_ON sleep.
|
||||||
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/** @brief Enable the DC/DC converter and configure GPIOTE wakeup on the PTT button. */
|
||||||
void power_init(void);
|
void power_init(void);
|
||||||
void power_sleep_until_button(void); /* SYSTEM_ON WFI, woken by GPIOTE event */
|
|
||||||
|
/**
|
||||||
|
* @brief Enter SYSTEM_ON low-power sleep and return on the next GPIOTE event.
|
||||||
|
*
|
||||||
|
* Sets TASKS_LOWPWR then executes WFI. The CPU wakes when the GPIOTE
|
||||||
|
* interrupt fires (button press) and resumes from here.
|
||||||
|
*/
|
||||||
|
void power_sleep_until_button(void);
|
||||||
|
|||||||
@@ -1,7 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* @file radio.h
|
||||||
|
* @brief RADIO peripheral driver -- NRF_1Mbit proprietary mode.
|
||||||
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void radio_init(void);
|
/** @brief Configure the RADIO peripheral (mode, packet format, address, CRC, power, channel). */
|
||||||
void radio_set_channel(uint8_t ch); /* 0-39, maps to 2402-2480 MHz */
|
void radio_init(void);
|
||||||
void radio_tx(const uint8_t *data, uint8_t len);
|
|
||||||
void radio_tx_burst(void); /* TX with FHSS hopping */
|
/**
|
||||||
|
* @brief Set the RF channel.
|
||||||
|
* @param ch Channel index 0-39, maps to 2400+ch MHz (MAP=0).
|
||||||
|
*/
|
||||||
|
void radio_set_channel(uint8_t ch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit one packet synchronously.
|
||||||
|
*
|
||||||
|
* Loads @p data into the internal packet buffer, asserts TASKS_TXEN, and
|
||||||
|
* returns after EVENTS_END fires. The RADIO is DISABLED automatically via
|
||||||
|
* the END_DISABLE shortcut before the function returns.
|
||||||
|
*
|
||||||
|
* @param data Payload bytes.
|
||||||
|
* @param len Payload length (0-255 bytes).
|
||||||
|
*/
|
||||||
|
void radio_tx(const uint8_t *data, uint8_t len);
|
||||||
|
|
||||||
|
/** @brief Transmit a burst with FHSS hopping (not yet implemented). */
|
||||||
|
void radio_tx_burst(void);
|
||||||
|
|||||||
181
include/regs.h
181
include/regs.h
@@ -1,154 +1,155 @@
|
|||||||
|
/**
|
||||||
|
* @file regs.h
|
||||||
|
* @brief 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.
|
||||||
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 */
|
/* GPIOTE */
|
||||||
|
|
||||||
/* CONFIG[n]: channel configuration */
|
/** @brief GPIOTE CONFIG[n]: channel configuration register. */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t MODE : 2; /* [1:0] 0=Disabled 1=Event 3=Task */
|
uint32_t MODE : 2; /* [1:0] 0=Disabled 1=Event 3=Task */
|
||||||
uint32_t : 6; /* [7:2] reserved */
|
uint32_t : 6; /* [7:2] reserved */
|
||||||
uint32_t PSEL : 5; /* [12:8] pin number within port */
|
uint32_t PSEL : 5; /* [12:8] pin number within port */
|
||||||
uint32_t PORT : 1; /* [13] 0=Port0 1=Port1 */
|
uint32_t PORT : 1; /* [13] 0=Port0 1=Port1 */
|
||||||
uint32_t : 2; /* [15:14] reserved */
|
uint32_t : 2; /* [15:14] reserved */
|
||||||
uint32_t POLARITY : 2; /* [17:16] 0=None 1=LoToHi 2=HiToLo 3=Toggle */
|
uint32_t POLARITY : 2; /* [17:16] 0=None 1=LoToHi 2=HiToLo 3=Toggle */
|
||||||
uint32_t : 2; /* [19:18] reserved */
|
uint32_t : 2; /* [19:18] reserved */
|
||||||
uint32_t OUTINIT : 1; /* [20] initial output value for Task mode */
|
uint32_t OUTINIT : 1; /* [20] initial output value for Task mode */
|
||||||
uint32_t : 11; /* [31:21] reserved */
|
uint32_t : 11; /* [31:21] reserved */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} gpiote_config_t;
|
} gpiote_config_t;
|
||||||
|
|
||||||
#define GPIOTE_MODE_DISABLED 0u
|
#define GPIOTE_MODE_DISABLED 0u
|
||||||
#define GPIOTE_MODE_EVENT 1u
|
#define GPIOTE_MODE_EVENT 1u
|
||||||
#define GPIOTE_MODE_TASK 3u
|
#define GPIOTE_MODE_TASK 3u
|
||||||
#define GPIOTE_POL_NONE 0u
|
#define GPIOTE_POL_NONE 0u
|
||||||
#define GPIOTE_POL_LOTOHI 1u
|
#define GPIOTE_POL_LOTOHI 1u
|
||||||
#define GPIOTE_POL_HITOLO 2u
|
#define GPIOTE_POL_HITOLO 2u
|
||||||
#define GPIOTE_POL_TOGGLE 3u
|
#define GPIOTE_POL_TOGGLE 3u
|
||||||
|
|
||||||
/* INTENSET / INTENCLR: interrupt enable */
|
/** @brief GPIOTE INTENSET / INTENCLR: interrupt enable register. */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t IN0 : 1; /* [0] channel 0 input event */
|
uint32_t IN0 : 1; /* [0] channel 0 input event */
|
||||||
uint32_t IN1 : 1; /* [1] channel 1 input event */
|
uint32_t IN1 : 1; /* [1] channel 1 input event */
|
||||||
uint32_t IN2 : 1; /* [2] */
|
uint32_t IN2 : 1; /* [2] */
|
||||||
uint32_t IN3 : 1; /* [3] */
|
uint32_t IN3 : 1; /* [3] */
|
||||||
uint32_t IN4 : 1; /* [4] */
|
uint32_t IN4 : 1; /* [4] */
|
||||||
uint32_t IN5 : 1; /* [5] */
|
uint32_t IN5 : 1; /* [5] */
|
||||||
uint32_t IN6 : 1; /* [6] */
|
uint32_t IN6 : 1; /* [6] */
|
||||||
uint32_t IN7 : 1; /* [7] */
|
uint32_t IN7 : 1; /* [7] */
|
||||||
uint32_t : 23; /* [30:8] reserved */
|
uint32_t : 23; /* [30:8] reserved */
|
||||||
uint32_t PORT : 1; /* [31] PORT event */
|
uint32_t PORT : 1; /* [31] PORT event */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} gpiote_inten_t;
|
} gpiote_inten_t;
|
||||||
|
|
||||||
/* RADIO */
|
/* RADIO */
|
||||||
|
|
||||||
/* FREQUENCY: radio channel */
|
/** @brief RADIO FREQUENCY: RF channel selection register. */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t FREQUENCY : 7; /* [6:0] offset from base frequency in MHz */
|
uint32_t FREQUENCY : 7; /* [6:0] offset from base frequency in MHz */
|
||||||
uint32_t : 1; /* [7] reserved */
|
uint32_t : 1; /* [7] reserved */
|
||||||
uint32_t MAP : 1; /* [8] 0: base=2400 MHz 1: base=2360 MHz */
|
uint32_t MAP : 1; /* [8] 0: base=2400 MHz 1: base=2360 MHz */
|
||||||
uint32_t : 23; /* [31:9] reserved */
|
uint32_t : 23; /* [31:9] reserved */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} radio_frequency_t;
|
} radio_frequency_t;
|
||||||
|
|
||||||
#define RADIO_MAP_DEFAULT 0u /* channel n -> 2400+n MHz */
|
#define RADIO_MAP_DEFAULT 0u /* channel n -> 2400+n MHz */
|
||||||
#define RADIO_MAP_BLE 1u /* channel n -> 2360+n MHz */
|
#define RADIO_MAP_BLE 1u /* channel n -> 2360+n MHz */
|
||||||
|
|
||||||
/* TXPOWER: transmit power */
|
/** @brief RADIO TXPOWER: transmit power register. */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
int32_t TXPOWER : 8; /* [7:0] signed dBm: +8, +7, +6, +5, +4, +3, +2,
|
int32_t TXPOWER : 8; /* [7:0] signed dBm: +8, +7, +6, +5, +4, +3, +2,
|
||||||
0, -4, -8, -12, -16, -20, -40 */
|
0, -4, -8, -12, -16, -20, -40 */
|
||||||
uint32_t : 24; /* [31:8] reserved */
|
uint32_t : 24; /* [31:8] reserved */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} radio_txpower_t;
|
} radio_txpower_t;
|
||||||
|
|
||||||
/* MODE: radio data rate and modulation */
|
/** @brief RADIO MODE: data rate and modulation register. */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t MODE : 4; /* [3:0] 0=NRF_1Mbit 1=NRF_2Mbit 4=BLE_1Mbit ... */
|
uint32_t MODE : 4; /* [3:0] 0=NRF_1Mbit 1=NRF_2Mbit 4=BLE_1Mbit ... */
|
||||||
uint32_t : 28; /* [31:4] reserved */
|
uint32_t : 28; /* [31:4] reserved */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} radio_mode_t;
|
} radio_mode_t;
|
||||||
|
|
||||||
#define RADIO_MODE_NRF_1MBIT 0u
|
#define RADIO_MODE_NRF_1MBIT 0u
|
||||||
#define RADIO_MODE_NRF_2MBIT 1u
|
#define RADIO_MODE_NRF_2MBIT 1u
|
||||||
#define RADIO_MODE_BLE_1MBIT 4u
|
#define RADIO_MODE_BLE_1MBIT 4u
|
||||||
|
|
||||||
/* PCNF0: packet configuration register 0 */
|
/** @brief RADIO PCNF0: packet configuration register 0 (header fields). */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t LFLEN : 4; /* [3:0] length of LENGTH field in bits */
|
uint32_t LFLEN : 4; /* [3:0] length of LENGTH field in bits */
|
||||||
uint32_t : 4; /* [7:4] reserved */
|
uint32_t : 4; /* [7:4] reserved */
|
||||||
uint32_t S0LEN : 1; /* [8] length of S0 field in bytes (0 or 1) */
|
uint32_t S0LEN : 1; /* [8] length of S0 field in bytes (0 or 1) */
|
||||||
uint32_t : 7; /* [15:9] reserved */
|
uint32_t : 7; /* [15:9] reserved */
|
||||||
uint32_t S1LEN : 4; /* [19:16] length of S1 field in bits */
|
uint32_t S1LEN : 4; /* [19:16] length of S1 field in bits */
|
||||||
uint32_t S1INCL : 1; /* [20] include S1 field in RAM even if zero length */
|
uint32_t S1INCL : 1; /* [20] include S1 field in RAM even if zero length */
|
||||||
uint32_t : 3; /* [23:21] reserved */
|
uint32_t : 3; /* [23:21] reserved */
|
||||||
uint32_t PLEN : 1; /* [24] 0=8-bit preamble 1=16-bit preamble */
|
uint32_t PLEN : 1; /* [24] 0=8-bit preamble 1=16-bit preamble */
|
||||||
uint32_t : 6; /* [30:25] reserved */
|
uint32_t : 6; /* [30:25] reserved */
|
||||||
uint32_t CRCINC : 1; /* [31] include CRC in LENGTH field */
|
uint32_t CRCINC : 1; /* [31] include CRC in LENGTH field */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} radio_pcnf0_t;
|
} radio_pcnf0_t;
|
||||||
|
|
||||||
/* PCNF1: packet configuration register 1 */
|
/** @brief RADIO PCNF1: packet configuration register 1 (payload and address). */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t MAXLEN : 8; /* [7:0] maximum payload length in bytes */
|
uint32_t MAXLEN : 8; /* [7:0] maximum payload length in bytes */
|
||||||
uint32_t STATLEN : 8; /* [15:8] static length added to payload */
|
uint32_t STATLEN : 8; /* [15:8] static length added to payload */
|
||||||
uint32_t BALEN : 3; /* [18:16] base address length (2-4 bytes) */
|
uint32_t BALEN : 3; /* [18:16] base address length (2-4 bytes) */
|
||||||
uint32_t : 5; /* [23:19] reserved */
|
uint32_t : 5; /* [23:19] reserved */
|
||||||
uint32_t ENDIAN : 1; /* [24] 0=little-endian 1=big-endian */
|
uint32_t ENDIAN : 1; /* [24] 0=little-endian 1=big-endian */
|
||||||
uint32_t WHITEEN : 1; /* [25] 1=enable data whitening */
|
uint32_t WHITEEN : 1; /* [25] 1=enable data whitening */
|
||||||
uint32_t : 6; /* [31:26] reserved */
|
uint32_t : 6; /* [31:26] reserved */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} radio_pcnf1_t;
|
} radio_pcnf1_t;
|
||||||
|
|
||||||
/* CRCCNF: CRC configuration */
|
/** @brief RADIO CRCCNF: CRC configuration register. */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t LEN : 2; /* [1:0] 0=disabled 1=1 byte 2=2 bytes 3=3 bytes */
|
uint32_t LEN : 2; /* [1:0] 0=disabled 1=1 byte 2=2 bytes 3=3 bytes */
|
||||||
uint32_t : 6; /* [7:2] reserved */
|
uint32_t : 6; /* [7:2] reserved */
|
||||||
uint32_t SKIPADDR : 1; /* [8] 1=skip address field in CRC calculation */
|
uint32_t SKIPADDR : 1; /* [8] 1=skip address field in CRC calculation */
|
||||||
uint32_t : 23; /* [31:9] reserved */
|
uint32_t : 23; /* [31:9] reserved */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} radio_crccnf_t;
|
} radio_crccnf_t;
|
||||||
|
|
||||||
#define RADIO_CRCCNF_LEN_DISABLED 0u
|
#define RADIO_CRCCNF_LEN_DISABLED 0u
|
||||||
#define RADIO_CRCCNF_LEN_ONE 1u
|
#define RADIO_CRCCNF_LEN_ONE 1u
|
||||||
#define RADIO_CRCCNF_LEN_TWO 2u
|
#define RADIO_CRCCNF_LEN_TWO 2u
|
||||||
#define RADIO_CRCCNF_LEN_THREE 3u
|
#define RADIO_CRCCNF_LEN_THREE 3u
|
||||||
|
|
||||||
/* SHORTS: shortcut register */
|
/** @brief RADIO SHORTS: hardware shortcut register. */
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t READY_START : 1; /* [0] READY -> TASKS_START */
|
uint32_t READY_START : 1; /* [0] READY -> TASKS_START */
|
||||||
uint32_t END_DISABLE : 1; /* [1] END -> TASKS_DISABLE */
|
uint32_t END_DISABLE : 1; /* [1] END -> TASKS_DISABLE */
|
||||||
uint32_t DISABLED_TXEN : 1; /* [2] DISABLED -> TASKS_TXEN */
|
uint32_t DISABLED_TXEN : 1; /* [2] DISABLED -> TASKS_TXEN */
|
||||||
uint32_t DISABLED_RXEN : 1; /* [3] DISABLED -> TASKS_RXEN */
|
uint32_t DISABLED_RXEN : 1; /* [3] DISABLED -> TASKS_RXEN */
|
||||||
uint32_t ADDRESS_RSSISTART : 1; /* [4] ADDRESS -> TASKS_RSSISTART */
|
uint32_t ADDRESS_RSSISTART : 1; /* [4] ADDRESS -> TASKS_RSSISTART */
|
||||||
uint32_t END_START : 1; /* [5] END -> TASKS_START */
|
uint32_t END_START : 1; /* [5] END -> TASKS_START */
|
||||||
uint32_t ADDRESS_BCSTART : 1; /* [6] ADDRESS -> TASKS_BCSTART */
|
uint32_t ADDRESS_BCSTART : 1; /* [6] ADDRESS -> TASKS_BCSTART */
|
||||||
uint32_t : 1; /* [7] reserved */
|
uint32_t : 1; /* [7] reserved */
|
||||||
uint32_t DISABLED_RSSISTOP : 1; /* [8] DISABLED -> TASKS_RSSISTOP */
|
uint32_t DISABLED_RSSISTOP : 1; /* [8] DISABLED -> TASKS_RSSISTOP */
|
||||||
uint32_t : 23; /* [31:9] reserved */
|
uint32_t : 23; /* [31:9] reserved */
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} radio_shorts_t;
|
} radio_shorts_t;
|
||||||
|
|||||||
46
justfile
46
justfile
@@ -12,6 +12,8 @@ user_ns := `command -v podman >/dev/null 2>&1 \
|
|||||||
&& echo "--userns=keep-id" \
|
&& echo "--userns=keep-id" \
|
||||||
|| echo "--user $(id -u):$(id -g)"`
|
|| echo "--user $(id -u):$(id -g)"`
|
||||||
|
|
||||||
|
src_files := "find /src/src /src/include -name '*.c' -o -name '*.h'"
|
||||||
|
|
||||||
# recipes
|
# recipes
|
||||||
# build container image (only rebuilt when Dockerfile changes)
|
# build container image (only rebuilt when Dockerfile changes)
|
||||||
image-build:
|
image-build:
|
||||||
@@ -27,6 +29,44 @@ build: image-build
|
|||||||
-DCMAKE_BUILD_TYPE=MinSizeRel /src \
|
-DCMAKE_BUILD_TYPE=MinSizeRel /src \
|
||||||
&& ninja -C /src/{{build_dir}}"
|
&& ninja -C /src/{{build_dir}}"
|
||||||
|
|
||||||
|
# reformat all source files in-place with clang-format
|
||||||
|
format: image-build
|
||||||
|
{{engine}} run --rm \
|
||||||
|
{{user_ns}} \
|
||||||
|
-v "{{justfile_directory()}}:/src:z" \
|
||||||
|
{{image}} \
|
||||||
|
sh -c "{{src_files}} | xargs clang-format -i --style=file:/src/.clang-format"
|
||||||
|
|
||||||
|
# check formatting without modifying files (used in CI)
|
||||||
|
format-check: image-build
|
||||||
|
{{engine}} run --rm \
|
||||||
|
{{user_ns}} \
|
||||||
|
-v "{{justfile_directory()}}:/src:z" \
|
||||||
|
{{image}} \
|
||||||
|
sh -c "{{src_files}} | xargs clang-format --dry-run --Werror --style=file:/src/.clang-format"
|
||||||
|
|
||||||
|
# static analysis with cppcheck
|
||||||
|
lint: image-build
|
||||||
|
{{engine}} run --rm \
|
||||||
|
{{user_ns}} \
|
||||||
|
-v "{{justfile_directory()}}:/src:z" \
|
||||||
|
{{image}} \
|
||||||
|
sh -c "cppcheck --error-exitcode=1 \
|
||||||
|
--enable=warning,style,performance,portability \
|
||||||
|
--suppress=missingInclude \
|
||||||
|
--inline-suppr \
|
||||||
|
--std=c11 \
|
||||||
|
-I /src/include \
|
||||||
|
/src/src/"
|
||||||
|
|
||||||
|
# generate HTML documentation with Doxygen
|
||||||
|
docs: image-build
|
||||||
|
{{engine}} run --rm \
|
||||||
|
{{user_ns}} \
|
||||||
|
-v "{{justfile_directory()}}:/src:z" \
|
||||||
|
{{image}} \
|
||||||
|
sh -c "cd /src && doxygen Doxyfile"
|
||||||
|
|
||||||
# flash firmware via pyocd on the host (requires USB / DAPLink)
|
# flash firmware via pyocd on the host (requires USB / DAPLink)
|
||||||
flash: build
|
flash: build
|
||||||
pyocd flash --target nrf52840 {{build_dir}}/firmware.hex
|
pyocd flash --target nrf52840 {{build_dir}}/firmware.hex
|
||||||
@@ -35,10 +75,10 @@ flash: build
|
|||||||
gdbserver:
|
gdbserver:
|
||||||
pyocd gdbserver --target nrf52840 --port 3333
|
pyocd gdbserver --target nrf52840 --port 3333
|
||||||
|
|
||||||
# remove build artifacts
|
# remove build artifacts and generated docs
|
||||||
clean:
|
clean:
|
||||||
rm -rf {{build_dir}}
|
rm -rf {{build_dir}} docs
|
||||||
|
|
||||||
# remove build artifacts AND the container image
|
# remove build artifacts, docs AND the container image
|
||||||
clean-all: clean
|
clean-all: clean
|
||||||
{{engine}} rmi {{image}} 2>/dev/null || true
|
{{engine}} rmi {{image}} 2>/dev/null || true
|
||||||
|
|||||||
16
src/fhss.c
16
src/fhss.c
@@ -1,13 +1,15 @@
|
|||||||
|
/** @file fhss.c
|
||||||
|
* @brief FHSS channel sequencer implementation.
|
||||||
|
*/
|
||||||
#include "fhss.h"
|
#include "fhss.h"
|
||||||
#include <aes.h>
|
#include <aes.h>
|
||||||
|
|
||||||
#define FHSS_CHANNELS 40u
|
#define FHSS_CHANNELS 40u
|
||||||
#define FHSS_DWELL_MS 2u
|
#define FHSS_DWELL_MS 2u
|
||||||
|
|
||||||
/* TODO: replace with a real shared secret before deployment */
|
/* TODO: replace with a real shared secret before deployment */
|
||||||
static const uint8_t shared_key[16] = {
|
static const uint8_t shared_key[16] = {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t slot;
|
static uint32_t slot;
|
||||||
@@ -25,11 +27,11 @@ uint8_t fhss_next_channel(void)
|
|||||||
/* encode slot counter big-endian into the AES input block */
|
/* encode slot counter big-endian into the AES input block */
|
||||||
block[0] = (uint8_t)(slot >> 24);
|
block[0] = (uint8_t)(slot >> 24);
|
||||||
block[1] = (uint8_t)(slot >> 16);
|
block[1] = (uint8_t)(slot >> 16);
|
||||||
block[2] = (uint8_t)(slot >> 8);
|
block[2] = (uint8_t)(slot >> 8);
|
||||||
block[3] = (uint8_t)(slot );
|
block[3] = (uint8_t)(slot);
|
||||||
|
|
||||||
AES_init_ctx(&ctx, shared_key);
|
AES_init_ctx(&ctx, shared_key);
|
||||||
AES_ECB_encrypt(&ctx, block); /* encrypts block in-place */
|
AES_ECB_encrypt(&ctx, block); /* encrypts block in-place */
|
||||||
|
|
||||||
slot++;
|
slot++;
|
||||||
return block[0] % FHSS_CHANNELS;
|
return block[0] % FHSS_CHANNELS;
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
/** @file main.c
|
||||||
|
* @brief Entry point: initialise peripherals and run the PTT event loop.
|
||||||
|
*/
|
||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
static const uint8_t test_frame[] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
static const uint8_t test_frame[] = {0xDE, 0xAD, 0xBE, 0xEF};
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
|||||||
16
src/power.c
16
src/power.c
@@ -1,10 +1,13 @@
|
|||||||
|
/** @file power.c
|
||||||
|
* @brief Power management implementation.
|
||||||
|
*/
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include "regs.h"
|
#include "regs.h"
|
||||||
#include <nrf52840.h>
|
#include <nrf52840.h>
|
||||||
#include <cmsis_gcc.h>
|
#include <cmsis_gcc.h>
|
||||||
|
|
||||||
/* P0.02 on XIAO BLE - adjust to match your schematic */
|
/* P0.02 on XIAO BLE - adjust to match your schematic */
|
||||||
#define BUTTON_PIN 2u
|
#define BUTTON_PIN 2u
|
||||||
|
|
||||||
void power_init(void)
|
void power_init(void)
|
||||||
{
|
{
|
||||||
@@ -13,14 +16,13 @@ void power_init(void)
|
|||||||
|
|
||||||
NRF_GPIOTE->CONFIG[0] = (gpiote_config_t){
|
NRF_GPIOTE->CONFIG[0] = (gpiote_config_t){
|
||||||
.bit = {
|
.bit = {
|
||||||
.MODE = GPIOTE_MODE_EVENT,
|
.MODE = GPIOTE_MODE_EVENT,
|
||||||
.PSEL = BUTTON_PIN,
|
.PSEL = BUTTON_PIN,
|
||||||
.PORT = 0u,
|
.PORT = 0u,
|
||||||
.POLARITY = GPIOTE_POL_LOTOHI,
|
.POLARITY = GPIOTE_POL_LOTOHI,
|
||||||
}
|
}}.reg;
|
||||||
}.reg;
|
|
||||||
|
|
||||||
NRF_GPIOTE->INTENSET = (gpiote_inten_t){ .bit.IN0 = 1u }.reg;
|
NRF_GPIOTE->INTENSET = (gpiote_inten_t){.bit.IN0 = 1u}.reg;
|
||||||
|
|
||||||
NVIC_EnableIRQ(GPIOTE_IRQn);
|
NVIC_EnableIRQ(GPIOTE_IRQn);
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/radio.c
62
src/radio.c
@@ -1,3 +1,6 @@
|
|||||||
|
/** @file radio.c
|
||||||
|
* @brief RADIO peripheral driver implementation.
|
||||||
|
*/
|
||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
#include "regs.h"
|
#include "regs.h"
|
||||||
#include <nrf52840.h>
|
#include <nrf52840.h>
|
||||||
@@ -13,8 +16,8 @@
|
|||||||
* TX is synchronous: function returns after EVENTS_END fires.
|
* TX is synchronous: function returns after EVENTS_END fires.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MAX_PAYLOAD 255u
|
#define MAX_PAYLOAD 255u
|
||||||
#define BUF_SIZE (1u + MAX_PAYLOAD)
|
#define BUF_SIZE (1u + MAX_PAYLOAD)
|
||||||
|
|
||||||
static uint8_t pkt_buf[BUF_SIZE];
|
static uint8_t pkt_buf[BUF_SIZE];
|
||||||
|
|
||||||
@@ -22,59 +25,52 @@ static uint8_t pkt_buf[BUF_SIZE];
|
|||||||
#define DEFAULT_CHANNEL 20u
|
#define DEFAULT_CHANNEL 20u
|
||||||
|
|
||||||
/* 4-byte base address (3-byte BALEN field means 3+1=4 total address bytes) */
|
/* 4-byte base address (3-byte BALEN field means 3+1=4 total address bytes) */
|
||||||
#define RADIO_BASE0 0x12345678u
|
#define RADIO_BASE0 0x12345678u
|
||||||
#define RADIO_PREFIX0 0xABu /* logical address 0: RADIO_BASE0 + RADIO_PREFIX0[7:0] */
|
#define RADIO_PREFIX0 0xABu /* logical address 0: RADIO_BASE0 + RADIO_PREFIX0[7:0] */
|
||||||
|
|
||||||
void radio_init(void)
|
void radio_init(void)
|
||||||
{
|
{
|
||||||
NRF_RADIO->MODE = (radio_mode_t){
|
NRF_RADIO->MODE = (radio_mode_t){.bit = {.MODE = RADIO_MODE_NRF_1MBIT}}.reg;
|
||||||
.bit = { .MODE = RADIO_MODE_NRF_1MBIT }
|
|
||||||
}.reg;
|
|
||||||
|
|
||||||
/* 8-bit LENGTH field, no S0/S1, 8-bit preamble, CRC not part of LENGTH */
|
/* 8-bit LENGTH field, no S0/S1, 8-bit preamble, CRC not part of LENGTH */
|
||||||
NRF_RADIO->PCNF0 = (radio_pcnf0_t){
|
NRF_RADIO->PCNF0 =
|
||||||
.bit = { .LFLEN = 8, .S0LEN = 0, .S1LEN = 0, .PLEN = 0, .CRCINC = 0 }
|
(radio_pcnf0_t){.bit = {.LFLEN = 8, .S0LEN = 0, .S1LEN = 0, .PLEN = 0, .CRCINC = 0}}.reg;
|
||||||
}.reg;
|
|
||||||
|
|
||||||
/* max 255-byte payload, 3-byte base address, little-endian, no whitening */
|
/* max 255-byte payload, 3-byte base address, little-endian, no whitening */
|
||||||
NRF_RADIO->PCNF1 = (radio_pcnf1_t){
|
NRF_RADIO->PCNF1 =
|
||||||
.bit = { .MAXLEN = MAX_PAYLOAD, .STATLEN = 0, .BALEN = 3,
|
(radio_pcnf1_t){
|
||||||
.ENDIAN = 0, .WHITEEN = 0 }
|
.bit = {.MAXLEN = MAX_PAYLOAD, .STATLEN = 0, .BALEN = 3, .ENDIAN = 0, .WHITEEN = 0}}
|
||||||
}.reg;
|
.reg;
|
||||||
|
|
||||||
NRF_RADIO->BASE0 = RADIO_BASE0;
|
NRF_RADIO->BASE0 = RADIO_BASE0;
|
||||||
NRF_RADIO->PREFIX0 = RADIO_PREFIX0;
|
NRF_RADIO->PREFIX0 = RADIO_PREFIX0;
|
||||||
NRF_RADIO->TXADDRESS = 0; /* transmit on logical address 0 */
|
NRF_RADIO->TXADDRESS = 0; /* transmit on logical address 0 */
|
||||||
NRF_RADIO->RXADDRESSES = 1; /* receive on logical address 0 */
|
NRF_RADIO->RXADDRESSES = 1; /* receive on logical address 0 */
|
||||||
|
|
||||||
/* 2-byte CRC, skip address field */
|
/* 2-byte CRC, skip address field */
|
||||||
NRF_RADIO->CRCCNF = (radio_crccnf_t){
|
NRF_RADIO->CRCCNF = (radio_crccnf_t){.bit = {.LEN = RADIO_CRCCNF_LEN_TWO, .SKIPADDR = 1}}.reg;
|
||||||
.bit = { .LEN = RADIO_CRCCNF_LEN_TWO, .SKIPADDR = 1 }
|
NRF_RADIO->CRCPOLY = 0x11021u; /* CRC-16/CCITT */
|
||||||
}.reg;
|
|
||||||
NRF_RADIO->CRCPOLY = 0x11021u; /* CRC-16/CCITT */
|
|
||||||
NRF_RADIO->CRCINIT = 0xFFFFu;
|
NRF_RADIO->CRCINIT = 0xFFFFu;
|
||||||
|
|
||||||
NRF_RADIO->TXPOWER = (radio_txpower_t){
|
NRF_RADIO->TXPOWER =
|
||||||
.bit = { .TXPOWER = 0 } /* 0 dBm */
|
(radio_txpower_t){
|
||||||
}.reg;
|
.bit = {.TXPOWER = 0} /* 0 dBm */
|
||||||
|
}
|
||||||
|
.reg;
|
||||||
|
|
||||||
NRF_RADIO->FREQUENCY = (radio_frequency_t){
|
NRF_RADIO->FREQUENCY =
|
||||||
.bit = { .FREQUENCY = DEFAULT_CHANNEL, .MAP = RADIO_MAP_DEFAULT }
|
(radio_frequency_t){.bit = {.FREQUENCY = DEFAULT_CHANNEL, .MAP = RADIO_MAP_DEFAULT}}.reg;
|
||||||
}.reg;
|
|
||||||
|
|
||||||
/* READY -> START and END -> DISABLE shortcuts so CPU only triggers TXEN */
|
/* READY -> START and END -> DISABLE shortcuts so CPU only triggers TXEN */
|
||||||
NRF_RADIO->SHORTS = (radio_shorts_t){
|
NRF_RADIO->SHORTS = (radio_shorts_t){.bit = {.READY_START = 1, .END_DISABLE = 1}}.reg;
|
||||||
.bit = { .READY_START = 1, .END_DISABLE = 1 }
|
|
||||||
}.reg;
|
|
||||||
|
|
||||||
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf;
|
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void radio_set_channel(uint8_t ch)
|
void radio_set_channel(uint8_t ch)
|
||||||
{
|
{
|
||||||
NRF_RADIO->FREQUENCY = (radio_frequency_t){
|
NRF_RADIO->FREQUENCY =
|
||||||
.bit = { .FREQUENCY = ch, .MAP = RADIO_MAP_DEFAULT }
|
(radio_frequency_t){.bit = {.FREQUENCY = ch, .MAP = RADIO_MAP_DEFAULT}}.reg;
|
||||||
}.reg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void radio_tx(const uint8_t *data, uint8_t len)
|
void radio_tx(const uint8_t *data, uint8_t len)
|
||||||
|
|||||||
136
src/startup.c
136
src/startup.c
@@ -1,12 +1,15 @@
|
|||||||
|
/** @file startup.c
|
||||||
|
* @brief Vector table and Reset_Handler for nRF52840 (no SoftDevice).
|
||||||
|
*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/* linker script symbols */
|
/* linker script symbols */
|
||||||
extern uint32_t _sidata; /* load address of .data in Flash */
|
extern uint32_t _sidata; /* load address of .data in Flash */
|
||||||
extern uint32_t _sdata; /* start of .data in RAM */
|
extern uint32_t _sdata; /* start of .data in RAM */
|
||||||
extern uint32_t _edata; /* end of .data in RAM */
|
extern uint32_t _edata; /* end of .data in RAM */
|
||||||
extern uint32_t _sbss;
|
extern uint32_t _sbss;
|
||||||
extern uint32_t _ebss;
|
extern uint32_t _ebss;
|
||||||
extern uint32_t _estack; /* address equals initial SP value */
|
extern uint32_t _estack; /* address equals initial SP value */
|
||||||
|
|
||||||
extern int main(void);
|
extern int main(void);
|
||||||
|
|
||||||
@@ -14,71 +17,73 @@ void Reset_Handler(void);
|
|||||||
|
|
||||||
static void __attribute__((used)) Default_Handler(void)
|
static void __attribute__((used)) Default_Handler(void)
|
||||||
{
|
{
|
||||||
while (1);
|
while (1)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARM Cortex-M4 core exceptions */
|
/* ARM Cortex-M4 core exceptions */
|
||||||
void NMI_Handler(void) __attribute__((weak, alias("Default_Handler")));
|
void NMI_Handler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void HardFault_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 MemManage_Handler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void BusFault_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 UsageFault_Handler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SVC_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 DebugMon_Handler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void PendSV_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")));
|
void SysTick_Handler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
|
|
||||||
/* nRF52840 peripheral IRQs (IRQ0-IRQ47) */
|
/* nRF52840 peripheral IRQs (IRQ0-IRQ47) */
|
||||||
void POWER_CLOCK_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void POWER_CLOCK_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void RADIO_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 UARTE0_UART0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void)
|
||||||
void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
__attribute__((weak, alias("Default_Handler")));
|
||||||
void NFCT_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void)
|
||||||
void GPIOTE_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
__attribute__((weak, alias("Default_Handler")));
|
||||||
void SAADC_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void NFCT_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void TIMER0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void GPIOTE_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void TIMER1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SAADC_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void TIMER2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void TIMER0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void RTC0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void TIMER1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void TEMP_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void TIMER2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void RNG_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void RTC0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void ECB_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void TEMP_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void CCM_AAR_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void RNG_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void WDT_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void ECB_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void RTC1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void CCM_AAR_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void QDEC_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void WDT_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void COMP_LPCOMP_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void RTC1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SWI0_EGU0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void QDEC_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SWI1_EGU1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void COMP_LPCOMP_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SWI2_EGU2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SWI0_EGU0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SWI3_EGU3_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SWI1_EGU1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SWI4_EGU4_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SWI2_EGU2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SWI5_EGU5_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SWI3_EGU3_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void TIMER3_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SWI4_EGU4_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void TIMER4_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SWI5_EGU5_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void PWM0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void TIMER3_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void PDM_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void TIMER4_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void MWU_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void PWM0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void PWM1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void PDM_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void PWM2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void MWU_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SPIM2_SPIS2_SPI2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void PWM1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void RTC2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void PWM2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void I2S_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void SPIM2_SPIS2_SPI2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void FPU_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void RTC2_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void USBD_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void I2S_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void UARTE1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void FPU_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void QSPI_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void USBD_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void CRYPTOCELL_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void UARTE1_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void PWM3_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
void QSPI_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
|
||||||
void SPIM3_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) */
|
/* vector table: 64 entries (16 core + 48 IRQs) */
|
||||||
|
|
||||||
typedef void (*vector_fn)(void);
|
typedef void (*vector_fn)(void);
|
||||||
|
|
||||||
__attribute__((section(".isr_vector"), used))
|
__attribute__((section(".isr_vector"), used)) const vector_fn vectors[64] = {
|
||||||
const vector_fn vectors[64] = {
|
|
||||||
/* 0 */ (vector_fn)&_estack,
|
/* 0 */ (vector_fn)&_estack,
|
||||||
/* 1 */ Reset_Handler,
|
/* 1 */ Reset_Handler,
|
||||||
/* 2 */ NMI_Handler,
|
/* 2 */ NMI_Handler,
|
||||||
@@ -126,8 +131,8 @@ const vector_fn vectors[64] = {
|
|||||||
/* IRQ27 */ TIMER4_IRQHandler,
|
/* IRQ27 */ TIMER4_IRQHandler,
|
||||||
/* IRQ28 */ PWM0_IRQHandler,
|
/* IRQ28 */ PWM0_IRQHandler,
|
||||||
/* IRQ29 */ PDM_IRQHandler,
|
/* IRQ29 */ PDM_IRQHandler,
|
||||||
/* IRQ30 */ 0, /* reserved */
|
/* IRQ30 */ 0, /* reserved */
|
||||||
/* IRQ31 */ 0, /* reserved */
|
/* IRQ31 */ 0, /* reserved */
|
||||||
/* IRQ32 */ MWU_IRQHandler,
|
/* IRQ32 */ MWU_IRQHandler,
|
||||||
/* IRQ33 */ PWM1_IRQHandler,
|
/* IRQ33 */ PWM1_IRQHandler,
|
||||||
/* IRQ34 */ PWM2_IRQHandler,
|
/* IRQ34 */ PWM2_IRQHandler,
|
||||||
@@ -139,10 +144,10 @@ const vector_fn vectors[64] = {
|
|||||||
/* IRQ40 */ UARTE1_IRQHandler,
|
/* IRQ40 */ UARTE1_IRQHandler,
|
||||||
/* IRQ41 */ QSPI_IRQHandler,
|
/* IRQ41 */ QSPI_IRQHandler,
|
||||||
/* IRQ42 */ CRYPTOCELL_IRQHandler,
|
/* IRQ42 */ CRYPTOCELL_IRQHandler,
|
||||||
/* IRQ43 */ 0, /* reserved */
|
/* IRQ43 */ 0, /* reserved */
|
||||||
/* IRQ44 */ 0, /* reserved */
|
/* IRQ44 */ 0, /* reserved */
|
||||||
/* IRQ45 */ PWM3_IRQHandler,
|
/* IRQ45 */ PWM3_IRQHandler,
|
||||||
/* IRQ46 */ 0, /* reserved */
|
/* IRQ46 */ 0, /* reserved */
|
||||||
/* IRQ47 */ SPIM3_IRQHandler,
|
/* IRQ47 */ SPIM3_IRQHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -153,16 +158,19 @@ void Reset_Handler(void)
|
|||||||
/* copy .data initializers from Flash to RAM */
|
/* copy .data initializers from Flash to RAM */
|
||||||
uint32_t *src = &_sidata;
|
uint32_t *src = &_sidata;
|
||||||
uint32_t *dst = &_sdata;
|
uint32_t *dst = &_sdata;
|
||||||
|
// cppcheck-suppress comparePointers
|
||||||
while (dst < &_edata) {
|
while (dst < &_edata) {
|
||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* zero .bss */
|
/* zero .bss */
|
||||||
dst = &_sbss;
|
dst = &_sbss;
|
||||||
|
// cppcheck-suppress comparePointers
|
||||||
while (dst < &_ebss) {
|
while (dst < &_ebss) {
|
||||||
*dst++ = 0u;
|
*dst++ = 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
while (1);
|
while (1)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user